GD32 I2C — I2C 主发从收 DMA

GD32 GD32F30x_Firmware_Library V3.0.3 I2C I2C 主发从收 DMA 示例教学

I2C — I2C 主发从收 DMA

固件库: GD32F30x_Firmware_Library V3.0.3
芯片: GD32
源文件: GD32F30x_Firmware_Library_V3.0.3/Examples/I2C/Master_transmitter&slave_receiver_dma/main.c


功能简介

本示例演示 I2C + DMA 通信。大数据量传输时,DMA 可以大幅降低 CPU 负载。

硬件准备

  • I2C 从设备(如 EEPROM、传感器模块)
  • SCL/SDA 线上需要 4.7K 上拉电阻

完整代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "gd32f30x.h"
#include <stdio.h>
#include "gd32f307c_eval.h"
#define I2C0_SLAVE_ADDRESS7      0x82
#define I2C1_SLAVE_ADDRESS7      0x72
#define ARRAYNUM(arr_nanme)      (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
#define I2C0_DATA_ADDRESS        0x40005410
#define I2C1_DATA_ADDRESS        0x40005810
#define BUFFER_SIZE              (ARRAYNUM(i2c0_buff_tx)-1)

void rcu_config(void);
void gpio_config(void);
void i2c_config(void);
ErrStatus memory_compare(uint8_t *src, uint8_t *dst, uint16_t length);

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    dma_parameter_struct dma_init_struct;

    gd_eval_led_init(LED2);
    gd_eval_led_init(LED3);
    rcu_config();
    gpio_config();
    i2c_config();

    /* initialize DMA channel4 */
    dma_deinit(DMA0, DMA_CH4);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)i2c1_buff_rx;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = BUFFER_SIZE;
    dma_init_struct.periph_addr = I2C1_DATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);

    /* initialize DMA channel5 */
    dma_deinit(DMA0, DMA_CH5);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)i2c0_buff_tx;
    dma_init_struct.periph_addr = I2C0_DATA_ADDRESS;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH5, &dma_init_struct);

    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);

    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));

    /* send slave address to I2C bus*/
    i2c_master_addressing(I2C0, I2C1_SLAVE_ADDRESS7, I2C_TRANSMITTER);

    /* wait until ADDSEND bit is set*/
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    /* clear ADDSEND bit */
    i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
    i2c_flag_clear(I2C1, I2C_FLAG_ADDSEND);

    /* enable I2C1 DMA */
    i2c_dma_config(I2C1, I2C_DMA_ON);
    /* enable I2C0 DMA */
    i2c_dma_config(I2C0, I2C_DMA_ON);
    /* enable DMA0 channel4 */
    dma_channel_enable(DMA0, DMA_CH4);
    /* enable DMA0 channel5 */
    dma_channel_enable(DMA0, DMA_CH5);

    /* DMA0 channel4 full transfer finish flag */
    while(!dma_flag_get(DMA0, DMA_CH4, DMA_FLAG_FTF));
    /* DMA0 channel5 full transfer finish flag */
    while(!dma_flag_get(DMA0, DMA_CH5, DMA_FLAG_FTF));

    /* send a stop condition to I2C bus*/
    i2c_stop_on_bus(I2C0);
    /* wait until stop condition generate */
    while(I2C_CTL0(I2C0) & 0x0200);
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_enable(I2C1);
    state = memory_compare(i2c0_buff_tx, i2c1_buff_rx, BUFFER_SIZE);
    if(SUCCESS == state) {
        gd_eval_led_on(LED2);
        gd_eval_led_on(LED3);
    } else {
        gd_eval_led_off(LED2);
        gd_eval_led_off(LED3);
    }
    while(1) {
    }
}

void rcu_config(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);
    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);
    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA0);
}

void gpio_config(void)
{
    /* connect PB6 to I2C0_SCL */
    /* connect PB7 to I2C0_SDA */
    /* connect PB10 to I2C1_SCL */
    /* connect PB11 to I2C1_SDA */
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11);
}

void i2c_config(void)
{
    /* configure I2C0 clock */
    i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
    /* configure I2C0 address */
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);
    /* configure I2C1 clock */
    i2c_clock_config(I2C1, 100000, I2C_DTCY_2);
    /* configure I2C1 address */
    i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C1_SLAVE_ADDRESS7);
    /* enable I2C1 */
    i2c_enable(I2C1);
    /* enable acknowledge */
    i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}

代码讲解

GPIO 配置:设置引脚为输出/输入模式,选择推挽/开漏输出,配置上拉/下拉。

DMA 配置:设置源地址、目标地址、传输方向、数据宽度。DMA 搬运数据不占用 CPU。

I2C 配置:设置通信速率(标准 100K / 快速 400K / 快速+ 1M)、从机地址、时钟拉伸。

实验现象

  • 主机和从机完成数据收发
  • 校验通过 LED 指示成功

注意事项

  • I2C 总线需要上拉电阻(一般 4.7K)
  • 从机地址要与设备手册一致(注意 7 位/8 位地址的区别)
  • 写 EEPROM 后需要等待 5ms 以上再读
世界是你们
使用 Hugo 构建
主题 StackJimmy 设计