stm32f0 iic从机
最近在捣鼓stm32f0的IIC从机,之前一直使用的是IIC主机,IIC主机主要用的是IO口模拟的,实现起来没什么问题。但是转到IIC从机后,发现通信读取数据过程中偶尔会出现串码的现象,大概一小时会出现两三次。以下是IIC从机的部分代码:/*-- defined -----------------------------------------------------------------*/
#define SLAVE_ADDR 0x16
#define POLYNOME 0x07
#define I2C_REC_BYTES 64
#define I2C_TX_BYTES 64
/*-- private variables -------------------------------------------------------*/
static I2C_HandleTypeDefhi2c1;
static u8_t slaveTxBuff = {0};
static u8_t slaveRxBuff = {0};
staticu8_t rsoc;
staticu16_t battVolt;
statics16_t current;
staticu16_t Temper;
staticu16_t cellVolt;
/*-- functions ---------------------------------------------------------------*/
staticvoidtx_match(u8_t cmd);
/**@brief
* @brief IIC初始化
* @param
* @return
*/
void hal_iic_init(void)
{
u32_ttmpisr = 0;
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x2000090E;
hi2c1.Init.OwnAddress1 = SLAVE_ADDR;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
}
/* Configure Analogue filter */
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
}
/* Configure Digital filter */
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
}
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_IRQn);
/**
I2C_IT_ADDRI: Address match interrupt.
I2C_IT_STOPI: STOP detection interrupt.
I2C_IT_NACKI: NACK received interrupt.
I2C_IT_ERRI: Errors interrupt.
I2C_IT_TCI: TC interrupt.
I2C_XFER_RX_IT: REC interrupt.
*/
tmpisr |= I2C_IT_ADDRI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ERRI | I2C_IT_RXI | I2C_IT_TXI;
__HAL_I2C_ENABLE_IT(&hi2c1, tmpisr);
}
/**@brief
* @brief
* @param
* @return
*/
voidi2c_err_irq_handler(I2C_HandleTypeDef *hi2c, u32_t isrFlag)
{
if((isrFlag & I2C_FLAG_ARLO) == I2C_FLAG_ARLO)
{ /* ARLO Err */
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
}
if((isrFlag & I2C_FLAG_BERR) == I2C_FLAG_BERR)
{ /* BERR Err */
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
}
if((isrFlag & I2C_FLAG_OVR) == I2C_FLAG_OVR)
{ /* OVR Err */
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR);
}
}
/**@brief
* @brief
* @param
* @return
*/
voidi2c_evt_irq_handler(I2C_HandleTypeDef *hi2c, u32_t isrFlag)
{
static u8_t txCounter = 0;
static u8_t rxCounter = 0;
u32_ttransferDir = 0;
if(hi2c->Instance == hi2c1.Instance)
{
if((isrFlag & I2C_FLAG_ADDR) == I2C_FLAG_ADDR)
{
/* EV1 */
transferDir = isrFlag & I2C_ISR_DIR;
/* 判断方向 */
if(transferDir)
{
/* 方向为从机发送 */
I2C1->ISR |= I2C_ISR_TXE;
I2C1->TXDR = slaveTxBuff;
txCounter = 1;
}
else
{
/* 方向为从机接收 */
rxCounter = 0;
}
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);
}
else if((isrFlag & I2C_FLAG_TXIS) == I2C_FLAG_TXIS)
{
/* EV3 */
I2C1->TXDR = slaveTxBuff;
}
else if((isrFlag & I2C_FLAG_RXNE) == I2C_FLAG_RXNE)
{
/* EV2 */
if(rxCounter < I2C_REC_BYTES)
{
slaveRxBuff = hi2c->Instance->RXDR;
/* 进行命令匹配 */
if(rxCounter == 0)
{
tx_match(slaveRxBuff);
}
rxCounter++;
}
}
else if((isrFlag & I2C_FLAG_STOPF) == I2C_FLAG_STOPF)
{
/* EV4 */
hi2c->Instance->ISR |= I2C_ISR_TXE;
hi2c->Instance->ISR |= I2C_ISR_TXIS;
txCounter = 0;
rxCounter = 0;
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
}
else if((isrFlag & I2C_FLAG_AF) == I2C_FLAG_AF)
{
/* EV3_2 */
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
}
}
}
/**
* @brief This function handles I2C1 global interrupt.
* @param
* @param
* @return
*/
void I2C1_IRQHandler(void)
{
u32_t isrFlag = 0;
isrFlag = hi2c1.Instance->ISR;
if (isrFlag & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR))
{
/* 异常处理 */
//HAL_I2C_ER_IRQHandler(&hi2c1);
i2c_err_irq_handler(&hi2c1, isrFlag);
}
else
{
/* 事件处理 */
//HAL_I2C_EV_IRQHandler(&hi2c1);
i2c_evt_irq_handler(&hi2c1, isrFlag);
}
}
/** @function
* @brief IIC从机匹配发送数据,发现如果使用switch-case出错率会更高,不知为何。
* @param
* @return
*/
staticvoidtx_match(u8_t cmd)
{
u8_tcounter = 0;
if(cmd == 0x08)
{
slaveTxBuff = Temper&0x00ff;
slaveTxBuff = (Temper&0xff00)>>8;
Temper++;
}
else if(cmd == 0x09)
{
slaveTxBuff = battVolt&0x00ff;
slaveTxBuff = (battVolt&0xff00)>>8;
battVolt++;
}
else if(cmd == 0x0A)
{
slaveTxBuff = current&0x00ff;
slaveTxBuff = (current&0xff00)>>8;
}
else if(cmd == 0x0D)
{
slaveTxBuff = rsoc&0x00ff;
slaveTxBuff = (rsoc&0xff00)>>8;
}
else if(cmd == 0x3F)
{
slaveTxBuff = cellVolt&0x00ff;
slaveTxBuff = (cellVolt&0xff00)>>8;
}
else if(cmd == 0x3E)
{
slaveTxBuff = cellVolt&0x00ff;
slaveTxBuff = (cellVolt&0xff00)>>8;
}
else if(cmd == 0x3D)
{
slaveTxBuff = cellVolt&0x00ff;
slaveTxBuff = (cellVolt&0xff00)>>8;
}
slaveTxBuff = CRC8(slaveTxBuff, counter, POLYNOME);
}
可能是因为本人对IIC从机原理理解得不够深,折腾了两天还是没什么进展,望由此经验的朋友多多指教,谢谢!
主机是模拟的做的,要注意对SCL的检测,因为从机使能了延展功能,延展期间要等等从机的响应。另外建议先调通简单的收发,再导入其他的分支处理程序。 butterflyspring 发表于 2020-7-9 10:19
主机是模拟的做的,要注意对SCL的检测,因为从机使能了延展功能,延展期间要等等从机的响应。另外建议先调通 ...
请问NoStretchMode成员设置为I2C_NOSTRETCH_ENABLE是允许时钟延伸吗?
按字面意思我以为是禁止了时钟延伸。 乐乐棠 发表于 2020-7-14 13:37
请问NoStretchMode成员设置为I2C_NOSTRETCH_ENABLE是允许时钟延伸吗?
按字面意思我以为是禁止了时钟延伸 ...
看字面的意思是使能为禁止的意思。不过最好的办法是对照手册,如图。可以调试观察这位在运行后设置的结果。
butterflyspring 发表于 2020-7-17 10:05
看字面的意思是使能为禁止的意思。不过最好的办法是对照手册,如图。可以调试观察这位在运行后设置的结果 ...
好的,谢谢,这个问题我只能先放一放,先处理急的事情,过段时间再弄一下。:lol 时钟的偏移呢? liuyangbo86 发表于 2020-7-22 17:53
时钟的偏移呢?
“hi2c1.Init.Timing = 0x2000090E” 请问说的是这个吗? 我把IIC从机中断优先级调整为最高级,经过几个小时的测试,数据一次都没有出错过,暂时认定为是其他中断影响了IIC从机中断的发送。
页:
[1]