GD32F303 debugging notes (9) FreeRTOS transplantation

Preface

It has been more than a year since the last article on the GD32 series was updated. According to the previous idea, it is over just to introduce the commonly used modules in GD32. In the subsequent development, I was fortunate to be able to use this IC as the main control again. Therefore, not only for my own essay, but also for the convenience of colleagues or classmates, I will write several articles during this period mainly on the transplantation and simple use of FreeRTOS , LVGL , FreeModbus and CJson using GD32F303 as the main control . Because RTOS is used, the following three open source libraries no longer introduce separate bare metal transplantation methods. Next, we began to officially enter the porting of RTOS.

FreeRTOS

  • An open source real-time operating system that can easily write business requirements without considering the coupling problems between modules. It is more effective in managing the CPU than bare metal and is widely used in various electronic industries.
  • There is no blind recommendation here. FreeRTOS is not the only RTOS, nor does product development in all directions require the use of RTOS. For example, some products that have extremely high real-time requirements (including extreme protection functions) will basically die if they use RTOS. .
  • For a detailed introduction to RTOS, you can consult online information by yourself, and I will not go into details here.

Transplant preparation

Please prepare the following before transplantation:

  1. GD32F303 includes the keil
    project of its corresponding standard library. The project can be created using official routines or according to the project creation and compilation of GD32F303 Debugging Notes (Zero) .
  2. FreeRTOS source code
    I am using V10.4.0, and the source code is on GITHUB . I replaced its kernel source code with V10.4.3 .
  3. A hardware board controlled by GD32F303 and containing corresponding input and output controls.

Migration steps

1. FreeRTOS is merged into the KEIL project

  1. Unzip the document
    Please add image description2. Focus on the files in the Source directory
    Please add image description
  • The core source code for FreeRTOS transplantation is the include folder, 7 C files and some files in the portable folder
    Please add image description
  1. Create a new FreeRTOS folder in the project directory and divide it into categories
    Please add image description
  • After the categories are divided, copy the include folder and 7 C files in the source code to the FreeRTOS->include folder and FreeRTOS->Src folder in the project respectively without increasing or decreasing.

Please add image description
Please add image description
Please add image description

  1. Next there is the port folder and a header file of FreeRTOSConfig.h
  • Let’s first solve the problem of the header file. You can copy it from the official source code example downloaded before, or you can apply the header file below.
    Please add image description
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/*-----------------------------------------------------------
 * Application specific definitions.
 *
 * These definitions should be adjusted for your particular hardware and
 * application requirements.
 *
 * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
 * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 
 *
 * See http://www.freertos.org/a00110.html
 *----------------------------------------------------------*/

#define configUSE_IDLE_HOOK			0
#define configUSE_TICK_HOOK			0
#define configCPU_CLOCK_HZ			( ( unsigned long ) 108000000 )	
#define configTICK_RATE_HZ			( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES		( 5 )
#define configMINIMAL_STACK_SIZE	( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE		( ( size_t ) ( 4 * 1024U ) )
#define configMAX_TASK_NAME_LEN		( 16 )
#define configUSE_TRACE_FACILITY	0
#define configUSE_16_BIT_TICKS		0

#define configUSE_PREEMPTION		1
#define configUSE_TIME_SLICING      1
#define configIDLE_SHOULD_YIELD		1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 		0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet		1
#define INCLUDE_uxTaskPriorityGet		1
#define INCLUDE_vTaskDelete				1
#define INCLUDE_vTaskCleanUpResources	0
#define INCLUDE_vTaskSuspend			1
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay				1

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 		255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY	15

#define vPortSVCHandler		SVC_Handler
#define xPortPendSVHandler	PendSV_Handler
//#define xPortSysTickHandler SysTick_Handler

#endif /* FREERTOS_CONFIG_H */
  1. There is one port folder left. The port folder needs to solve two problems, the internal memory management of RTOS and the interface with the IC hardware we actually use.
  • For the memory management part, the official provides 5 methods. We only use the 4th method, but we still copy them all.
    Please add image description
    Please add image description
  • The selection of IC hardware interface files depends on two questions: What is the chip core we use? What is the development (compilation) environment we use for this IC?
  • You can think carefully about the above two questions. If you understand these two, it will not be a problem even if you change to a chip you have never used and want to run FreeRTOS.
  • I gave the answer directly to the GD32F303. The classification in FreeRTOS is ARM-CortexM4 core without MPU. Since I use the V5 compiler in the Keil project, the transplanted file chooses the file in RVDS.
    Please add image description
    Please add image description
  1. After copying all the required source code into the project, we need to also configure and associate these files in the Keil project
  • First confirm whether the compiler version you are using is V5
    Please add image description
  • Create a folder in the project directory and add files

Please add image description
Please add image description
Please add image description

  • Add the path to the above file

Please add image description
Please add image description

  1. After completing the above steps, there are still several important interface functions in port.c left.
  • There are three important functions in port.cPlease add image description

  • We need to associate the interface function names related to FreeRTOS and MCU. There are many methods online. Here we choose the most convenient method to rename the function through macros.
    Please add image description

  • Comment out SVC_Handler();PendSV_Handler(); in gd32f30x_it.c.

/*!
    \brief      this function handles PendSV exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
//void PendSV_Handler(void)
//{
    
    
//}

/*!
    \brief      this function handles PendSV exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
//void PendSV_Handler(void)
//{
    
    
//}
  • Add xPortSysTickHandler() to SysTick_Handler() in gd32f30x_it.c;
  • It is also recommended here to set the macro value of INCLUDE_xTaskGetSchedulerState to 1 to determine whether the RTOS creates the task first and then performs scheduling.
extern void xPortSysTickHandler(void);
/*!
    \brief      this function handles SysTick exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SysTick_Handler(void)
{
    
    
	if(0U != delay)
	delay--;

	#if (INCLUDE_xTaskGetSchedulerState  == 1 )
		if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
		{
    
    
	#endif   
			xPortSysTickHandler();
	#if (INCLUDE_xTaskGetSchedulerState  == 1 )
		}
	#endif  

}
  1. Adjust stack size in startup file
  • Here I have adjusted it to a relatively large value, but you can actually adjust it to a smaller value. The IC I used has 96k SRAM, so it can be used very easily.
    Insert image description here
  1. After completing the above steps, add the corresponding header file, compile and use FreeRTOS normally.

Please add image descriptionPlease add image descriptionPlease add image description

2. Board verification

  1. Create 3 tasks first
  • Create the LCD_BG_task task to adjust the screen backlight on and off to produce a breathing effect.
  • lcd_backlight_breathe() is used to adjust the PWM of the backlight
  • xSemaphoreGive() is used to release a binary semaphore to synchronize tasks
void LCD_BG_task(void * pvParameters)
{
    
      
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 1UL );
	for(;;)
	{
    
    		
		if(pdTRUE == lcd_backlight_breathe())
			xSemaphoreGive(xBinarySemaphore);
		vTaskDelay(xTicksToWait);
	}
}
  • Create Usart_Send_task task to send serial port information regularly
void Usart_Send_task(void * pvParameters)
{
    
    
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 1000UL );
	TickType_t xLastWakeTime;
    
	/* 获得当前的Tick Count */
	xLastWakeTime = xTaskGetTickCount();
	
	while(1)
	{
    
    
		Usartx_Transmit_DMA(USART1,(uint8_t *)"FreeRTOS_1S_Task!\n",18);
		
		xTaskDelayUntil(&xLastWakeTime,xTicksToWait);
	}	
}
  • Create the Lcd_Refresh_task task to refresh the screen display content
  • xSemaphoreTake() is used to obtain the synchronization information given by task 1 and refresh the display content when the screen is turned off.
  • LCD_Clear() is used to refresh the screen and change the screen to the specified color.
void Lcd_Refresh_task(void * pvParameters)
{
    
    
	static uint8_t i=0;
	
	while(1)
	{
    
    
		if( xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE )
		{
    
    
			if(i<2)	i++;
			else		i=0;
			
			if(i==0)		LCD_Clear(0xF800);	/* 红色   */ 
			else if(i==1)	LCD_Clear(0x001F);	/* 蓝色   */
			else if(i==2)	LCD_Clear(0xFFE0);	/* 黄色   */
		}
	}	
}
  1. main function
  • Create tasks and perform scheduling
#include "gd32f30x.h"
#include "gd32f30x_libopt.h"
#include "main.h"

FLAG_BIT Module;

extern uint32_t delay;

uint8_t lcd_backlight_breathe(void);

#define LCD_BG_TASK_PRIO  		( tskIDLE_PRIORITY + 2 )
#define UART_TASK_PRIO    		( tskIDLE_PRIORITY + 2 )
#define LCD_REFRESH_TASK_PRIO   ( tskIDLE_PRIORITY + 2 )

TaskHandle_t LCDBGTask_Handle;

void LCD_BG_task(void * pvParameters);
void Usart_Send_task(void * pvParameters);
void Lcd_Refresh_task(void * pvParameters);

/* 队列句柄, 创建队列时会设置这个变量 */
QueueHandle_t xQueue;
/* 二进制信号量句柄 */
SemaphoreHandle_t xBinarySemaphore;

int main()
{
    
    	
	
	SystemTick_Init();	
	SystemClock_Reconfig();	
		
	GPIO_Init();
	Timer3_Init();
	SPIx_Init();
	USARTx_Init();	
//	ADCx_Init();
	DMA_Init();
	NVIC_Init();
	LCD_Init();

	/* 创建二进制信号量 */
	xBinarySemaphore = xSemaphoreCreateBinary( );
	
	if( xBinarySemaphore != NULL )
	{
    
    
		xTaskCreate(LCD_BG_task, "LcdBG_Task", configMINIMAL_STACK_SIZE, NULL, LCD_BG_TASK_PRIO, (TaskHandle_t*  )&LCDBGTask_Handle);
		xTaskCreate(Usart_Send_task, "Uart_Task", configMINIMAL_STACK_SIZE, NULL, UART_TASK_PRIO, NULL);
		xTaskCreate(Lcd_Refresh_task,"LCD_Refresh_Task",configMINIMAL_STACK_SIZE, NULL, LCD_REFRESH_TASK_PRIO, NULL);
	
		vTaskStartScheduler();
	}
	else
	{
    
    
	
	}

	while(1)
	{
    
    

	}

}
  1. final effect
  • The effect of the serial port data sent by task 2 on the host computer is as follows:
    Insert image description here
  • The display effect of tasks 1 and 3 on the physical board is as follows:

GD32F303+FreeRTOS refresh screen display

  • Let me think about it here. The color of the screen in the video changes from green->blue->yellow->red->blue->yellow->red. Why not green->red->blue->yellow->red->blue? ->yellow->red?

Project Files

  • The project source code of this article is also provided here. It is not provided for free. You can download it if you need it.

Please add image description

Guess you like

Origin blog.csdn.net/qq_37554315/article/details/131060820