档案信息网站开发利用,少儿编程培训机构排名前十,百度网址大全首页设为首页,875网站建设怎么样By Toradex秦海
1). 简介
NXP i.MX8 系列处理器均为异构多核架构 SoC#xff0c;除了可以运行 Linux 等复杂操作系统的 Cortax-A 核心#xff0c;还包含了可以运行实时操作系统比如 FreeRTOS 的 Cortex-M 核心#xff0c;本文就演示通过 NXP i.MX8MM 处理器集成的 Cortex-…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.MX8MM ARM核心版配合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 管脚资源。
imx8mm-verdin.dtsi « freescale « dts « boot « arm64 « arch - linux-toradex.git - Linux kernel for Apalis and Colibri modules 6). 总结
本文简单示例了基于i.MX8MM Cortex-M4 核心 GPT Capture 功能供参考。