mirror of
https://github.com/Sovichea/avr-i2c-library.git
synced 2025-10-16 07:54:47 +03:00
Updated Readme with example
This commit is contained in:
89
README.md
89
README.md
@@ -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.
|
@@ -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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send STOP condition */
|
if (!repeat_start)
|
||||||
tw_stop();
|
{
|
||||||
|
/* Send STOP condition */
|
||||||
|
tw_stop();
|
||||||
|
}
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
@@ -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
128
twi_test.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user