Adding FINSH Console to FreeRTOS

1 FINSH ConsoleWith the console, we can reduce trial and error costs when debugging hardware, change PID parameters in real-time without needing to reprogram, and customize commands to call serial API for testing communication protocols. This article summarizes the entire porting process.2 Preparation Before Porting2.1 Testing EnvironmentThis test is an extension based on the io_toggle example of the AT32F437ZMT7 development board.2.2 Porting FreeRTOS2.2.1 Download the official source code FreeRTOS 202212.01 link: https://wap.freertos.org/zh-cn-cmn-s/a00104.html2.2.2 Porting Source Code – Copy files from the Source directory

Adding FINSH Console to FreeRTOS

– Keep only the portable directory

Adding FINSH Console to FreeRTOS

– Copy FreeRTOSConfig.h and add it to the KEIL project

Adding FINSH Console to FreeRTOS

– Comment out conflicting interrupt handlers

Adding FINSH Console to FreeRTOS

2.2.3 Testing FreeRTOS– Add sys_tick as the heartbeat source for RTOS

/* systick configuration */void rt_hw_systick_init(void){    systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV);    SysTick_Config(system_core_clock / configTICK_RATE_HZ);    nvic_irq_enable(SysTick_IRQn, 0, 0);    _systick_ms = 1000u / configTICK_RATE_HZ;    if(_systick_ms == 0)        _systick_ms = 1;}

– Add GPIO initialization

void gpio_config(void){  gpio_init_type gpio_init_struct;  /* enable the gpioa clock */  crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);  /* set default parameter */  gpio_default_para_init(&gpio_init_struct);  /* configure the gpio */  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;  gpio_init_struct.gpio_pins = GPIO_PINS_13|GPIO_PINS_14;  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;  gpio_init(GPIOD, &gpio_init_struct);}

– Create LED tasks

#define LED0_TASK_PRIO    4#define LED0_STK_SIZE     128  TaskHandle_t LED0Task_Handler;TaskHandle_t LED1Task_Handler;void led0_task(void *pvParameters);void led1_task(void *pvParameters);void led0_task(void *pvParameters){    while(1)    {      /* set pa.01 */      GPIOD->scr = GPIO_PINS_13;       vTaskDelay(1000);      /* reset pa.01 */      GPIOD->clr = GPIO_PINS_13;      vTaskDelay(1000);    }}void led1_task(void *pvParameters){    while(1)    {      /* set pa.01 */      GPIOD->scr = GPIO_PINS_14;       vTaskDelay(500);      /* reset pa.01 */      GPIOD->clr = GPIO_PINS_14;      vTaskDelay(500);    }}  xTaskCreate((TaskFunction_t )led0_task,                     (const char*    )"led0_task",                   (uint16_t       )LED0_STK_SIZE,               (void*          )NULL,                      (UBaseType_t    )LED0_TASK_PRIO,                (TaskHandle_t*  )&LED0Task_Handler);                  xTaskCreate((TaskFunction_t )led1_task,                     (const char*    )"led1_task",                   (uint16_t       )LED0_STK_SIZE,               (void*          )NULL,                      (UBaseType_t    )LED0_TASK_PRIO,                (TaskHandle_t*  )&LED1Task_Handler);                   vTaskStartScheduler();

After powering onif both LEDs are blinking,it indicates that the porting was successful.

2.3 Adding Serial Port DriverThe development board uses PA9 and PA10 to connect to AT-link by default.2.3.1 Initialization Code

void usart_configuration(void){  gpio_init_type gpio_init_struct;  /* enable the usart2 and gpio clock */  crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);  gpio_default_para_init(&gpio_init_struct);  /* configure the usart2 tx pin */  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;  gpio_init_struct.gpio_pins = GPIO_PINS_9|GPIO_PINS_10;  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;  gpio_init(GPIOA, &gpio_init_struct);    gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_7);  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_7);    nvic_irq_enable(USART1_IRQn, 0 ,0);  /* configure usart3 param */  usart_init(USART1, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);  usart_receiver_enable(USART1, TRUE);  usart_transmitter_enable(USART1, TRUE);  usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE);   //usart_receiver_mute_enable(USART1, TRUE);  usart_enable(USART1, TRUE);}

2.3.2 Interrupt Handling

void USART1_IRQHandler(void){    if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)    {        g_queue_put(usart_data_receive(USART1));    }}

2.3.3 Print Output

#include "stdarg.h"void g_hal_usart_putchar(uint8_t ch){    usart_data_transmit(USART1, (uint8_t)ch);    while (usart_flag_get(USART1, USART_TDC_FLAG) == RESET);}void put_string(uint8_t *string){    while ((*string) != '\0')    {        if ('\n' == *string)        {            g_hal_usart_putchar('\r');            g_hal_usart_putchar('\n');            string++;        }        else        {            g_hal_usart_putchar(*string++);        }    }}int rt_kprintf(const char *fmt, ...){    va_list ap;    //This is support the format output      char string[128];    va_start(ap,fmt);    vsprintf(string,fmt,ap); // Store the string in the String buffer    put_string((uint8_t *)string);    va_end(ap);        return 0;}

2.4 Adding FINSH2.4.1 Copy Related Source FilesCopy the following files from the RT-Thread source directory

Adding FINSH Console to FreeRTOS

Adding FINSH Console to FreeRTOS

2.4.2 Add to KEIL Project

Adding FINSH Console to FreeRTOS

– Add macro definitions

Adding FINSH Console to FreeRTOS

2.5 Modify Shell Task – Change Task Creation and Loop Processing

//    tid = rt_thread_create(FINSH_THREAD_NAME,//                           finsh_thread_entry, RT_NULL,//                           FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10);      xTaskCreate((TaskFunction_t )finsh_thread_entry,                     (const char*    )"led1_task",                   (uint16_t       )FINSH_THREAD_STACK_SIZE,               (void*          )NULL,                      (UBaseType_t    )FINSH_THREAD_PRIORITY,                (TaskHandle_t*  )&ShellTask_Handler);               while (1)    {        ch = (int)finsh_getchar();              vTaskDelay(10);              if (ch < 0)        {            continue;        }...

– Use queue method to receive characters

int finsh_getchar(void){#ifdef RT_USING_DEVICE    char ch = -1;#ifdef RT_USING_POSIX_STDIO    if(read(STDIN_FILENO, &ch, 1) > 0)    {        return ch;    }    else    {        return -1; /* EOF */    }#else    if (0 == is_queue_empty())    {        ch = g_queue_get();    }        return ch;#endif /* RT_USING_POSIX_STDIO */#else    extern char rt_hw_console_getchar(void);    return rt_hw_console_getchar();#endif /* RT_USING_DEVICE */}

3 Test Program3.1 Main Function

extern int finsh_system_init(void);int main(void){ system_clock_config();    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);    gpio_config();    set_queue_null();    rt_hw_systick_init();    usart_configuration();    finsh_system_init();    xTaskCreate((TaskFunction_t )led0_task,                     (const char*    )"led0_task",                   (uint16_t       )LED0_STK_SIZE,               (void*          )NULL,                      (UBaseType_t    )LED0_TASK_PRIO,                (TaskHandle_t*  )&LED0Task_Handler);                  xTaskCreate((TaskFunction_t )led1_task,                     (const char*    )"led1_task",                   (uint16_t       )LED0_STK_SIZE,               (void*          )NULL,                      (UBaseType_t    )LED0_TASK_PRIO,                (TaskHandle_t*  )&LED1Task_Handler);                   vTaskStartScheduler();                while(1)  {  }

3.2 Custom Command

static int cmd_test(int argc, char **argv){    uint8_t get_val = atoi(argv[1]);       if (2 == argc)    {       rt_kprintf("get_val[%d]\n",get_val);    }    return 0;}MSH_CMD_EXPORT_ALIAS(cmd_test, test,test: [val]);

4 Test Results

msh >helpRT-Thread shell commands:test             - test: [val]clear            - clear the terminal screenversion          - show RT-Thread version informationlist             - list objectshelp             - RT-Thread shell help.ps               - List threads in the system.free             - Show the memory usage in the system.msh >test 123get_val[123]

5 SummaryFurther improvements are needed for commands like list, ps, free, etc. FreeRTOS allows specifying task handles for communication, and its message queue has a peek function. FreeRTOS is present in many projects, and to enhance competitiveness, it is best to master and deliberately apply it. The related source files summarized in this article can be obtained by replying with the keyword “FINSH”.

Leave a Comment