cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 I2C HAL slave receive callback not called

Arete sw
Associate II
Posted on July 22, 2017 at 02:47

I find when I make a call to HAL_I2C_Slave_Receive_IT it returns HAL_OK but it never manages to call the callback function, my HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle) implementation.

Using a logic analyzer, I find that the device never acks the address and instead holds the clock line low till the device is reset.

I find if I use the synchronous api, HAL_I2C_Slave_Receive it ACKs and get's data just fine.

Also I am using the latest version of the STM32CubeMX + Keil ARM-MDK.

Any ideas? Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
Posted on July 27, 2017 at 12:29

This means that not all information you tried to receive received!!

you put at HAL_I2C_Slave_Receive_IT(I2cHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);

Means that RXBUFFERSIZE is bigger than the bytes you received , so adjust buffersize according the bytes you want to receive

A different aproximation is to wait for a fixed size 'header' which contains the length of a future transaction.

Also ,dont call transaction functions  inside callbacks , you will face lock situations

View solution in original post

13 REPLIES 13
Posted on July 22, 2017 at 16:00

Hello Arete.

What hardware you use?

Is your I2C ISR being  interrupted by some other ISR with higher priority?

Try to put a breakpoint  at HAL_I2C_EV_IRQHandler(..) function to observe the behaviour.

Arete sw
Associate II
Posted on July 25, 2017 at 00:48

Hi Vangelis,

I am using the STM32F0308 discovery board. I tried to set a breakpoint in the HAL_I2C_EV_IRQHandler but found it was getting optimized out, so I couldn't set a breakpoint. This is with code generated with the STM32CubeMX software.

Thanks.

Posted on July 25, 2017 at 01:24

Hello!

It is not 'optimized'  It is not duilt nor linked!

I faced this issue  in keil but i did not found a 'formal solution'

I put  a  function(like dummy) in module stm32f0xx_it.c This function is called from Main.c

This ensures that stm32f0xx_it.c  will include in build procedure and will linked in executable file.

Try it!

Regards

Posted on July 26, 2017 at 00:15

Hello Again!!

At first check your bus's pullup resistors.

About your problem now.

Actualy is not a problem.. 

You have to call HAL_I2C_Slave_Receive_IT(...)  every time you want to initiate a transaction as slave!!

so i suggest to set a custom flag inside HAL_I2C_SlaveTxCpltCallback(...) callback function to inform your while loop about reception event and to call again after this the HAL_I2C_Slave_Receive_IT(..)

Posted on July 25, 2017 at 23:31

Ok after working on this a bit I found that, I can get ack and receive data only one time, after the first success the mcu holds the clock line low where the ack should be and leaves it there till a reset. Still the HAL_I2C_SlaveRxCpltCallback doesn't get called. The following i2c message receives appears to result in HAL_I2C_ERROR_AF and a stuck clock line.

I started a new project working off the TwoBoards_ComIT example:

♯ include 'main.h'

/** @addtogroup STM32F0xx_HAL_Examples

* @{

*/

/** @addtogroup I2C_TwoBoards_ComIT

* @{

*/

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Uncomment this line to use the board as master, if not it is used as slave */

// ♯ define MASTER_BOARD

// ♯ define I2C_ADDRESS 0x30F

/* I2C TIMING Register define when I2C clock source is SYSCLK */

/* I2C TIMING is calculated in case of the I2C Clock source is the SYSCLK = 48 MHz */

/* This example use TIMING to 0x00A51314 to reach 1 MHz speed (Rise time = 100 ns, Fall time = 100 ns) */

♯ define I2C_TIMING 0x00A51314

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* I2C handler declaration */

I2C_HandleTypeDef I2cHandle;

/* Buffer used for reception */

uint8_t aRxBuffer[RXBUFFERSIZE];

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void Error_Handler(void);

/* Private functions ---------------------------------------------------------*/

/**

* @brief Main program

* @param None

* @retval None

*/

int main(void)

{

/* STM32F0xx HAL library initialization:

- Configure the Flash prefetch

- Systick timer is configured by default as source of time base, but user

can eventually implement his proper time base source (a general purpose

timer for example or other time source), keeping in mind that Time base

duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and

handled in milliseconds basis.

- Low Level Initialization

*/

HAL_Init();

/* Configure the system clock to 48 MHz */

SystemClock_Config();

/* Configure LED3 and LED4 */

BSP_LED_Init(LED3);

BSP_LED_Init(LED4);

I2cHandle.Instance = I2C1;

I2cHandle.Init.Timing = 0x2000090E;

I2cHandle.Init.OwnAddress1 = 30 << 1;//60;

I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

I2cHandle.Init.OwnAddress2 = 0;

I2cHandle.Init.OwnAddress2Masks = I2C_OA2_NOMASK;

I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;

I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

HAL_I2C_Init(&I2cHandle);

/**Configure Analogue filter

*/

HAL_I2CEx_ConfigAnalogFilter(&I2cHandle, I2C_ANALOGFILTER_ENABLE);

/**Configure Digital filter

*/

HAL_I2CEx_ConfigDigitalFilter(&I2cHandle, 0);

/* The board receives the message and sends it back */

/* ♯ ♯ -2- Put I2C peripheral in reception process ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ */

if(HAL_I2C_Slave_Receive_IT(&I2cHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)

{

/* Transfer error in reception process */

Error_Handler();

}

/* Infinite loop */

while (1)

{

}

}

/**

* @brief System Clock Configuration

* The system Clock is configured as follow :

* System Clock source = PLL (HSE)

* SYSCLK(Hz) = 48000000

* HCLK(Hz) = 48000000

* AHB Prescaler = 1

* APB1 Prescaler = 1

* HSE Frequency(Hz) = 8000000

* PREDIV = 1

* PLLMUL = 6

* Flash Latency(WS) = 1

* @param None

* @retval None

*/

void SystemClock_Config(void)

{

RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_OscInitTypeDef RCC_OscInitStruct;

/* Select HSE Oscillator as PLL source */

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

RCC_OscInitStruct.HSEState = RCC_HSE_ON;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;

RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)

{

/* Initialization Error */

while(1);

}

/* Select PLL as system clock source and configure the HCLK and PCLK1 clocks dividers */

RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1);

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1)!= HAL_OK)

{

/* Initialization Error */

while(1);

}

}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle)

{

/* Toggle LED3: Transfer in reception process is correct */

BSP_LED_Toggle(LED3);

HAL_I2C_Slave_Receive_IT(I2cHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);

}

void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *I2cHandle) {

HAL_I2C_Slave_Receive_IT(I2cHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE);

}

/**

* @brief I2C error callbacks.

* @param I2cHandle: I2C handle

* @note This example shows a simple way to report transfer error, and you can

* add your own implementation.

* @retval None

*/

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *I2cHandle)

{

/** Error_Handler() function is called when error occurs.

* 1- When Slave don't acknowledge it's address, Master restarts communication.

* 2- When Master don't acknowledge the last data transferred, Slave don't care in this example.

*/

if (HAL_I2C_GetError(I2cHandle) != HAL_I2C_ERROR_AF)

{

/* Turn Off LED3 */

BSP_LED_Off(LED3);

/* Turn On LED4 */

BSP_LED_On(LED4);

}

}
Posted on July 26, 2017 at 00:26

The Problem is that 

HAL_I2C_SlaveTxCpltCallback still never gets called.

thanks for your help.

Posted on July 26, 2017 at 00:36

you wrote ' I can get ack and receive data only one time'

every time you start a new project in KEIL  the  stm32f0xx_it.c never built or linked

Posted on July 26, 2017 at 00:41

Apologies for the confusion. stm32f0xx_it.c is definitely getting built and linked.

At this point, I can see that the stm32 is acking the address (the first time after a reset) but doesn't end up calling 

HAL_I2C_SlaveTxCpltCallback.

Thanks.

Posted on July 26, 2017 at 00:59

Make another try. .Put a breakpoint to I2C1IRQ_handler. . Not to callback.

Check also in debuging mode the peripherals-NVIC to observe the behaviour of I2c1 interrupt. (enable,priority, active, pending) after you call the receive function. Is the master responsible for the pullup resistors in the bus?