[toc]
一、背景介绍
1.1 N32G45X介绍
N32G457系列采用 32 bit ARM Cortex-M4F内核,最高工作主频144MHz,支持浮点运算和DSP指令,
集成多达512KB Flash、144KB SRAM、4x12bit 5Msps ADC、4xOPAMP、7xCOMP、2x1Msps 12bitDAC,支持多达24通道电容式触摸按键,集成多路U(S)ART、I2C、SPI、QSPI、USB、CAN通信接
口,1xSDIO接口,1x10/100M以太网接口,数字摄像头(DVP)接口,内置密码算法硬件加速引擎。
1)内核 CPU
- 32 位 ARM Cortex-M4 内核+ FPU,单周期硬件乘除法指令,支持 DSP 指令和 MPU
- 内置 8KB 指令 Cache 缓存,支持 Flash 加速单元执行程序 0 等待
- 最高主频 144MHz,180DMIPS
2)加密存储器
- 高达 512KByte 片内 Flash,支持加密存储、多用户分区管理及数据保护,支持硬件 ECC 校验,10
万次擦写次数,10 年数据保持
- 144KByte 片内 SRAM(包含 16KByte Retention RAM),Retention RAM 支持硬件奇偶校验
3)通信接口
- 7 个 U(S)ART 接口, 最高速率达 4.5 Mbps,其中 3 个 USART 接口(支持 1xISO7816,1xIrDA,
LIN),4 个 UART 接口
- 3 个 SPI 接口,速率高达 36 MHz,其中 2 个支持 I2S
- 1 个 QSPI 接口,速率高达 144 Mbps
- 4 个 I2C 接口,速率高达 1 MHz,主从模式可配,从机模式下支持双地址响应
- 1 个 USB2.0 Full speed Device 接口
- 2 个 CAN 2.0A/B 总线接口
- 1 个 SDIO 接口,支持 SD/MMC 格式
- 1 个 Ethernet MAC 接口,支持 10M/100M 以太网
- 1 个 DVP (Digital Video Port)接口
1.2 freeRTOS介绍
FreeRTOS 是市场领先的微控制器和小型微处理器的实时操作系统 (RTOS),与世界领先的芯片公司合作开发,历时 15 年,现在每 170 秒下载一次。FreeRTOS 在麻省理工学院的开源许可证下免费分发,包括一个内核和越来越多的适用于所有行业领域的库。FreeRTOS 的构建强调可靠性和易用性。
freeRTOS源码:https://github.com/freeRTOS
freeRTOS文档:https://www.freertos.org/zh-cn-cmn-s/features.html
二、freeRTOS API介绍
2.1 任务
2.1.1 xTaskCreate
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);
pvTaskCode:任务处理函数,一个独立的任务,不能返回,可以在函数内删除。
pcName:任务的名称,用于标识任务。
usStackDepth:任务栈的宽度,该值表示栈单元的数量,一个栈单元为16位或者32位,由portSTACK_TYPE指定,当该值与一个栈单元的大小(16或32)相乘即可得任务栈的大小。
pvParameters:任务的参数,用于向创建的任务传递信息。
uxPriority:任务优先级。
pxCreatedTask:任务句柄的指针,在删除任务的时候需要用到任务句柄。
2.1.2 xTaskCreateStatic
TaskHandle_t xTaskCreateStatic(
TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer );
pxTaskCode:任务处理函数
pcName:任务名称
ulStackDepth:任务栈的宽度
pvParameters:任务处理函数的参数
uxPriority:优先级
puxStackBuffer:任务栈,一般为成员为StackType_t的数组
pxTaskBuffer:保存任务控制块(Task control block)TCB结构体的buffer。
2.1.3 vTaskDelete
void vTaskDelete( TaskHandle_t xTask );
xTask:任务句柄。
2.2 队列、互斥锁、信号量
2.2.1 xQueueCreate
QueueHandle_t xQueueCreate(
UBaseType_t uxQueueLength,
UBaseType_t uxItemSize );
uxQueueLength:队列所能容纳的数据项的最大个数
uxItemSize:数据项的大小,单位为字节
返回:
QueueHandle_t:成功则返回创建队列的句柄,失败返回NULL。
2.2.2 xQueueCreateStatic
QueueHandle_t xQueueCreateStatic(
UBaseType_t uxQueueLength,
UBaseType_t uxItemSize,
uint8_t *pucQueueStorageBuffer,
StaticQueue_t *pxQueueBuffer )
uxQueueLength:队列能容纳的数据项的最大个数。
uxItemSize:数据项的大小。
pucQueueStorageBuffer:保存队列的buffer,大小为uxItemSize乘uxQueueLength。
pxQueueBuffer:保存消息队列结构体的buffer。
2.2.3 xQueueSend
BaseType_t xQueueSend(
QueueHandle_t xQueue,
const void * pvItemToQueue,
TickType_t xTicksToWait );
xQueue:队列句柄
pvItemToQueue:指向数据项的指针
xTicksToWait:超时时间,超过该值未将消息发送出去则返回错误
2.2.4 xQueueReceive
BaseType_t xQueueReceive(
QueueHandle_t xQueue,
void *pvBuffer,
TickType_t xTicksToWait );
xQueue:消息队列句柄。
pvBuffer:接收缓冲区,接受到的数据项将缓存到这里。
xTicksToWait:超时时间。如果 INCLUDE_vTaskSuspend 设置为 “1” ,则将阻塞时间指定为 portMAX_DELAY 会导致任务无限期地阻塞(没有超时)。
2.2.5 xSemaphoreCreateBinary
SemaphoreHandle_t xSemaphoreCreateBinary( void );
返回:
SemaphoreHandle_t 信号量句柄。
2.2.6 xSemaphoreCreateMutex
SemaphoreHandle_t xSemaphoreCreateMutex( void )
返回
SemaphoreHandle_t:互斥信号量句柄。
2.2.7 vSemaphoreDelete
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
xSemaphore:信号量句柄。
2.2.8 xSemaphoreTake
xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
xSemaphore:信号量句柄。
xTicksToWait:超时时间。
2.2.9 xSemaphoreGive
xSemaphoreGive( SemaphoreHandle_t xSemaphore );
xSemaphore:信号量句柄。
2.3 事件组
2.3.1 xEventGroupCreate
EventGroupHandle_t xEventGroupCreate( void );
返回:
EventGroupHandle_t:事件组句柄。
2.3.2 vEventGroupDelete
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
xEventGroup:事件组句柄。
2.3.3 xEventGroupWaitBits
EventBits_t xEventGroupWaitBits(
const EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
xEventGroup:事件组句柄。
uxBitsToWaitFor:等待的事件组的位,该值为正在等待的事件位的按位或,如(1<<5)|(1<<3)的值表示等待bit5和bit3。
xClearOnExit:return前是否清除相应的位。
xWaitForAllBits:是否等待所有位都被设置。
xTicksToWait:超时时间。
返回:
EventBits_t:事件组的事件位被设置的状态。
2.3.4 xEventGroupSetBits
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
xEventGroup:事件组句柄。
uxBitsToSet:设置的位。
返回:
EventBits_t:事件组的事件位的状态。
2.4 软件定时器
2.4.1 xTimerCreate
TimerHandle_t xTimerCreate
( const char * const pcTimerName,
const TickType_t xTimerPeriod,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
pcTimerName:定时器的名称。
xTimerPeriod:定时器周期,若需要延时的时间是的单位是ms,可使用pdMS_TO_TICKS。
uxAutoReload:循环定时器还是单次定时器。
pvTimerID:定时器ID,用于一个回调函数被注册到多个定时器的情况下识别定时器。
pxCallbackFunction:定时器回调函数,需满足void vCallbackFunction( TimerHandle_t xTimer )原型。
2.4.2 xTimerStart
BaseType_t xTimerStart( TimerHandle_t xTimer,
TickType_t xBlockTime );
xTimer:定时器句柄。
xBlockTime:如果在xTimerStart的时候定时器的守护进程的队列已满,xBlockTime表示阻塞等待的时间。定时器队列的长度由configTIMER_QUEUE_LENGTH指定。
2.4.3 xTimerStop
BaseType_t xTimerStop( TimerHandle_t xTimer,
TickType_t xBlockTime );
xTimer:定时器句柄。
xBlockTime:同xTimerStart的xBlockTime。
2.4.4 xTimerDelete
BaseType_t xTimerDelete( TimerHandle_t xTimer,
TickType_t xBlockTime );
xTimer:定时器句柄。
xBlockTime:同xTimerStart的xBlockTime。
三、freeRTOS移植
3.1 源码下载和源码文件结构
3.1.1 源码下载
https://freertos.org/zh-cn-cmn-s/index.html
3.1.2 源码文件结构
根目录的freeRTOS是内核,freeRTOS-plus是扩展,扩展中有freeRTOS的命令行工具CLI,TCP、和调试freeRTOS时获取任务调度、内存管理、消息队列和互斥量等各种事件信息的Trace。
进入内核目录(即freeRTOS文件夹)的Source。
- include文件夹存放freeRTOS的头文件。
- portable文件夹为移植文件,里面有不同MCU内核、不同内存算法的适配文件,移植时根据平台的架构选择。
- 其他.c文件:内核源码。
3.2 keil配置源文件和头文件
1)添加内核源码
2)添加移植文件
3)添加头文件
3.3 增加freeRTOS配置文件
从Demo\CORTEX_M4F_STM32F407ZG-SK中复制freeRTOSConfig.h到一个已经被keil设置好的inc目录下,该文件用于配置内核。
3.4 删除n32g45x_it.c中的systick和svc中断
四、freeRTOS运行示例
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
#include "event_groups.h"
#include "semphr.h"
EventGroupHandle_t xEventGroup;
SemaphoreHandle_t xBinarySemaphore;
SemaphoreHandle_t xMutex;
TaskHandle_t notifyTask;
#define mainFIRST_TASK_BIT ( 1UL << 0UL )
#define mainSECOND_TASK_BIT ( 1UL << 1UL )
#define mainISR_BIT ( 1UL << 2UL )
static void vTask1( void *pvParameters );
static void vTask2( void *pvParameters );
static void vTask3( void *pvParameters );
static void vTask4( void *pvParameters );
static void vTask5( void *pvParameters );
static void vTask6( void *pvParameters );
static void vTask7( void *pvParameters );
static void vTask8( void *pvParameters );
static void vTask9( void *pvParameters );
typedef enum
{
FAILED = 0,
PASSED = !FAILED
} TestStatus;
#define countof(a) (sizeof(a) / sizeof(*(a)))
USART_InitType USART_InitStructure;
void RCC_Configuration(void);
void GPIO_Configuration(void);
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
USART_InitStructure.BaudRate = 115200;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
USART_Init(USARTx, &USART_InitStructure);
USART_Enable(USARTx, ENABLE);
printf("\n\r===FreeRTOS demo===\n\r");
static xQueueHandle xMessageQueue;
xMessageQueue = xQueueCreate( 10, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
xTaskCreate( vTask1, "vTask1", configMINIMAL_STACK_SIZE, ( void * ) &xMessageQueue, tskIDLE_PRIORITY, NULL );
xTaskCreate( vTask2, "vTask2", configMINIMAL_STACK_SIZE, ( void * ) &xMessageQueue, tskIDLE_PRIORITY, NULL );
printf("[1.1]current free heap:%d\r\n",xPortGetFreeHeapSize());
xEventGroup = xEventGroupCreate();
printf("[1.2]current free heap:%d\r\n",xPortGetFreeHeapSize());
xTaskCreate( vTask3, "vtask3", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate( vTask4, "vtask4", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
printf("[1.3]current free heap:%d\r\n",xPortGetFreeHeapSize());
xTaskCreate( vTask5, "vtask5", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
xTaskCreate( vTask6, "vtask6", configMINIMAL_STACK_SIZE, NULL, 4, NULL);
printf("[1.4]current free heap:%d\r\n",xPortGetFreeHeapSize());
xTaskCreate( vTask7, "vtask7", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
printf("[1.5]current free heap:%d\r\n",xPortGetFreeHeapSize());
xTaskCreate( vTask8, "vtask8", configMINIMAL_STACK_SIZE, NULL, 7, NULL);
xTaskCreate( vTask9, "vtask9", configMINIMAL_STACK_SIZE, NULL, 6, ¬ifyTask);
xBinarySemaphore = xSemaphoreCreateBinary();
if (NULL == xBinarySemaphore)
{
printf("create binary semaphore failed");
return -1;
}
xMutex = xSemaphoreCreateMutex( );
vTaskStartScheduler();
while (1)
{
}
}
void RCC_Configuration(void)
{
GPIO_APBxClkCmd(USARTx_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE);
USART_APBxClkCmd(USARTx_CLK, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
GPIO_InitStructure.Pin = USARTx_TxPin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pin = USARTx_RxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);
}
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while (BufferLength--)
{
if (*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
int fputc(int ch, FILE* f)
{
USART_SendData(USARTx, (uint8_t)ch);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXDE) == RESET)
;
return (ch);
}
static void vTask1( void *pvParameters )
{
unsigned short usValue = 0, usLoop;
xQueueHandle *pxQueue;
const unsigned short usNumToProduce = 3;
short sError = pdFALSE;
pxQueue = ( xQueueHandle * ) pvParameters;
for( ;; )
{
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
{
printf("Task1 will send: %d\r\n", usValue);
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( portTickType ) 0 ) != pdPASS )
{
sError = pdTRUE;
}
else
{
++usValue;
}
}
vTaskDelay( 2000 );
}
}
static void vTask2( void *pvParameters )
{
unsigned short usData = 0;
xQueueHandle *pxQueue;
pxQueue = ( xQueueHandle * ) pvParameters;
for( ;; )
{
while( uxQueueMessagesWaiting( *pxQueue ) )
{
if( xQueueReceive( *pxQueue, &usData, ( portTickType ) 0 ) == pdPASS )
{
printf("Task2 received:%d\r\n", usData);
}
}
vTaskDelay( 5000 );
}
}
static void vTask3( void *pvParameters )
{
for( ;; )
{
vTaskDelay( 2000 );
printf( "Bit setting task -\t ready to set bit 0.\r\n" );
xEventGroupSetBits( xEventGroup, mainFIRST_TASK_BIT );
vTaskDelay( 2000 );
printf( "Bit setting task -\t ready to set bit 1.\r\n" );
xEventGroupSetBits( xEventGroup, mainSECOND_TASK_BIT );
}
}
static void vTask4( void *pvParameters )
{
EventBits_t xEventGroupValue;
const EventBits_t xBitsToWaitFor = ( mainFIRST_TASK_BIT |
mainSECOND_TASK_BIT |
mainISR_BIT );
for( ;; )
{
xEventGroupValue = xEventGroupWaitBits(
xEventGroup,
xBitsToWaitFor,
pdTRUE,
pdFALSE,
portMAX_DELAY );
if( ( xEventGroupValue & mainFIRST_TASK_BIT ) != 0 )
{
printf( "Bit reading task -\t Event bit 0 was set\r\n" );
}
if( ( xEventGroupValue & mainSECOND_TASK_BIT ) != 0 )
{
printf( "Bit reading task -\t Event bit 1 was set\r\n" );
}
}
}
static void vTask5( void *pvParameters )
{
BaseType_t xReturn = pdTRUE;
int iCount = 0;
for( ;; )
{
printf("start post sem\r\n");
if(iCount >= 3)
{
iCount=0;
vSemaphoreDelete(xBinarySemaphore);
xBinarySemaphore = NULL;
printf(" but delete binary semaphore\r\n");
}
if( xBinarySemaphore != NULL )
{
xReturn = xSemaphoreGive(xBinarySemaphore);
if (pdTRUE == xReturn)
{
printf("post sem succeed\r\n");
}
else
{
printf("post sem error\r\n");
}
iCount++;
}
printf("=========icount=%d\r\n", iCount);
vTaskDelay(2500);
}
}
static void vTask6( void *pvParameters )
{
BaseType_t xReturn = pdTRUE;
for( ;; )
{
printf("wait sem");
xReturn = xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);
if (pdTRUE == xReturn)
{
printf("get sem succeed\r\n");
}
else
{
printf("get sem error\r\n");
}
}
}
static void vTask7( void *pvParameters )
{
int i = 0;
for( ;; )
{
xSemaphoreTake(xMutex, portMAX_DELAY);
for(i=0; i<20; i++)
{
printf("###i=%d\r\n", i);
}
xSemaphoreGive(xMutex);
vTaskDelay(3000);
}
}
static void vTask8( void *pvParameters )
{
for( ;; )
{
#if 0
if(xTaskNotify(notifyTask, 88, eSetValueWithoutOverwrite) == pdPASS)
{
printf("####put data notify task9 successed\r\n");
}
else
{
printf("put data notify task9 faield\r\n");
}
#else
if(xTaskNotifyGive(notifyTask) == pdPASS)
{
printf("$$$ send notify signal success\r\n");
}
else
{
printf("$$$ send notify signal failed\r\n");
}
#endif
vTaskDelay(2000);
}
}
static void vTask9( void *pvParameters )
{
uint32_t receData = 0;
BaseType_t xResult;
int notifySignalNum = 0;
for( ;; )
{
#if 0
xResult = xTaskNotifyWait(
0,
0,
&receData,
portMAX_DELAY
);
if(xResult == pdPASS)
{
printf("####receive notify data: %d success\r\n", receData);
}
#else
notifySignalNum = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
while (notifySignalNum--)
{
printf("$$$ i am receive task8 signal\r\n");
}
#endif
}
}
# if 0
void vApplicationStackOverflowHook( TaskHandle_t pxTask,
char * pcTaskName )
{
( void ) pxTask;
while(1)
{
printf("task %s is stack overflow. \r\n", pcTaskName);
vTaskDelay(500);
}
}
#endif
#ifdef USE_FULL_ASSERT
void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line)
{
printf("Wrong parameters value: file %s on line %d\r\n", file, line);
while (1)
{
}
}
#endif
五、注意事项
1)keil要使能C99,否则编译会报错。
2)keil需要5.3版本,否则n32g的dfp安装不成功。
六、参考
https://blog.csdn.net/qq_49864684/article/details/119207495![Image 2.png]