NXP iMX8MM Cortex-M4 核心 GPT Capture 測(cè)試
1). 簡(jiǎn)介
NXP i.MX8 系列處理器均為異構(gòu)多核架構(gòu) SoC,除了可以運(yùn)行 Linux 等復(fù)雜操作系統(tǒng)的 Cortax-A 核心,還包含了可以運(yùn)行實(shí)時(shí)操作系統(tǒng)比如 FreeRTOS 的 Cortex-M 核心,本文就演示通過 NXP i.MX8MM 處理器集成的 Cortex-M4 核心來(lái)運(yùn)行 GPT (General Purpose Timer) 輸入采集功能模塊的測(cè)試。
I.MX8M Mini 處理器 GPT 模塊硬件比較簡(jiǎn)單,如下框圖,可以實(shí)現(xiàn) Capture 捕獲輸入功能和 Compare 定時(shí)輸出功能。
本文所演示的ARM平臺(tái)來(lái)自于Toradex 基于NXP i.MX8M Mini ARM處理器的Verdin iMX8MM ARM嵌入式平臺(tái)。
2. 準(zhǔn)備
a). Verdin i.MX8MM ARM核心版配合Verdin Development Board,連接調(diào)試串口(載板X66)到開發(fā)主機(jī)方便調(diào)試,X66 連接了4個(gè)串口,其中第三個(gè)是 Cortex-M4 核心的默認(rèn)調(diào)試串口,第四個(gè)是 Cortex-A53 核心的默認(rèn)調(diào)試串口。
b). 為了測(cè)試 GPT 輸入捕獲, 相應(yīng)的需要一個(gè)PWM 波發(fā)生設(shè)備,這里使用Toradex 基于NXP i.MX8M Plus ARM處理器的Verdin i.MX8MP 核心板配合 Dahlia Board 作為PWM output使用。同樣連接調(diào)試串口(載板X18)到開發(fā)主機(jī)方便調(diào)試。
c). Verdin i.MX8MP Cortex-A53 核心系統(tǒng)使用Toradex Yocto Linux BSP6, 更多說明請(qǐng)參考這里。
d). 參考如下將 Verdin i.MX8MP PWM1 連接到 Verdin i.MX8MM GPT1 Capture 管腳,同時(shí)為了阻斷載板其他電路干擾,將 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) 架構(gòu)基本說明請(qǐng)參考如下:
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 編譯運(yùn)行 M4 firmware 操作流程請(qǐng)參考如下文章
https://developer.toradex.cn/software/real-time/freertos/freertos-on-the-cortex-m4-of-a-verdin-imx8mm
d). MCUXpresso SDK 包含的 sample 示例應(yīng)用可以參考如下 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示例驅(qū)動(dòng)開發(fā)
a). Verdin i.MX8MM MCUXpresso SDK 已經(jīng)包含一個(gè)簡(jiǎn)單的 GPT Capture sample驅(qū)動(dòng),本文基于此 sample 進(jìn)行修改測(cè)試。
-----------------------------
$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). 首先先確認(rèn) pin_mux 定義以及其他 i.MX8MM 初始化基本配置,如果需要可以進(jìn)行修改
./ pin_mux.h/pin_mux.c 用于確定項(xiàng)目中使用的管腳定義,本文中使用的正好就是示例默認(rèn)的 GPT1 Capture1 管腳,因此無(wú)需修改。如果用到其他管腳,就需要進(jìn)行修改,支持的所有管腳定義可以參考 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 核心基本時(shí)鐘配置,本文不做修改。
c). GPT Capture 功能實(shí)現(xiàn)
./ 本文 GPT Capture 功能定義
GPT1 capture1 管腳輸入一個(gè)給定頻率(如 1k Hz )和占空比(如 50% ) 的PWM 信號(hào),通過捕獲輸入上升/下降沿中斷,分別獲得相鄰兩次中斷的 GPT Counter 計(jì)數(shù)器的計(jì)數(shù),并以此來(lái)計(jì)算輸入 PWM 信號(hào)的半波周期。
./ GPT Capture 功能基本都是通過 gpt_capture.c 文件代碼來(lái)實(shí)現(xiàn),默認(rèn) sample 是捕獲上升沿中斷后,打印中斷當(dāng)時(shí)的 GPT Counter 計(jì)數(shù)數(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 定義為第一次捕獲中斷開始標(biāo)志
// gptIsrFlag_Finish 定義為第二次捕獲中斷結(jié)束標(biāo)志
// gptIsrFlag_Overflow 定義為 GPT Counter 溢出標(biāo)志
// captureVal 定義為第二次中斷 GPT Counter 數(shù)值
// captureVal_Last 定義為第一次中斷 GPT Counter 數(shù)值
./ GPT Interrupt 函數(shù)修改如下:
首先處理計(jì)數(shù)器溢出情況,如果中斷發(fā)生時(shí)候已經(jīng)發(fā)生溢出,則聲明 gptIsrFlag_Overflow 溢出標(biāo)志位;然后通過 gptIsrFlag_Start / gptIsrFlag_Finish 標(biāo)志位來(lái)分別處理第一次和第二次中斷,獲取第一次和第二次中斷時(shí)候的 GPT Counter 數(shù)值,同時(shí)分別翻轉(zhuǎn) GPT Capture Interrupt 模式。另外,當(dāng)溢出發(fā)生在第一次中斷計(jì)數(shù)和第二次中斷計(jì)數(shù)之間的時(shí)候,需要將第二次中斷計(jì)數(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ù)獲取默認(rèn)的 GPT Capture 配置,參考 docs 目錄下的 MCUXpresso SDK API Reference Manual_MIMX8MM6.pdf 文檔,可以查到默認(rèn)配置如下,如果需要也可以修改這個(gè)配置
-----------------------------
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,使能對(duì)應(yīng)中斷
// while 函數(shù)循環(huán)執(zhí)行當(dāng) gptIsrFlag_Finish 第二次中斷采集結(jié)束標(biāo)志位聲明后,打印捕獲的輸入 PWM 波的半波周期。這里需要說明下,由于 NXP iMX8MM SoC 也受到如下 Errata 影響,因此 GPT Clock Source 只能使用內(nèi)部 24M Hz 時(shí)鐘源,所以這里 printf 函數(shù)直接使用 24M 來(lái)算出半波周期是多少 us 。
https://www.nxp.com.cn/docs/en/errata/IMX8X_C0_0N99Z_ER.pdf
5). Verdin i.MX8MM Cortex-M4核心FreeRTOS GPT Capture示例部署測(cè)試
a). 將上述修改后的項(xiàng)目參考章節(jié) 3 的相關(guān)資料編譯后,復(fù)制 gpt_capture.bin 可執(zhí)行文件到 Verdin i.MX8MM 核心板 Linux /home/root 目錄下保存。
b). 對(duì)Verdin i.MX8MM 模塊進(jìn)入 U-boot 命令行,通過如下命令配置 Cortex-M4 核心 Firmware 下載和運(yùn)行
-----------------------------
# 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 核心運(yùn)行后其調(diào)試串口打印信息
-----------------------------
GPT input capture example
Once the input signal is received the input capture half peroid is printed
-----------------------------
d). 此時(shí)在 Verdin i.MX8MP 平臺(tái)通過如下腳本使能 1kHz 50% 占空比 PWM 輸出 10s 時(shí)間
-----------------------------
#!/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). 這時(shí) Verdin i.MX8MM Cortex-M4 調(diào)試串口就會(huì)打印出對(duì)應(yīng)的半波周期
-----------------------------
...
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 輸出周期會(huì)對(duì)應(yīng)變化
-----------------------------
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 下默認(rèn)是用于 WAKEUP GPIO 使用,如果需要同時(shí)運(yùn)行 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). 總結(jié)
本文簡(jiǎn)單示例了基于i.MX8MM Cortex-M4 核心 GPT Capture 功能供參考。
提交
Verdin AM62 LVGL 移植
基于 NXP iMX8MM 測(cè)試 Secure Boot 功能
隆重推出 Aquila - 新一代 Toradex 計(jì)算機(jī)模塊
Verdin iMX8MP 調(diào)試串口更改
嵌入式Linux下使用 Plymouth 實(shí)現(xiàn)開機(jī)畫面示例