STM32H563ZI的性能已经接近MPU的能力,很多的MCU的设计已经不能体现STM32H563ZI的性能,使用RTOS已经成为必然。这次有意测评各种RTOS系统在,我比较熟悉的系统是freeRTOS,本次测试就使用freeRTOS系统进行PWM和GPIO的测试。
首先需要安装STM32Cube的STM32H的freeRTOS系统模块,为了省事新建项目时选择“ACCESS TO EXAMPLE SELECTOR”项目,选择开发板NUCLEO-H563ZI,
选择 FreeRTOS_Semaphore_LowPower项目,这个项目比较简单。
项目默认打开了PWR管理,还有三个LED外设。从这个项目就可以开始测试了,而且这个项目还可以作为标准的模板项目。
主要的程序是使用一个低功耗定时器LPTIM4作为信号源来控制GPIO的输出。
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : app_freertos.c
* Description : Code for freertos applications
******************************************************************************
* [url=home.php?mod=space&uid=1020061]@attention[/url] *
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os2.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define DEFAULT_TIMEOUT (1000)
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
extern LPTIM_HandleTypeDef hlptim4;
/* USER CODE END Variables */
/* Definitions for MainThread */
osThreadId_t MainThreadHandle;
const osThreadAttr_t MainThread_attributes = {
.name = "MainThread",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 256 * 4
};
/* Definitions for BinarySemaphore */
osSemaphoreId_t BinarySemaphoreHandle;
const osSemaphoreAttr_t BinarySemaphore_attributes = {
.name = "BinarySemaphore"
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
void SystemClock_Config(void);
/* USER CODE END FunctionPrototypes */
void MainThread_Entry(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* USER CODE BEGIN PREPOSTSLEEP */
void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{
/* This is needed to prevent TIM6 from triggering an interrupt,
* which could prevent the CPU from entering STOP mode */
HAL_SuspendTick();
/* Start low power timer */
HAL_LPTIM_TimeOut_Start_IT(&hlptim4, DEFAULT_TIMEOUT);
/* Enter STOP mode */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
void PostSleepProcessing(uint32_t ulExpectedIdleTime)
{
/* Restore Clock settings */
SystemClock_Config();
/* Resume HAL timebase */
HAL_ResumeTick();
}
/* USER CODE END PREPOSTSLEEP */
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* creation of BinarySemaphore */
BinarySemaphoreHandle = osSemaphoreNew(1, 1, &BinarySemaphore_attributes);
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* creation of MainThread */
MainThreadHandle = osThreadNew(MainThread_Entry, NULL, &MainThread_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_MainThread_Entry */
/**
* @brief Function implementing the MainThread thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_MainThread_Entry */
void MainThread_Entry(void *argument)
{
/* USER CODE BEGIN MainThread */
/* Infinite loop */
for(;;osSemaphoreAcquire(BinarySemaphoreHandle, osWaitForever))
{
HAL_GPIO_TogglePin(LED1_GREEN_GPIO_Port, LED1_GREEN_Pin);
}
/* USER CODE END MainThread */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
if(hlptim->Instance == LPTIM4)
{
osSemaphoreRelease(BinarySemaphoreHandle);
HAL_LPTIM_TimeOut_Stop_IT(&hlptim4);
}
}
/* USER CODE END Application */
程序中首先声明了一个信号量BinarySemaphoreHandle,作为GPIO的控制开关,然后在中断回调HAL_LPTIM_CompareMatchCallback中生成这个信号量。
//信号量
osSemaphoreId_t BinarySemaphoreHandle;
//回调函数
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
if(hlptim->Instance == LPTIM4)
{
osSemaphoreRelease(BinarySemaphoreHandle);
HAL_LPTIM_TimeOut_Stop_IT(&hlptim4);
}
}
信号生成后,等待系统自己调度,这时需要将LPTIM4中断关掉。HAL_LPTIM_TimeOut_Stop_IT(&hlptim4);
/* USER CODE END Header_MainThread_Entry */
void MainThread_Entry(void *argument)
{
/* USER CODE BEGIN MainThread */
/* Infinite loop */
for(;;osSemaphoreAcquire(BinarySemaphoreHandle, osWaitForever))
{
HAL_GPIO_TogglePin(LED2_YELLOW_GPIO_Port, LED2_YELLOW_Pin);
}
/* USER CODE END MainThread */
}
信号到达后翻转GPIO输出,系统运行后LED2,进入不停的闪烁。这里我把LED1改成了LED2
PWM的测试选择了FreeRTOS_Mutex 例程,主要是因为PWM的输出需要更加严格的同步和控制。同时低功耗模式也不适合该应用。PWM的输出设置需要搞清楚程序的同步逻辑。
程序首先定义了两个线程Thread1和Thread2,一个Mutex锁信号MutexHandle,通过这个信号进行UART资源的保护运行。
osThreadId_t Thread1Handle;
const osThreadAttr_t Thread1_attributes = {
.name = "Thread1",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 256 * 4
};
/* Definitions for Thread2 */
osThreadId_t Thread2Handle;
const osThreadAttr_t Thread2_attributes = {
.name = "Thread2",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 256 * 4
};
/* Definitions for Mutex */
osMutexId_t MutexHandle;
const osMutexAttr_t Mutex_attributes = {
.name = "Mutex"
};
首先两个线程在运行前半段使用信号锁进行共用资源uart的运行,后面进行运行。
/* USER CODE BEGIN Header_Thread1_Entry */
/**
* @brief Function implementing the Thread1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Thread1_Entry */
void Thread1_Entry(void *argument)
{
/* USER CODE BEGIN Thread1 */
uint16_t i;
/* Infinite loop */
for(i = 0; i < 10; ++i)
{
#if EXAMPLE_USES_MUTEX
osMutexAcquire(MutexHandle, osWaitForever);
printf ("Thread1: Mutex Acquired!\n");
#endif
printf("Thread1 : This is message number %u\n", i+1);
#if EXAMPLE_USES_MUTEX
printf ("Thread1: Mutex Released!\n");
osMutexRelease(MutexHandle);
#endif
HAL_GPIO_TogglePin(LED1_GREEN_GPIO_Port, LED1_GREEN_Pin);
osDelay(200);
}
while(1)
{
HAL_GPIO_TogglePin(LED1_GREEN_GPIO_Port, LED1_GREEN_Pin);
osDelay(1000);
}
/* USER CODE END Thread1 */
}
/* USER CODE BEGIN Header_Thread2_Entry */
/**
* @brief Function implementing the Thread2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Thread2_Entry */
void Thread2_Entry(void *argument)
{
/* USER CODE BEGIN Thread2 */
uint16_t i;
/* Infinite loop */
for(i = 0; i < 10; ++i)
{
#if EXAMPLE_USES_MUTEX
osMutexAcquire(MutexHandle, osWaitForever);
printf ("Thread2: Mutex Acquired!\n");
#endif
printf("Thread2 : This is message number %u\n", i+1);
#if EXAMPLE_USES_MUTEX
printf ("Thread2: Mutex Released!\n");
osMutexRelease(MutexHandle);
#endif
HAL_GPIO_TogglePin(LED2_YELLOW_GPIO_Port, LED2_YELLOW_Pin);
osDelay(200);
}
while(1)
{
HAL_GPIO_TogglePin(LED2_YELLOW_GPIO_Port, LED2_YELLOW_Pin);
osDelay(1000);
}
/* USER CODE END Thread2 */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
进程先获取信号锁,在进行打印输出,输出完成后在解锁,这样可以保证三段打印都是同一个线程的输出。
可以看出每次的输出都是一个线程的信息。下面进行PWM的改造测试
PWM的设置如图,我使用LED1作为PWM的输出,所以设置PB0作为TIM3的CH3通道,PWM输出,脉宽比为50%,所以计数为2048,PLUSE VALUE=1024
设置好以后将程序进行改造,另起一个项目通过CUBE生成初始化代码,然后改造项目。
/* USER CODE BEGIN Header_Thread1_Entry */
/**
* @brief Function implementing the Thread1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Thread1_Entry */
void Thread1_Entry(void *argument)
{
osMutexAcquire(MutexHandle, osWaitForever);
printf ("Thread1: Mutex Acquired!\n");
printf("Thread1 : PWM starter\n ");
printf ("Thread1: Mutex Released!\n");
osMutexRelease(MutexHandle);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
while(1)
{
osDelay(1);
}
/* USER CODE END Thread1 */
}
项目启动后。可以看到LED1开始开始工作。
|