0
\$\begingroup\$

I have worked on bare metal programming so far. I want to make a step into RTOS. I have a Nuvoton made M032SG8AE MCU.I want to port FreeRTOS to it.

I created a project and ported heap_1.c, port.c, timers.c, tasks.c, queue.c, list.c, event_groups.c and croutine.c files to my library. I also chose the include path in Keil.

I want to make a simple LED toggle example. Therefore, I need a task which toggles the pin that is connected to led.

This is the code that I am currently working on:

#include "NuMicro.h"
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"


volatile uint32_t systemTick;

/*------INIT FUNCTIONS------*/
void SYS_Init(void)
{
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* If the macros do not exist in your project, please refer to the related clk.h in Header folder of the tool package */
    /* Enable clock source */
    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Waiting for clock source ready */
    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Disable PLL first to avoid unstable when setting PLL */
    CLK_DisablePLL();

    /* Set PLL frequency */
    CLK->PLLCTL = (CLK->PLLCTL & ~(0x000FFFFFUL)) | 0x0008C03EUL;

    /* Waiting for PLL ready */
    CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk);

    /* Set HCLK clock */
    CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));

    /* Set PCLK-related clock */
    CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV1 | CLK_PCLKDIV_APB1DIV_DIV1);

    /* Enable IP clock */
    CLK_EnableModuleClock(ADC_MODULE);
    CLK_EnableModuleClock(I2C0_MODULE);
    CLK_EnableModuleClock(ISP_MODULE);
    CLK_EnableModuleClock(PWM0_MODULE);
    CLK_EnableModuleClock(TMR0_MODULE);
    CLK_EnableModuleClock(TMR1_MODULE);
    CLK_EnableModuleClock(TMR2_MODULE);
    CLK_EnableModuleClock(TMR3_MODULE);
    CLK_EnableModuleClock(UART0_MODULE);
    CLK_EnableModuleClock(UART1_MODULE);
    CLK_EnableModuleClock(UART2_MODULE);
    CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HIRC_DIV2, 0);

    /* Set IP clock */
    CLK_SetModuleClock(ADC_MODULE, CLK_CLKSEL2_ADCSEL_PCLK1, CLK_CLKDIV0_ADC(1));
    CLK_SetModuleClock(PWM0_MODULE, CLK_CLKSEL2_PWM0SEL_PCLK0, MODULE_NoMsk);
    CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_HIRC, MODULE_NoMsk);
    CLK_SetModuleClock(TMR1_MODULE, CLK_CLKSEL1_TMR1SEL_HIRC, MODULE_NoMsk);
    CLK_SetModuleClock(TMR2_MODULE, CLK_CLKSEL1_TMR2SEL_HIRC, MODULE_NoMsk);
    CLK_SetModuleClock(TMR3_MODULE, CLK_CLKSEL1_TMR3SEL_HIRC, MODULE_NoMsk);
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_PCLK0, CLK_CLKDIV0_UART0(1));
    CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART1SEL_PCLK1, CLK_CLKDIV0_UART1(1));
    CLK_SetModuleClock(UART2_MODULE, CLK_CLKSEL3_UART2SEL_PCLK0, CLK_CLKDIV4_UART2(1));

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
    SystemCoreClockUpdate();

     /* Set PB multi-function pins for UART0 RXD=PB.12 and TXD=PB.13 */
    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \
                    (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);
     
     SYS->GPB_MFPH = SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB14MFP_Msk) | SYS_GPB_MFPH_PB14MFP_GPIO;
    /* Lock protected registers */
    SYS_LockReg();

}

void SysTick_Handler(void)
{
    systemTick++;
}

uint32_t HAL_GetTick(void)
{
    return systemTick;
}


void UART0_Initial(void)
{
    /* Reset UART0 system module*/
    SYS_ResetModule(UART0_RST);
    
    /* Open UART0 */
    UART_Open(UART0,115200);
}



void GPIO_Initial(void)
{
    //Configure PB14 as output
    GPIO_SetMode(PB,BIT14,GPIO_MODE_OUTPUT);
    //Configure pin as low
    PB14 = 0;
}

void LED_Task( void *pvParameters )
{
    while(1)
    {
        PB14 ^= 1;
        
        vTaskDelay(500/portTICK_RATE_MS);   
        // delay(500000);
    }
}


int main()
{
    SYS_Init();
    SysTick_Config(SystemCoreClock / 1000);
    UART0_Initial();
    GPIO_Initial();

    
    xTaskCreate(LED_Task,"LED_Task",configMINIMAL_STACK_SIZE,NULL,1,NULL);
    vTaskStartScheduler();

    
    while(1);
}

However, I am facing a problem right now. The led is on but it is not getting off. It says on. I realised that the code is stuck in PendSV_Handler in M031Series.s file when I debugged. While I was looking for an answer on Google, I saw people talking about vTaskDelay() function. I commented the vTaskDelay and put a simple delay function instead and it worked.

enter image description here

What seems to be a problem here?

This link is the port.c file which I use in the project.

\$\endgroup\$
2
  • \$\begingroup\$ Who knows. Do you call the FreeRTOS tick anywhere, so it could determine that the time has elapsed and it's time to go run the toggle task? \$\endgroup\$
    – Justme
    Jul 26, 2023 at 23:39
  • \$\begingroup\$ You need to make sure that FreeRTOS's xPortSysTickHandler() function gets called from the SysTick interrupt. \$\endgroup\$
    – brhans
    Jul 27, 2023 at 4:46

1 Answer 1

1
\$\begingroup\$

The interrupt handler for the PendSV interrupt isn't mapped to the proper FreeRTOS function instead it's mapped to the default function which is effectively an endless loop that halts the program.

There should be a line like this in your FreeRTOSConfig.h that maps the handlers:

/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
 standard names - or at least those used in the unmodified vector table. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

Make sure it's there and the functions are named correctly.

You also shouldn't overwrite the SysTick_Handler. Remove these lines from your code:

void SysTick_Handler(void)
{
    systemTick++;
}

xPortSysTickHandler is the proper handler and should be defined in port.c. If you want to know the current tick value, use xTaskGetTickCount.

Your program works without vTaskDelay because no context switch is triggered. Your LED task simply runs forever since there is no other higher priority task to interrupt it.

\$\endgroup\$
7
  • \$\begingroup\$ I have checked the port.c file. There is not mapping but prototypes of exception handlers. void xPortPendSVHandler( void ); void xPortSysTickHandler( void ); void vPortSVCHandler( void ); \$\endgroup\$
    – Bowman
    Jul 27, 2023 at 11:11
  • 1
    \$\begingroup\$ @Bowman Where did you get the port.c file from? Is it a complete implementation for your MCU or just a template? \$\endgroup\$
    – nanash1
    Jul 27, 2023 at 11:15
  • \$\begingroup\$ I got it from the official web site of FreeRTOS. \$\endgroup\$
    – Bowman
    Jul 27, 2023 at 12:09
  • \$\begingroup\$ @Bowman Please add a link to the port.c file you're using to the question. \$\endgroup\$
    – nanash1
    Jul 27, 2023 at 13:52
  • \$\begingroup\$ I have edited my question and added the github link that shows the port.c file. \$\endgroup\$
    – Bowman
    Jul 27, 2023 at 14:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.