AnsweredAssumed Answered

I2C slave interrupt issues

Question asked by kureigu on Sep 2, 2015
Latest reply on Jul 5, 2016 by nwankwo.sam
I have been struggling over the last few days to implement an I2C slave interrupt on my STM32F030F4P6 using the HAL drivers.

I set a new project up using STM32CubeMX, adding in only the I2C pins (and interrupt configuration) along with an LED output for diagnostics. Through polling  HAL_I2C_GetState(&hi2c1) I can see that I2C is consistently busy. An official example I found that came with the STM32CubeF0 stuff sets up in the same way I'm doing it (though I've not tested it).

So my first question is: What would cause I2C to remain busy here? What might I change to allow the slave to ready itself?

I notice that even though the I2C indicates it is busy, it will still be interrupted by a transmission on the bus. It enters the I2C_SlaveReceive_ISR() where it realises I2C_FLAG_ADDR is set and clears it -- Good, at least it responds to its address. It then jumps back around to this section of the ISR:

else if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET)
{
  /* Read data from RXDR */
  (*hi2c->pBuffPtr++) = hi2c->Instance->RXDR;
  hi2c->XferSize--;
  hi2c->XferCount--

and as soon as it executes the first line of the statement it jumps into a HardFault Handler:
HardFault_Handler
                PROC
                EXPORT  HardFault_Handler              [WEAK]
                B       .
                ENDP

My second question: Anyone have any idea why this might be happening? How do I avoid this to allow the slave to actually receive the data?

Lastly, and not related: Am I correct in assuming that the HAL_I2C_EV_IRQHandler() will allow me to distinguish between Slave Read/Write commands?

Here is the rest of my code:

main.c:
/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx_hal.h"
 
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
 
/* Private variables ---------------------------------------------------------*/
uint8_t data = 0xFF;
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
 
/* Private function prototypes -----------------------------------------------*/
 
 
int main(void)
{
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
 
     
 while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  {
        // Waiting for setup? - Flash at 2Hz
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
        HAL_Delay(250);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
        HAL_Delay(250);
  }
     
 
 
  while(HAL_I2C_Slave_Receive_IT(&hi2c1, (uint8_t *) data, 1) != HAL_OK)
  {
    // Transfer error in transmission process - Flash at 1Hz
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
        HAL_Delay(500);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
        HAL_Delay(500);
  }
     
  while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  {
        // 5Hz flash while not ready
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
        HAL_Delay(100);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
        HAL_Delay(100);
  }
     
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
 
  while (1)
  {
         
    // 0.5Hz blip when idle
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    HAL_Delay(1900);
 
 
  }
  
}
 
 
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}
     
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    HAL_Delay(900);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    HAL_Delay(100);
}
 
 
/** System Clock Configuration */
void SystemClock_Config(void)
{
 
 
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;
 
 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);
 
 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
 
 
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
 
 
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 
 
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
 
}
 
 
/* I2C1 init function */
void MX_I2C1_Init(void)
{
 
 
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x2000090E;
  hi2c1.Init.OwnAddress1 = 0xC2;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
  if(HAL_I2C_Init(&hi2c1) != HAL_OK){
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    }
 
 
    /**Configure Analogue filter
    */
  HAL_I2CEx_AnalogFilter_Config(&hi2c1, I2C_ANALOGFILTER_ENABLED);
 
 
}
 
 
/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{
 
 
  GPIO_InitTypeDef GPIO_InitStruct;
 
 
  /* GPIO Ports Clock Enable */
  __GPIOA_CLK_ENABLE();
 
 
  /*Configure GPIO pin : PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
 
}
 
 
 
 
#ifdef USE_FULL_ASSERT
 
 
void assert_failed(uint8_t* file, uint32_t line)
{
 
 
}
 
 
#endif
 
 
/**
  * @}
  */
 
 
/**
  * @}
*/

Additional I2C configuration:
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
 
  GPIO_InitTypeDef GPIO_InitStruct;
  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */
 
  /* USER CODE END I2C1_MspInit 0 */
   
    /**I2C1 GPIO Configuration   
    PA9     ------> I2C1_SCL
    PA10     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    /* Peripheral clock enable */
    __I2C1_CLK_ENABLE();
  /* Peripheral interrupt init*/
    HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C1_IRQn);
  /* USER CODE BEGIN I2C1_MspInit 1 */
 
  /* USER CODE END I2C1_MspInit 1 */
  }
 
}


Relevant section of the I2C IRQ event handler:
void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c)
{
  /* I2C in mode Transmitter ---------------------------------------------------*/
  if (((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TCR) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TC) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET)) && (__HAL_I2C_GET_IT_SOURCE(hi2c, (I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_TXI | I2C_IT_ADDRI)) == SET))
  {    
    /* Slave mode selected */
    if (hi2c->State == HAL_I2C_STATE_SLAVE_BUSY_TX)
    {
      I2C_SlaveTransmit_ISR(hi2c);
    }
  }
     
  if (((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TCR) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TC) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET)) && (__HAL_I2C_GET_IT_SOURCE(hi2c, (I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_TXI)) == SET))
  {    
    /* Master mode selected */
    if ((hi2c->State == HAL_I2C_STATE_MASTER_BUSY_TX) || (hi2c->State == HAL_I2C_STATE_MEM_BUSY_TX))
    {
      I2C_MasterTransmit_ISR(hi2c);
    }
  }
     
  /* I2C in mode Receiver ----------------------------------------------------*/
  if (((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TCR) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TC) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET)) && (__HAL_I2C_GET_IT_SOURCE(hi2c, (I2C_IT_TCI| I2C_IT_STOPI| I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_ADDRI)) == SET))
  {
    /* Slave mode selected */
    if (hi2c->State == HAL_I2C_STATE_SLAVE_BUSY_RX)
    {
      I2C_SlaveReceive_ISR(hi2c);  // <<<<<<<<----------- ENTERS ISR HERE
    }
  }
  if (((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TCR) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TC) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) || (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET)) && (__HAL_I2C_GET_IT_SOURCE(hi2c, (I2C_IT_TCI| I2C_IT_STOPI| I2C_IT_NACKI | I2C_IT_RXI)) == SET))
  {
    /* Master mode selected */
    if ((hi2c->State == HAL_I2C_STATE_MASTER_BUSY_RX) || (hi2c->State == HAL_I2C_STATE_MEM_BUSY_RX))
    {
      I2C_MasterReceive_ISR(hi2c);
    }
  }
}

Relevant section of  I2C_SlaveReceive_ISR:
static HAL_StatusTypeDef I2C_SlaveReceive_ISR(I2C_HandleTypeDef *hi2c)
{
  /* Process Locked */
  __HAL_LOCK(hi2c);
   
  if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) != RESET)
  {
    /* Clear NACK Flag */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
 
    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);
     
    hi2c->ErrorCode |= HAL_I2C_ERROR_AF;
    HAL_I2C_ErrorCallback(hi2c);
  }
  else if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET)
  {
    /* Clear ADDR flag */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);  /////  <<<<<----- No Problems when this runs
  }
  else if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET)
  {
    /* Read data from RXDR */
    (*hi2c->pBuffPtr++) = hi2c->Instance->RXDR;   /////  <<<<<----- HARD FAULT ERROR OCCURS HERE
    hi2c->XferSize--;
    hi2c->XferCount--;
  }
  else if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET)
  {
    /* Disable ERRI, TCI, STOPI, NACKI, ADDRI, RXI, TXI interrupt */
    __HAL_I2C_DISABLE_IT(hi2c,I2C_IT_ERRI | I2C_IT_TCI| I2C_IT_STOPI| I2C_IT_NACKI | I2C_IT_ADDRI | I2C_IT_RXI | I2C_IT_RXI );
     
    /* Disable Address Acknowledge */
    hi2c->Instance->CR2 |= I2C_CR2_NACK;
 
    /* Clear STOP Flag */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
 
    hi2c->State = HAL_I2C_STATE_READY;
     
    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);
 
    HAL_I2C_SlaveRxCpltCallback(hi2c); 
  }
 
  /* Process Unlocked */
  __HAL_UNLOCK(hi2c);
   
  return HAL_OK;    

Outcomes