学习目标

  1. 理解I2C通讯原理
  2. 理解I2C通讯过程中的信号
  3. 理解软件I2C实现过程
  4. 理解硬件I2C的工作内容

    学习内容

    I2C通讯规则

    041.png
    I2C总线包括两根信号线:SDA(串行数据线)和SCL(串行时钟线)。这两根信号线共用一个总线,因此在总线上可以连接多个设备。在I2C总线上,每个设备都有一个唯一的地址,用于标识设备。
    SCL线是时钟线,用于控制数据传输的速度和时序;SDA线是数据线,用于传输实际的数据.

    I2C写操作

    流程如下:

  5. 开始。

  6. 发送设备地址,等待从设备响应
  7. 发送寄存器地址,等待从设备响应
  8. 发送一个字节,等待从设备响应。这个操作是循环执行,直到没有数据。
  9. 停止。

031.png

I2C读流程

流程如下:

  1. 开始。
  2. 发送设备地址(写地址),等待从设备响应
  3. 发送寄存器地址,等待从设备响应。
  4. 开始
  5. 发送设备地址(读地址),等待从设备响应
  6. 接收一个字节,发送响应给从设备。这个操作是循环执行,直到没有数据。当是最后一个数据时,发送空响应。
  7. 停止。

32.png

通讯信号

开始

033.png

  1. static void start() {
  2. SDA_OUT();
  3. SDA(1);
  4. delay_1us(5);
  5. SCL(1);
  6. delay_1us(5);
  7. SDA(0);
  8. delay_1us(5);
  9. SCL(0);
  10. delay_1us(5);
  11. }

结束

034.png

  1. static void stop() {
  2. SDA_OUT();
  3. SCL(0);
  4. SDA(0);
  5. SCL(1);
  6. delay_1us(5);
  7. SDA(1);
  8. delay_1us(5);
  9. }

发送数据

bit发送

035.png
数据有效性:

  • SCL上升沿到下降沿这个阶段,SDA电平的高低,表示数据bit的1和0
  • 如果SDA电平在这个阶段发生变化,则无效,参考start和stop信号。

    Byte发送

    基于数据有效性,将byte按bit位变化为高低电平,发送出去。
    091.png

    1. static void send(uint8_t data) {
    2. uint8_t i;
    3. SDA_OUT();
    4. for(i = 0; i < 8; i++) {
    5. if(data & 0x80) {
    6. SDA(1);
    7. } else {
    8. SDA(0);
    9. }
    10. SCL(1);
    11. delay_1us(5);
    12. SCL(0);
    13. delay_1us(5);
    14. data <<= 1;
    15. }
    16. }

等待响应

wait ack:_Ack_nowledge character。表示等待响应,每发送一个数据,需要确认对方是否收到,就需要等待对方响应。
image.png

  1. static uint8_t wait_ack() {
  2. int8_t retry = 10;
  3. SCL(0);
  4. SDA(1);
  5. SDA_IN();
  6. delay_1us(5);
  7. SCL(1);
  8. delay_1us(5);
  9. while(SDA_STATE() == 1 && retry > 0) {
  10. retry --;
  11. delay_1us(5);
  12. }
  13. if(retry <= 0) {
  14. stop();
  15. return 1;
  16. } else {
  17. SCL(0);
  18. SDA_OUT();
  19. }
  20. return 0;
  21. }

接收数据

bit接收

039.png

Byte接收

092.png

  1. static uint8_t recv() {
  2. uint8_t i, data;
  3. SDA_IN();
  4. data = 0;
  5. for(i = 0; i < 8; i++) {
  6. SCL(0);
  7. delay_1us(5);
  8. SCL(1);
  9. delay_1us(5);
  10. data <<= 1;
  11. data |= SDA_STATE();
  12. delay_1us(5);
  13. }
  14. SCL(0);
  15. return data;
  16. }

发送响应

112.png

  1. static void send_ack() {
  2. SDA_OUT();
  3. SCL(0);
  4. SDA(0);
  5. delay_1us(5);
  6. SDA(0);
  7. SCL(1);
  8. delay_1us(5);
  9. SCL(0);
  10. SDA(1);
  11. }
  1. static void send_nack() {
  2. SDA_OUT();
  3. SCL(0);
  4. SDA(0);
  5. delay_1us(5);
  6. SDA(1);
  7. SCL(1);
  8. delay_1us(5);
  9. SCL(0);
  10. SDA(1);
  11. }

软件I2C

开发流程

  1. 引脚初始化
  2. 引脚功能定义
  3. 实现读操作
  4. 实现写操作

    GD32F4软件I2C初始化

    1. void SoftI2C_init() {
    2. // 时钟配置
    3. rcu_periph_clock_enable(SCL_RCU);
    4. // 设置输出模式
    5. gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCL_PIN);
    6. gpio_output_options_set(SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, SCL_PIN);
    7. // 时钟配置
    8. rcu_periph_clock_enable(SDA_RCU);
    9. // 设置输出模式
    10. gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN);
    11. gpio_output_options_set(SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, SDA_PIN);
    12. }
  • I2C引脚高低电平

    GD32F4软件I2C引脚功能

    ```c

    define SCL_RCU RCU_GPIOB

    define SCL_PORT GPIOB

    define SCL_PIN GPIO_PIN_6

    define SCL_AF GPIO_AF_4

define SDA_RCU RCU_GPIOB

define SDA_PORT GPIOB

define SDA_PIN GPIO_PIN_7

define SDA_AF GPIO_AF_4

/** io */

define SCL(BIT) gpio_bit_write(SCL_PORT, SCL_PIN, BIT?SET:RESET)

define SDA(BIT) gpio_bit_write(SDA_PORT, SDA_PIN, BIT?SET:RESET)

define SDA_STATE() gpio_input_bit_get(SDA_PORT, SDA_PIN)

define SDA_IN() gpio_mode_set(SDA_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SDA_PIN)

define SDA_OUT() gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN)

  1. - IO引脚定义
  2. - 引脚输出模式高低电平输出:SCL高和低,SDA高和低
  3. - SDA模式配置:SDA输出模式,SDA输入模式
  4. - SDA输入模式状态读取。
  5. <a name="tWatG"></a>
  6. #### 写操作
  7. ![031.png](https://cdn.nlark.com/yuque/0/2023/png/27903758/1692842768446-3c8ee866-5cbf-4ef6-820e-3fc85b744592.png#averageHue=%23140a04&clientId=uff3818e1-2c0e-4&from=ui&height=425&id=u42a0aaa4&originHeight=760&originWidth=442&originalType=binary&ratio=1&rotation=0&showTitle=false&size=194479&status=done&style=none&taskId=u6e0b107f-f9ad-4c5b-99e3-7e152dffed5&title=&width=247)
  8. ```c
  9. uint8_t SoftI2C_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
  10. start();
  11. send(addr << 1); //发送设备写地址
  12. if(wait_ack()) return 1; //等待响应
  13. send(reg); //发送寄存器地址
  14. if(wait_ack()) return 2; //等待响应
  15. do {
  16. send(*data++);
  17. if(wait_ack()) return 3;
  18. } while(--len);
  19. stop();
  20. return 0;
  21. }

读操作

32.png

  1. uint8_t SoftI2C_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
  2. start();
  3. send(addr << 1); //发送设备写地址
  4. if(wait_ack()) return 1; //等待响应
  5. send(reg); //发送寄存器地址
  6. if(wait_ack()) return 2; //等待响应
  7. start();
  8. send((addr << 1) | 0x01); //发送设备读地址
  9. if(wait_ack()) return 3; //等待响应
  10. do {
  11. *data = recv();
  12. data++;
  13. if(len != 1) send_ack(); // 发送 NACK
  14. } while(--len);
  15. send_nack(); // 发送 NACK
  16. stop();
  17. return 0;
  18. }

硬件I2C-GD32F4系列

初始化操作

  1. uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
  2. uint32_t i2cx_scl_port = GPIOB;
  3. uint32_t i2cx_scl_pin = GPIO_PIN_6;
  4. uint32_t i2cx_scl_af = GPIO_AF_4;
  5. uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
  6. uint32_t i2cx_sda_port = GPIOB;
  7. uint32_t i2cx_sda_pin = GPIO_PIN_7;
  8. uint32_t i2cx_sda_af = GPIO_AF_4;
  9. uint32_t i2cx = I2C0;
  10. uint32_t i2cx_rcu = RCU_I2C0;
  11. uint32_t i2cx_speed = 400000;
  12. /****************** GPIO config **********************/
  13. // 时钟配置
  14. rcu_periph_clock_enable(i2cx_scl_port_rcu);
  15. // 设置复用功能
  16. gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
  17. // 设置输出模式
  18. gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
  19. gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);
  20. // 时钟配置
  21. rcu_periph_clock_enable(i2cx_sda_port_rcu);
  22. // 设置复用功能
  23. gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
  24. // 设置输出模式
  25. gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
  26. gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);
  27. /****************** I2C config **********************/
  28. i2c_deinit(i2cx);
  29. // 时钟配置
  30. rcu_periph_clock_enable(i2cx_rcu);
  31. // I2C速率配置
  32. i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);
  33. // 使能i2c
  34. i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
  35. i2c_enable(i2cx);
  36. // i2c ack enable
  37. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  • 哪个I2C
  • SCL是哪个引脚
  • SDA是哪个引脚
  • 速度是多快

    写操作流程

    开始
    ```c /* start */ // 等待I2C闲置 if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

// start i2c_start_on_bus(i2cx);

// 等待I2C主设备成功发送起始信号 if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;

  1. <a name="WtaJX"></a>
  2. ##### 发送设备地址
  3. ```c
  4. /************* device address **************/
  5. // 发送设备地址
  6. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  7. // 等待地址发送完成
  8. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  9. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

发送寄存器地址
  1. /************ register address ************/
  2. // 寄存器地址
  3. // 等待发送数据缓冲区为空
  4. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  5. // 发送数据
  6. i2c_data_transmit(i2cx, reg);
  7. // 等待数据发送完成
  8. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;

数据发送
  1. /***************** data ******************/
  2. // 发送数据
  3. uint32_t i;
  4. for(i = 0; i < data_len; i++) {
  5. uint32_t d = data[i];
  6. // 等待发送数据缓冲区为空
  7. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
  8. // 发送数据
  9. i2c_data_transmit(i2cx, d);
  10. // 等待数据发送完成
  11. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
  12. }

停止
  1. /***************** stop ********************/
  2. // stop
  3. i2c_stop_on_bus(i2cx);
  4. if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;

读操作流程

开始
  1. /************* start ***********************/
  2. // 等待I2C空闲
  3. if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
  4. // 发送启动信号
  5. i2c_start_on_bus(i2cx);
  6. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;

发送设备地址(写)
  1. /************* device address **************/
  2. // 发送从设备地址
  3. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  4. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  5. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

发送寄存器地址
  1. /********** register address **************/
  2. // 等待发送缓冲区
  3. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  4. // 发送寄存器地址
  5. i2c_data_transmit(i2cx, reg);
  6. // 等待发送数据完成
  7. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
  8. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

开始
  1. /************* start ***********************/
  2. // 发送再启动信号
  3. i2c_start_on_bus(i2cx);
  4. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;

发送设备地址(读)
  1. /************* device address **************/
  2. // 发送从设备地址
  3. i2c_master_addressing(i2cx, address, I2C_RECEIVER);
  4. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
  5. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  6. //ack
  7. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  8. i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  9. if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;

数据读取
  1. /************* data **************/
  2. //ack
  3. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  4. i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  5. if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;
  6. // 读取数据
  7. uint8_t i;
  8. for (i = 0; i < len; i++) {
  9. if(i != len - 1) {
  10. // 等待接收缓冲区
  11. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
  12. }
  13. // 等待ACK数据发送完成
  14. // 等待接收缓冲区
  15. if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
  16. data[i] = i2c_data_receive(i2cx);
  17. if (i == len - 1) {
  18. // 在读取最后一个字节之前,禁用ACK,并发送停止信号
  19. // 配置自动NACK
  20. i2c_ack_config(i2cx, I2C_ACK_DISABLE);
  21. }
  22. }

结束
  1. /***************** stop ********************/
  2. i2c_stop_on_bus(i2cx);
  3. if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;

GD32F4寄存器

流程 功能 标记 描述
START I2C_FLAG_I2CBSY busy标记。I2C是否占用,没有占用才可以使用。
I2C_FLAG_SBSEND 起始信号发送状态标记。START成功或失败。
数据 设备地址 I2C_FLAG_ADDSEND 地址发送状态标记。成功或失败。
发送 I2C_FLAG_TBE 发送数据寄存器是否为空的标记。为空才可以继续发送。
I2C_FLAG_BTC 发送数据寄存器中数据是否发送完成。
接收 I2C_FLAG_RBNE 接收缓冲区寄存器是否为空的标记。为空才可以继续接收。
STOP I2C_CTL0_STOP 停止标记位。

完整代码

  1. #ifndef __I2C0_H__
  2. #define __I2C0_H__
  3. #include "systick.h"
  4. #include "gd32f4xx.h"
  5. void I2C0_init();
  6. uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);
  7. uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);
  8. uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len);
  9. void I2C0_deinit();
  10. #endif
  1. #include "I2C0.h"
  2. void I2C0_init() {
  3. uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
  4. uint32_t i2cx_scl_port = GPIOB;
  5. uint32_t i2cx_scl_pin = GPIO_PIN_6;
  6. uint32_t i2cx_scl_af = GPIO_AF_4;
  7. uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
  8. uint32_t i2cx_sda_port = GPIOB;
  9. uint32_t i2cx_sda_pin = GPIO_PIN_7;
  10. uint32_t i2cx_sda_af = GPIO_AF_4;
  11. uint32_t i2cx = I2C0;
  12. uint32_t i2cx_rcu = RCU_I2C0;
  13. uint32_t i2cx_speed = 400000;
  14. /****************** GPIO config **********************/
  15. // 时钟配置
  16. rcu_periph_clock_enable(i2cx_scl_port_rcu);
  17. // 设置复用功能
  18. gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
  19. // 设置输出模式
  20. gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
  21. gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);
  22. // 时钟配置
  23. rcu_periph_clock_enable(i2cx_sda_port_rcu);
  24. // 设置复用功能
  25. gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
  26. // 设置输出模式
  27. gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
  28. gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);
  29. /****************** I2C config **********************/
  30. i2c_deinit(i2cx);
  31. // 时钟配置
  32. rcu_periph_clock_enable(i2cx_rcu);
  33. // I2C速率配置
  34. i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);
  35. // 使能i2c
  36. i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
  37. i2c_enable(i2cx);
  38. // i2c ack enable
  39. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  40. //i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  41. }
  42. static uint8_t I2C_wait(uint32_t i2cx, uint32_t flag) {
  43. uint16_t TIMEOUT = 50000;
  44. uint16_t cnt = 0;
  45. while(!i2c_flag_get(i2cx, flag)) {
  46. cnt++;
  47. if(cnt > TIMEOUT) return 1;
  48. }
  49. return 0;
  50. }
  51. static uint8_t I2C_waitn(uint32_t i2cx, uint32_t flag) {
  52. uint16_t TIMEOUT = 50000;
  53. uint16_t cnt = 0;
  54. while(i2c_flag_get(i2cx, flag)) {
  55. cnt++;
  56. if(cnt > TIMEOUT) return 1;
  57. }
  58. return 0;
  59. }
  60. uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t data_len) {
  61. uint32_t i2cx = I2C0;
  62. uint8_t address = addr << 1;
  63. /************* start ***********************/
  64. // 等待I2C闲置
  65. if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
  66. // start
  67. i2c_start_on_bus(i2cx);
  68. // 等待I2C主设备成功发送起始信号
  69. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
  70. /************* device address **************/
  71. // 发送设备地址
  72. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  73. // 等待地址发送完成
  74. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  75. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  76. /************ register address ************/
  77. // 寄存器地址
  78. // 等待发送数据缓冲区为空
  79. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  80. // 发送数据
  81. i2c_data_transmit(i2cx, reg);
  82. // 等待数据发送完成
  83. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
  84. /***************** data ******************/
  85. // 发送数据
  86. uint32_t i;
  87. for(i = 0; i < data_len; i++) {
  88. uint32_t d = data[i];
  89. // 等待发送数据缓冲区为空
  90. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
  91. // 发送数据
  92. i2c_data_transmit(i2cx, d);
  93. // 等待数据发送完成
  94. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
  95. }
  96. /***************** stop ********************/
  97. // stop
  98. i2c_stop_on_bus(i2cx);
  99. if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
  100. return 0;
  101. }
  102. uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len) {
  103. uint32_t i2cx = I2C0;
  104. uint8_t address = addr << 1;
  105. /************* start ***********************/
  106. // 等待I2C闲置
  107. if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
  108. // start
  109. i2c_start_on_bus(i2cx);
  110. // 等待I2C主设备成功发送起始信号
  111. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
  112. /************* device address **************/
  113. // 发送设备地址
  114. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  115. // 等待地址发送完成
  116. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  117. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  118. /************ register address ************/
  119. // 寄存器地址
  120. // 等待发送数据缓冲区为空
  121. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  122. // 发送数据
  123. i2c_data_transmit(i2cx, reg);
  124. // 等待数据发送完成
  125. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
  126. /***************** data ******************/
  127. // 发送数据
  128. do {
  129. // 等待发送数据缓冲区为空
  130. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
  131. // 发送数据
  132. i2c_data_transmit(i2cx, *data);
  133. data += offset;
  134. // 等待数据发送完成
  135. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
  136. } while(--len);
  137. /***************** stop ********************/
  138. // stop
  139. i2c_stop_on_bus(i2cx);
  140. if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
  141. return 0;
  142. }
  143. void I2C0_deinit() {
  144. }
  145. uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
  146. uint32_t i2cx = I2C0;
  147. uint8_t address = addr << 1;
  148. /************* start ***********************/
  149. // 等待I2C空闲
  150. if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
  151. // 发送启动信号
  152. i2c_start_on_bus(i2cx);
  153. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
  154. /************* device address **************/
  155. // 发送从设备地址
  156. i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
  157. // //ack
  158. // i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  159. // i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  160. // if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;
  161. // // i2c_ack_config(i2cx, I2C_ACK_DISABLE);
  162. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
  163. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  164. /********** register address **************/
  165. // 等待发送缓冲区
  166. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
  167. // 发送寄存器地址
  168. i2c_data_transmit(i2cx, reg);
  169. // 等待发送数据完成
  170. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
  171. if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
  172. /************* start ***********************/
  173. // 发送再启动信号
  174. i2c_start_on_bus(i2cx);
  175. if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;
  176. /************* device address **************/
  177. // 发送从设备地址
  178. i2c_master_addressing(i2cx, address, I2C_RECEIVER);
  179. if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
  180. i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
  181. /************* data **************/
  182. //ack
  183. i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  184. i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
  185. if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;
  186. // 读取数据
  187. uint8_t i;
  188. for (i = 0; i < len; i++) {
  189. if(i != len - 1) {
  190. // 等待ACK发送完成
  191. if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
  192. }
  193. // 等待ACK数据发送完成
  194. // 等待接收缓冲区
  195. if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
  196. data[i] = i2c_data_receive(i2cx);
  197. if (i == len - 1) {
  198. // 在读取最后一个字节之前,禁用ACK,并发送停止信号
  199. // 配置自动NACK
  200. //i2c_ackpos_config(i2cx, I2C_ACKPOS_NEXT);
  201. //if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 9;
  202. i2c_ack_config(i2cx, I2C_ACK_DISABLE);
  203. }
  204. }
  205. /***************** stop ********************/
  206. i2c_stop_on_bus(i2cx);
  207. if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;
  208. return 0;
  209. }