本帖最后由 sunsili 于 2023-7-19 08:39 编辑
STM32H5测评 | 开箱硬件测评分析与GPIO和PWM测试
来源:EEWORLD论坛网友 bigbat 版权归原作者所有
开箱硬件测评分析随着物联网的不断推进,网络通讯安全级别也在不断提高,普通的MCU在应对加解密和安全验证等应用时就有点力不从心,MCU的主要应用是小型的嵌入式设备,但安全应用又需要硬件具备一定性能,安全算法除了占用一定的MCU性能外还需要大量的代码和RAM空间,因而市场出现了很多“组合设计”,最常见的就是“MCU+高性能通讯模块”,在应用环境恶劣的场景下面临挑战,如在北方冬季无人值守的站点,因气温很低,会给通讯模块带来很多问题。基于arm Cortex-M33内核的高性能MCU — STM32H5,针对安全性和通讯性能增加了很多的性能。STM32H5系列提供了较大RAM(640K)和Flash(2M+),提供 4K Backup RAM 用来存储待机数据,主频更是提高到了250MHz。在安全方面,STM32H5 也是提供了M33内核的全部安全特性,TrustZone、内存保护、加密存储等特性。
NUCLEO-H563ZI 是主核为STM32H563ZI、144PIN脚的DEMO板。该板接口由原来的USB接口更新为 Type-C 接口,有以下外设:1、一个 RJ45 以太网口、PHY 使用的是 LAN8742,一个网络变压器;2、一个 VDD 触发按键作为输入,按键接了一个ESD ALC6V1的保护;3、一个LPUSART 接口,链接到板载的虚拟串口,与ST-LINK V3共用一个USB;4、一个全速 USB TYPE-C 接口,提供芯片的USB功能,及硬件保护和电源管理;5、LED和REST按键等外设。从板卡设计中可以看出ST公司加入了大量的接口保护设计参考。因板卡新的硬件特性,需要升级软件环境,STM32CubeMX需要升级到 v6.9 版,Java jre升级到17版;Keil 升级到 v6.0以上版本,同时下载STM32H5的包,ST-link V3的驱动也需要升级。点灯程序:
NYUCLEO-H563ZI开发板的硬件引脚基本已经配置好了,只需配置没有扩展的引脚。程序点亮的是LED2。程序不是很复杂,代码很简单,但是M33内核需要的设置却很多。/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ HAL_GPIO_TogglePin(LED2_YELLOW_GPIO_Port, LED2_YELLOW_Pin); HAL_Delay(500); /* USER CODE BEGIN 3 */ }
GPIO和PWM测试为了呈现 STM32H563ZI 接近MPU的性能,本次测试使用freeRTOS系统进行PWM和GPIO的测试。首先,需要安装STM32Cube的STM32H5的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 ****************************************************************************** * @attention * * 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 */ /** * @brief 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开始开始工作。
|