Updated Readme with example

This commit is contained in:
Sovichea Tep
2019-07-14 12:48:31 +07:00
parent 98308579ff
commit 34b88ad099
4 changed files with 225 additions and 7 deletions

View File

@@ -1 +1,88 @@
# avr-i2c-library # TWI/I2C Library for AVR
## Description
This library is tested on ATMega328p, but it should work with any AVR compatible microcontroller. To use with other type of ATMega, change the I2C pin definition in `twi_master.h` according the datasheet. In ATMega328p, I2C pins are describe as follows:
```c
#define TW_SCL_PIN PORTC5
#define TW_SDA_PIN PORTC4
```
## Usage
There are 3 functions available for this library:
```c
void tw_init(twi_freq_mode_t twi_freq, bool pullup_en);
```
Initialize I2C with predefined frequency and enable internal pull-up resistors. There are 3 mode of frequency to choose from: `TW_FREQ_100K`, `TW_FREQ_250K` and `TW_FREQ_400K`. Then set `pullup_en` bit to `true` to enable internal pull-up resistors on `SCL` and `SDA` pin, or set it to `false` if external pull-up is used.
```c
ret_code_t tw_master_transmit(uint8_t slave_addr, uint8_t* p_data, uint8_t len, bool repeat_start);
```
This function transmits data bytes to a desired slave address. If `repeat_start` bit is set to `true`, I2C module will send REPEATED START condition instead of STOP condition. This is useful in multi-master environment where one Master sends a command and wait for response from slave without having to release the Bus, thus preventing the other Master from taking control of the Bus in between the transaction.
`ret_code_t` is return to the user to handle the state of transmission such as transmission success, arbitration lost, slave acknowledge, etc.
```c
ret_code_t tw_master_receive(uint8_t slave_addr, uint8_t* p_data, uint8_t len);
```
This functions receives the data bytes from the desired slave address and return `ret_code_t` for error handling as have been discussed in `tw_master_transmit`.
## Example
The example provided with this library is tested with MPU6050 to read the value of acceleration in X, Y and Z axis. In order to activate MPU6050, we have to write `0` to `PWR_MGMT_1` register as shown below:
```c
void mpu_init(void)
{
ret_code_t error_code;
puts("Write 0 to PWR_MGMT_1 reg to wakeup MPU.");
uint8_t data[2] = {PWR_MGMT_1, 0};
error_code = tw_master_transmit(MPU6050_ADDR, data, sizeof(data), false);
ERROR_CHECK(error_code);
}
```
In this situation, we want to write the value but don't read back the response; therefore, `repeat_start` bit is set to `false`.
To read the value of accelerometer, we have to transmit the register that we want to read, which is `ACCEL_XOUT_H` then wait for the response using `tw_master_receive` as shown below:
```c
void mpu_get_accel_raw(mpu_data_t* mpu_data)
{
ret_code_t error_code;
/* 2 registers for each of accel x, y and z data */
uint8_t data[6];
data[0] = ACCEL_XOUT_H;
error_code = tw_master_transmit(MPU6050_ADDR, data, 1, true);
ERROR_CHECK(error_code);
error_code = tw_master_receive(MPU6050_ADDR, data, sizeof(data));
ERROR_CHECK(error_code);
/* Default accel config +/- 2g */
mpu_data->x = (int16_t)(data[0] << 8 | data[1]) / 16384.0;
mpu_data->y = (int16_t)(data[2] << 8 | data[3]) / 16384.0;
mpu_data->z = (int16_t)(data[4] << 8 | data[5]) / 16384.0;
}
```
In this situation, since we write and then want to wait for the response from MPU, `repeat_start` bit is set to `true` to prevent other Master from pulling the Bus in between write and read process. This step is, however, not necessary if there is only one Master on the Bus.
## Debugging I2C Transaction
Found in `tw_master.h`, you can set `DEBUG_LOG` variable to `1` or `0` to enable or disable debug functionality of the library. However, this requires that you have UART library included in your project.

View File

@@ -165,7 +165,7 @@ void tw_init(twi_freq_mode_t twi_freq_mode, bool pullup_en)
} }
ret_code_t tw_master_transmit(uint8_t slave_addr, uint8_t* p_data, uint8_t len) ret_code_t tw_master_transmit(uint8_t slave_addr, uint8_t* p_data, uint8_t len, bool repeat_start)
{ {
ret_code_t error_code; ret_code_t error_code;
@@ -193,8 +193,11 @@ ret_code_t tw_master_transmit(uint8_t slave_addr, uint8_t* p_data, uint8_t len)
} }
} }
if (!repeat_start)
{
/* Send STOP condition */ /* Send STOP condition */
tw_stop(); tw_stop();
}
return SUCCESS; return SUCCESS;
} }

View File

@@ -8,10 +8,10 @@
#ifndef TWI_MASTER_H_ #ifndef TWI_MASTER_H_
#define TWI_MASTER_H_ #define TWI_MASTER_H_
#include <avr/io.h> #include <avr/io.h>
#include <util/twi.h> #include <util/twi.h>
#include <stdbool.h> #include <stdbool.h>
#include "uart.h"
#define DEBUG_LOG 0 #define DEBUG_LOG 0
#define SUCCESS 0 #define SUCCESS 0
@@ -33,7 +33,7 @@ typedef enum {
} twi_freq_mode_t; } twi_freq_mode_t;
void tw_init(twi_freq_mode_t twi_freq, bool pullup_en); void tw_init(twi_freq_mode_t twi_freq, bool pullup_en);
ret_code_t tw_master_transmit(uint8_t addr, uint8_t* p_data, uint8_t len); ret_code_t tw_master_transmit(uint8_t slave_addr, uint8_t* p_data, uint8_t len, bool repeat_start);
ret_code_t tw_master_receive(uint8_t addr, uint8_t* p_data, uint8_t len); ret_code_t tw_master_receive(uint8_t slave_addr, uint8_t* p_data, uint8_t len);
#endif /* TWI_MASTER_H_ */ #endif /* TWI_MASTER_H_ */

128
twi_test.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* TWI_Test.c
*
* Created: 08-Jun-19 10:06:47 AM
* Author : TEP SOVICHEA
*/
#include "uart.h"
#include "twi_master.h"
#include <avr/io.h>
#include <util/delay.h>
/************************************************************************/
/* Initializations */
/************************************************************************/
#define MPU6050_ADDR 0x68
/* MPU6050 register address */
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define PWR_MGMT_1 0x6B
typedef struct
{
float x;
float y;
float z;
} mpu_data_t;
/************************************************************************/
/* Prototype functions */
/************************************************************************/
void ERROR_CHECK(ret_code_t error_code);
void mpu_init(void);
void mpu_get_accel_raw(mpu_data_t* mpu_data);
void mpu_get_accel(mpu_data_t* mpu_data);
/************************************************************************/
/* Function definitions */
/************************************************************************/
void ERROR_CHECK(ret_code_t error_code)
{
if (error_code != SUCCESS)
{
/* Print error code and loop indefinitely until reset */
printf(BR "App error! error_code = 0x%02X\n" RESET, error_code);
while (1); // loop indefinitely
}
}
void mpu_init(void)
{
ret_code_t error_code;
puts("Write 0 to PWR_MGMT_1 reg to wakeup MPU.");
uint8_t data[2] = {PWR_MGMT_1, 0};
error_code = tw_master_transmit(MPU6050_ADDR, data, sizeof(data), false);
ERROR_CHECK(error_code);
}
void mpu_get_accel_raw(mpu_data_t* mpu_data)
{
ret_code_t error_code;
/* 2 registers for each of accel x, y and z data */
uint8_t data[6];
data[0] = ACCEL_XOUT_H;
error_code = tw_master_transmit(MPU6050_ADDR, data, 1, true);
ERROR_CHECK(error_code);
error_code = tw_master_receive(MPU6050_ADDR, data, sizeof(data));
ERROR_CHECK(error_code);
/* Default accel config +/- 2g */
mpu_data->x = (int16_t)(data[0] << 8 | data[1]) / 16384.0;
mpu_data->y = (int16_t)(data[2] << 8 | data[3]) / 16384.0;
mpu_data->z = (int16_t)(data[4] << 8 | data[5]) / 16384.0;
}
void mpu_get_accel(mpu_data_t* mpu_data)
{
mpu_get_accel_raw(mpu_data);
mpu_data->x = mpu_data->x * 9.81;
mpu_data->y = mpu_data->y * 9.81;
mpu_data->z = mpu_data->z * 9.81;
}
/************************************************************************/
/* Main application */
/************************************************************************/
int main(void)
{
/* Initialize UART */
uart_init(250000); // bps
cli_reset();
puts(BY "Initializing TWI_Test Project...\n" RESET);
/* Initialize project configuration */
tw_init(TW_FREQ_400K, true); // set I2C Frequency, enable internal pull-up
mpu_init();
mpu_data_t accel;
puts(BG CURSOR_RIGHT("14")
"--------------- Application Started ---------------\n" RESET);
while (1)
{
puts("Read accelerometer data.");
mpu_get_accel(&accel);
printf("Accel X: %5.2f\n", accel.x);
printf("Accel Y: %5.2f\n", accel.y);
printf("Accel Z: %5.2f\n", accel.z);
_delay_ms(200);
}
}