打印
[AT32F403/403A]

AT32 I2C程序使用讲解

[复制链接]
3642|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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嘛?

使用特权

评论回复
5
骑着蜗牛狂奔O|  楼主 | 2022-2-10 09:06 | 只看该作者
febgxu 发表于 2022-2-9 23:15
:I2C协议、模拟I2C底层驱动都有吗

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

使用特权

评论回复
评论
初夏的毛毛虫 2022-5-28 17:35 回复TA
大佬,我去看了SC0006程序,发现里面SDA引脚没有in和out的切换,是不需要吗? 
6
骑着蜗牛狂奔O|  楼主 | 2022-2-10 09:08 | 只看该作者
caigang13 发表于 2022-2-10 08:18
这个硬件IIC有bug嘛?

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

使用特权

评论回复
7
sesefadou| | 2022-2-10 09:12 | 只看该作者
这个有硬件iic的问题吗?配置不成功的。   

使用特权

评论回复
8
骑着蜗牛狂奔O|  楼主 | 2022-2-10 09:12 | 只看该作者
alvpeg 发表于 2022-2-9 23:23
只能使用IO模拟的方式来驱动I2C器件。

硬件I2C更省MCU资源

使用特权

评论回复
9
adolphcocker| | 2022-2-10 09:21 | 只看该作者
使用软件模拟I2C主要是方便程序的移植

使用特权

评论回复
10
sparrow054| | 2022-2-10 15:42 | 只看该作者
非常好,速度和可靠性上是不是有所提升

使用特权

评论回复
11
biechedan| | 2022-3-3 22:13 | 只看该作者
最近使用的都是模拟iic

使用特权

评论回复
12
pixhw| | 2022-3-3 22:42 | 只看该作者
是用的硬件I2C吗  

使用特权

评论回复
13
yujielun| | 2022-3-3 23:04 | 只看该作者
AT32 I2C程序代码有吗

使用特权

评论回复
14
ulystronglll| | 2022-3-3 23:26 | 只看该作者
好久没有操作硬件iic了呢

使用特权

评论回复
15
wsnsyy| | 2022-3-4 11:27 | 只看该作者
有个I2C3_SMBA引脚是做啥用的?

使用特权

评论回复
16
xafb| | 2022-3-4 11:34 | 只看该作者
模拟IIC最大的好处就是引脚可以自由选择

使用特权

评论回复
17
phoenixwhite| | 2022-3-4 20:08 | 只看该作者
这个存在硬件iic的坑吗  

使用特权

评论回复
18
wsnsyy| | 2022-3-11 19:11 | 只看该作者
IIC从机发数据时,PECTRA置1就会立刻发送PEC吗?发完PEC后如果主机继续读,还能正常发数据出去吗?

使用特权

评论回复
19
七毛钱| | 2022-3-15 15:56 | 只看该作者
模拟IIC让我们实现引脚选择自由

使用特权

评论回复
20
hoop| | 2022-3-15 19:26 | 只看该作者
wsnsyy 发表于 2022-3-11 19:11
IIC从机发数据时,PECTRA置1就会立刻发送PEC吗?发完PEC后如果主机继续读,还能正常发数据出去吗? ...

PEC发完后通讯就应该结束。主机重更新开启数据传输

使用特权

评论回复
评论
wsnsyy 2022-3-16 21:41 回复TA
@骑着蜗牛狂奔O :是的,主机是别人的系统。现在的需求就是要发完数据就发PEC,主机继续发时钟就一直发0或者1。但是现在发完数据使能PEC传输不会发校验值,不知道咋实现。 
骑着蜗牛狂奔O 2022-3-16 19:14 回复TA
@wsnsyy :那是你主机接收个数没有和从机设置成一样 
wsnsyy 2022-3-16 18:07 回复TA
我从机发送的数据是结束了,但是主机还会发时钟读。 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

126

帖子

2

粉丝