i2c1采用DMA方式的读写函数
1、关于i2c1的DMA的映射如图
 
 2、关于代码的宏定义配置
 Application目录的Makefile中 ENABLE_I2C_TEST = yes才会编译I2C1的相关代码。
 同时修改i2c.h文件,定义I2C1_MODE为I2C1_MODE_DMA,这样i2c1的配置为dma模式。
#define I2C1_MODE                   I2C1_MODE_DMA
3、I2C相关配置,外部调用函数,供main.c初始化i2c1时使用。
 代码如下:
void i2c1_dma_init(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_DMA0);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);
    /* connect PB10 to I2C1_SCL */
    /* connect PB11 to I2C2_SDA */
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);//配置PB10,PB11为复用功能
    /* configure I2C clock */
    i2c_clock_config(I2C1, I2C1_SPEED, I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0xff);
    /* enable I2C1 */
    i2c_enable(I2C1);
    /* enable acknowledge */
    i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}
4、DMA发送函数,可发送多字节寄存器+数据格式。
static void i2c1_dma_tx_config(uint8_t *p_data,uint8_t len)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel3 */
    dma_deinit(DMA0, DMA_CH3);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)p_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = len;
    dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C1);
    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_CH3, &dma_init_struct);
}
static void i2c1_dma_tx_data(uint8_t slave_addr,uint8_t *p_data,uint8_t len)
{
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while( SET != i2c_flag_get(I2C1, I2C_FLAG_TBE));
    i2c1_dma_tx_config(p_data,len);
    
      /* enable I2C1 DMA */
    i2c_dma_config(I2C1, I2C_DMA_ON);
    /* enable DMA0 channel3 */
    dma_channel_enable(DMA0, DMA_CH3);
    /* DMA0 channel3 full transfer finish flag */
    while(!dma_flag_get(DMA0, DMA_CH3, DMA_FLAG_FTF));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C1)&0x0200);  
}
/**
 * 封装一个函数按寄存器写的函数,寄存器地址可以有多位。
 * 数据可以有多个
 * dma方式
*/
void i2c1_dma_send_data(uint8_t slave_addr,uint8_t *reg_addr,
                        uint16_t addr_len,uint8_t *p_data,uint8_t data_len)
{
    uint8_t data[I2C_TX_RX_DATA_LEN_MAX] = {0};
    uint8_t *p;
    if ((addr_len + data_len) > I2C_TX_RX_DATA_LEN_MAX)
    {
        perror("data to long and return\r\n");
        return ;
    }
    p = data;
    memcpy(p,reg_addr,addr_len);
    p += addr_len;
    memcpy(p,p_data,data_len);
    i2c1_dma_tx_data(slave_addr,data,(addr_len+data_len));
}	
5、DMA接收函数封装,注意读取一个自己数据的时候,不能采用dma的方式,在函数中做了判断,一个字节的读取继续用poll方式。
uint8_t i2c1_buff_rx[128];
static void i2c1_dma_rx_config(uint8_t *p_data,uint8_t len)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel4 */
    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)p_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = len;
    dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C1);
    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);
}
void i2c1_dma_receive_data(uint8_t slave_addr, uint8_t *reg_addr,uint16_t addr_len,  
            uint8_t* p_buffer, uint16_t number_of_byte)
{  
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while(SET != i2c_flag_get( I2C1 , I2C_FLAG_TBE));
    /* enable I2C1*/
    i2c_enable(I2C1);
    
    /* send the EEPROM's internal address to write to */
    while (addr_len)
    {
        i2c_data_transmit(I2C1, *reg_addr++); 
        addr_len--; 
        /* wait until BTC bit is set */
        while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
    }
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C1, slave_addr, I2C_RECEIVER);
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
    if(number_of_byte < 2) 
    {
        /* disable acknowledge */
        i2c_ack_config(I2C1, I2C_ACK_DISABLE);
        /* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register (I2C_STAT0 has already been read) */
        i2c_flag_get(I2C1, I2C_FLAG_ADDSEND);
        /* send a stop condition to I2C bus*/
        i2c_stop_on_bus(I2C1);
        /* wait for the byte to be received */
        while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE));
        /* read the byte received from the EEPROM */
        *p_buffer = i2c_data_receive(I2C1);
        /* decrement the read bytes counter */
        number_of_byte--;     
    } 
    else
    {
        i2c1_dma_rx_config(p_buffer,number_of_byte);
        i2c_dma_last_transfer_config(I2C1, I2C_DMALST_ON);
        /* enable I2C1 DMA */
        i2c_dma_config(I2C1, I2C_DMA_ON);
        /* enable DMA0 channel5 */
        dma_channel_enable(DMA0, DMA_CH4);
        /* wait until BTC bit is set */
        while(!dma_flag_get(DMA0, DMA_CH4, DMA_FLAG_FTF));
    }
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C1)&0x0200);
    i2c_stop_on_bus(I2C1);
    /* enable acknowledge */
    i2c_ack_config(I2C1,I2C_ACK_ENABLE);
    i2c_ackpos_config(I2C1,I2C_ACKPOS_CURRENT);
}
5、main.c中调用,往eeprom中写入{0x02,0x07,0x05,0x45,0x56,0x89,0xF3,然后读出来,看看是否一致。
uint8_t addr = 0x00;
unsigned char data[7] = {0x02,0x07,0x05,0x45,0x56,0x89,0xF3};
i2c1_dma_init();
i2c1_dma_send_data(0xA0,&addr,1,data,7);
delay_1ms(200);
unsigned char r_data[7];
i2c1_dma_receive_data(0xA0,&addr,1,r_data,7);
print_register_value(r_data,7);

 读出来是一样的
 6、代码路径:https://gitee.com/xiaoguo-tec_0/gd32-iap-code.git



















