乐乐棠 发表于 2020-6-24 09:53:34

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从机原理理解得不够深,折腾了两天还是没什么进展,望由此经验的朋友多多指教,谢谢!


butterflyspring 发表于 2020-7-9 10:19:34

主机是模拟的做的,要注意对SCL的检测,因为从机使能了延展功能,延展期间要等等从机的响应。另外建议先调通简单的收发,再导入其他的分支处理程序。

乐乐棠 发表于 2020-7-14 13:37:39

butterflyspring 发表于 2020-7-9 10:19
主机是模拟的做的,要注意对SCL的检测,因为从机使能了延展功能,延展期间要等等从机的响应。另外建议先调通 ...

请问NoStretchMode成员设置为I2C_NOSTRETCH_ENABLE是允许时钟延伸吗?
按字面意思我以为是禁止了时钟延伸。

butterflyspring 发表于 2020-7-17 10:05:15

乐乐棠 发表于 2020-7-14 13:37
请问NoStretchMode成员设置为I2C_NOSTRETCH_ENABLE是允许时钟延伸吗?
按字面意思我以为是禁止了时钟延伸 ...

看字面的意思是使能为禁止的意思。不过最好的办法是对照手册,如图。可以调试观察这位在运行后设置的结果。

乐乐棠 发表于 2020-7-21 08:00:45

butterflyspring 发表于 2020-7-17 10:05
看字面的意思是使能为禁止的意思。不过最好的办法是对照手册,如图。可以调试观察这位在运行后设置的结果 ...

好的,谢谢,这个问题我只能先放一放,先处理急的事情,过段时间再弄一下。:lol

liuyangbo86 发表于 2020-7-22 17:53:40

时钟的偏移呢?

乐乐棠 发表于 2020-7-24 15:04:38

liuyangbo86 发表于 2020-7-22 17:53
时钟的偏移呢?

“hi2c1.Init.Timing = 0x2000090E” 请问说的是这个吗?

乐乐棠 发表于 2020-8-15 08:40:29

我把IIC从机中断优先级调整为最高级,经过几个小时的测试,数据一次都没有出错过,暂时认定为是其他中断影响了IIC从机中断的发送。
页: [1]
查看完整版本: stm32f0 iic从机