# Lab 0
<!-- {%hackmd hackmd-dark-theme %} -->
> 國立成功大學 資訊工程學系
嵌入式作業系統分析與實作 Analysis and Implementation of Embedded Operating Systems [CSIE7618] 2022 Spring
## 事前準備
- 開發板:STM32F407G-DISC1 (以下是此開發板的一些資訊)
- ARM Cortex M4 32-bit processor
- 1-Mbyte Flash memory, 192-Kbyte RAM
- 3-axis accelerometer
- audio sensor omnidirectional digital microphone speaker
- LEDs
- push-buttons
- 
- Mini-USB
- USB-to-TTL轉接線 (後面的lab會用到,可以一起買)


## Download and Install STM32CubeIDE
https://www.st.com/en/development-tools/stm32cubeide.html
去網站註冊帳號並下載Mac的版本~

下載完後解壓縮~

:::danger

很重要的是!第一次安裝的話記得要安裝左上方的驅動程式!!!
我之前都沒注意到他(他長ㄉ實在太不顯眼ㄌ😑),沒安裝他,結果都沒辦法讓板子照我的code執行,重新安裝IDE到第四次才發現有這個驅動程式,害我搞好久嗚嗚嗚嗚嗚😭😭😭😭😭

如果設計成這樣就顯眼多了484!既顯眼又有美感~真應該聘我去當UI設計師捏!😊
:::
## Create an STM32 Project with STM32CubeIDE
打開 STM32CubeIDE,選擇你要的workspace的directory

然後可以點上方的 `myST` 並且 `Login` 帳號密碼 (好像更新一些package之類的會需要登入帳密)

<!--  -->
點 `File` -> 點 `New` -> 點 `STM32 Project`

在 `Commercial Part Number` 輸入 `STM32F407VG`
點擊右側 `Board` 欄位的 `STM32F407G-DISC1` (也就是我們的開發板)

確認型號,點 `Next`

輸入Project的名稱

按 `No` 就好了 (但也不知道點 `Yes` 會有什麼差別就是了🤔)

不知道要按哪個,先按yes @_@ (應該是沒差(吧)?!)

下載package當中~

Agree & Finish!

## FreeRTOS v10.2.1
下載FreeRTOS v10.2.1,並解壓縮
https://github.com/FreeRTOS/FreeRTOS/tree/V10.2.1
在 `lab0` 這個project的directory內創建名為 `FreeRTOS` 的資料夾,並依以下步驟將前述解壓縮的FreeRTOS v10.2.1檔案移到專案內的 `FreeRTOS` 資料夾:
- `FreeRTOS/Source/include` 的整個 `include` 資料夾放到 `lab0/FreeRTOS/` 內
- `FreeRTOS/Source/*.c` (`Source` 內全部的 `.c` 檔) 放到`lab0/FreeRTOS/` 內
- `FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK/FreeRTOSConfig.h` 將此檔案放到 `lab0/FreeRTOS/include/` 內
- 在 `lab0/FreeRTOS/` 內新增一個名為 `portable` 的資料夾
- 在 `lab0/FreeRTOS/portable` 內新增一個名為 `MemMang` 的資料夾
- 將 `FreeRTOS/Source/portable/MemMang/heap_4.c` 放到 `lab0/FreeRTOS/portable/MemMang/` 內
- 將 `FreeRTOS/Source/portable/GCC/ARM_CM4F` 的 `ARM_CM4F` 整個資料夾放到 `lab0/FreeRTOS/portable` 裡面
`FreeRTOS` 資料夾裡面的資料夾和檔案應該會長得跟下面一樣:
```
FreeRTOS
├── include
│ ├── FreeRTOS.h
│ ├── FreeRTOSConfig.h
│ ├── StackMacros.h
│ ├── croutine.h
│ ├── deprecated_definitions.h
│ ├── event_groups.h
│ ├── list.h
│ ├── message_buffer.h
│ ├── mpu_prototypes.h
│ ├── mpu_wrappers.h
│ ├── portable.h
│ ├── projdefs.h
│ ├── queue.h
│ ├── semphr.h
│ ├── stack_macros.h
│ ├── stdint.readme
│ ├── stream_buffer.h
│ ├── task.h
│ └── timers.h
├── portable
│ ├── ARM_CM4F
│ │ ├── port.c
│ │ └── portmacro.h
│ └── MemMang
│ └── heap_4.c
├── croutine.c
├── event_groups.c
├── list.c
├── queue.c
├── stream_buffer.c
├── tasks.c
└── timers.c
```
接下來,對專案點擊右鍵,點 `Refresh`,讓 `FreeRTOS` 資料夾出現

## 修改 `lab0/FreeRTOS/include/FreeRTOSConfig.h`
- 首先,修改 `FreeRTOSConfig.h` 第45行的 `#ifdef __ICCARM__`
- 可將其修改為 `#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)`
- 或是 `#ifdef __GNUC__`
修改前:

修改後:

:::info
其中 `#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)` ,是因為 ARM 系列目前支援三大主流的工具鏈:
- ARM RealView (armcc) =>ARM keil/MDK
- IAR EWARM (iccarm) =>IAR
- GNU Compiler Collection (gcc) =>GCC
由於我們是用gcc,所以也可以改成 `#ifdef __GNUC__`
:::
- 接下來,將以下幾個macro設定為 `0`
- 第51行: `#define configUSE_IDLE_HOOK`
- 第52行: `#define configUSE_TICK_HOOK `
- 第64行: `#define configCHECK_FOR_STACK_OVERFLOW`
- 第66行: `#define configUSE_MALLOC_FAILED_HOOK`


:::success
建議可以把此專案資料夾內的 `FreeRTOS` 整個copy一份,後面的lab會再用到,到時候直接把資料夾copy到之後lab的專案內就好了,就不用每次都要搬來搬去設定來設定去~
:::
## 設定 C/C++ Paths and Symbols
對專案點右鍵,點 `Properties`

點 `C/C++ General` -> `Paths and Symbols` -> `Source Location` -> `Add Folder...`

選擇此專案路徑內的 `FreeRTOS`

設定完成~

再來~ 點 `Includes` ,再點 `Add...`

點 `File system...` ,選擇專案內的 `FreeRTOS/include` 和 `FreeRTOS/portable/ARM_CM4F` 這兩個資料夾

設定完成~ `Apply and Close`

Yes~ please `Rebuild Index`~

:::info
這裡的步驟,只要每次產生新專案,並弄好 `FreeRTOS` 都要做一次這裡的設定
:::
## 設定 Basic Timer & NVIC
點 `lab0.ioc` ,再點 `System Core` 底下的 `SYS` , `Debug` 欄位選擇 `Serial Wire` , `Timebase Source` 欄位選擇 `TIM7`

再來點 `NVIC` ,`Priority Group` 欄位選擇 `4 bits for pre-emption...` (PS. 要把這個畫面拉開一點,這個選單才會出現😑)

點 `File` -> `Save` ,會跳出這個視窗, `Yes` ~ please generate code~ 😇

:::info
每次只要修改 `.ioc` 檔案,並generate code的話,我們寫的code有可能會被覆蓋掉,所以我們要把我們的code寫在以下這種註解的區間內才不會被覆蓋:
```cpp!
/* USER CODE BEGIN ... */
// 我們的程式碼寫在USER CODE BEGINE跟END才不會被覆蓋掉
/* USRE CODE END */
```
:::
## 註解掉一些 handler
將 `lab0/Core/Inc/stm32f4xx_it.h` 和 `lab0/Core/Src/stm32f4xx_it.c` 這兩個檔案內的以下handler都註解掉:
- SVC_Handler
- PendSV_Handler
- SysTickHandler
`lab0/Core/Inc/stm32f4xx_it.h`

`lab0/Core/Src/stm32f4xx_it.c`


:::warning
這一部分的動作,只要每次generate code,都要重做一次。所以建議把 `.ioc` 檔的設定都一次設定到位後才generate code~
:::
## 測試
### 確定LED燈有開啟
以下測試會用到LED燈,所以先開啟 `lab0.ioc` ,確認右側的 `PD12` ~ `PD15` 有打開,這4個是控制LED燈的

如果沒打開的話,可以對他點左鍵,選 `GPIO_Output` ,然後再 `Save` 這個 `.ioc` 檔案 & `Generate Code`

### 編輯 `lab0/Core/Src/main.c`
開啟 `lab0/Core/Src/main.c` ,然後要include兩個header file ( `FreeRTOS.h` 和 `task.h` )
```cpp=19
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "FreeRTOS.h"
#include "task.h"
/* USER CODE END Includes */
```
:::danger
必須先 `#include "FreeRTOS.h"` 才能 `#include "task.h"` !
為什麼會有這規定呢?
在使用FreeRTOS的嵌入式系統項目中,首先需包含FreeRTOS的header file,然後再包含特定的FreeRTOS模組的header file,如 `task.h`、`queue.h` 等。這是由於FreeRTOS的header file之間存在相依性和順序要求,為了確保編譯順利進行,需要遵循正確的順序。
這是為什麼這個順序重要的原因:
1. FreeRTOS配置和定義:`FreeRTOS.h` 包含了FreeRTOS的全局配置、macro定義以及一些整體設置。這些設置會影響 FreeRTOS 的運作方式,包括一些低層次的定義。若是先包含 `task.h`,而不先包含 `FreeRTOS.h`,那麼一些必要的配置可能會丟失,導致編譯錯誤或運行時錯誤。
2. 符號定義和類型:`FreeRTOS.h` 包含了許多FreeRTOS使用的符號定義和自定義數據類型的宣告。這些定義在 `task.h` 和其他FreeRTOS模組中被使用。如果你先包含 `task.h`,那麼這些符號和類型可能會被未定義,導致編譯錯誤。
3. FreeRTOS模組之間的相依性:FreeRTOS的不同模組之間存在相依性,例如 `task.h` 依賴於 `FreeRTOS.h` 定義的許多內容。因此,為了確保這些模組正確協同工作,需要遵循正確的包含順序。
總之,為了確保FreeRTOS的正確運行,應該先包含 `FreeRTOS.h`,然後再包含其他特定的FreeRTOS模組的標頭文件,如 `task.h`、`queue.h`、`semphr.h` 等。這樣可以確保所有必要的配置和定義都已經生效,並且避免編譯和運行時的問題。
:::
建立以下幾個LED tasks
```cpp=57
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
BaseType_t xReturned;
TaskHandle_t xHandle=NULL;
void green_LED_task(void *pvParameters)
{
while (1) {
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
vTaskDelay(800);
}
vTaskDelete(NULL);
}
void orange_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(200);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
vTaskDelay(600);
}
vTaskDelete(NULL);
}
void red_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(400);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);
vTaskDelay(400);
}
vTaskDelete(NULL);
}
void blue_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(600);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
vTaskDelay(200);
}
vTaskDelete(NULL);
}
/* USER CODE END 0 */
```
接下來,在 `main(void)` 裡面create tasks,以及 `vTaskStartScheduler();`
```cpp=110
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
xTaskCreate(red_LED_task, "RED_LED", 100, NULL, 0, NULL);
xTaskCreate(blue_LED_task, "BLUE_LED", 100, NULL, 0, NULL);
xTaskCreate(green_LED_task, "GREEN_LED", 100, NULL, 0, NULL);
xTaskCreate(orange_LED_task, "ORANGE_LED", 100, NULL, 0, NULL);
vTaskStartScheduler();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
```
存檔後,按 `Project` -> `Build Project`

照理說~Console的地方應該會顯示 `0 errors, 0 warnings`

把開發版用Mini-USB跟電腦連接~
點 `Run` -> `Run` ,然後板子燒錄的燈就會開始紅綠紅綠交錯閃一陣子,停下來之後就會看到LED燈依照綠橘紅藍的順序發亮啦~

<!-- ### Code說明
#### Task Function
以下是一個task function的例子
```cpp!
void blue_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(600);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
vTaskDelay(200);
}
vTaskDelete(NULL);
}
```
一個task function應該要長得像這樣:
```cpp!
void vATaskFunction(void *pvParameters) {
for (;;) {
/* Task application code here*/
// 基本上不應該離開這個for/while loop
}
// 不應該return from這個function
// 若離開了前面的for/while loop
// 建議用vTaskDelete(NULL)把這個task刪掉,不要直接return
vTaskDelete(NULL);
}
```
#### Create Tasks
```cpp!
xTaskCreate(red_LED_task, "RED_LED", 100, NULL, 0, NULL);
```
-->
## 參考資料
- [Discovery kit with STM32F407VG MCU - User manual](https://www.st.com/resource/en/user_manual/dm00039084-discovery-kit-with-stm32f407vg-mcu-stmicroelectronics.pdf)
- 開發板的使用說明書
- [STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 advanced Arm®-based 32-bit MCUs - Reference manual](https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf)
- 開發板硬體SPEC規格書
- [FreeRTOS API Reference](https://www.freertos.org/a00106.html)
- FreeRTOS的API的說明
## `main.c` 測試檔
最後附上 `main.c` 測試檔完整的code~
```cpp=
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @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 "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include"FreeRTOS.h"
#include"task.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
BaseType_t xReturned;
TaskHandle_t xHandle=NULL;
void green_LED_task(void *pvParameters)
{
while (1) {
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
vTaskDelay(800);
}
vTaskDelete(NULL);
}
void orange_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(200);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
vTaskDelay(600);
}
vTaskDelete(NULL);
}
void red_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(400);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);
vTaskDelay(400);
}
vTaskDelete(NULL);
}
void blue_LED_task(void *pvParameters)
{
while (1) {
vTaskDelay(600);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
vTaskDelay(200);
}
vTaskDelete(NULL);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
xTaskCreate(red_LED_task, "RED_LED", 100, NULL, 0, NULL);
xTaskCreate(blue_LED_task, "BLUE_LED", 100, NULL, 0, NULL);
xTaskCreate(green_LED_task, "GREEN_LED", 100, NULL, 0, NULL);
xTaskCreate(orange_LED_task, "ORANGE_LED", 100, NULL, 0, NULL);
vTaskStartScheduler();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 50;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(CS_I2C_SPI_GPIO_Port, CS_I2C_SPI_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(OTG_FS_PowerSwitchOn_GPIO_Port, OTG_FS_PowerSwitchOn_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, LD4_Pin|LD3_Pin|LD5_Pin|LD6_Pin
|Audio_RST_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : CS_I2C_SPI_Pin */
GPIO_InitStruct.Pin = CS_I2C_SPI_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(CS_I2C_SPI_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : OTG_FS_PowerSwitchOn_Pin */
GPIO_InitStruct.Pin = OTG_FS_PowerSwitchOn_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(OTG_FS_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PDM_OUT_Pin */
GPIO_InitStruct.Pin = PDM_OUT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(PDM_OUT_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : I2S3_WS_Pin */
GPIO_InitStruct.Pin = I2S3_WS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(I2S3_WS_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : SPI1_SCK_Pin SPI1_MISO_Pin SPI1_MOSI_Pin */
GPIO_InitStruct.Pin = SPI1_SCK_Pin|SPI1_MISO_Pin|SPI1_MOSI_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : BOOT1_Pin */
GPIO_InitStruct.Pin = BOOT1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BOOT1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : CLK_IN_Pin */
GPIO_InitStruct.Pin = CLK_IN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(CLK_IN_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : LD4_Pin LD3_Pin LD5_Pin LD6_Pin
Audio_RST_Pin */
GPIO_InitStruct.Pin = LD4_Pin|LD3_Pin|LD5_Pin|LD6_Pin
|Audio_RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pins : I2S3_MCK_Pin I2S3_SCK_Pin I2S3_SD_Pin */
GPIO_InitStruct.Pin = I2S3_MCK_Pin|I2S3_SCK_Pin|I2S3_SD_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : VBUS_FS_Pin */
GPIO_InitStruct.Pin = VBUS_FS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(VBUS_FS_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : OTG_FS_ID_Pin OTG_FS_DM_Pin OTG_FS_DP_Pin */
GPIO_InitStruct.Pin = OTG_FS_ID_Pin|OTG_FS_DM_Pin|OTG_FS_DP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : OTG_FS_OverCurrent_Pin */
GPIO_InitStruct.Pin = OTG_FS_OverCurrent_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(OTG_FS_OverCurrent_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : Audio_SCL_Pin Audio_SDA_Pin */
GPIO_InitStruct.Pin = Audio_SCL_Pin|Audio_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : MEMS_INT2_Pin */
GPIO_InitStruct.Pin = MEMS_INT2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(MEMS_INT2_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM7 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM7) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
```
<!--  -->
<!--  -->
<!--  -->
<!--  -->
<!--  -->
<!-- 選NO -->
<!--  -->
<!-- <!-- <!-- 根據你當初建立project的設定,找到你 STM32 project 檔的位置
 --> --> -->
<!-- 註冊
點[myst] -> sign in
help->check for target selector device ...
help->check for embedded software package update
help->manage embedded software packages,並安裝 -->
<!--  -->
<!--  -->