Electronic – Use STM32 interrupt with FreeRTOS

freertoshal-librarystm32

I'm confused in using HAL-defined interrupts with FreeRTOS. I'm trying to implement "6.3 Deferred Interrupt Processing" in the guide of FreeRTOS, but I don't know how to do it.

The problem is how to use the peripherals of the STM32 with FreeRTOS. Should I give a semaphore to another task (which read and treat the values) within the irqn "ADC_IRQHandler()" for the ADC or the callback "HAL_ADC_ConvCpltCallback()" for the ADC or just read values with the HAL functions and treat them with FreeRTOS tasks (this one works, but it does not seem to use the RTOS power)?

The manual I talk about: 6.3 Deferred Interrupt Processing (PDF)

Best Answer

First of all, the semaphore can be given in "ADC_IRQHandler()" or "HAL_ADC_ConvCpltCallback()" (ADC) by adding:

BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

At the end of the function it seems that "HAL_ADC_ConvCpltCallback" is also an ISR when I use xSemaphoreGive( xBinarySemaphore);. With it the program crashes.

It is also important to set the priority of the IRQHandler numerically higher than configMAX_SYSCALL_INTERRUPT_PRIORITY, in my case '80', by adding (5 for example). HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);, priority 5 ? 15 in my case. You can check this for more information: http://www.freertos.org/RTOS-Cortex-M3-M4.html.

Anyway this code is working and takes the ADC init from https://visualgdb.com/tutorials/arm/stm32/adc/.

Code

#include "stm32f4xx.h"
#include "stm32f4_discovery.h"


#include <stdlib.h>
#include <string.h>

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "semphr.h"


SemaphoreHandle_t xBinarySemaphore=NULL;
ADC_HandleTypeDef g_AdcHandle;
uint32_t g_ADCValue=0;

void SystemClock_Config(void);
void ConfigureADC();
static void ledL( void*); // Task to change the brightness of the LED 12 of GPIOD when changing the value of potentiometer
static void vHandlerTask( void*); // Task to toggle GPIOD 13 every time a conversion is achieved and sleep for 300 ms
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef*);
void ADC_IRQHandler();

int main(void){

    HAL_Init();
    SystemClock_Config();
    ConfigureADC();
    HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(ADC_IRQn);

    GPIO_InitTypeDef GPIO_InitStructure;
    __GPIOD_CLK_ENABLE();
    GPIO_InitStructure.Pin = GPIO_PIN_12|GPIO_PIN_13;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);


    vSemaphoreCreateBinary(xBinarySemaphore);

    if( xBinarySemaphore != NULL ){

        xTaskCreate(vHandlerTask, "Task 1", 1000, NULL, 1, NULL);
        xTaskCreate(ledL, "Task 2", 1000, NULL, 1, NULL);
        vTaskStartScheduler();
    }

    for(;;){}
}

//ISR
void ADC_IRQHandler(){
    HAL_ADC_IRQHandler(&g_AdcHandle);
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}

//CALLBACK CALLED WHEN CONVERTION COMPLETE
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle){

    g_ADCValue = HAL_ADC_GetValue(AdcHandle);
}

static void vHandlerTask( void *pvParameters ){

    HAL_ADC_Start_IT(&g_AdcHandle);

    for( ;; ){
        xSemaphoreTake( xBinarySemaphore, portMAX_DELAY );
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
        vTaskDelay(pdMS_TO_TICKS(200UL));

    }
}

static void ledL( void *pvParameters ){
    for (;;)
    {
        int onTime = g_ADCValue;
        int offTime = 4096 - onTime;
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
        for (int i = 0; i < onTime; i++)
            asm("nop");

        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
        for (int i = 0; i < offTime; i++)
            asm("nop");
    }
}

void SystemClock_Config(void)
{
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_OscInitTypeDef RCC_OscInitStruct;

    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

    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.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 288;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 6;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
    SystemCoreClockUpdate();

    if (HAL_GetREVID() == 0x1001)
        __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
}

void ConfigureADC()
{
    GPIO_InitTypeDef gpioInit;

    __GPIOC_CLK_ENABLE();
    __ADC1_CLK_ENABLE();

    gpioInit.Pin = GPIO_PIN_1;
    gpioInit.Mode = GPIO_MODE_ANALOG;
    gpioInit.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &gpioInit);

    HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC_IRQn);

    ADC_ChannelConfTypeDef adcChannel;

    g_AdcHandle.Instance = ADC1;

    g_AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
    g_AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
    g_AdcHandle.Init.ScanConvMode = DISABLE;
    g_AdcHandle.Init.ContinuousConvMode = ENABLE;
    g_AdcHandle.Init.DiscontinuousConvMode = DISABLE;
    g_AdcHandle.Init.NbrOfDiscConversion = 0;
    g_AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    g_AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
    g_AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    g_AdcHandle.Init.NbrOfConversion = 1;
    g_AdcHandle.Init.DMAContinuousRequests = ENABLE;
    g_AdcHandle.Init.EOCSelection = DISABLE;

    HAL_ADC_Init(&g_AdcHandle);

    adcChannel.Channel = ADC_CHANNEL_11;
    adcChannel.Rank = 1;
    adcChannel.SamplingTime = ADC_SAMPLETIME_480CYCLES;
    adcChannel.Offset = 0;

    if (HAL_ADC_ConfigChannel(&g_AdcHandle, &adcChannel) != HAL_OK)
    {
        asm("bkpt 255");
    }
}
Related Topic