1. 前言
在TrustZone架构中,中断是可以分配到S或者NS侧的,所以在很多的场景中,为了充分利用MCU的资源,中断的重映射就成了很常见的需求。 本文将展示如何在使能TrustZone的STM32H5上,实现外部中断的共享,即实现将外部中断动态分配给S和NS侧。
2. 创建工程
基于STM32H563ZI-NUCLEO实验板,STM32H5通过串口接收上位机的指令,来决定外部中断按键是响应S侧的中断服务函数,还是NS侧的中断服务函数。 通过STM32CubeMX创建基于STM32H5的激活了TrustZone的基础工程,可以从选择芯片开始创建工程。
3. 在S侧的secure_nsc.c 文件中,添加如下代码,实现中断的重映射:
在STM32CubeMX中完成上述配置,就可以生成代码了,然后编译,正常的话,工程是可以编译通过的。因为本文不考虑ICACHE,所以在下图中选择“Yes”,即生成代码。
2.1. NS侧应用示例 1. 在NS侧的main.c文件中,添加以下宏定义和变量的申明:
- /* USER CODE BEGIN PV */
- #define PRINTF_UART_INSTANCE huart3
- uint8_t rxBuffer=0;
- /* USER CODE END PV */
2. 实现串口重定向,外部中断的回调函数(翻转NS侧的LED2和LED3)。
- /* USER CODE BEGIN PV */
- #ifdef __GNUC__
- int _write(int file, char *ptr, int len)
- {
- /* Wait for the ready status of the transfer */
- while(RESET == __HAL_UART_GET_FLAG(&PRINTF_UART_INSTANCE, UART_FLAG_TXE));
- /* Start the transmission process */
- if (HAL_UART_Transmit(&PRINTF_UART_INSTANCE, (uint8_t *)ptr, len,
- HAL_MAX_DELAY) != HAL_OK)
- {
- Error_Handler();
- }
-
- /* Wait for the end of the transfer */
- while(RESET == __HAL_UART_GET_FLAG(&PRINTF_UART_INSTANCE, UART_FLAG_TC));
-
- return len;
- }
- #endif /* __GNUC__ */
- void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
- {
- printf("Button pressed in NS!\r\n");
- HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
- HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
- }/* USER CODE END PV */
3. 在NS侧的主函数中,添加如下代码实现信息的输出,以及接收上位机的命令:
- /* USER CODE BEGIN 2 */
-
- printf("======================================================\r\n");
- printf("= STM32H563 Re-TargetISR\r\n");
- printf("= Build time: %s %s\r\n", __DATE__, __TIME__);
-
- printf("======================================================\r\n");
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- if(HAL_UART_Receive(&huart3, &rxBuffer, 1, 100) == HAL_OK)
- {
- printf("= UartRx: 0x%x\r\n", rxBuffer);
- SECURE_RetargetISR(rxBuffer);
- }
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- /* USER CODE BEGIN 1 */
- /**
- * [url=/u/brief]@brief[/url] This function handles EXTI Line13 interrupt.
- */
- void EXTI13_IRQHandler(void)
- {
- /* USER CODE BEGIN EXTI13_IRQn 0 */
-
- /* USER CODE END EXTI13_IRQn 0 */
- HAL_GPIO_EXTI_IRQHandler(B1_USER_Pin);
- /* USER CODE BEGIN EXTI13_IRQn 1 */
-
- /* USER CODE END EXTI13_IRQn 1 */
- }
-
- /* USER CODE END 1 */
- /* USER CODE BEGIN 4 */
- void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
- {
- HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
- }
- /* USER CODE END 4 */
3. 在S侧的secure_nsc.c 文件中,添加如下代码,实现中断的重映射:
- CMSE_NS_ENTRY void SECURE_RetargetISR(uint8_t flag)
- {
- if(flag == 0x31)
- {
- NVIC_DisableIRQ(EXTI13_IRQn);
- HAL_EXTI_ConfigLineAttributes(EXTI_LINE_13, EXTI_LINE_NSEC);
- NVIC_SetTargetState(EXTI13_IRQn);
- NVIC_EnableIRQ(EXTI13_IRQn);
- }
- else if(flag == 0x30)
- {
- NVIC_DisableIRQ(EXTI13_IRQn);
- HAL_EXTI_ConfigLineAttributes(EXTI_LINE_13, EXTI_LINE_SEC);
- NVIC_ClearTargetState(EXTI13_IRQn);
- NVIC_EnableIRQ(EXTI13_IRQn);
- }
- }
4. 在 secure_nsc.h 中申明该函数:
- void SECURE_RegisterCallback(SECURE_CallbackIDTypeDef CallbackId, void *func);
- void SECURE_RetargetISR(uint8_t flag);
2.3. 其他注意事项 1. 不可以在外设中断里面重映射当前的中断,这样会引发Fault。
2. 编译顺序:TrustZone架构中,要求先编译S工程,然后再编译NS工程;但下载不区分先后顺序。
2.4. 选项字节的配置 对于TrustZone架构中,芯片的选项字节同样也要有对应的配置。
1. 使能TrustZone
2. 配置Flash Watermark
在使用STM32CubeProgrammer完成上述配置之后,我们便可以将S和NS的程序分别下载到芯片中,然后按下开发板的复位按钮。
3. 验证 打开串口终端连接上串口,按下复位按钮,我们可以看到如下信息;当我们直接按下开发板上的用户按键时,可以看到LED2和LED3同时翻转,这是NS侧的外部中断实现的功能。当通过串口工具发送0x30(如果使用其他不支持16进制发送的串口终端,可直接输入0)给MCU之后,再次按下按钮时,能看到仅有LED1在翻转,说明外部中断被重映射到S侧了,实验完成。
4. 小结 本文实验附有完整的实验工程供大家直接使用,希望对大家有所帮助。
文档中所用到的工具及版本
STM32CubeMX V6.14.1 STM32CubeIDE V1.17.0 STM32CubeProgrammer V2.19.0 XCOM V2.0
LAT中的附件 LAT1591 STM32H5 在使能TrustZone下实现外部中断的共享_V0.2.zip
|