【电子DIY】DIY行车记录仪为游戏机之主控软件开发(3)适配freertos
代码见:https://github.com/qinyunti/py32f403-nes.git一.前言
为了后面方便复杂点的业务开发,我们来适配FreeRTOS。 下面分享整个过程。
二.添加代码
下载代码
git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git
提取FreeRTOS-Kernel内核文件
保留FreeRTOS-Kernel下以下c文件
保留FreeRTOS-Kernel\include文件夹,并添加到头文件包含路径。
复制portable\MemMang下的heap_4.c,如果使用其他的堆实现则复制对应的文件。
复制FreeRTOS-Kernel\portable\GCC\ARM_CM4F下的所有文件
复制examples/template_configuration/FreeRTOSConfig.h
添加后文件如下,设置include和FreeRTOSConfig.h所在路径到头文件包含路径
工程添加文件如下
三.配置
工程配置
FreeRTOSConfig.h中
#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_64_BITS
改为
#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_32_BITS
设置堆大小
#define configTOTAL_HEAP_SIZE 4096
改为
#define configTOTAL_HEAP_SIZE (4096*10)
设置中断优先级宏
/* configKERNEL_INTERRUPT_PRIORITY sets the priority of the tick and context
* switch performing interrupts. Not supported by all FreeRTOS ports. See
* https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific to
* ARM Cortex-M devices. */
#define configKERNEL_INTERRUPT_PRIORITY 0
/* configMAX_SYSCALL_INTERRUPT_PRIORITY sets the interrupt priority above which
* FreeRTOS API calls must not be made. Interrupts above this priority are
* never disabled, so never delayed by RTOS activity. The default value is set
* to the highest interrupt priority (0). Not supported by all FreeRTOS ports.
* See https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific
* to ARM Cortex-M devices. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0
/* Another name for configMAX_SYSCALL_INTERRUPT_PRIORITY - the name used depends
* on the FreeRTOS port. */
#define configMAX_API_CALL_INTERRUPT_PRIORITY 0
改为
#include "py32f403xD.h"
/* configKERNEL_INTERRUPT_PRIORITY sets the priority of the tick and context
* switch performing interrupts. Not supported by all FreeRTOS ports. See
* https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific to
* ARM Cortex-M devices. */
#define configKERNEL_INTERRUPT_PRIORITY (7<<(8-__NVIC_PRIO_BITS))
/* configMAX_SYSCALL_INTERRUPT_PRIORITY sets the interrupt priority above which
* FreeRTOS API calls must not be made. Interrupts above this priority are
* never disabled, so never delayed by RTOS activity. The default value is set
* to the highest interrupt priority (0). Not supported by all FreeRTOS ports.
* See https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific
* to ARM Cortex-M devices. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5<<(8-__NVIC_PRIO_BITS))
/* Another name for configMAX_SYSCALL_INTERRUPT_PRIORITY - the name used depends
* on the FreeRTOS port. */
#define configMAX_API_CALL_INTERRUPT_PRIORITY (5<<(8-__NVIC_PRIO_BITS))
#define configCHECK_FOR_STACK_OVERFLOW 2
改为
#define configCHECK_FOR_STACK_OVERFLOW 0
使用3位优先级即__NVIC_PRIO_BITS为3,即优先级寄存器8位高3位有效。
这里设置系统调用最高中断优先级为5,如果中断中要调用系统API则中断优先级不能高于5.
滴答等内核中断优先级设置为最低优先级7.
(对于NVIC数字越大优先级越低)
#define configCPU_CLOCK_HZ ( ( unsigned long ) 20000000 )
根据实际的systick频率修改,我这里是
#define configCPU_CLOCK_HZ ( ( unsigned long ) 144000000 )
#define configTICK_RATE_HZ 100改为
#define configTICK_RATE_HZ 1000
Systick 1ms中断一次,调度一次。
由于OS使用Systick,且HAL层也使用Systick,我们在系统初始化之前不使用HAL。
使用LL。
工程中定义宏
USE_FULL_LL_DRIVER
修改py32f403_hal.c中
函数
HAL_StatusTypeDef HAL_Init(void)
注释掉,先不初始化systick等到os中启动时初始化。
//HAL_InitTick(TICK_INT_PRIORITY);
编译报错
1602 | __STATIC_INLINE uint32_t LL_ADC_DMA_GetRegAddr(ADC_TypeDef *ADCx, uint32_t Register)
先不编译
.\PY32F403_HAL_Driver\Src\py32f403_ll_adc.c
py32f403_it.c中,系统滴答中回调os的滴答处理和HAL的处理。
extern void xPortSysTickHandler( void );
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
xPortSysTickHandler();
HAL_IncTick();
}
修改
startup_py32f403xx.s中
替换所有SVC_Handler 为vPortSVCHandler
替换所有PendSV_Handler 为xPortPendSVHandle
及对应OS需要的调度中断处理。
四.测试
#include "FreeRTOS.h"
#include "task.h"
uint8_t rx_buffer[64];
static void shell_task(void * arg)
{
(void)arg;
uart_init(0, 115200);
uart_init(1, 115200);
uart_send(1,(uint8_t*)"Hello World\r\n",strlen("Hello World\r\n"));
while(1){
uint32_t len = uart_read(1, rx_buffer, sizeof(rx_buffer));
if(len > 0){
uart_send(1,rx_buffer,len);
}
}
}
int main(void)
{
HAL_Init();
clk_init();
clk_out();
TaskHandle_t xHandle;
xTaskCreate( shell_task, "shell", 1024, NULL, 1, &xHandle );
vTaskStartScheduler();
}
可以看到串口收发正常
五.总结
由于官方都有对应平台的移植,所以适配只需要添加对应的文件即可。需要注意下编译器版本,这里使用ARM编译器版本6,GNU兼容配置,所以选用GCC的Port。 另外注意中断相关的优先级配置,堆大小配置等一些关键配置。