--- tags: 嵌入式作業系統分析與實作 --- # lab2-sensor_and_interrupt contributed by <`RusselCK` > ###### tags: `RusselCK` ## 作業要求 * Must use sensor interrupt : motion detection. * When you shake your board, it will trigger the interrupt. * Please use the deferred interrupt handling task. * Use semephore. * ISR will give the semephore and the handler task enters the running state. * At the beginning,the green LED blinking,then shake the board, the red LED triggered(switch state) by ISR and the orange LED blinking five times in handler task. * When orange LED blinking, you should not trigger the sensor interrupt if you shake the board. ## Pinout & Configuration ![](https://i.imgur.com/3pW6PMY.png) ![](https://i.imgur.com/gbjV0hv.png) ![](https://i.imgur.com/zhj2Mce.png) ![](https://i.imgur.com/wTP9PdO.png) ![](https://i.imgur.com/b2ug5Dt.png) ## 程式架構 ![](https://i.imgur.com/cCCXbeC.png) `vLab02_task_1` : the Green LED blinking `ISR` : the Red LED triggered (switch state) `vLab02_Handler_task` : the Orange LED blinking 5 times **Priority** : `ISR` > `vLab02_Handler_task` > `vLab02_task_1` ## 程式碼與解說 ### Include, Macro and Variables ```c /* USER CODE BEGIN Includes */ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" /* USER CODE END Includes */ ``` ```c /* Private macro -----------------------------------------------------------------------*/ /* USER CODE BEGIN PM */ #define Green_LED_High HAL_GPIO_WritePin(Green_LED_GPIO_Port, GPIO_PIN_12, GPIO_PIN_SET) #define Green_LED_Low HAL_GPIO_WritePin(Green_LED_GPIO_Port, GPIO_PIN_12, GPIO_PIN_RESET) #define Orange_LED_High HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_13, GPIO_PIN_SET) #define Orange_LED_Low HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_13, GPIO_PIN_RESET) #define Red_LED_High HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_14, GPIO_PIN_SET) #define Red_LED_Low HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_14, GPIO_PIN_RESET) #define Red_LED_Toggle HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14) /* USER CODE END PM */ ``` 為了方便之後程式碼的閱讀,我們將會用到的 GPIO Read/Write/Toggle 指令換成可讀性較高的 Macro ```c /* USER CODE BEGIN PV */ SemaphoreHandle_t xSemaphore; /* USER CODE END PV */ ``` 我們先 declare 之後會用到的 SemaphoreHandle ### Motion Sensor Interrupt - [ ] [MEMS digital output motion sensor: ultra-low-power high-performance three-axis “nano” accelerometer](https://www.st.com/resource/en/datasheet/lis3dsh.pdf) - [ ] [LIS3DSH: 3-axis digital output accelerometer](https://www.st.com/resource/en/application_note/dm00026768-lis3dsh-3axis-digital-output-accelerometer-stmicroelectronics.pdf) ```c void MEMS_Write(uint8_t address,uint8_t data){ HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1,&address,1,10); HAL_SPI_Transmit(&hspi1,&data,1,10); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3,GPIO_PIN_SET); } void vLab02_sensor_init() { MEMS_Write(0x21,0x01); MEMS_Write(0x23,0x48); MEMS_Write(0x20,0x67); MEMS_Write(0x24,0x00); MEMS_Write(0x57,0x55); MEMS_Write(0x40,0x05); MEMS_Write(0x41,0x11); MEMS_Write(0x59,0xFC); MEMS_Write(0x5A,0xFC); MEMS_Write(0x5B,0x01); } ``` ![](https://i.imgur.com/hxaEiqd.png) ![](https://i.imgur.com/TwSkbfM.png) ![](https://i.imgur.com/nlUS4kZ.png) 只要參照文件設置 Registers 的 Values,我們就可以達成「晃動板子便有 interrupt signal」的效果 ### `vLab02_task_1()` ```c void vLab02_task_1( void *pvParameters ) { while(1) { /* Green LED blinking */ Green_LED_High; // Green LED ON vTaskDelay(500); Green_LED_Low; // Green LED OFF vTaskDelay(500); } } ``` Task1 要做的事情是「綠燈不斷閃爍」,從程式碼的註解可以很直觀的明白每一行程式碼在做的事情 ### ISR ```c /* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN) { /* switch Red LED state */ Red_LED_Toggle; /* semaphore give */ BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } /* USER CODE END 4 */ ``` > `EXIT` stand for External Interrupt ISR 要做的事情就是「改變 Red LED state」 和「give a semaphore」 #### Interrupt handler `Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c` ```c /** * @brief This function handles EXTI interrupt request. * @param GPIO_Pin Specifies the pins connected EXTI line * @retval None */ void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) { /* EXTI line interrupt detected */ if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin); } } /** * @brief EXTI line detection callbacks. * @param GPIO_Pin Specifies the pins connected EXTI line * @retval None */ __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { /* Prevent unused argument(s) compilation warning */ UNUSED(GPIO_Pin); /* NOTE: This function Should not be modified, when the callback is needed, the HAL_GPIO_EXTI_Callback could be implemented in the user file */ } ``` 根據原生程式碼的提示,我們需要將 ISR 的內容寫在 `main.c` 的 `HAL_GPIO_EXTI_Callback()` 裡頭 ### `vLab02_Handler_task()` ```c #define LONG_TIME 0xFFFF void vLab02_Handler_task(void *pvParameters) { while(1) { if(xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE) { /* Orange LED blinking 5 times */ for (int i = 0; i < 5; ++i) { Orange_LED_High; vTaskDelay(500); Orange_LED_Low; vTaskDelay(500); } } } } ``` 當 `vLab02_Handler_task()` 成功接收到 semephore 時,Handler task 就會執行「橘燈閃爍 5 次」 ## 使用方式 ```c void vLab02_start (void *pvParameters) { vLab02_sensor_init(); xSemaphore = xSemaphoreCreateBinary(); xTaskCreate(vLab02_task_1, "Lab02_task_1", 1000, NULL, 3, NULL); xTaskCreate(vLab02_Handler_task, "Lab02_Handler_task", 1000, NULL, 2, NULL); vTaskDelete(NULL); } int main (void) { ... /* USER CODE BEGIN 2 */ xTaskCreate(vLab02_start, "Lab02_Start", 1000, NULL, 1, NULL); vTaskStartScheduler(); /* USER CODE END 2 */ ... } ``` ## 問題與解決 ### Q1. Sensor interrup 只會執行一次 將 `vLab02_sensor_init();` 加到 `ISR` 、 `vLab02_Handler_task` 或 `vLab02_task_1` 之中,達到 sensor register reinitialization 的效果。 ### Q2. 如何在橘燈閃爍的途中,避免 sensor interrup 的執行? 等橘燈閃爍完之後再初始化 sensor register ```c void vLab02_Handler_task(void *pvParameters) { while(1) { if(xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE) { /* Orange LED blinking 5 times */ for (int i = 0; i < 5; ++i) { Orange_LED_High vTaskDelay(500); Orange_LED_Low vTaskDelay(500); } /* reset motion sensor registers */ vLab02_sensor_init(); } } } ```