How to suspend a task using FreeRTOS - rtos

Am trying to learn freeRTOS. How can I make a task to go to sleep after running for 2 seconds? I've tried using vTaskSuspend() to stop the task immediately and i also tried to put v taskDelay(2000), but it doesn't work either.
I want to sleep the fast blinking task 2 seconds after it was called and run the normal blinking task.
void resourse(const TickType_t xFrequency)
{
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
while(1)
{
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
vTaskDelayUntil( &xLastWakeTime, xFrequency);
}
}
xSemaphoreHandle botton_one = 0;
void botton(void* r)
{
while(1)
{
if(xSemaphoreTake(botton_one, 1))
{
HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
xSemaphoreGive(botton_one);
}
vTaskDelay(1);
}
}
void normal_blinking(void* r)
{
while(1)
{
if(xSemaphoreTake(botton_one, 1))
{
resourse(500);
xSemaphoreGive(botton_one);
}
}
}
void fast_blinking(void* s)
{
while(1){
if((HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin))== 0)
{
xSemaphoreTake(botton_one, 1);
resourse(50);
xSemaphoreGive(botton_one);
}
vTaskDelay(2000);
vTaskSuspend(NULL);
}
}
int main(void)
{
TaskHandle_t xHandle;
botton_one = xSemaphoreCreateMutex();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
xTaskCreate(botton, (const char*)"task_1", 1024, 0, 3, 0);
xTaskCreate(normal_blinking, (const char*)"task_2", 1024, 0, 2,0);
xTaskCreate(fast_blinking, (const char*)"task_3", 1024, 0, 1,0);
vTaskStartScheduler();
while (1){
}
}

It is not clear what you are wanting to do, or what is not working as you want. You suggest using both vTaskSuspend() and vTaskDelay(), but they are used for different things.
If you call vTaskDelay() then the task will enter the Blocked state (stop being available as a task that can be actually executing) for whatever period you specify, then automatically leave the Blocked state after that period.
If you call vTaskSuspend() then the task will enter the Suspended state, and will never run again unless another task or interrupt calls vTaskResume().
Do you just want the task to run for two seconds, and then never again? In which case you could do something simple like:
void mytask( void *pv )
{
TickType_t xTimeOnEntering = xTaskGetTickCount();
while( xTaskGetTickCount() - xTimeOnEntering < pdMS_TO_TICKS( 2000 ) )
{
/* Run your code here. */
}
/* Two seconds of execution is up, delete the task. */
vTaskDelete( NULL );
}

Related

Using DMA with two UART peripherals - is it possible?

I want to connect two UART peripherals using STM32G0 microcontroller via DMA. Not knowing the length of the messages in forward, I'm using function HAL_UARTEx_ReceiveToIdle_DMA() in order to receive them. Here is the part of my code:
main.h
.
.
.
StartDMAReceptionOverUART1();
StartDMAReceptionOverUART4();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(10);
}
.
.
.
void StartDMAReceptionOverUART1(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_modulePort.huart, m_modulePort.rxBuffer, m_modulePort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_TC);
}
void StartDMAReceptionOverUART4(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_meterPort.huart, m_meterPort.rxBuffer, m_meterPort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_TC);
}
.
.
.
These functions are similar: first HAL_UARTEx_ReceiveToIdle_DMA() is checked, then Half Transfer and Transfer Complete interrupts are disabled in order to relieve processor (I need only IDLE interrupt). The problem is inside StartDMAReceptionOverUART1() function, HAL_UARTEx_ReceiveToIdle_DMA() never returns HAL_OK and program jumps on Error_Handler(). On the other hand, StartDMAReceptionOverUART4() works perfectly fine. What could be the problem?
Also, here is the receive callback function, also written inside main.h:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == m_meterPort.huart->Instance) // huart == UART4
{
memcpy(m_modulePort.txBuffer, m_meterPort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_modulePort.huart, m_modulePort.txBuffer, Size);
StartDMAReceptionOverUART4();
}
else if (huart->Instance == m_modulePort.huart->Instance) // huart == UART1
{
memcpy(m_meterPort.txBuffer, m_modulePort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_meterPort.huart, m_meterPort.txBuffer, Size);
}
else
{
return;
}
}
Callback function, in dependence of the periphery, will copy received data to a buffer and send it to the other periphery (functions memcpy() and HAL_UART_Transmit_DMA()). DMA over UART4 is in Normal mode, therefore StartDMAReceptionOverUART4() is called, inside which is HAL_UARTEx_ReceiveToIdle_DMA(). On the other hand, DMA over UART1 is in Circular mode, so there is no need for calling StartDMAReceptionOverUART4().

Hang up with UART and DMA

I am trying to use UART and DMA. When I insert a call to HAL_Delay() in the USART3_IRQHandler(), the program hang in the HAL_Delay(). The SysTick interrupt is not called anymore. I don't understand?
int main(void)
{
...
MX_DMA_Init();
MX_USART3_UART_Init();
uint32_t nextCall = uwTick;
while (1)
{
if (nextCall < uwTick) {
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
HAL_UART_Transmit_DMA( &huart3, dataTx, sizeof( dataTx ) );
nextCall = uwTick + 1000;
}
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart3);
if (( USART3->SR & UART_IT_IDLE) != 0 )
{
__HAL_UART_CLEAR_IDLEFLAG( &huart3 );
HAL_UART_DMAStop(&huart3);
uint8_t data_length = sizeof( dataRx ) - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
memset( dataRx,0,sizeof( dataRx ));
HAL_UART_Receive_DMA(&huart3, (uint8_t*)dataRx, sizeof( dataRx ));
HAL_Delay( 1 );
// Delay() does not return
}
}
Abstracting from the completely wrong impossible to repair UART code HAL_Delay to work in the interrupt context requires SYSTICK interrupt priority to be higher than the UART interrupt. Otherwise it is not invoked and the internal counter does not increase and the function ends in the dead loop.

FreeRTOS scheduler performing context switching for the same task

I noticed strange behavior when debugging the system I am analyzing. The system has three periodic tasks:
"Task-1", with 10 milliseconds of periodicity. High priority.
"Task-2", with 10 milliseconds of periodicity. Medium priority.
"Task-3" with 10 milliseconds of periodicity. Low priority.
The content of the three tasks is just a critical section, a critical section that is shared. The inversion of priorities occurs frequently, and I am forcing this situation to see how the system behaves temporally. The Systick has a period of 1ms.
From what I read about FreeRTOS, in Cortex-M the context change of a task is done through a pending bit, which in the scenario of periodic tasks can be activated through:
Tick timer handler finds a task with the highest priority in the
ready queue and sets the pending context switch bit;
In the “vDelayTaskUntil” function, which waits for the next
activation;
When a semaphore is busy and the task that tries to acquire it.
That said, I found this behavior:
Sometimes, while the high priority task is within the semaphore, the context switching takes place for itself, as explained below.
As noted, task-1 does a context switch for itself.
Do you know how to tell me why this happens?
Attaching the code of test:
Task-1:
void vTask1_handler(void *params) {
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
xLastWakeTime = xTaskGetTickCount();
int i = 0, to =0;
for (;;) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
to = DWT->CYCCNT;
for (i = 0; i < to % 500; i++);
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
to = DWT->CYCCNT;
for (i = 0; i < to % 5000; i++);
xSemaphoreGive(xSemaphore);
}
}
}
Task-2:
void vTask2_handler(void *params) {
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
xLastWakeTime = xTaskGetTickCount();
int i = 0, to = 0;
for (;;) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
to = DWT->CYCCNT;
for (i = 0; i < to % 200; i++);
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
to = DWT->CYCCNT;
for (i = 0; i < to % 10000; i++);
xSemaphoreGive(xSemaphore);
}
}
Task-3:
void vTask3_handler(void *params) {
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
xLastWakeTime = xTaskGetTickCount();
int i = 0, to=0;
for (;;) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
to = DWT->CYCCNT;
for (i = 0; i < to % 200; i++);
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
to = DWT->CYCCNT;
for (i = 0; i < to % 10000; i++);
xSemaphoreGive(xSemaphore);
}
}
}
Thank you.
I suspect it is going to the scheduler in the give or take semaphore API call and concluding it is still the highest priority ready task.
freertos have a periodic interrupt, that when happening it is checking if it is now time to unblock or wake a task. I think what you see is this interrupt.
please look at https://www.freertos.org/implementation/a00011.html for details about the tick interrupt.
you also may want to look at https://www.freertos.org/low-power-tickless-rtos.html if you want to disable it when entering idle low power task.

STM32F4 SPI interrupts stop firing with FreeRTOS

I'm trying to make an SPI communication between a F410 MCU and a RPi using SPI.
I post below the code that currently works (without FreeRTOS usage):
main.c
volatile int tx_done = 0;
volatile int rx_done = 0;
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
tx_done = 1;
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
rx_done = 1;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI5_Init();
MX_USART2_UART_Init();
const uint8_t BUF_SIZE = 16 * sizeof(uint8_t);
uint8_t buf[16];
// For UART debug
uint8_t dbg_buffer[64];
while (1) {
memset(buf, 0, BUF_SIZE);
HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, BUF_SIZE);
while (rx_done == 0) {};
rx_done = 0;
sprintf((char*) dbg_buffer, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d]\r\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
buf[7], buf[8], buf[9], buf[10], buf[11], buf[12],
buf[13], buf[14], buf[15]);
HAL_UART_Transmit(&huart2, dbg_buffer, strlen((char const*) dbg_buffer), 50);
HAL_SPI_Transmit_IT(&hspi5, (uint8_t*) &buf, BUF_SIZE);
while (tx_done == 0) {};
tx_done = 0;
}
}
stm32f4xx_it.c
/**
* #brief This function handles TIM1 trigger and commutation interrupts and TIM11 global interrupt.
*/
void TIM1_TRG_COM_TIM11_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim11);
}
/**
* #brief This function handles SPI5 global interrupt.
*/
void SPI5_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi5);
}
spi.c
/* SPI5 init function */
void MX_SPI5_Init(void)
{
hspi5.Instance = SPI5;
hspi5.Init.Mode = SPI_MODE_SLAVE;
hspi5.Init.Direction = SPI_DIRECTION_2LINES;
hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi5.Init.NSS = SPI_NSS_HARD_INPUT;
hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi5.Init.CRCPolynomial = 15;
if (HAL_SPI_Init(&hspi5) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
[...]
HAL_NVIC_SetPriority(SPI5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI5_IRQn);
}
This working fine with my test code on the other (raspberry pi) side, sending a SPI frame every second, waiting 100ms and reading the answer from the F410.
Now, when I activate FreeRTOS, I move the while(1) loop content to a task, and creates it with
BaseType_t task1 = xTaskCreate(task_1, "task_1", 512, NULL, tskIDLE_PRIORITY, &xHandle);
and osKernelStart(). I also use the TIM11 as Timebase Source (under SYS tab on CubeMX as advised by the software itself)
Then I have the following behavior: If I place breakpoints inside both Tx/Rx SPI interrupt, I found that a couple (3-4 ?) of them are fired, then never again. If I stop my code I see I'm stucked in the
while (rx_done == 0) {};
loop, confirming that I don't get SPI RX interrupts anymore whereas there is still frame coming on the SPI bus.
To dig a little into that theory, I made another test with this in my task:
while(1) {
memset(buf, 0, 16);
HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, 16);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
// Wait for RX interrupt, task is suspended to give processing time to (incoming) others tasks
vTaskSuspend(NULL);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
and in my Rx interrupt, I simply call
xTaskResumeFromISR(task1Handle);
With this code, the first packet sent is read correctly by the STM32F4, and task print it on USART2 and suspend itself again. From then, (checked with a breakpoint inside), the Rx interrupt is never called again, so the task resume inside neither, and my code is frozen...
It really looks like there is a messing between FreeRTOS and STM32 HAL SPI/interrupt handling ?
Any help will be gladly accepted !
Do you call NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); as described in the red text on this page: https://www.freertos.org/RTOS-Cortex-M3-M4.html ?
If you are using an STM32 with the STM32 driver library then ensure all the priority bits are assigned to be preempt priority bits by calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.

vTaskDelay never return

My application run on stm32F4 with FreeRTOS V9.0.0 and port files Source\portable\RVDS\ARM_CM4F (imported via RTE Keil).
The main, call some initialization functions, create the task and then call the vTaskStartScheduler.
The task simply call vTaskDelay(1000) which never return. The system is not is fault. The fault report dosen't show any error or problem.
The code is:
int main(void)
{
init_foo1()
init_foo2()
xTaskCreate(aTask, "name",1280, NULL, 6, NULL);
init_foo3();
vTaskStartScheduler();
}
void aTask()
{
vTaskDelay(1000);
bar();
}
What is wrong?
Thanks all
You need to put infinite loop firstly:
Example usage of vTaskDelay function accordinly to documentation:
void vTaskFunction( void * pvParameters )
{
/* Block for 500ms. */
const TickType_t xDelay = 500 / portTICK_PERIOD_MS;
for( ;; )
{
/* Simply toggle the LED every 500ms, blocking between each toggle. */
vToggleLED();
vTaskDelay( xDelay );
}
}
Also test the priority in xTaskCreate
UBaseType_t uxPriority