cancel
Showing results for 
Search instead for 
Did you mean: 

Trying to write data over I2C to an STM32F103C6 working as a slave in IT mode only gives a hard fault and the data is not stored in the array

VRami.1
Associate III

***Edited to show the probably all the code involved without including the HAL libraries***

Hi all, I'm using HAL libraries to code an STM32F103C6 as a slave and I'm using HAL_I2C_Slave_Receive_IT(), debugging I can see that the slave recognize its address and reads the data but the data is not processed to be stored in the array prepared for that.

As soon as the I2C peripheral receives the first data byte it generates a interrupt for hard fault, I've been trying to read HSFR to have an idea of what generated the hard fault but inside the hard fault handler HFSR always reads zero. I've putted breakpoints in the I2C interrupt handler and I could check that the program never enters in the i2c interrupt handler which means that its interrupt is doesn't been managed.

The main.c file is this:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "rtc.h"
#include "gpio.h"
 
uint8_t mensaje[2];
uint8_t result;
/* USER CODE END PTD */
 
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
void SystemClock_Config(void);
 
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_ADC1_Init();
  MX_I2C1_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
  HAL_I2C_MspInit(&hi2c1);
 
  HAL_GPIO_WritePin(GPIOA,FASE6_ROJO_Pin,GPIO_PIN_SET);
  if(HAL_I2C_Slave_Receive_IT(&hi2c1,mensaje,1) != HAL_OK)
  {
	  HAL_GPIO_WritePin(GPIOA,FASE1_AMA_Pin,GPIO_PIN_SET);
  }
  HAL_GPIO_WritePin(GPIOA,FASE1_AMA_Pin,GPIO_PIN_RESET);
 
  /* USER CODE BEGIN WHILE */
  while (1)
  {
 
  }
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_ADC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
 
void Error_Handler(void)
{
 
}
 
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{ 
 
}
#endif /* USE_FULL_ASSERT */

the stm32f1xx_it.c function is this:

#include "main.h"
#include "stm32f1xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
 
extern I2C_HandleTypeDef hi2c1;
extern RTC_HandleTypeDef hrtc;
 
void NMI_Handler(void)
{
 
}
 
void HardFault_Handler(void)
{
	volatile unsigned long _CFSR = (*((volatile unsigned long *)(0xE000ED28)));
	volatile unsigned long _HFSR = (*((volatile unsigned long *)(0xE000ED2C)));
	volatile unsigned long _DFSR = (*((volatile unsigned long *)(0xE000ED30)));
	volatile unsigned long _AFSR = (*((volatile unsigned long *)(0xE000ED3C)));
	volatile unsigned long _MMAR = (*((volatile unsigned long *)(0xE000ED34)));
	volatile unsigned long _BFAR = (*((volatile unsigned long *)(0xE000ED38)));
	__asm("bkpt #0");
	__asm volatile ("movs r0,#4");	/* Carga el número 4 a r0.  			 */
	__asm volatile ("movs r1, lr");	/* Carga el link register a r1.          */
	__asm volatile ("tst r0, r1");	/* Prueba el valor de r0 contra r1 y     */
									/* descarta el resultado pero actualiza  */
									/* las banderas.                         */
	__asm volatile ("beq _MSP");	/* Salta a la etiqueta _MSP si Z está en */
									/* 1, es decir, salta si el resultado de */
									/* la operación anterior es cero.        */
	__asm volatile ("mrs r0, psp");	/* Mueve el contenido del registo        */
									/* especial PSP a r0.                    */
	__asm volatile ("b _HALT");		/* Salta inmediatamente a la etiqueta    */
	__asm volatile ("_MSP:");		/* _HALT.								 */
	__asm volatile ("mrs r0, msp");	/* Mueve el contenido del registro 		 */
									/* especial MSP a r0.               	 */
	__asm volatile ("_HALT:");		/* Etiqueta _HALT. 						 */
	__asm volatile ("ldr r1,[r0,#24]");/* Se carga a r1 con la dirección     */
									/* contenida en r0 desplazada en 20.	 */
	__asm volatile ("bkpt #0");		/* Es un breakpoint.					 */
  while (1)
  {
 
  }
}
 
void MemManage_Handler(void)
{
  while (1)
  {
 
  }
}
 
void BusFault_Handler(void)
{
 
  while (1)
  {
 
  }
}
 
void UsageFault_Handler(void)
{
  while (1)
  {
 
  }
}
 
void SVC_Handler(void)
{
 
}
 
void DebugMon_Handler(void)
{
 
}
 
void PendSV_Handler(void)
{
 
}
 
void SysTick_Handler(void)
{
  HAL_IncTick();
}
 
void RTC_IRQHandler(void)
{
 
}
 
void RCC_IRQHandler(void)
{
 
}
 
void I2C1_EV_IRQHandler(void)
{
  HAL_I2C_EV_IRQHandler(&hi2c1);
}
 
void I2C1_ER_IRQHandler(void)
{
 
}

in the hard fault handler can be seen al the code to read the fault status registers and what I think gives me the PC addres of the line that caused the hard fault or at least the stacked line of PC. When the status registers are read all of them are read as zero -I don't know why- and the stacked PC address stored in r1 after read it is 200027F8, when the code is dissasembled and I give the instruction to the code view to go to that address line then the line showed is the last line of "HAL_StatusTypedef HAL_I2C_Mem_Read()" and I don't know why this is happening. The following picture shows in blue the code shown when I look for the address 200027F8.

0693W000003BdFoQAK.png

When this happens the main code is looping in the while(1) so that means the code left the HAL_I2C_Slave_Receive_IT() function and I don't have implemented the SlaveRxCpltCallback() function as user because until I read is not mandatory to implement it since it is defined as a __weak function and I verified that the _weak functions is defined but its only line of code is the UNUSED() macro

the i2c.c file is this:

#include "i2c.h"
 
I2C_HandleTypeDef hi2c1;
 
void MX_I2C1_Init(void)
{
 
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 34;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  { 
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = SCL_Pin|SDA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    __HAL_RCC_I2C1_CLK_ENABLE();
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 2);
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
  }
}
 
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
  if(i2cHandle->Instance==I2C1)
  {
    __HAL_RCC_I2C1_CLK_DISABLE();
    HAL_GPIO_DeInit(GPIOB, SCL_Pin|SDA_Pin);
    HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
  }
} 

HAL library manual says that after calling the HAL_I2C_Slave_Receive_IT() it exits the function almos inmediatly releasing the code to do any other task and I've checked this before I don have any clue on what is happening to not have the i2c interrupt working.

Can anyone help me with this?, I'll be very grateful.

3 REPLIES 3

Selective cut-n-paste not helping here.

Show the IRQ Handlers and callback functions.

Show definition and scope of variable mensaje

Get a proper Hard Fault Handler which can dump registers.

Look at disassembly of faulting code sequence.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi @clive1, I've edited the first post of this thread to include more code and explain some more. Thanks for all the help that you could bring me.

It is pretty much the code of my previous post where I talk about RXNE, BTF and ADDR set after received the first data byte, finally when all this happens the mcu simply puts the SCL low and enters in the hard fault handler.