骑着蜗牛狂奔O 发表于 2022-2-9 22:01

AT32 I2C程序使用讲解

AT32官方BSP里面提供了I2C的使用例程,极大的方便了我们使用I2C,代码位置:BSP里面的project\at_start_f403a\examples\i2c,该路径下有以下四个demo:


communication_dma -- 使用DMA进行传输
communication_int -- 使用中断进行传输
communication_poll -- 使用轮寻的方式传输
eeprom -- eeprom 使用示例


关于I2C传输数据的流程,官方已经封装了一个应用层,用户无需再关心数据传输流程,只需要调用相关接口初始化I2C,然后再调用相关接口传输数据即可,在以下两个文件中:
i2c_application.c
i2c_application.h


i2c_config -- 调用此函数初始化I2C            
i2c_lowlevel_init -- 用户实现这个函数,完成I2C底层初始化,例如初始化GPIO、时钟、中断、DMA等   
                        
i2c_master_transmit -- 主机发送数据-轮询方式
i2c_master_receive -- 主机接收数据-轮询方式
i2c_slave_transmit -- 从机发送数据-轮询方式
i2c_slave_receive -- 从机接收数据-轮询方式
                        
i2c_master_transmit_int -- 主机发送数据-中断方式
i2c_master_receive_int -- 主机接收数据-中断方式
i2c_slave_transmit_int -- 从机发送数据-中断方式
i2c_slave_receive_int -- 从机接收数据-中断方式
                        
i2c_master_transmit_dma -- 主机发送数据-DMA方式   
i2c_master_receive_dma -- 主机接收数据-DMA方式   
i2c_slave_transmit_dma -- 从机发送数据-DMA方式   
i2c_slave_receive_dma -- 从机接收数据-DMA方式   
                        
i2c_memory_write   -- 写数据到EEPROM-轮询方式      
i2c_memory_write_int -- 写数据到EEPROM-中断方式         
i2c_memory_write_dma -- 写数据到EEPROM-DMA方式         
i2c_memory_read      -- 从EEPROM读数据-轮询方式         
i2c_memory_read_int-- 从EEPROM读数据-中断方式         
i2c_memory_read_dma-- 从EEPROM读数据-DMA方式   


我们对communication_dma例程代码进行举例分析

1. 首先实现i2c_lowlevel_init函数,实现I2C的底层初始化
void i2c_lowlevel_init(i2c_handle_type* hi2c)
{
gpio_init_type gpio_initstructure;

if(hi2c->i2cx == I2Cx_PORT)
{
    /* i2c periph clock enable */
    crm_periph_clock_enable(I2Cx_CLK, TRUE);   
    crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
    crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);
   
    /* gpio configuration */
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_initstructure.gpio_pull         = GPIO_PULL_UP;
    gpio_initstructure.gpio_mode         = GPIO_MODE_MUX;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;

    /* configure i2c pins: scl */   
    gpio_initstructure.gpio_pins = I2Cx_SCL_PIN;
    gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_initstructure);


    /* configure i2c pins: sda */   
    gpio_initstructure.gpio_pins = I2Cx_SDA_PIN;
    gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_initstructure);
   
    /* configure and enable i2c dma channel interrupt */
    nvic_irq_enable(I2Cx_DMA_TX_IRQn, 0, 0);
    nvic_irq_enable(I2Cx_DMA_RX_IRQn, 0, 0);      
   
    /* i2c dma tx and rx channels configuration */
    /* enable the dma clock */
    crm_periph_clock_enable(I2Cx_DMA_CLK, TRUE);

    /* i2c dma channel configuration */
    dma_reset(hi2c->dma_tx_channel);
    dma_reset(hi2c->dma_rx_channel);   
   
    hi2c->dma_tx_channel = I2Cx_DMA_TX_CHANNEL;
    hi2c->dma_rx_channel = I2Cx_DMA_RX_CHANNEL;

    dma_default_para_init(&hi2c->dma_init_struct);
    hi2c->dma_init_struct.peripheral_inc_enable    = FALSE;
    hi2c->dma_init_struct.memory_inc_enable      = TRUE;
    hi2c->dma_init_struct.peripheral_data_width    = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    hi2c->dma_init_struct.memory_data_width      = DMA_MEMORY_DATA_WIDTH_BYTE;
    hi2c->dma_init_struct.loop_mode_enable         = FALSE;
    hi2c->dma_init_struct.priority               = DMA_PRIORITY_LOW;
    hi2c->dma_init_struct.direction                = DMA_DIR_MEMORY_TO_PERIPHERAL;
   
    dma_init(hi2c->dma_tx_channel, &hi2c->dma_init_struct);
    dma_init(hi2c->dma_rx_channel, &hi2c->dma_init_struct);
   
    i2c_init(hi2c->i2cx, I2C_FSMODE_DUTY_2_1, I2Cx_SPEED);
   
    i2c_own_address1_set(hi2c->i2cx, I2C_ADDRESS_MODE_7BIT, I2Cx_ADDRESS);
}
}

2. 实现中断函数

void I2Cx_DMA_RX_IRQHandler(void)
{
i2c_dma_rx_irq_handler(&hi2cx);
}


void I2Cx_DMA_TX_IRQHandler(void)
{
i2c_dma_tx_irq_handler(&hi2cx);
}

3.调用i2c_config初始化i2c,调用i2c_master_transmit_dma、i2c_slave_receive_dma进行数据收发

int main(void)
{
i2c_status_type i2c_status;


/* config nvic priority group */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);


system_clock_config();

at32_board_init();

hi2cx.i2cx = I2Cx_PORT;

i2c_config(&hi2cx);

while(1)
{
   
#if defined (MASTER_BOARD)   

    /* wait for key USER_BUTTON press before starting the communication */
    while(at32_button_press() != USER_BUTTON)
    {
    }
   
    /* start the request reception process */
    if((i2c_status = i2c_master_transmit_dma(&hi2cx, I2Cx_ADDRESS, tx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)
    {
      error_handler(i2c_status);
    }
   
    /* wait for the communication to end */
    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)
    {
      error_handler(i2c_status);
    }
   
    delay_ms(10);
   
    /* start the request reception process */
    if((i2c_status = i2c_master_receive_dma(&hi2cx, I2Cx_ADDRESS, rx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)
    {
      error_handler(i2c_status);
    }
   
    /* wait for the communication to end */
    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)      
    {
      error_handler(i2c_status);
    }   
   
    if(buffer_compare(tx_buf, rx_buf, BUF_SIZE) == 0)
    {
      at32_led_on(LED3);
    }
    else
    {
      error_handler(i2c_status);
    }
   
#else
   
    /* wait for key USER_BUTTON press before starting the communication */
    while(at32_button_press() != USER_BUTTON)
    {
    }
   
    /* start the transmission process */
    if((i2c_status = i2c_slave_receive_dma(&hi2cx, rx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)
    {
      error_handler(i2c_status);
    }
   
    /* wait for the communication to end */
    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)   
    {
      error_handler(i2c_status);
    }
   
    if((i2c_status = i2c_slave_transmit_dma(&hi2cx, tx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)
    {
      error_handler(i2c_status);
    }
   
    /* wait for the communication to end */
    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)   
    {
      error_handler(i2c_status);
    }


    if(buffer_compare(tx_buf, rx_buf, BUF_SIZE) == 0)
    {
      at32_led_on(LED3);
    }
    else
    {
      error_handler(i2c_status);
    }
   
#endif

}   
}

febgxu 发表于 2022-2-9 23:15

:I2C协议、模拟I2C底层驱动都有吗   

alvpeg 发表于 2022-2-9 23:23

只能使用IO模拟的方式来驱动I2C器件。

caigang13 发表于 2022-2-10 08:18

这个硬件IIC有bug嘛?

骑着蜗牛狂奔O 发表于 2022-2-10 09:06

febgxu 发表于 2022-2-9 23:15
:I2C协议、模拟I2C底层驱动都有吗

有的,雅特力官网搜索,SC0006,就是模拟I2C程序

骑着蜗牛狂奔O 发表于 2022-2-10 09:08

caigang13 发表于 2022-2-10 08:18
这个硬件IIC有bug嘛?

我试过,没有类似ST103的bug,使用官方的应用层,使用很方便

sesefadou 发表于 2022-2-10 09:12

这个有硬件iic的问题吗?配置不成功的。   

骑着蜗牛狂奔O 发表于 2022-2-10 09:12

alvpeg 发表于 2022-2-9 23:23
只能使用IO模拟的方式来驱动I2C器件。

硬件I2C更省MCU资源

adolphcocker 发表于 2022-2-10 09:21

使用软件模拟I2C主要是方便程序的移植

sparrow054 发表于 2022-2-10 15:42

非常好,速度和可靠性上是不是有所提升

biechedan 发表于 2022-3-3 22:13

最近使用的都是模拟iic

pixhw 发表于 2022-3-3 22:42

是用的硬件I2C吗

yujielun 发表于 2022-3-3 23:04

AT32 I2C程序代码有吗

ulystronglll 发表于 2022-3-3 23:26

好久没有操作硬件iic了呢

wsnsyy 发表于 2022-3-4 11:27

有个I2C3_SMBA引脚是做啥用的?

xafb 发表于 2022-3-4 11:34

模拟IIC最大的好处就是引脚可以自由选择

phoenixwhite 发表于 2022-3-4 20:08

这个存在硬件iic的坑吗

wsnsyy 发表于 2022-3-11 19:11

IIC从机发数据时,PECTRA置1就会立刻发送PEC吗?发完PEC后如果主机继续读,还能正常发数据出去吗?

七毛钱 发表于 2022-3-15 15:56

模拟IIC让我们实现引脚选择自由

hoop 发表于 2022-3-15 19:26

wsnsyy 发表于 2022-3-11 19:11
IIC从机发数据时,PECTRA置1就会立刻发送PEC吗?发完PEC后如果主机继续读,还能正常发数据出去吗? ...

PEC发完后通讯就应该结束。主机重更新开启数据传输
页: [1]
查看完整版本: AT32 I2C程序使用讲解