硬件IIC主从机中断代码注释解析
硬件IIC的主从中断在582的最新EVT中已支持。
对于IIC从机中断,例程中已封装好中断处理过程,用户调用app_i2c时,初始化中需要配置回调函数。
初始化的配置如下。
struct i2c_slave_cb slave_user = { //配置回调结构体
.on_receive = i2c_on_slave_receive_user,
.on_transmit = i2c_on_slave_transmit_user,
};
i2c_app_init(RxAdderss); //IIC硬件模块的初始化及软件标志的初始化
i2c_slave_cb_register(&slave_user); //注册回调
默认回调函数如下。
static void i2c_on_slave_transmit_user(uint8_t *data, uint8_t *len)
{
*len = sizeof(TxData);
memcpy(data, TxData, sizeof(TxData));
} static void i2c_on_slave_receive_user(uint8_t *data, uint8_t len)
{
PRINT("I2C slave receiver callback: received (");
for(int i = 0; i < len; i++) {
PRINT(" %#x", data[i]);
}
PRINT(" )\n");
}
若需要串口打印日志,可以在工程预编译中增加宏CONFIG_I2C_DEBUG。
接下来以注释的方式解析一下中断服务函数中做了哪些处理。
__INTERRUPT
__HIGH_CODE
void I2C_IRQHandler(void)
{
uint32_t event = I2C_GetLastEvent();
print_i2c_irq_sta(event); /* I2C Master */
if (event & (RB_I2C_MSL << 16)) { //判断为主机模式
if (event & RB_I2C_SB) { //判断主机模式已发送起始信号
/* Start condition sent, send address */
I2C_SendData(i2c_slave_addr_rw); //写从地址到数据寄存器后,SB位会自动清除
I2C_DBG("Master selected, send address\n");
} /* I2C Master transmitter */
if (event & (RB_I2C_TRA << 16)) { //判断是主机的发送模式
I2C_DBG("Master transmitter:\n");
/* Slave receiver acked address or sent bit */
if (event & (RB_I2C_ADDR | RB_I2C_BTF | RB_I2C_TxE | (RB_I2C_TRA << 16))) {
/* if there is data to send, send it, otherwise stop */
if (i2c_master_buffer_index < i2c_master_buffer_length) { //判断待发送数据还没发完
I2C_SendData(i2c_master_buffer[i2c_master_buffer_index++]);
I2C_DBG(" send (%#x)\n",
i2c_master_buffer[i2c_master_buffer_index - 1]);
} else {
if (i2c_send_stop) { //判断数据发完了,如果允许产生停止位则产生停止位
i2c_state = I2C_READY;
I2C_GenerateSTOP(ENABLE); //产生停止位
I2C_DBG(" send STOP\n");
} else {
i2c_in_repstart = true; //置标志表示即将重起始
/* we're gonna send the START, don't enable the interrupt. */
I2C_ITConfig(I2C_IT_BUF, DISABLE);
I2C_ITConfig(I2C_IT_EVT, DISABLE);
I2C_ITConfig(I2C_IT_ERR, DISABLE);
I2C_GenerateSTART(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" restart\n");
}
}
} /* Address or data sent, nack received */
if (event & RB_I2C_AF) { //地址/数据发送后应答失败
I2C_ClearFlag(I2C_FLAG_AF); //清标志 i2c_error = I2C_MT_NACK; //置主机发送接收错误标志
i2c_state = I2C_READY; //发送停止信号停止帧传输
I2C_GenerateSTOP(ENABLE); //产生停止信号
I2C_DBG(" NACK received, sent stop\n");
}
} else { //判断为主机的接收模式
/* I2C Master reveiver */
I2C_DBG("Master receiver:\n"); /* address sent, ack received */
if(event & RB_I2C_ADDR) { //主机成功设置了从机的地址
/* ack if more bytes are expected, otherwise nack */
if (i2c_master_buffer_length) { //判断接下来需要接收多少字节,如果需要接收多个字节,就置自动回ACK
//注意这里判断条件,在1.8的583EVT与之前的EVT不同,以这里的为准。
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" address sent\n");
I2C_DBG(" ACK next\n");
} else { //判断接下来只接收一个字节,关闭自动回ACK即自动回NACK
//XXX: Should not delay too match before NACK
I2C_AcknowledgeConfig(DISABLE);
is_nack_sent = true; //置标志,数据接收时做具体处理
I2C_DBG(" address sent\n");
I2C_DBG(" NACK next\n");
}
} /* data reveived */
if (event & (RB_I2C_RxNE)) { //接收数据寄存器内非空,即收到数据
/* put byte into buffer */
i2c_master_buffer[i2c_master_buffer_index++] = I2C_ReceiveData(); //接收数据到buffer中 if (i2c_master_buffer_index < i2c_master_buffer_length) { //判断接下来是否为期望接收的最后一个字节
I2C_AcknowledgeConfig(ENABLE); //接下来不是最后一个字节,接收应答设置为自动回ACK
I2C_DBG(" ACK next\n");
} else {
//XXX: Should not delay too match before NACK
I2C_AcknowledgeConfig(DISABLE); //连续读倒数最后一个字节前将接收应答ACK关闭,即最后一个字节后自动回NACK
I2C_DBG(" NACK next\n"); if (is_nack_sent) { //如果已设置最后一个字节前置了接收应答NACK
is_nack_sent = false; //清标志
if (i2c_send_stop) {
I2C_GenerateSTOP(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" send STOP\n");
} else {
i2c_in_repstart = true; //写完了从机内的目标寄存器,发重起始信号
/* we're gonna send the START, don't enable the interrupt. */
I2C_ITConfig(I2C_IT_BUF, DISABLE);
I2C_ITConfig(I2C_IT_EVT, DISABLE);
I2C_ITConfig(I2C_IT_ERR, DISABLE);
I2C_GenerateSTART(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" restart\n");
}
} else {
is_nack_sent = true; //没有要求
}
} I2C_DBG(" received data (%#x)\n",
i2c_master_buffer[i2c_master_buffer_index - 1]);
} /* nack received */
if (event & RB_I2C_AF) { //主机接收模式最后一个字节后为NACK
I2C_ClearFlag(I2C_FLAG_AF);
/* put final byte into buffer */
i2c_master_buffer[i2c_master_buffer_index++] = I2C_ReceiveData(); //收下最后一个字节的数据 if (i2c_send_stop) { //判断读完之后是停止信号还是重起始信号
i2c_state = I2C_READY;
I2C_GenerateSTOP(ENABLE);
I2C_DBG(" NACK received, send STOP\n");
} else {
i2c_in_repstart = true; //读完后不停止,会产生重起始信号以衔接后续操作
/* we're gonna send the START, don't enable the interrupt. */
I2C_ITConfig(I2C_IT_BUF, DISABLE);
I2C_ITConfig(I2C_IT_EVT, DISABLE);
I2C_ITConfig(I2C_IT_ERR, DISABLE);
I2C_GenerateSTART(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" restart\n");
}
}
} } else { //判断为从机模式
/* I2C slave */
/* addressed, returned ack */
if (event & RB_I2C_ADDR) { //地址匹配,接下来判断方向 if (event & ((RB_I2C_TRA << 16) | RB_I2C_TxE)) { //判断从机发送方向匹配或者发送方向寄存器空,那么接下来需要发送数据 //发送方向寄存器空需要判断吗?
I2C_DBG("Slave transmitter address matched\n"); i2c_state = I2C_STX;
i2c_slave_txbuffer_index = 0;
i2c_slave_txbuffer_length = 0; if (slave_cb && slave_cb->on_transmit) { //如果注册了回调,就按照回调函数,将数据拷贝到i2c_slave_txbuffer中
slave_cb->on_transmit(i2c_slave_txbuffer, &i2c_slave_txbuffer_length);
}
} else { //判断从机接收方向地址匹配,那么接下来需要接收数据
I2C_DBG("Slave reveiver address matched\n"); i2c_state = I2C_SRX;
i2c_slave_rxbuffer_index = 0;
}
} if (event & (RB_I2C_TRA << 16)) { //从机发送
/* Slave transmintter */
I2C_AcknowledgeConfig(ENABLE); //预设自动回复ACK
I2C_DBG("Slave transmitter:\n"); if (event & RB_I2C_AF) { //收到了NACK,发送失败
/* Nack received */
I2C_ClearFlag(I2C_FLAG_AF); //清除应答失败标志
I2C_AcknowledgeConfig(ENABLE); //预设自动回复ACK
I2C_DBG(" Nack received\n"); /* leave slave receiver state */
i2c_state = I2C_READY;
/* clear status */
event = 0;
} if(event & (RB_I2C_BTF | RB_I2C_TxE)) { //字节发送结束或者发送方向寄存器空
/* copy data to output register */ I2C_SendData(i2c_slave_txbuffer[i2c_slave_txbuffer_index++]); //逐字节发送数据 /* if there is more to send, ack, otherwise nack */
if (i2c_slave_txbuffer_index < i2c_slave_txbuffer_length) {
I2C_AcknowledgeConfig(ENABLE); //预设自动回复ACK
}else{
I2C_AcknowledgeConfig(DISABLE); //预设自动回复NACK
}
I2C_DBG(" send (%#x)\n",
i2c_slave_txbuffer[i2c_slave_txbuffer_index - 1]);
}
} else { //从机接收
/* Slave receiver */
I2C_DBG("Slave receiver:\n"); if (event & RB_I2C_RxNE) { //判断非空即收到了数据
/* if there is still room in the rx buffer */
//判断还有没有缓存空间,如果仍有空间就接收数据并回ACK,没有更多空间了就回NACK
if (i2c_slave_rxbuffer_index < I2C_BUFFER_LENGTH) {
/* put byte in buffer and ack */
i2c_slave_rxbuffer[i2c_slave_rxbuffer_index++] = I2C_ReceiveData();
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" received (%#x)\n",
i2c_slave_rxbuffer[i2c_slave_rxbuffer_index - 1]);
} else {
// otherwise nack
I2C_AcknowledgeConfig(DISABLE);
}
} if (event & RB_I2C_STOPF) { //从机接收模式下收到停止位,清标志,清数组下标索引
/* ack future responses and leave slave receiver state */ R16_I2C_CTRL1 |= RB_I2C_PE; //clear flag I2C_DBG(" reveive stop\n"); /* callback to user defined callback */
if (slave_cb && slave_cb->on_receive) {
slave_cb->on_receive(i2c_slave_rxbuffer, i2c_slave_rxbuffer_index);
}
/* since we submit rx buffer , we can reset it */
i2c_slave_rxbuffer_index = 0;
} if (event & RB_I2C_AF) { //如果接收模式中接收到了NACK,清标志,预设自动回复ACK
I2C_ClearFlag(I2C_FLAG_AF); /* ack future responses */
I2C_AcknowledgeConfig(ENABLE);
}
}
} if(event & RB_I2C_BERR){ //总线错误
I2C_ClearFlag(RB_I2C_BERR);
I2C_GenerateSTOP(ENABLE); i2c_error = I2C_BUS_ERROR;
I2C_DBG("RB_I2C_BERR\n");
} if(event & RB_I2C_ARLO){ //仲裁丢失错误
I2C_ClearFlag(RB_I2C_ARLO); i2c_error = I2C_ARB_LOST;
I2C_DBG("RB_I2C_ARLO\n");
} I2C_DBG("\n");
}
硬件IIC主从机中断代码注释解析的更多相关文章
- STM32F10x_硬件I2C主从通信(轮询发送,中断接收)
Ⅰ.写在前面 关注我分享文章的朋友应该知道我在前面讲述过(软件.硬件)I2C主机控制从机EEPROM的例子.在I2C通信主机控制程序是比较常见的一种,可以说在实际项目中,很多应用都会使用到I2C通信. ...
- STM32 IIC双机通信—— HAL库硬件IIC版
参考传送门 关于IIC的原理这里我就不多说了,网上有很多很好的解析,如果要看我个人对IIC的理解的话,可以点击查看,这里主要讲一下怎样利用STM32CubeMx实现IIC的通讯,经过个人实践,感觉HA ...
- Hash源码注释解析
部分代码注释解析: 1 import java.io.IOException; 2 import java.io.InvalidObjectException; 3 import java.io.Se ...
- 硬件IIC驱动原理
1.IIC物理层 IIC通信属于同步半双工通信,IIC总线由两根信号线组成.一根是数据线SDA,一根是时钟线SCL,时钟线只能由主机发送给从机,数据线可以双向进行通信,总线上可挂载多个设备,挂载数量受 ...
- S3C2440硬件IIC详解
S3C2440A RISC微处理器可以支持一个多主控IIC 总线串行接口.一条专用串行数据线(SDA)和一条专用串行时钟线(SCL)传递连接到IIC总线的总线主控和外设之间的信息.SDA和SCL线都为 ...
- linux内核代码注释 赵炯 第三章引导启动程序
linux内核代码注释 第三章引导启动程序 boot目录中的三个汇编代码文件 bootsect.s和setup.s采用近似intel的汇编语法,需要8086汇编器连接器as86和ld86 head ...
- Arduino IIC 主从设备连接通信
目的: 实现Arduino主从设备之间的互相IIC通信,掌握IIC通信协议的使用方法. 器材: Arduino UNO R3 一块 Arduino Nano 三块 面包板 导线 3K ...
- STM32硬件IIC操作
Stm32具有IIC接口,接口有以下主要特性 多主机功能:该模块既可做主设备也可做从设备 主设备功能 C地址检测 位/10位地址和广播呼叫 支持不同的通讯速度 状态标志: 发送器/接收器模式标志 字节 ...
- STM32硬件IIC
/** * @brief 写一个字节到I2C设备中 * @param * @arg pBuffer:缓冲区指针 * @arg WriteAddr:写地址 * @retval 正常返回1,异常返回0 * ...
- 菜鸟笔记 -- Chapter 4.7 代码注释与编码规范
4.7 代码注释与编码规范 在程序代码中适当的添加注释可以提高程序的可读性和可维护性.好的编码规范可以使程序更易阅读和理解.下面我们将介绍几种代码注释,以及应该注意的编码规范. 4.7.1 代码注释 ...
随机推荐
- 真正“搞”懂HTTP协议08之重定向
我们知道,用来传输页面的协议就是HTTP协议,全称是超文本传输协议,而浏览器展示的页面则是用HTML编写的,HTML的全称则是超文本标记语言.你看,都叫做超文本,我在第一篇文章的时候也详细的聊过,超文 ...
- django框架之drf:2、restful规范,序列、反序列化,drf安装及使用(django原生接口及drf接口编写)
Django之drf 一.restful规范 1.概念 REST全称是Representational State Transfer,中文意思是表述:表征性状态转移,它首次出现在2000年Roy ...
- Java入门与进阶 P-3.5+P-3.6
计数循环 这个循环需要执行多少次? 循环停下来的时候,有没有输出到最后的0 ? 循环结束后count的值是多少 算数平方 让用户输入一系列的正整数,最后输入-1标识输入结束,然后程序计算出这些数字的平 ...
- 行为型模式 - 迭代器模式iterator
模式的定义与特点 迭代器模式(iterator Pattern),为的提是可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象.多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对 ...
- MyBatis的使用六(解决字段名与成员名不一致)
本文主要讲述mybatis如何解决mysql的字段名与java实体类的成员变量名称不一致. 一. 介绍实体类和数据表 1. 实体类Employee public class Employee { pr ...
- touchke变化值小的解决办法
方法一,提高主频 方法二,减小充电时间. 方法三,充电电流减半(具体看RM手册touchkey章节) 建议测试时采样值维持在3000-4000 其实以上操作就是增大Y轴间隔,以增大按下和未按下时的采样 ...
- YonBuilder移动开发平台App拉起第三方应用
在App的开发过程中,有一种常见场景,就是拉起第三方app,那么使用YonBuilder移动开发做app的时候,是怎么拉起第三方App的呢,下边我们讲一下步骤. 我们以安卓应用打开支付宝为例进行说明: ...
- 【踩坑记录】单测中@PostConstruct多次执行
问题复现: 单测中@PostConstruct修饰的方法被多次执行 原因: @PostConstruct在Spring中常用于在构造函数后初始化对象,执行顺序如下: 构造方法->成员变量注入-& ...
- springBoot集成flowable
前言 Flowable可以十分灵活地加入你的应用/服务/构架.可以将JAR形式发布的Flowable库加入应用或服务,来嵌入引擎. 以JAR形式发布使Flowable可以轻易加入任何Java环境:Ja ...
- 分布式共识算法随笔 —— 从 Quorum 到 Paxos
分布式共识算法随笔 -- 从 Quorum 到 Paxos 本文主要参考各类英文文献,部分专业术语翻译较为生硬,望谅解. 概览: 为什么需要共识算法? 昨夜西风凋碧树,独上高楼,望尽天涯路 复制(Re ...