大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRT上的普通GPIO與高速GPIO差異。
GPIO 可以說是 MCU 上最簡單最常用的外設模塊了,當一些原生功能外設接口模塊不能滿足項目設計要求時,我們常常會考慮使用 GPIO 來軟件模擬實現相應功能,這時候 GPIO 本身性能就顯得至關重要了。
在早期的 i.MXRT1015/1020/1024/1050 型號上,GPIO 都是普通性能(注意這里的普通其實相比一般低端 MCU 來說已經夠性能優越了),考慮到 i.MXRT 是性能怪獸,需要配置更強的 GPIO,因此在后續的 i.MXRT1010/1060/1064/1160/1170 型號上,出現了 HSGPIO,今天痞子衡就跟大家聊一聊 GPIO 和 HSGPIO差異:
一、HSGPIO是什么?
HSGPIO 是 High-Speed GPIO 縮寫,有時候也叫緊耦合 GPIO 或者單時鍾周期 GPIO,簡單說就是其模塊(IP)時鍾源速度高於普通 GPIO 時鍾源,因此我們可以以更高頻率訪問其模塊寄存器。下表列出了 i.MXRT 各型號上 HSGPIO 分布:
型號 | 普通GPIO | 高速GPIO |
---|---|---|
i.MXRT1010 | GPIO1、GPIO5 | GPIO2 |
i.MXRT1060/1064 | GPIO1 - GPIO5 | GPIO6 - GPIO9 |
i.MXRT1160/1170 | GPIO1 - GPIO13 | CM7_GPIO2、CM7_GPIO3 |
我們以 i.MXRT1060 為例,翻看其參考手冊 CCM 時鍾模塊章節,可以看到普通 GPIO1-5 的時鍾源是 IPG_CLK_ROOT、而高速 GPIO6-9 的時鍾源則是 AHB_CLK_ROOT:
在 i.MXRT1060 上 IPG_CLK_ROOT 最高頻率是 150MHz、而 AHB_CLK_ROOT 即內核頻率,可到 600MHz,所以單從時鍾源角度來看,HSGPIO 訪問性能應是 GPIO 的 "四倍"(這里打了個引號,實際芯片設計時,HSGPIO 總線訪問有延遲,做不到跟 AHB 總線同頻):
下圖是 i.MXRT1060 內核結構框圖,可以看到其實 HSGPIO 與 AHBP 總線之間經過了 Split 和 AIPS-Lite 兩級處理,所以 HSGPIO 最終訪問頻率並不等於 AHBP 總線頻率,只是時鍾源來自於 AHBP 總線。
- Note1: i.MXRT1170 內核結構里 HSGPIO 也是一樣會經過 Split 和 AIPS-Lite 兩級處理。
- Note2: i.MXRT1010 內核結構里 HSGPIO 做過了優化,僅 Split 一級處理。
二、共享 PAD 設計
從芯片內部來說,GPIO 與 HSGPIO 模塊是獨立的,但是因為芯片外部引腳(PAD)資源有限,因此部分 HSGPIO 是與 GPIO 模塊共享 PAD 的,最終 I/O 實際性能其實受限於同一個物理 PAD 特性。
我們以封裝最簡單的 i.MXRT1010 為例,下圖最左側列出了全部的 PAD,其中 GPIO_SD[13:0] 是 HSGPIO 專用引腳,而 GPIO[13:0]、GPIO_AD[14:0] 則是 GPIO 與 HSGPIO 復用引腳,當這些 GPIO/HSGPIO 復用引腳被配置為 GPIO 功能時,它們既可以映射到 GPIO1(普通GPIO),也可以映射到 GPIO2(HSGPIO):
- Note:如果已經將 GPIO_SD[13:0] 配置為了 GPIO2,則不要再將 GPIO[13:0] 配置為 HSGPIO,會發生沖突。
具體 GPIO 映射功能是由 IOMUXC_GPR26 寄存器來控制的(注意這是個軟復位不置位的寄存器)。比如當 GPIO_11 被配置為了 GPIOMUX_IO11 功能時,那么 IOMUXC_GPR26[11] 決定了其映射關系:
IOMUXC_GPR26[11] = 0,則 GPIO_11 對應 GPIO1[11],為普通 GPIO
IOMUXC_GPR26[11] = 1,則 GPIO_11 對應 GPIO2[11],為 HSGPIO
下表列出了 i.MXRT 各型號上 GPIO/HSGPIO 切換控制關系:
型號 | PAD切換控制寄存器 | ALT功能名 | 對應切換GPIO |
---|---|---|---|
i.MXRT1010 | IOMUXC_GPR->GPR26 | GPIO_MUX | GPIO1與GPIO2 |
i.MXRT1060/1064 | IOMUXC_GPR->GPR26 IOMUXC_GPR->GPR27 IOMUXC_GPR->GPR28 IOMUXC_GPR->GPR29 |
GPIO_MUX1 GPIO_MUX2 GPIO_MUX3 GPIO_MUX4 |
GPIO1與GPIO6 GPIO2與GPIO7 GPIO3與GPIO8 GPIO4與GPIO9 |
i.MXRT1160/1170 | IOMUXC_GPR->GPR40、41 IOMUXC_GPR->GPR42、43 |
GPIO_MUX2 GPIO_MUX3 |
GPIO2與CM7_GPIO2 GPIO3與CM7_GPIO3 |
三、PAD 運行速度
前面講了,不管是使能了普通 GPIO 還是 HSGPIO,最終都是由同一個物理 PAD 來輸出信號,因此 I/O 實際性能最終受限於這個 PAD 最大運行速度。
繼續以 i.MXRT1010 為例,每個 PAD 在 IOMUXC 模塊里都有一個專門配置電氣屬性的寄存器 IOMUXC_SW_PAD_CTL_PAD_xxIO,選取 GPIO_11 的相應配置寄存器為例,組合其中 SRE、DSE、SPEED 位可以得到不同運行速度(具體組合值可在參考手冊 GPIO 章節搜索 Operating Frequency 小節查看),不過我們能看到 PAD 最大運行速度是 200MHz:
在 i.MXRT1010 數據手冊里,我們還可以看到更具體的 I/O 翻轉時間測試:
四、HSGPIO 示例代碼
基於上面的理論知識,我們改造一下 i.MXRT1010 SDK 里的 \driver_examples\gpio\led_output 例程,加入如下 HSGPIO 相關代碼,同樣可以達到閃爍 LED 燈的功能。
介紹了這么多,如果只是用 HSGPIO 控制小燈閃爍,似乎看不出性能差異,下一篇文章,痞子衡將用示波器為大家實測 GPIO 與 HSGPIO 極限翻轉頻率,再提前劇透一下,GPIO->DR_TOGGLE 和 GPIO->DR 寄存器實現 I/O 翻轉效率還不一樣哦。
bool is_normal_gpio = false;
int main(void)
{
BOARD_ConfigMPU();
BOARD_InitBootClocks();
/* Define the init structure for the output LED pin*/
gpio_pin_config_t led_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
CLOCK_EnableClock(kCLOCK_Iomuxc);
IOMUXC_SetPinMux(IOMUXC_GPIO_11_GPIOMUX_IO11, 0U);
if (is_normal_gpio)
{
// GPIO1
IOMUXC_GPR->GPR26 &= ~(1u << 11);
// Slow Slew Rate, 100MHz
IOMUXC_SetPinConfig(IOMUXC_GPIO_11_GPIOMUX_IO11, 0x70A0U);
GPIO_PinInit(GPIO1, 11, &led_config);
}
else
{
// GPIO2
IOMUXC_GPR->GPR26 |= (1u << 11);
// Fast Slew Rate, 200MHz
IOMUXC_SetPinConfig(IOMUXC_GPIO_11_GPIOMUX_IO11, 0x70F9U);
GPIO_PinInit(GPIO2, 11, &led_config);
}
while (1)
{
SDK_DelayAtLeastUs(100000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
if (is_normal_gpio)
{
//GPIO1->DR_TOGGLE = (1u << 11);
GPIO1->DR ^= (1u << 11);
__DSB();
}
else
{
//GPIO2->DR_TOGGLE = (1u << 11);
GPIO2->DR ^= (1u << 11);
__DSB();
}
}
}
至此,i.MXRT上的普通GPIO與高速GPIO差異痞子衡便介紹完畢了,掌聲在哪里~~~
歡迎訂閱
文章會同時發布到我的 博客園主頁、CSDN主頁、知乎主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。