NXP iMX8MM Cortex-M4 核心 GPT Capture 測試
1). 簡介
NXP i.MX8 系列處理器均為異構多核架構 SoC,除了可以運行 Linux 等復雜操作系統(tǒng)的 Cortax-A 核心,還包含了可以運行實時操作系統(tǒng)比如 FreeRTOS 的 Cortex-M 核心,本文就演示通過 NXP i.MX8MM 處理器集成的 Cortex-M4 核心來運行 GPT (General Purpose Timer) 輸入采集功能模塊的測試。
I.MX8M Mini 處理器 GPT 模塊硬件比較簡單,如下框圖,可以實現(xiàn) Capture 捕獲輸入功能和 Compare 定時輸出功能。
本文所演示的ARM平臺來自于Toradex 基于NXP i.MX8M Mini ARM處理器的Verdin iMX8MM ARM嵌入式平臺。
2. 準備
a). Verdin i.MX8MM ARM核心版配合Verdin Development Board,連接調試串口(載板X66)到開發(fā)主機方便調試,X66 連接了4個串口,其中第三個是 Cortex-M4 核心的默認調試串口,第四個是 Cortex-A53 核心的默認調試串口。
b). 為了測試 GPT 輸入捕獲, 相應的需要一個PWM 波發(fā)生設備,這里使用Toradex 基于NXP i.MX8M Plus ARM處理器的Verdin i.MX8MP 核心板配合 Dahlia Board 作為PWM output使用。同樣連接調試串口(載板X18)到開發(fā)主機方便調試。
c). Verdin i.MX8MP Cortex-A53 核心系統(tǒng)使用Toradex Yocto Linux BSP6, 更多說明請參考這里。
d). 參考如下將 Verdin i.MX8MP PWM1 連接到 Verdin i.MX8MM GPT1 Capture 管腳,同時為了阻斷載板其他電路干擾,將 Verdin Development Board X6 Pin_24 的跳線帽去掉。
Dahlia Board X20 Pin_9 -> Verdin Development Board X5Pin_24 SODIMM_252
3). Verdin i.MX8MM M4核心FreeRTOS基本資料
a). Verdin i.MX8MM HMP(Heterogeneous Multi-core Processing) 架構基本說明請參考如下:
https://developer.toradex.cn/software/cortex-m/hmp-memory-areas-on-toradex-soms/
b). 參考如下說明下載配置 NXP 用于開發(fā) Cortex-M 核心的 MCUXpresso SDK
https://developer.toradex.cn/software/cortex-m/setting-up-sdk-toolchain/
c). Verdin i.MX8MM 編譯運行 M4 firmware 操作流程請參考如下文章
https://developer.toradex.cn/software/real-time/freertos/freertos-on-the-cortex-m4-of-a-verdin-imx8mm
d). MCUXpresso SDK 包含的 sample 示例應用可以參考如下 SDK 源位置
-----------------------------
$cd
$ tree -L 2
.
├── cmsis_driver_examples
│ ├── ecspi
│ ├── enet
│ ├── i2c
│ └── uart
├── demo_apps
│ ├── hello_world
│ └── sai_low_power_audio
├── driver_examples
│ ├── ecspi
│ ├── enet
│ ├── gpio
│ ├── gpt
│ ├── i2c
│ ├── pdm
│ ├── pwm
│ ├── rdc
│ ├── sai
│ ├── sdma
│ ├── sema4
│ ├── tmu
│ ├── uart
│ └── wdog
├── evkmimx8mm.png
├── freertos_examples
│ ├── freertos_event
│ ├── freertos_generic
│ ├── freertos_hello
│ ├── freertos_mutex
│ ├── freertos_queue
│ ├── freertos_sem
│ ├── freertos_swtimer
│ └── freertos_tickless
├── multicore_examples
│ ├── rpmsg_lite_pingpong_rtos
│ └── rpmsg_lite_str_echo_rtos
└── project_template
├── board.c
├── board.h
├── BOARD_Project_Template_evkmimx8mm.cmake
├── clock_config.c
├── clock_config.h
├── peripherals.c
├── peripherals.h
├── pin_mux.c
└── pin_mux.h
-----------------------------
4). Verdin i.MX8MM Cortex-M4核心FreeRTOS GPT Capture示例驅動開發(fā)
a). Verdin i.MX8MM MCUXpresso SDK 已經(jīng)包含一個簡單的 GPT Capture sample驅動,本文基于此 sample 進行修改測試。
-----------------------------
$cd
$ tree -L 1
.
├── armgcc
├── board.c
├── board.h
├── clock_config.c
├── clock_config.h
├── empty_rsc_table.c
├── fsl_iomuxc.h
├── gpt_capture.c
├── gpt_capture_v3_14.xml
├── pin_mux.c
├── pin_mux.h
└── readme.md
-----------------------------
b). 首先先確認 pin_mux 定義以及其他 i.MX8MM 初始化基本配置,如果需要可以進行修改
./ pin_mux.h/pin_mux.c 用于確定項目中使用的管腳定義,本文中使用的正好就是示例默認的 GPT1 Capture1 管腳,因此無需修改。如果用到其他管腳,就需要進行修改,支持的所有管腳定義可以參考 fsl_iomuxc.h 文件。
-----------------------------
/* FUNCTION ************************************************************************************************************
*
* Function Name : BOARD_InitPins
* Description : Configures pin routing and optionally pin electrical features.
*
* END ****************************************************************************************************************/
void BOARD_InitPins(void) { /*!< Function assigned for the core: Cortex-M4[m4] */
IOMUXC_SetPinMux(IOMUXC_SAI3_RXFS_GPT1_CAPTURE1, 0U);
IOMUXC_SetPinMux(IOMUXC_UART4_RXD_UART4_RX, 0U);
...
-----------------------------
./ board.h/board.c 用于 i.MX8MM M4 核心基本初始化配置,本文不做修改。
./ clock_config.h/clock_config.c 用于 i.MX8MM M4 核心基本時鐘配置,本文不做修改。
c). GPT Capture 功能實現(xiàn)
./ 本文 GPT Capture 功能定義
GPT1 capture1 管腳輸入一個給定頻率(如 1k Hz )和占空比(如 50% ) 的PWM 信號,通過捕獲輸入上升/下降沿中斷,分別獲得相鄰兩次中斷的 GPT Counter 計數(shù)器的計數(shù),并以此來計算輸入 PWM 信號的半波周期。
./ GPT Capture 功能基本都是通過 gpt_capture.c 文件代碼來實現(xiàn),默認 sample 是捕獲上升沿中斷后,打印中斷當時的 GPT Counter 計數(shù)數(shù)值。
./ 為了實現(xiàn)本文定義的捕獲功能,首先增加如下全局變量定義
-----------------------------
/*******************************************************************************
* Variables
******************************************************************************/
volatile bool gptIsrFlag_Start = false;
volatile bool gptIsrFlag_Finish = false;
volatile bool gptIsrFlag_Overflow = false;
volatile uint32_t captureVal = 0;
volatile uint32_t captureVal_Last = 0;
-----------------------------
// gptIsrFlag_Start 定義為第一次捕獲中斷開始標志
// gptIsrFlag_Finish 定義為第二次捕獲中斷結束標志
// gptIsrFlag_Overflow 定義為 GPT Counter 溢出標志
// captureVal 定義為第二次中斷 GPT Counter 數(shù)值
// captureVal_Last 定義為第一次中斷 GPT Counter 數(shù)值
./ GPT Interrupt 函數(shù)修改如下:
首先處理計數(shù)器溢出情況,如果中斷發(fā)生時候已經(jīng)發(fā)生溢出,則聲明 gptIsrFlag_Overflow 溢出標志位;然后通過 gptIsrFlag_Start / gptIsrFlag_Finish 標志位來分別處理第一次和第二次中斷,獲取第一次和第二次中斷時候的 GPT Counter 數(shù)值,同時分別翻轉 GPT Capture Interrupt 模式。另外,當溢出發(fā)生在第一次中斷計數(shù)和第二次中斷計數(shù)之間的時候,需要將第二次中斷計數(shù)數(shù)值增加溢出值 0xffffffff。
-----------------------------
void EXAMPLE_GPT_CAPTURE_IRQHandler(void)
{
/* GPT Counter Overflow processing */
if (GPT_GetStatusFlags(DEMO_GPT_BASE, kGPT_RollOverFlag) != false)
{
if (gptIsrFlag_Start != true)
{
gptIsrFlag_Overflow = true;
}
GPT_ClearStatusFlags(DEMO_GPT_BASE, kGPT_RollOverFlag);
}
if (GPT_GetStatusFlags(DEMO_GPT_BASE, kGPT_InputCapture1Flag) != false)
{
if(gptIsrFlag_Finish != true)
{
/* First time IRQ */
if (gptIsrFlag_Start == false)
{
captureVal_Last = GPT_GetInputCaptureValue(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL);
/* Switch Interrupt mode to falling edge */
GPT_SetInputOperationMode(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL, kGPT_InputOperation_FallEdge);
gptIsrFlag_Start = true;
}
/* Second time IRQ */
/* GPT counter overflow */
else if (gptIsrFlag_Overflow == true)
{
captureVal = GPT_GetInputCaptureValue(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL) + 0xffffffff;
/* Switch Interrupt mode to rising edge */
GPT_SetInputOperationMode(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL, kGPT_InputOperation_RiseEdge);
gptIsrFlag_Start = false;
gptIsrFlag_Finish = true;
}
else
{
captureVal = GPT_GetInputCaptureValue(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL);
/* Switch Interrupt mode to rising edge */
GPT_SetInputOperationMode(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL, kGPT_InputOperation_RiseEdge);
gptIsrFlag_Start = false;
gptIsrFlag_Finish = true;
}
}
GPT_ClearStatusFlags(DEMO_GPT_BASE, BOARD_GPT_CHANNEL_FLAG);
}
SDK_ISR_EXIT_BARRIER;
}
-----------------------------
./ Main 主函數(shù)修改如下:
-----------------------------
int main(void)
{
gpt_config_t gptConfig;
...
GPT_GetDefaultConfig(&gptConfig);
/* Initialize GPT module */
GPT_Init(DEMO_GPT_BASE, &gptConfig);
...
/* Setup input capture on a gpt channel */
GPT_SetInputOperationMode(DEMO_GPT_BASE, BOARD_GPT_INPUT_CAPTURE_CHANNEL, kGPT_InputOperation_RiseEdge);
...
/* Enable GPT Overflow interrupt */
GPT_EnableInterrupts(DEMO_GPT_BASE, kGPT_RollOverFlagInterruptEnable);
...
while (true)
{
/* Check whether occur 2nd interupt */
if (true == gptIsrFlag_Finish)
{
PRINTF("\r\n Input Capture Half Period Value =%u us\r\n", (captureVal - captureVal_Last)/24);
gptIsrFlag_Finish = false;
}
else
{
__WFI();
}
}
}
-----------------------------
// 通過 GPT_GetDefaultConfig 函數(shù)獲取默認的 GPT Capture 配置,參考 docs 目錄下的 MCUXpresso SDK API Reference Manual_MIMX8MM6.pdf 文檔,可以查到默認配置如下,如果需要也可以修改這個配置
-----------------------------
config->clockSource = kGPT_ClockSource_Periph;
config->divider = 1U;
config->enableRunInStop = true;
config->enableRunInWait = true;
config->enableRunInDoze = false;
config->enableRunInDbg = false;
config->enableFreeRun = false;
config->enableMode = true;
-----------------------------
// 通過 GPT_SetInputOperationMode 函數(shù)將 GPT Capture 模式初始配置為上升沿觸發(fā)
// 為了處理 GPT Counter Overflow,使能對應中斷
// while 函數(shù)循環(huán)執(zhí)行當 gptIsrFlag_Finish 第二次中斷采集結束標志位聲明后,打印捕獲的輸入 PWM 波的半波周期。這里需要說明下,由于 NXP iMX8MM SoC 也受到如下 Errata 影響,因此 GPT Clock Source 只能使用內部 24M Hz 時鐘源,所以這里 printf 函數(shù)直接使用 24M 來算出半波周期是多少 us 。
https://www.nxp.com.cn/docs/en/errata/IMX8X_C0_0N99Z_ER.pdf
5). Verdin i.MX8MM Cortex-M4核心FreeRTOS GPT Capture示例部署測試
a). 將上述修改后的項目參考章節(jié) 3 的相關資料編譯后,復制 gpt_capture.bin 可執(zhí)行文件到 Verdin i.MX8MM 核心板 Linux /home/root 目錄下保存。
b). 對Verdin i.MX8MM 模塊進入 U-boot 命令行,通過如下命令配置 Cortex-M4 核心 Firmware 下載和運行
-----------------------------
# setenv load_cmd "ext4load mmc 0:2"
# setenv m4image "/home/root/gpt_capture.bin"
> setenv m4image_size 17000
> setenv loadm4image "${load_cmd} ${loadaddr} ${m4image}"
> setenv m4boot "${loadm4image}; cp.b ${loadaddr} 0x7e0000 ${m4image_size}; dcache flush; bootaux 0x7e0000"
> saveenv
> run m4boot
-----------------------------
c). Verdin i.MX8MM Cortex-M4 核心運行后其調試串口打印信息
-----------------------------
GPT input capture example
Once the input signal is received the input capture half peroid is printed
-----------------------------
d). 此時在 Verdin i.MX8MP 平臺通過如下腳本使能 1kHz 50% 占空比 PWM 輸出 10s 時間
-----------------------------
#!/bin/sh
cd /sys/class/pwm/pwmchip0/
echo 0 > export
echo 1000000 > pwm0/period
echo 500000 > pwm0/duty_cycle
echo "normal" > pwm0/polarity
echo 1 > pwm0/enable
sleep 10
echo 0 > pwm0/enable
-----------------------------
e). 這時 Verdin i.MX8MM Cortex-M4 調試串口就會打印出對應的半波周期
-----------------------------
...
Input Capture Half Period Value =500 us
Input Capture Half Period Value =499 us
Input Capture Half Period Value =499 us
Input Capture Half Period Value =499 us
...
-----------------------------
f). 嘗試將 Verdin i.MX8MP PWM 修改為 10kHz 80%/20% 占空比
-----------------------------
...
echo 100000 > pwm0/period
echo 80000 > pwm0/duty_cycle
...
-----------------------------
g). Verdin i.MX8MM Cortex-M4 輸出周期會對應變化
-----------------------------
Input Capture Half Period Value =80 us
Input Capture Half Period Value =80 us
Input Capture Half Period Value =80 us
Input Capture Half Period Value =80 us
-----------------------------
h). 最后,由于 Verdin i.MX8MM GPT1 CAPTURE1 管腳在 Cortex-A53 核心 Linux 下默認是用于 WAKEUP GPIO 使用,如果需要同時運行 Verdin i.MX8MM Cortex-A53 核心和 Cortex-M4 核心,就需要在 Linux device-tree 文件中將 WAKEUP gpio-key 功能替換為其他 GPIO 管腳資源。
https://git.toradex.cn/cgit/linux-toradex.git/tree/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi?h=toradex_5.15-2.2.x-imx#n40
6). 總結
本文簡單示例了基于i.MX8MM Cortex-M4 核心 GPT Capture 功能供參考。
提交
Verdin AM62 LVGL 移植
基于 NXP iMX8MM 測試 Secure Boot 功能
隆重推出 Aquila - 新一代 Toradex 計算機模塊
Verdin iMX8MP 調試串口更改
嵌入式Linux下使用 Plymouth 實現(xiàn)開機畫面示例