工控網(wǎng)首頁
>

應用設計

>

NXP iMX8MM Cortex-M4 核心 GPT Capture 測試

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 定時輸出功能。

 

NXP iMX8MM Cortex-M4 核心 GPT Capture 測試_web333.png 

本文所演示的ARM平臺來自于Toradex 基于NXP i.MX8M Mini ARM處理器的Verdin iMX8MM ARM嵌入式平臺。

 

 

2. 準備

a). Verdin i.MX8MM ARM核心版配合Verdin Development Board,連接調(diào)試串口(載板X66)到開發(fā)主機方便調(diào)試,X66 連接了4個串口,其中第三個是 Cortex-M4 核心的默認調(diào)試串口,第四個是 Cortex-A53 核心的默認調(diào)試串口。

 

b). 為了測試 GPT 輸入捕獲, 相應的需要一個PWM 波發(fā)生設備,這里使用Toradex 基于NXP i.MX8M Plus ARM處理器的Verdin i.MX8MP 核心板配合 Dahlia Board 作為PWM output使用。同樣連接調(diào)試串口(載板X18)到開發(fā)主機方便調(diào)試。

 

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/boards/evkmimx8mm/

$ 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ū)動開發(fā)

a). Verdin i.MX8MM MCUXpresso SDK 已經(jīng)包含一個簡單的 GPT Capture sample驅(qū)動,本文基于此 sample 進行修改測試。

-----------------------------

$cd/boards/evkmimx8mm/driver_examples/gpt/capture

$ 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ù)值,同時分別翻轉(zhuǎn) 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 只能使用內(nèi)部 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é) 的相關資料編譯后,復制 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 核心運行后其調(diào)試串口打印信息

-----------------------------

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 調(diào)試串口就會打印出對應的半波周期

-----------------------------

...

 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-M核心 GPT Capture 功能供參考。

審核編輯(
王靜
)
投訴建議

提交

查看更多評論
其他資訊

查看更多

Verdin AM62 LVGL 移植

基于 NXP iMX8MM 測試 Secure Boot 功能

隆重推出 Aquila - 新一代 Toradex 計算機模塊

Verdin iMX8MP 調(diào)試串口更改

嵌入式Linux下使用 Plymouth 實現(xiàn)開機畫面示例