1.什么是端口復用?
STM32有很多的內置外設(把一些功能ADC\看門狗…集中到芯片里面),這些外設的外部引腳都是與GPIO復用的。也就是說,一個GPIO如果可以復用為內置外設的功能引腳,那么當這個GPIO作為內置外設使用的時候,就叫做復用。
例如串口1 的發送接收引腳是PA9,PA10,當我們把PA9,PA10不用作GPIO,而用做復用功能串口1的發送接收引腳的時候,叫端口復用。
可在芯片STM32767IGT6資料中的pin and ball definitions中找到:
STM32(M4內核以上)的端口復用映射原理
STM32系列微控制器IO引腳通過一個復用器連接到內置外設或模塊。該復用器一次只允許一個外設的復用功能(AF)連接到對應的IO口。這樣可以確保共用同一個IO引腳的外設之間不會發生沖突。
每個IO引腳都有一個復用器,該復用器采用16路復用功能輸入(AF0到AF15),可通過GPIOx_AFRL(針對引腳0-7)和GPIOx_AFRH(針對引腳8-15)寄存器對這些輸入進行配置,每四位控制一路復用。
對於每一組GPIO都有GPIO 復用功能低位寄存器 (GPIOx_AFRL) (x = A…K):比如GPIOA有16個IO口,GPIOx_AFRL是32位,可以配置引腳0-7。
GPIOx_AFRL寄存器:
GPIO 復用功能高位寄存器 (GPIOx_AFRH) (x = A…J):
比如配置PA9連接到AF7,那么就是配置GPIOA_AFRH的AFR9,配置成0111 。
1.系統功能:將I/O連接到AF0,然后根據所用功能進行配置:
- JTAG/SWD:在各器件復位之后,會將這些引腳指定為專用引腳,可供片上調試模塊立即使用 (不受GPIO控制器控制)
- RTC_REFIN:此引腳應配置為輸入浮空模式。
- MCO1和MCO2:這些引腳必須配置為復用功能模式。
2.GPIO:在GPIOx_MODER寄存器中將所需I/O配置為輸出或輸入。
3.外設復用功能:
對於ADC和DAC,在GPIOx_MODER寄存器中將所需I/O配置為模擬通道。對於其它外設:
- 在GPIOx_MODER寄存器中將所需I/O配置為復用功能
- 通過GPIOx_OTYPER、GPIOx_PUPDR和GPIOx_OSPEEDER寄存器,分別選擇類型、上拉/下拉以及輸出速度。
- 在GPIOx_AFRL或GPIOx_AFRH寄存器中,將I/O連接到所需AFx
以PA9、PA10配置為串口1為例:
1.GPIO端口時鍾使能。
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIO時鍾
2.復用外設時鍾使能。
比如你要將端口PA9,PA10復用為串口,所以要使能串口時鍾。
__HAL_RCC_USART1_CLK_ENABLE(); //使能串口1時鍾
3.端口模式配置為復用功能。 HAL_GPIO_Init函數。
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //復用推挽輸出
4.配置GPIOx_AFRL或者GPIOx_AFRH寄存器,將IO連接到所需的AFx。HAL_GPIO_Init函數。
GPIO_Initure.Alternate=GPIO_AF7_USART1;//復用為USART1
在文件system-usart.c中可以找到:HAL_UART_MspInit
void HAL_UART_MspInit(UART_HandleTypeDef *huart) { //GPIO端口設置 GPIO_InitTypeDef GPIO_Initure; if(huart->Instance==USART1)//如果是串口1,進行串口1 MSP初始化 { __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA時鍾 __HAL_RCC_USART1_CLK_ENABLE(); //使能USART1時鍾 GPIO_Initure.Pin=GPIO_PIN_9; //PA9 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //復用推挽輸出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FAST; //高速 GPIO_Initure.Alternate=GPIO_AF7_USART1; //復用為USART1 HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9 GPIO_Initure.Pin=GPIO_PIN_10; //PA10 HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10 #if EN_USART1_RX HAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中斷通道 HAL_NVIC_SetPriority(USART1_IRQn,3,3); //搶占優先級3,子優先級3 #endif } }