NXP iMX8MM Cortex-M4 核心 GPT Capture 测试

By Toradex秦海

1). 简介

NXP i.MX8 系列处理器均为异构多核架构 SoC,除了可以运行 Linux 等复杂操作系统的 Cortax-A 核心,还包含了可以运行实时操作系统比如 FreeRTOS 的 Cortex-M 核心,本文就演示通过 NXP i.MX8MM 处理器集成的 Cortex-M4 核心来运行 GPT (General Purpose Timer) 输入采集功能模块的测试。


I.MX8M Mini 处理器 GPT 模块硬件比较简单,如下框图,可以实现 Capture 捕获输入功能和 Compare 定时输出功能。



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



2. 准备

a). Verdin i.MX8MMARM核心版配合Verdin Development Board,连接调试串口(载板X66)到开发主机方便调试,X66 连接了4个串口,其中第三个是 Cortex-M4 核心的默认调试串口,第四个是 Cortex-A53 核心的默认调试串口。


b). 为了测试 GPT 输入捕获, 相应的需要一个PWM 波发生设备,这里使用Toradex 基于NXP i.MX8M Plus ARM处理器的Verdin i.MX8MP核心板配合Dahlia Board作为PWM output使用。同样连接调试串口(载板X18)到开发主机方便调试。


c). Verdin i.MX8MP Cortex-A53 核心系统使用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 用于开发 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 <SDK_root>/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示例驱动开发

a). Verdin i.MX8MM MCUXpresso SDK 已经包含一个简单的 GPT Capture sample驱动,本文基于此sample 进行修改测试。

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

$cd <SDK_root>/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 功能实现

./ 本文 GPT Capture 功能定义

GPT1 capture1 管脚输入一个给定频率(如 1k Hz )和占空比(如  50% ) 的PWM 信号,通过捕获输入上升/下降沿中断,分别获得相邻两次中断的 GPT Counter 计数器的计数,并以此来计算输入 PWM 信号的半波周期。


./ GPT Capture 功能基本都是通过 gpt_capture.c 文件代码来实现,默认 sample 是捕获上升沿中断后,打印中断当时的 GPT Counter 计数数值。


./ 为了实现本文定义的捕获功能,首先增加如下全局变量定义

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

/*******************************************************************************

* Variables

******************************************************************************/

volatile bool gptIsrFlag_Start = false;

volatile bool gptIsrFlag_Finish = false;

volatile uint8_t gptIsrFlag_Overflow = 0;

volatile uint32_t captureVal = 0;

volatile uint32_t captureVal_Last = 0;

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


// gptIsrFlag_Start 定义为第一次捕获中断开始标志

// gptIsrFlag_Finish 定义为第二次捕获中断结束标志

// gptIsrFlag_Overflow 定义为 GPT Counter 溢出标志计数

// captureVal 定义为第二次中断 GPT Counter 数值

// captureVal_Last 定义为第一次中断 GPT Counter 数值


./ GPT Interrupt 函数修改如下:

首先处理计数器溢出情况,如果中断发生时候已经发生溢出,则增加gptIsrFlag_Overflow 溢出标志计数的数值;然后通过 gptIsrFlag_Start / gptIsrFlag_Finish 标志位来分别处理第一次和第二次中断,获取第一次和第二次中断时候的 GPT Counter 数值,同时分别翻转 GPT Capture Interrupt 模式。

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

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 ++;

}

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 */

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 主函数修改如下:

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

int main(void)

{

    uint64_t int_Peroid = 0;

        uint32_t time_Ms = 0;

        uint32_t time_Us = 0;

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)

        {

            /* GPT counter diff value between 2 IRQs */

            int_Peroid = gptIsrFlag_Overflow * (uint64_t) 0xffffffff;

            int_Peroid = int_Peroid + captureVal;

            int_Peroid = int_Peroid - captureVal_Last;

            /* transfer counter value to peroid */

            time_Us = (uint32_t) ((int_Peroid / 24) % 1000);

            time_Ms = (uint32_t) ((int_Peroid / 24) / 1000);

            PRINTF("\r\n interval between 2 rising edge =%u ms and %u us\r\n", time_Ms, time_Us);

            gptIsrFlag_Overflow = 0;

            gptIsrFlag_Finish = false;

        }

        else

        {

            __WFI();

        }

    }

}

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


// 通过 GPT_GetDefaultConfig函数获取默认的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函数将GPT Capture 模式初始配置为上升沿触发

// 为了处理 GPT Counter Overflow,使能对应中断

// while 函数循环执行当  gptIsrFlag_Finish第二次中断采集结束标志位声明后,打印捕获的输入PWM 波的半波周期。如果有溢出发生,则需要考虑增加相应的 0xffffffff 溢出计数次数。这里需要说明下,由于 NXP iMX8MM SoC 也受到如下 Errata 影响,因此 GPT Clock Source 只能使用内部 24M Hz 时钟源,所以这里直接使用 24M 来算出半波周期是多少 ms 和 us 。

https://www.nxp.com.cn/docs/en/errata/IMX8X_C0_0N99Z_ER.pdf 



5).Verdin i.MX8MM Cortex-M4核心FreeRTOS GPT Capture示例部署测试

a). 将上述修改后的项目参考章节3 的相关资料编译后,复制 gpt_capture.bin 可执行文件到 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 = 0ms and 500us


Input Capture Half Period Value = 0ms and 500us


Input Capture Half Period Value = 0ms and 500us


Input Capture Half Period Value = 0ms and 500us

...

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


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 = 0ms and 80us


Input Capture Half Period Value = 0ms and 80us


Input Capture Half Period Value = 0ms and 80us


Input Capture Half Period Value = 0ms and 80us

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


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 功能供参考。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容