【雅特力AT32】IIC使用指南_附读写EEPROM案例

目录

1.12C接口简介
2.12C接口通信

2.1主机通信流程
2.1.1 主机通信初始化
1>主机时钟初始化
2>主机通信初始化
3>主机 10 bits 寻址的特殊时序初始化
2.1.2 主机通信初始化软件接口
2.1.3 主机发送流程
2.1.4 主机发送流程软件接口
2.1.5 主机接收流程
2.1.6 主机接收流程软件接口

2.2 从机通信流程

2.2.1 从机通信初始化
1>从机地址配置
2>从机地址匹配
3>从机字节控制模式(通常SMBus 模式下才使用)
2.2.2 从机通信初始化软件接口
2.2.3 从机发送流程
2.2.4 从机发送流程软件接口
2.2.5 从机接收流程
2.2.6 从机接收流程软件接口

2.3 唤醒深睡眠模式

2.4 IIC读写EEPROM

2.4.1 功能简介
2.4.2 资源准备
2.4.3 软件设计

引言

​ AT32 的 I2C 总线接口用于处理微控制器和串行 I2C 总线之间的通信,支持主机和从机模式,支持唤醒深睡眠模式,最大通信速度为 1Mbit/s(增强快速模式 fast mode plus)。

​ 本文主要就 I 2C 总线接口的基本功能进行讲解和案列解析。

1. I2C接口简介

​ I2C 接口是由数据线 SDA 和时钟线 SCL 构成,在标准模式下通信速度可达到 100kHz快速模式下则可以达到 400kHz增强快速模式可达到 1MHz

​ 一帧数据传输从开始信号开始,在结束信号后停止,在收到开始信号后总线被认为是繁忙的,当收到结束信号后,总线被认为再次空闲。

​ I2C 接口具有主机和从机模式、多主机功能、可编程建立和保持时间、时钟延展功能、DMA 存取数据、支持SMBus 2.0 协议等特点。

在这里插入图片描述

I 2C1 可透过配置 CRM 中 PICLKS 寄存器的 I2C1SEL 位,时钟来源可选择来自 SYSCLK、PCLK和 HICK,并且支持从 Deepsleep mode 唤醒, I2C1 有模拟滤波器,可以滤掉 50ns 内的噪声

在这里插入图片描述

I 2C2 / I 2C3 时钟来源为 PCLK,不支持 Deepsleep mode 唤醒并且没有模拟滤波器。

2. I2C接口通信

2.1主机通信流程

2.1.1 主机通信初始化
1> 主机时钟初始化

在启动外设(I2CEN)之前,必须先设置 I2Cx_CLKCTRL 寄存器的各个位用以配置 I 2C 主时钟。

― DIV[7:0]:	I2C 时钟分频;
― SDAD[3:0]:数据保持时间(tHD;DAT)
― SCLD[3:0]:数据建立时间(tSU;DAT)
― SCLH[7:0]:SCL 高电平时间
― SCLL[7:0]:SCL 低电平时间

​ 该寄存器的配置可以使用 Artery_I2C_Timing_Configuration 时钟配置工具计算,见第三部分。

  • 低电平控制
当检测到 SCL 总线为低电平时,内部 SCLL 计数器开始计数,当计数值达到 SCLL 值时,释放 SCL 线,SCL 线变为高电平。
  • 高电平控制
当检测到 SCL 总线为高电平时,内部 SCLH 计数器开始计数,当计数值达到 SCLH 值时,拉低 SCL 线,SCL 线变为低电平,当在高电平期间,如果被外部总线拉低,那么内部 SCLH 计数器停止计数,并开始低电平计数,这为时钟同步提供了条件。

在这里插入图片描述

2> 主机通信初始化

启动通讯前须先设定 I2C_CTRL2 寄存器中的几项参数:

  • 1)设置传输字节数

    • ​ ≤255 字节

      配置 I2C_CTRL2 的 RLDEN=0,关闭重载模式
      配置 I2C_CTRL2 的 CNT[7:0] = N 
      
    • ​ ->255 字节

      配置 I2C_CTRL2 的 RLDEN=1,使能重载模式
      配置 I2C_CTRL2 的 CNT[7:0]=255
      剩余传输字节数 N = N - 255
      
  • 2)设置传输结束模式

    • 软件结束模式

      ASTOPEN=0:软件结束模式,当数据传输完成后,I2C_STS 的 TDC 标志置 1,软件设置GENSTOP=1 或者 GENSTART=1,发送 STOP 条件或者 START 条件。
      
    • 自动结束模式

      ASTOPEN=1:自动结束模式,当数据传输完成后,自动发送 STOP 条件。
      
  • 3)设置从机地址

    设置寻址的从机地址值(I2C_CTRL2 的 SADDR)
    
    设置从机地址模式(I2C_CTRL2 的 ADDR10)
    ADDR10=0:7 位地址模式
    ADDR10=1:10 位地址模式
    
  • 4)设置传输方向(I2C_CTRL2 的 DIR)

        DIR=0:主机接收数据
    	DIR=1:主机发送数据
    
  • 5)开始传输

    设置 I2C_CTRL2 的 GENSTART=1,主机开始在总线上**发送 START 条件和从机地址**。
    
3> 主机 10 bits 寻址的特殊时序初始化

在 10 位地址传输模式下,I2C_CTRL2 的 READH10 用于产生特殊时序,当 READH10=1 时,支持如下传输序:主机先发送数据给从机,然后再从从机读取数据,传输时序图如下图所示:

在这里插入图片描述

2.1.2 主机通信初始化软件接口

主机通信初始化所用到的软件接口通过独立的函数接口实现,如下:

/* 主机时钟初始化 */
void i2c_init(i2c_type *i2c_x, uint8_t dfilters, uint32_t clk); 
/* 主机通信初始化 */
void i2c_transmit_set
    (
        i2c_type *i2c_x, 
        uint16_t address, 
        uint8_t cnt, 
        i2c_reload_stop_mode_type rld_stop, 
        i2c_start_stop_mode_type start_stop
	); 
/* 10 位地址使能 */
void i2c_addr10_mode_enable(i2c_type *i2c_x, confirm_state new_state); 
 /* 10 位地址头读取时序使能 */
void i2c_addr10_header_enable(i2c_type *i2c_x, confirm_state new_state);

i2c_init 函数

用于主机时钟初始化,三个参数分别为:所使用的 I2C、数字滤波值和主机时钟配置值。

i2c_transmit_set 函数

用于初始化通信参数,包括:所使用的 I2C、从机地址、传输字节数、停止条件产生模式和起始条件产生模式。

i2c_addr10_mode_enable 函数

用于使能 10 位地址模式。

i2c_addr10_header_enable 函数

用于使能 10 位地址头读取时序,即主机发送完整的 10 位从机地址读序列或主机只发送 10 位地址的前 7 位。
2.1.3 主机发送流程
  1. I2C_TXDT 数据寄存器为空,I2C_STS 的 TDIS=1;

  2. 向 TXDT 数据寄存器写入数据,数据开始发送;

  3. 重复 1、2 步骤直到发送 CNT[7:0]个数据;

  4. 如果此时 I2C_STS 的 TCRLD=1(重载模式),分为以下两种情况:

    ― 剩余字节数 N>255:
    	向 CNT 写入 255,N=N-255,TCRLD 被自动清 0,传输继续;
    ― 剩余字节数 N≤255:
    	关闭重载模式(RLDEN=0),向 CNT 写入 N,TCRLD 被自动清 0,传输继续。
    
  5. 结束时序

    ― 停止条件产生:

    软件结束模式(ASTOPEN=0):此时 I2C_STS 的 TDC 置 1,设置 GENSTOP=1产生 STOP 条件;
    
    自动结束模式(ASTOPEN=1):自动产生 STOP 条件。
    

    ― 等待产生 STOP 条件:

    当 STOP 条件产生时,I2C_STS 的 STOPF 置 1,将 I2C_CLR的 STOPC 写 1,清除 STOPF 标志,传输结束.
    

在这里插入图片描述
在这里插入图片描述

2.1.4 主机发送流程软件接口

主机发送通过独立的函数接口实现,如下:

i2c_status_type i2c_master_transmit
(
    i2c_handle_type* hi2c, 
    uint16_t address, 
    uint8_t* pdata, 
    uint16_t size, 
    uint32_t timeout
);

i2c_master_transmit 函数为 i2c_application.c 文件所提供的应用层接口函数,参数包括:I2C 结构体指针、从机地址、发送数据指针、发送数据字节数和函数超时时间。

注:此函数为Artery 所提供的标准主机发送函数。用户也可根据前述主机发送流程,自行编写主机发送函数。

2.1.5 主机接收流程
  1. 当收到数据后,RDBF=1,读取 RXDT 数据寄存器,RDBF 被自动清零;

  2. 重复步骤 2 直到接收 CNT[7:0]个数据;

  3. 如果此时 I2C_STS 的 TCRLD=1(重载模式),分为以下两种情况:

    ― 剩余字节数 N>255:向 CNT 写入 255,N=N-255,TCRLD 被自动清 0,传输继续;
    
    ― 剩余字节数 N≤255:关闭重载模式(RLDEN=0),向 CNT 写入 N,TCRLD 被自动清 0,传输继续。
    
  4. 当在接收到最后一个字节时,主机会自动发送一个 NACK。

  5. 结束时序

    ― 停止条件产生:
    	软件结束模式(ASTOPEN=0):此时 I2C_STS 的 TDC 置 1,设置 GENSTOP=1 产生STOP 条件;
    	自动结束模式(ASTOPEN=1):自动产生 STOP 条件。
    ― 等待产生 STOP 条件:
    	当 STOP 条件产生时,I2C_STS 的 STOPF 置 1,将 I2C_CLR 的STOPC 写 1,清除 STOPF 标志,传输结束。
    

在这里插入图片描述
在这里插入图片描述

2.1.6 主机接收流程软件接口

主机接收通过独立的函数接口实现,如下:

i2c_status_type i2c_master_receive
(
    i2c_handle_type* hi2c, 
    uint16_t address, uint8_t* pdata, 
    uint16_t size, 
    uint32_t timeout
);

i2c_master_receive 函数为 i2c_application.c 文件所提供的应用层接口函数,参数包括:I2C 结构体指针、从机地址、接收数据指针、接收数据字节数和函数超时时间。

注:此函数为 Artery 所提供的标准主机接收函数。用户也可根据前述主机接收流程,自行编写主机接收函数。

2.2 从机通信流程

2.2.1 从机通信初始化
1> 从机地址配置

每个 I 2C 从设备可同时支持 2 个从设备地址,由 OADDR1 和 OADDR2 指定

  • I2C_OADDR1

    — 通过 ADDR1EN 使能
    — 通过 ADDR1MODE 配置为 7 位(默认)或 10 位地址
    
  • I2C_OADDR2

    — 通过 ADDR2EN 使能
    — 固定 7 位地址模式
    — 可通过 ADDR2MASK [2:0]来在进行地址匹配比较时屏蔽掉 0~7 个 LSB 地址位
    	ADDR2MASK = 0 表示 7 位地址中的每一位都要参与匹配比较
    	ADDR2MASK = 7 表示任何非保留地址的 7 位地址都会被该从设备应答
    
2> 从机地址匹配
当 I 2C 启用的地址选中匹配时,ADDRF 中断状态标志会被置 1,如果 ADDRIEN 位为 1,就会产生一个中断。
如果两个从地址都使能,在地址匹配产生 ADDR 中断时,可以查看状态寄存器中的ADDR [6:0]来得知是 OADDR1 还是 OADDR2 被寻址了。
3> 从机字节控制模式(通常 SMBus 模式下才使用)

从设备可以对每个收到的字节进行应答控制。

所需配置:SCTRL = 1 & RLDEN =1 & STRETCH = 0 & CNT ≥ 1

从机字节控制流程:

1) 每收到一个字节 TCRLD 置位,时钟延展于第 8 和第 9 个脉冲之间
2) 软件读取 RXDT 中的值,并决定是否置位 ACK
3) 软件重装载 CNT = 1 来停止时钟延展
4) 应答或非应答信号在第 9 个脉冲时刻出现在总线上

注意:

置位 SCTRL 时,必须开启时钟延展,即 STRETCH = 0;
CNT 可以是大于 1 的值,来实现多个字节以自动 ACK 接收完毕后再启动应答控制,从设备发送时推荐关闭 SCTRL,此时无需字节应答控制。
2.2.2 从机通信初始化软件接口

从机通信初始化所用到的软件接口通过独立的函数接口实现,如下:

void i2c_own_address1_set(i2c_type *i2c_x, i2c_address_mode_type mode, uint16_t address);
void i2c_own_address2_set(i2c_type *i2c_x, uint8_t address, i2c_addr2_mask_type mask);
void i2c_own_address2_enable(i2c_type *i2c_x, confirm_state new_state);
void i2c_slave_data_ctrl_enable(i2c_type *i2c_x, confirm_state new_state);
void i2c_clock_stretch_enable(i2c_type *i2c_x, confirm_state new_state);
void i2c_reload_enable(i2c_type *i2c_x, confirm_state new_state);

i2c_own_address1_set 函数用于配置 OADDR1 地址模式以及 ADDR1 地址值。

i2c_own_address2_set 函数用于配置 ADDR2 地址值以及 ADDR2 屏蔽位。

i2c_own_address2_enable 函数用于使能 ADDR2 地址。

i2c_slave_data_ctrl_enable 函数用于使能从机字节控制模式。

i2c_clock_stretch_enable 函数用于使能从机时钟延展功能。

i2c_reload_enable 函数用于使能发送数据重载模式。

2.2.3 从机发送流程
  1. 响应主机地址,匹配时回复 ACK;

  2. TXDT 为空时,置位 TDIS,从设备写入发送数据;

  3. 每发送一个字节会收到 ACK,且置位 TDIS;

  4. 如果收到 NACK 位:

    — 置位 NACKF,产生中断;
    — 从设备自动释放 SCL 和 SDA(以便主设备发送 STOP 或 RESTART);
    
  5. 如果收到 STOP 位:

    — 置位 STOPF,产生中断;
    

​ 当从机发送开启时钟延展(STRETCH = 0)时,在等待 ADDRF 标志时和发送前一个数据的第 9 个时钟脉冲后,会把 TXDT 中的数据拷贝到移位寄存器中,如果此时 TDIS 还是置位,表示 TXDT 没有写进待发送数据,将发生时钟延展,如下流程图:

在这里插入图片描述

​ 需要注意的是,在时钟延展关闭(STRETCH=1)的情况下,如果在将要传输数据的第一个 Bit 位开始发送之前,也就是 SDA 边沿产生之前,如果数据还未写入 TXDT 数据寄存器,那么会发生欠载错误,此时 I2C_STS 的 OUF 将会置 1,并将 0xFF 发送到总线。

​ 为了能及时的写入数据,可以在通信开始前,先将数据写入到 DT 寄存器:软件先将 TDBE 置 1,目的是为了清空 TXDT 寄存器的数据,然后将第一个数据写入 TXDT 寄存器,此时 TDBE 清零。

在这里插入图片描述

2.2.4 从机发送流程软件接口

从机发送通过独立的函数接口实现,如下:

i2c_status_type i2c_slave_transmit
(
    i2c_handle_type* hi2c, 
    uint8_t* pdata, 
    uint16_t size, 
    uint32_t timeout
);

i2c_slave_transmit 函数为 i2c_application.c 文件所提供的应用层接口函数,参数包括:I2C 结构体指针、发送数据指针、发送数据字节数和函数超时时间

注:此函数为 Artery 所提供的标准从机发送函数。用户也可根据前述从机发送流程,自行编写从机发送函数。

2.2.5 从机接收流程
  1. 当收到数据后,RDBF=1,读取 RXDT 数据寄存器,RDBF 被自动清零;

  2. 重复步骤 2 直到所有数据接收完成;

  3. 等待收到 STOP 条件,当收到 STOP 条件时,I2C_STS 的 STOPF 置 1,将 I2C_CLR的 STOPC 写 1,清除 STOPF 标志,传输结束。

在这里插入图片描述

2.2.6 从机接收流程软件接口

从机接收通过独立的函数接口实现,如下:

i2c_status_type i2c_slave_receive
(
    i2c_handle_type* hi2c, 
    uint8_t* pdata, 
    uint16_t size, 
    uint32_t timeout
);

i2c_slave_receive 函数为 i2c_application.c 文件所提供的应用层接口函数,参数包括:I2C 结构体指针、接收数据指针、接收数据字节数和函数超时时间

注:此函数为 Artery 所提供的标准从机接收函数。用户也可根据前述从机接收流程,自行编写从机接收函数。

2.3 唤醒深睡眠模式

A423 上有 3 个 I2C,其中只有 I2C1 支持在被寻址到时将系统从深睡眠模式(DEEPSLEEP)唤醒

使用此功能的配置步骤

  1. 使能 I2C 唤醒深睡眠模式功能(I2C1_CTRL1 的 WAKEUPEN 位置 1)

    i2c_wakeup_enable(i2cx, TRUE);
    
  2. 数字滤波器值设置为 0(I2C1_CTRL1 的 DFLT 位设为 0)

    i2c_init(i2cx, 0x00, I2Cx_CLKCTRL);
    
  3. 开启时钟延展模式(I2C1_CTRL1 的 STRETCH 位设为 0)

    i2c_clock_stretch_enable(i2cx, TRUE);
    
  4. I2C 时钟选择 HICK(CRM_MISC2 的 I2C1SEL 位)

    crm_i2c1_clock_source_set(CRM_I2C1_CLOCK_SOURCE_HICK48);
    

关于 A423 唤醒深睡眠模式更多详细信息请参考《AN0208_AT32A423_PWC_Application_Note

2.4 IIC读写EEPROM

4.1 功能简介

使用硬件 I 2C 接口对 EEPROM 存储设备进行读写访问。

4.2 资源准备
  1. 硬件环境:

    对应产品型号的 AT-START BOARD
    
    4.7K 上拉电阻
    
    EEPROM 存储设备
    
  2. 软件环境

    project\at_start_a4xx\examples\i2c\eeprom
    
4.3 软件设计
  1. 配置流程

     开启 I2C 外设时钟
     配置 I2C 所复用的 GPIO
     配置 I2C 所用的 DMA 通道
     使能 I2C 外设接口
     写入 EEPROM 并读取写入的数据
     比较读写数据内容是否正确
    
  2. 代码介绍 main.c

    如若读写数据完全相同,则 LED3 会被点亮。

    int main(void)
    {
     i2c_status_type i2c_status;
     
     /* 初始化系统时钟 */ 
     system_clock_config(); 
     
     /* 配置 NVIC 优先级组 */
     nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
     
     /* at-start board 初始化 */
     at32_board_init();
     hi2cx.i2cx = I2Cx_PORT;
     
     /* 配置 I2C */
     i2c_config(&hi2cx);
     
     while(1)
     {
         /* wait for key USER_BUTTON press before starting the communication */
         while(at32_button_press() != USER_BUTTON)
         {
         }
    
         /* 写数据到 EEPROM */ 
         if((i2c_status = i2c_memory_write(&hi2cx, I2Cx_ADDRESS, 0, tx_buf1, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)
         {
             error_handler(i2c_status);
         }
    
         delay_ms(5);
    
         /* 读 EEPROM 数据 */ 
         if((i2c_status = i2c_memory_read(&hi2cx, I2Cx_ADDRESS, 0, rx_buf1, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)
         { 
             error_handler(i2c_status);
         } 
        (省略部分代码,完整代码请查看 BSP)
         /* 等待通讯完成 */ 
         if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)
         {
             error_handler(i2c_status);
         }
        /* 比较读写数据 */
         if((buffer_compare(tx_buf1, rx_buf1, BUF_SIZE) == 0) &&
         (buffer_compare(tx_buf2, rx_buf2, BUF_SIZE) == 0) &&
         (buffer_compare(tx_buf3, rx_buf3, BUF_SIZE) == 0))
         {
             at32_led_on(LED3);
         }
         else
         {
             error_handler(i2c_status);
         }
    
         } 
    }
             error_handler(i2c_status);
         } 
        (省略部分代码,完整代码请查看 BSP)
         /* 等待通讯完成 */ 
         if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)
         {
             error_handler(i2c_status);
         }
        /* 比较读写数据 */
         if((buffer_compare(tx_buf1, rx_buf1, BUF_SIZE) == 0) &&
         (buffer_compare(tx_buf2, rx_buf2, BUF_SIZE) == 0) &&
         (buffer_compare(tx_buf3, rx_buf3, BUF_SIZE) == 0))
         {
             at32_led_on(LED3);
         }
         else
         {
             error_handler(i2c_status);
         }
    
         } 
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值