Semaphore doesn't work on STM32F103

I am new in trying freeRTOS. I am trying to make a simple project in MDK: creat two tasks and a timer. From the timer handler give a semaphore and one task take it and print a string. Without using semaphore, the project works normally. But when the semaphore is added, though the project can be compiled without error, it doesn’t work after it is downloaded into the board, there is not any printing from the board. I tried to use debug and find it stopped at hardfault. The following is the pictures of the projects. Please help me to find what happened. Thank you. The following are the programs:
/* main file */

#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_conf.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "list.h"
#include "misc.h"
#include "portable.h"
#include "FreeRTOSConfig.h"
#include "usart1.h"
#include "timerConfig.h"


static void vUART1_1_Task(void *pvParameters);
static void vUART1_2_Task(void *pvParameters);

SemaphoreHandle_t xBinarySemaphore;

int main(void)
{

	USART1_Config();
	TIM2_Init();	

	xBinarySemaphore = xSemaphoreCreateBinary();	
	if (xBinarySemaphore != NULL)
	{
		xTaskCreate(vUART1_1_Task, (const portCHAR*)"UART1_1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
		xTaskCreate(vUART1_2_Task, (const portCHAR*)"UART1_2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
		vTaskStartScheduler();
	}
	
	return 0;
}

void vUART1_1_Task(void *pvParameters)
{
	TickType_t xDelay = pdMS_TO_TICKS(2000);
	while(1)
	{
		printf("\r\n This is task1 ! \r\n");
		vTaskDelay(xDelay);  //ÑÓʱ2s	
	}
}


void vUART1_2_Task(void *pvParameters)
{
	while(1)
	{
		if(xSemaphoreTake(xBinarySemaphore, portMAX_DELAY))
		{
			printf("Semaphore works!\n\r");
		}
	}
		
//	TickType_t xDelay = pdMS_TO_TICKS(2000);
//	while(1)
//	{
//		printf("\r\n This is task2 !!! \r\n");
//		vTaskDelay(xDelay);  //ÑÓʱ2s	
//	}
}

/timer configure file/

#include "FreeRTOS.h"
#include "semphr.h"
#include "timerConfig.h"
#include "misc.h"
#include "usart1.h"
#include "stm32f10x_tim.h"


void TIM2_Init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 
	
	TIM_TimeBaseStructure.TIM_Period = TIM2_Period; 
	TIM_TimeBaseStructure.TIM_Prescaler = TIM2_Prescaler; 
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
 	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); 
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure);  

	TIM_Cmd(TIM2, ENABLE);  /			 
}

void TIM2_IRQHandler(void)   
{
	extern SemaphoreHandle_t xBinarySemaphore;	
	BaseType_t xHigherPriorityTaskWoken;
	
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  
		{		
			TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );    
			xHigherPriorityTaskWoken = pdTRUE;
			xSemaphoreGive(xBinarySemaphore);
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
//			printf("\r\n Timer !!! \r\n");
		}
}

Please check your stack sizes, minimal may overflow.

I changed the stacksize of the two tasks, and follow the debug, find it run to hardFault_handler directly from TIM2_init(). I wonder if there is anything wrong with the timer initiation? but I checked it and can not find problem. What’s more, it can work when the semaphore was commeted out.

Where and how do you create the semaphore? You shoul check for a null handle before accessing it…

edit: please ignore, i found it…

another take: Your init code may be enabling interrupts too early. They must remain disabled until scheduler start

One possible reason is that interrupt is firing before semaphore is created. Try changing the main to the following:


int main(void)
{
	xBinarySemaphore = xSemaphoreCreateBinary();	
	if (xBinarySemaphore != NULL)
	{
		xTaskCreate(vUART1_1_Task, (const portCHAR*)"UART1_1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
		xTaskCreate(vUART1_2_Task, (const portCHAR*)"UART1_2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

	    USART1_Config();
 	    TIM2_Init();	

		vTaskStartScheduler();
	}
	
	return 0;
}

Also, you are calling the xSemaphoreGive API from an ISR while you should call xSemaphoreGiveFromISR:

void TIM2_IRQHandler(void)   
{
	extern SemaphoreHandle_t xBinarySemaphore;	
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  
	{		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );    
		xSemaphoreGiveFromISR(xBinarySemaphore, &( xHigherPriorityTaskWoken ));
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	}
}

Really thank you guys, you are great! I put the TIM_Init() into a task and then it works. Just like you said, the interrupt runs before the semaphore is created. I don’t know this rule. Thank you very much.

It’s not exactly a rule - it’s just about using an uninitialized variable.
If xBinarySemaphore is not yet created but accidentally used (too early) in the ISR, an invalid handle is used which is a license to crash :wink:

Yeah, I see. When the timer start, the IRQ handler works and the xBinarySemaphore was called, but it is still not created. I was accustomed to initializing everything in the beginning and made this mistake. Thank you very much!