Embedded STM32F40x芯片的I2C外围设备没有可用于固件的r/w位
我想知道是否有人找到了一种方法来确定主机与stm32f40x芯片通信的意图?从stm32f40x芯片固件的角度来看,主机发送的地址不可用,其中包含的r/w位(地址的位0)也不可用。那么如何防止碰撞呢?还有其他人处理过吗?如果是这样,你使用了什么技术?我的暂定方案如下,以供参考。我延迟了对DR数据寄存器的任何写入,直到TXE中断发生。起初我以为这样做太晚了,一个字节的垃圾会被打卡,但它似乎在工作Embedded STM32F40x芯片的I2C外围设备没有可用于固件的r/w位,embedded,communication,stm32,i2c,stm32f4discovery,Embedded,Communication,Stm32,I2c,Stm32f4discovery,我想知道是否有人找到了一种方法来确定主机与stm32f40x芯片通信的意图?从stm32f40x芯片固件的角度来看,主机发送的地址不可用,其中包含的r/w位(地址的位0)也不可用。那么如何防止碰撞呢?还有其他人处理过吗?如果是这样,你使用了什么技术?我的暂定方案如下,以供参考。我延迟了对DR数据寄存器的任何写入,直到TXE中断发生。起初我以为这样做太晚了,一个字节的垃圾会被打卡,但它似乎在工作 static inline void LLEVInterrupt(uint16_t irqSrc) {
static inline void LLEVInterrupt(uint16_t irqSrc)
{
uint8_t i;
volatile uint16_t status;
I2CCBStruct* buffers;
I2C_TypeDef* addrBase;
// see which IRQ occurred, process accordingly...
switch (irqSrc)
{
case I2C_BUS_CHAN_1:
addrBase = this.addrBase1;
buffers = &this.buffsBus1;
break;
case I2C_BUS_CHAN_2:
addrBase = this.addrBase2;
buffers = &this.buffsBus2;
break;
case I2C_BUS_CHAN_3:
addrBase = this.addrBase3;
buffers = &this.buffsBus3;
break;
default:
while(1);
}
// ...START condition & address match detected
if (I2C_GetITStatus(addrBase, I2C_IT_ADDR) == SET)
{
// I2C_IT_ADDR: Cleared by software reading SR1 register followed reading SR2, or by hardware
// when PE=0.
// Note: Reading I2C_SR2 after reading I2C_SR1 clears the ADDR flag, even if the ADDR flag was
// set after reading I2C_SR1. Consequently, I2C_SR2 must be read only when ADDR is found
// set in I2C_SR1 or when the STOPF bit is cleared.
status = addrBase->SR1;
status = addrBase->SR2;
// Reset the index and receive count
buffers->txIndex = 0;
buffers->rxCount = 0;
// setup to ACK any Rx'd bytes
I2C_AcknowledgeConfig(addrBase, ENABLE);
return;
}
// Slave receiver mode
if (I2C_GetITStatus(addrBase, I2C_IT_RXNE) == SET)
{
// I2C_IT_RXNE: Cleared by software reading or writing the DR register
// or by hardware when PE=0.
// copy the received byte to the Rx buffer
buffers->rxBuf[buffers->rxCount] = (uint8_t)I2C_ReadRegister(addrBase, I2C_Register_DR);
if (RX_BUFFER_SIZE > buffers->rxCount)
{
buffers->rxCount++;
}
return;
}
// Slave transmitter mode
if (I2C_GetITStatus(addrBase, I2C_IT_TXE) == SET)
{
// I2C_IT_TXE: Cleared by software writing to the DR register or
// by hardware after a start or a stop condition or when PE=0.
// send any remaining bytes
I2C_SendData(addrBase, buffers->txBuf[buffers->txIndex]);
if (buffers->txIndex < buffers->txCount)
{
buffers->txIndex++;
}
return;
}
// ...STOP condition detected
if (I2C_GetITStatus(addrBase, I2C_IT_STOPF) == SET)
{
// STOPF (STOP detection) is cleared by software sequence: a read operation
// to I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to
// I2C_CR1 register (I2C_Cmd() to re-enable the I2C peripheral).
// From the reference manual RM0368:
// Figure 163. Transfer sequence diagram for slave receiver
// if (STOPF == 1) {READ SR1; WRITE CR1}
// clear the IRQ status
status = addrBase->SR1;
// Write to CR1
I2C_Cmd(addrBase, ENABLE);
// read cycle (reset the status?
if (buffers->txCount > 0)
{
buffers->txCount = 0;
buffers->txIndex = 0;
}
// write cycle begun?
if (buffers->rxCount > 0)
{
// pass the I2C data to the enabled protocol handler
for (i = 0; i < buffers->rxCount; i++)
{
#if (COMM_PROTOCOL == COMM_PROTOCOL_DEBUG)
status = ProtProcRxData(buffers->rxBuf[i]);
#elif (COMM_PROTOCOL == COMM_PROTOCOL_PTEK)
status = PTEKProcRxData(buffers->rxBuf[i]);
#else
#error ** Invalid Host Protocol Selected **
#endif
if (status != ST_OK)
{
LogErr(ST_COMM_FAIL, __LINE__);
}
}
buffers->rxCount = 0;
}
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_AF) == SET)
{
// The NAck received from the host on the last byte of a transmit
// is shown as an acknowledge failure and must be cleared by
// writing 0 to the AF bit in SR1.
// This is not a real error but just how the i2c slave transmission process works.
// The hardware has no way to know how many bytes are to be transmitted, so the
// NAck is assumed to be a failed byte transmission.
// EV3-2: AF=1; AF is cleared by writing ‘0’ in AF bit of SR1 register.
I2C_ClearITPendingBit(addrBase, I2C_IT_AF);
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_BERR) == SET)
{
// There are extremely infrequent bus errors when testing with I2C Stick.
// Safer to have this check and clear than to risk an
// infinite loop of interrupts
// Set by hardware when the interface detects an SDA rising or falling
// edge while SCL is high, occurring in a non-valid position during a
// byte transfer.
// Cleared by software writing 0, or by hardware when PE=0.
I2C_ClearITPendingBit(addrBase, I2C_IT_BERR);
LogErr(ST_COMM_FAIL, __LINE__);
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_OVR) == SET)
{
// Check for other errors conditions that must be cleared.
I2C_ClearITPendingBit(addrBase, I2C_IT_OVR);
LogErr(ST_COMM_FAIL, __LINE__);
return;
}
if (I2C_GetITStatus(addrBase, I2C_IT_TIMEOUT) == SET)
{
// Check for other errors conditions that must be cleared.
I2C_ClearITPendingBit(addrBase, I2C_IT_TIMEOUT);
LogErr(ST_COMM_FAIL, __LINE__);
return;
}
// a spurious IRQ occurred; log it
LogErr(ST_INV_STATE, __LINE__);
}
静态内联无效LLEVInterrupt(uint16\u t irqSrc)
{
uint8_t i;
易失性uint16_t状态;
I2CCBStruct*缓冲区;
I2C_TypeDef*addrBase;
//查看发生的IRQ,相应地处理。。。
交换机(irqSrc)
{
案例I2C_总线_CHAN_1:
addrBase=this.addrBase1;
缓冲区=&this.buffsBus1;
打破
案例I2C_总线_CHAN_2:
addrBase=this.addrBase2;
缓冲区=&this.buffsBus2;
打破
案例I2C_总线_CHAN_3:
addrBase=this.addrBase3;
缓冲区=&this.buffsBus3;
打破
违约:
而(1),;
}
//…检测到开始条件和地址匹配
if(I2C_GetITStatus(addrBase,I2C_IT_ADDR)==SET)
{
//I2C_IT_ADDR:通过软件读取SR1寄存器,然后读取SR2,或通过硬件进行清除
//当PE=0时。
//注意:在读取I2C_SR1之后读取I2C_SR2将清除ADDR标志,即使ADDR标志已被删除
//在读取I2C_SR1后设置。因此,当找到ADDR时,I2C_SR2必须为只读
//在I2C_SR1或清除STOPF位时设置。
status=addrBase->SR1;
status=addrBase->SR2;
//重置索引和接收计数
缓冲区->txIndex=0;
缓冲区->rxCount=0;
//设置为确认任何接收字节
I2C_确认图(添加数据库,启用);
回来
}
//从接收机模式
if(I2C_GetITStatus(addrBase,I2C_IT_RXNE)==SET)
{
//I2C_IT_RXNE:通过软件读取或写入DR寄存器进行清除
//或在PE=0时通过硬件。
//将接收到的字节复制到Rx缓冲区
buffers->rxBuf[buffers->rxCount]=(uint8_t)I2C_读取寄存器(addrBase,I2C_寄存器\u DR);
如果(接收缓冲区大小>缓冲区->接收计数)
{
缓冲区->rxCount++;
}
回来
}
//从发射机模式
if(I2C_GetITStatus(addrBase,I2C_IT_TXE)==SET)
{
//I2C_IT_TXE:通过软件写入DR寄存器或
//在启动或停止条件后或PE=0时通过硬件。
//发送剩余的字节
I2C_SendData(addrBase,buffers->txBuf[buffers->txIndex]);
如果(缓冲区->txIndextxCount)
{
缓冲区->txIndex++;
}
回来
}
//…检测到停止条件
if(I2C_GetITStatus(addrBase,I2C_IT_STOPF)==SET)
{
//STOPF(停止检测)通过软件顺序清除:读取操作
//到I2C_SR1寄存器(I2C_GetITStatus()),然后执行写入操作
//I2C_CR1寄存器(I2C_Cmd()用于重新启用I2C外围设备)。
//参考手册RM0368:
//图163.从接收机的传输序列图
//如果(STOPF==1){READ SR1;WRITE CR1}
//清除IRQ状态
status=addrBase->SR1;
//写入CR1
I2C_Cmd(addrBase,ENABLE);
//读取循环(重置状态?
如果(缓冲区->txCount>0)
{
缓冲区->txCount=0;
缓冲区->txIndex=0;
}
//写周期开始了吗?
如果(缓冲区->rxCount>0)
{
//将I2C数据传递给已启用的协议处理程序
对于(i=0;irxCount;i++)
{
#if(通信协议==通信协议调试)
状态=扩展数据(缓冲区->rxBuf[i]);
#elif(通信协议==通信协议PTEK)
状态=PTEKProcRxData(缓冲区->rxBuf[i]);
#否则
#错误**选择的主机协议无效**
#恩迪夫
如果(状态!=ST_OK)
{
日志错误(ST通信故障,线路故障);
}
}
缓冲区->rxCount=0;
}
回来
}
if(I2C_GetITStatus(addrBase,I2C_IT_AF)==SET)
{
//在传输的最后一个字节上从主机接收的NAck
//显示为确认故障,必须由
//将0写入SR1中的AF位。
//这不是真正的错误,而是i2c从机传输过程的工作原理。
//硬件无法知道要传输多少字节,因此
//假设NAck是一个失败的字节传输。
//EV3-2:AF=1;通过在SR1寄存器的AF位中写入“0”来清除AF。
I2C_ClearITPendingBit(添加数据库、I2C_IT_AF);
回来
}
if(I2C_GetITStatus(addrBase,I2C_IT_BERR)==SET)
{
//使用I2C棒测试时,总线错误极为罕见。
//进行此检查和清除比冒险
//无限循环中断
//当接口检测到SDA上升或下降时,由硬件设置
//SCL高时的边缘,在故障期间发生在无效位置
//字节传输。
//通过软件写入0清除,或在PE=0时通过硬件清除。
I2C_ClearITPendingBit(添加数据库,I2C_IT_BERR);
日志错误(ST通信故障,线路故障);
回来
}
if(I2C_GetITStatus(addrBase,I2C_IT_OVR)==SET)
{
//检查其他