Hard Fault using SPI commands in lower priority Threads

I’m using an STM32F411 with an accelerometer (SPI) in my project. I used CubeMX to generate code in which i’m using FreeRTOS with CMSIS v2. I code using the HAL because I’m a noob.

I have three threads in my code with three different priorities. One manages the power system, one control the motor and one reads data from the accelerometer.
The last one is of the lowest priority because it is naturally the case.

The function that gets data from the accelerometer works fine in the thread with the highest priority but gets stuck in the Hard Fault Handler when i move it into any of the other threads.

the function is actually of a lower priority and I don’t need it to run while the other threads are doing the serious stuff.

Using the debugger I was able to see that it crashes after entering the HAL_SPI_Receive function.
Why is this happening ? What should I do ?

I tried using DMA for the SPI Peripheral, it still crashes, but doesn’t go to Hard Fault Handler instead goes around in a loop deep in the codes and I can’t track it… somewhere inside vTaskDelay(). But function in the highest priority thread works just fine.

I’m new to FreeRTOS. Are these sort of bugs common to face ? How do I avoid ?

I’m putting the code below…

int main(void)
{
	/* USER CODE BEGIN 1 */

	/* USER CODE END 1 */


	/* MCU Configuration--------------------------------------------------------*/

	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();

	/* USER CODE BEGIN Init */

	/* USER CODE END Init */

	/* Configure the system clock */
	SystemClock_Config();

	/* USER CODE BEGIN SysInit */

	/* USER CODE END SysInit */

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_SPI4_Init();
	MX_DMA_Init();
	/* USER CODE BEGIN 2 */

	adxl362Init();

	/* USER CODE END 2 */

	osKernelInitialize();

	/* USER CODE BEGIN RTOS_MUTEX */
	/* add mutexes, ... */
	/* USER CODE END RTOS_MUTEX */

	/* USER CODE BEGIN RTOS_SEMAPHORES */
	/* add semaphores, ... */
	/* USER CODE END RTOS_SEMAPHORES */

	/* USER CODE BEGIN RTOS_TIMERS */
	/* start timers, add new ones, ... */
	/* USER CODE END RTOS_TIMERS */

	/* USER CODE BEGIN RTOS_QUEUES */
	/* add queues, ... */
	/* USER CODE END RTOS_QUEUES */

	/* Create the thread(s) */
	/* definition and creation of defaultTask */
	const osThreadAttr_t defaultTask_attributes = {
			.name = "defaultTask",
			.priority = (osPriority_t) osPriorityHigh,
			.stack_size = 128
	};
	defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

	/* definition and creation of power */
	const osThreadAttr_t power_attributes = {
			.name = "power",
			.priority = (osPriority_t) osPriorityAboveNormal,
			.stack_size = 128
	};
	powerHandle = osThreadNew(powerManager, NULL, &power_attributes);

	/* definition and creation of inclination */
	const osThreadAttr_t inclination_attributes = {
			.name = "inclination",
			.priority = (osPriority_t) osPriorityBelowNormal,
			.stack_size = 128
	};
	inclinationHandle = osThreadNew(incline, NULL, &inclination_attributes);

	/* USER CODE BEGIN RTOS_THREADS */
	/* add threads, ... */
	/* USER CODE END RTOS_THREADS */

	/* Start scheduler */
	osKernelStart();

	/* We should never get here as control is now taken by the scheduler */

	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1)
	{
		/* USER CODE END WHILE */

		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */
}
void StartDefaultTask(void *argument) //Above normal (works here)
{

/*...*/

}

/*...*/

void powerManager(void *argument) //Normal (doesn't work here too)
{

/*...*/

}

void incline(void *argument) //Below Normal (supposed to work here)
{

adxlData12();  
osDelay(1);

}

void adxlData12(void)
{

	adxl362Read(ADXL362_XDATAL,8);

	ADXLData12[0] = 	(adxlRxData[1]<<8) + adxlRxData[0];
	ADXLData12[1] = 	(adxlRxData[3]<<8) + adxlRxData[2];
	ADXLData12[2] = 	(adxlRxData[5]<<8) + adxlRxData[4];
	ADXLData12[3] = 	(adxlRxData[7]<<8) + adxlRxData[6];
	ADXLData12[3] = 	(ADXLData12[3]/13)+14;
	
        /*....*/

}

void adxl362Read(uint8_t reg,uint8_t count)
{

	adxlTxData[0] = ADXL362_REG_READ;
	adxlTxData[1] = reg;
	HAL_GPIO_WritePin(SPI4_CS_GPIO_Port,SPI4_CS_Pin,GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi4,adxlTxData,2,100);
	HAL_SPI_Receive(&hspi4,adxlRxData,count,100);  ///////////////////Crashes inside here
	HAL_GPIO_WritePin(SPI4_CS_GPIO_Port,SPI4_CS_Pin,GPIO_PIN_SET);

}

No idea - all I can do is make suggestions :grinning:

First, if it works in one task but not in another, it could potentially be that it causes a stack overflow in one task but not the other. Do you have stack overflow detection turned on? FreeRTOS - stacks and stack overflow checking

Second - have you read through the following list, including things like the recommendation to have configASSERT() defined, etc.? FreeRTOS - Open Source RTOS Kernel for small embedded systems