本文介绍了恩智浦 FRDM-MCXA156 开发板的相关软硬件资料、开发环境搭建流程、工程编译、上传与测试流程等。
1.介绍主控
MCXA156 系统框图
特征主要特点
® Arm Cortex-M33® 96MHz,带 396 CoreMark (4.12 CoreMark/MHz)
高达 1MB 的闪存、高达 128KB 的 SRAM、带 ECC 的 8 kB SRAM
所有 RAM 都可以保留到深度掉电模式
温度范围:-40 °C 至 125 °C
Arm 32 位 Cortex-M33 CPU,带 FPU 和 DSP 扩展指令 set、no TrustZone、no MPU
单区闪存:高达 1024 kB 的闪存,带 ECC(支持 1 位) 校正和两位检测)
Flash 的最小编程大小为 16 字节
支持 8 kB 粒度的 Flash Swap
具有 4 kB RAM 的缓存引擎
高达 128 kB 的 RAM,可通过 ECC 配置高达 8 kB(支持 单位校正、两位检测)
所有 RAM 都可以保留到深度 Power-down 模式
模拟
最多两个采样率为 4.0 的单端 16 位 ADC 12 位模式下的 Msamples/s,16 位模式下的 3.2Msamples/sec。 多达 32 个 ADC 输入通道,具有多个内部和外部通道 触发输入
每个 ADC 一个集成温度传感器
一个 12 位 DAC
两个高速比较器,具有 8 个输入引脚和一个 8 位 DAC 作为 内部参考,一个比较器功能低至 省电模式,可用作低功耗的唤醒源 模式
一个运算放大器支持 PGA
定时器
多达 5 个 32 位标准通用异步 定时器/计数器,每个定时器最多支持四个捕获输入和 4 个 compare 输出;可以选择特定的计时器事件 生成 DMA 请求
低功耗定时器
频率测量定时器
窗口式看门狗定时器
唤醒定时器
从 1 MHz 时钟运行的 Microtick 计时器 (UTICK)。这可以从 低功耗模式直至关闭闪光灯的深度睡眠,功耗极低
42 位自由运行的操作系统定时器作为系统的连续时基,可用于任何 低功耗模式
通信接口
USB 2.0 全速器件控制器,带片上 PHY,支持无晶振操作 设备模式
多达 2 个 LPSPI 模块,在初级模式下支持高达 50MHz 的工作频率
多达四个 LPI2C,支持 Standard、Fast、Fast+ 和 Ultra Fast 模式
多达 5 个 LPUART 提供异步、串行通信功能
一个 I3C 总线接口
一个 FlexIO 可编程为各种串行和并行接口,包括但不限于 仅限于显示驱动程序和摄像头接口(取决于部件号)
一个带 FD 的 FlexCAN(取决于零件编号)
高级电机控制子系统
最多两个 FlexPWM,每个 FlexPWM 有 3 个子模块,提供 12 个 PWM 互补输出(无 Nanoedge 模块)
多达两个正交解码器 (eQDC),提供位置/速度的接口能力 工业电机控制应用中使用的传感器
最多两个 AOI(和/或/反转)模块支持最多 4 个输出触发器
MCUXpresso生态系统支持
选择 IDE 选项
引脚、时钟、外设、安全和内存配置工具
安全编程和配置工具
软件开发工具包 (SDK)
设备生命周期管理
Flash 读/写/执行权限保护 MBC 并可锁定
每个设备 128 位通用唯一标识符 (UUID) 符合 IETF 的 RFC4122 版本 5 规范
代码看门狗和抗毛刺攻击的密钥访问 (Glikey) 支持安全监控
LQFP100 (14x14 mm)
: MCX A14x/15x MCU搭载Arm® Cortex® M33内核,提供可扩展的设备选项、低功耗和智能外设
: I3C/I²C总线精确数字温度传感器,精度为±0.5 °C
: ±2g/±4g/±8g/±16g、12位低功耗数字加速度传感器
: ±2g/±4g/±8g/±16g、12位低功耗数字加速度传感器
引脚定义
特征微控制器
MCXA15x Arm Cortex-M33 内核®®
高达 128KB 的闪存,高达 32 kB 的 RAM,8kB ECC, LPLUART、LPSPI、LPI2C、FS USB、DMA 和 LDO
FS USB 端口,带 USB Type-C 连接器,用于设备功能
HS USB Type-C 连接器(板载 MCU-Link 调试器)
SPI/I²C/UART 连接器(Arduino、PMOD/mikroBUS、DNP)
Wi-Fi 连接器(Arduino、PMOD/mikroBUS、DNP)
带有 CMSIS-DAP 的板载 MCU-Link 调试器
JTAG/SWD 连接器
I3C/I²C 温度传感器
Arduino 接头®
FRDM 报头
Pmod (英语)™*DNP
米克罗巴士™
RGB 用户 LED,以及重置、ISP、唤醒按钮
供电
外设
MCU-Link
MCU-Link Debug
Arduino
开箱
开发板展示
上电
FRDM-MCXA156 开发板 LED 闪烁程序,以验证设备是否按预期工作。
将 Type-C USB 数据线连接开发板和主机(电源),以启动电路板并运行演示程序。此时,RGB LED 以稳定的节奏闪烁。
系统框图
示例工程Demo
开发板示例工程详见官方 GitHub 仓库 .
SDK 构建通过 快速构建 SDK
下载并安装 开发环境;
打开示例工程,软件会自动安装相应设备的 pack 包;
或在 Keil 官网 下载后手动安装。
安装
根据首页提示安装开发板 SDK 文件, 选择 Download and Install SDKs
MCUXpresso IDE 是基于 Eclipse 的开发环境,适用于基于Arm® Cortex®-M内核的恩智浦® MCU,包括通用、跨界和无线MCU。
MCUXpresso IDE 提供高级编辑、编译和调试功能,增加了MCU专用的调试视图、代码跟踪和分析、多核调试和集成配置工具。
MCUXpresso IDE调试连接采用来自恩智浦、P&E Micro® 和SEGGER® 优化的开源和商用硬件调试器,支持Freedom、塔式® 系统、LPCXpresso、基于i.MX RT的EVK,以及定制开发板。
打开目标工程, Rebuild 工程,点击魔术棒 - Debug - 选择 CMSIS-DAP 调试 - Setting - 读取到设备信息
点击 Download 按钮即可上传工程。
MCUXpresso 设置点击 Import SDK examples - Go straight to the Wizard... - 勾选目标 Demo 工程,即可打开示例工程;
工程文件夹右键 - 构建工程,
工程文件夹右键 - 调试方式 - 调试配置 - 双击第一个选项 C/C++ (NXP Semiconductors) MCU Application ,点击 Debug 即可
3.工程测试Blink
上传工程至开发板,Reset 运行程序。
代码#include "board.h" #include "app.h" void SysTick_Handler(void) { /* Toggle pin connected to LED */ GPIO_PortToggle(BOARD_LED_GPIO, 1u << BOARD_LED_GPIO_PIN); } int main(void) { /* Board pin init */ BOARD_InitHardware(); while (1) { } }效果
串口打印
上传工程至开发板,配置串口参数并连接串口通信助手软件,Reset 运行程序。
代码#include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "board.h" #include "app.h" int main(void) { char ch; /* Init board hardware. */ BOARD_InitHardware(); PRINTF("hello world.\r\n"); while (1) { ch = GETCHAR(); PUTCHAR(ch); } }串口配置
波特率 115200
数据位 8
校验位 None
停止位1
流控制 None
电源模式切换
上传工程至开发板,配置串口参数并连接串口通信助手软件,Reset 运行程序。
运行工程时,调试控制台显示命令MCU进入目标电源模式的菜单。
短按复位按钮可从深度掉电模式唤醒,并串口打印【Normal Boot】。
代码#include "fsl_cmc.h" #include "fsl_spc.h" #include "fsl_clock.h" #include "fsl_debug_console.h" #include "power_mode_switch.h" #include "app.h" #include "board.h" #include "fsl_lpuart.h" #include "fsl_waketimer.h" #include "fsl_wuu.h" #include "fsl_gpio.h" static void APP_SetSPCConfiguration(void); static void APP_SetVBATConfiguration(void); static void APP_SetCMCConfiguration(void); static void APP_InitWaketimer(void); static app_wakeup_source_t APP_SelectWakeupSource(void); static uint8_t APP_GetWakeupTimeout(void); static void APP_GetWakeupConfig(app_power_mode_t targetMode); static void APP_PowerPreSwitchHook(void); static void APP_PowerPostSwitchHook(void); static void APP_EnterSleepMode(void); static void APP_EnterDeepSleepMode(void); static void APP_EnterPowerDownMode(void); static void APP_EnterDeepPowerDownMode(void); static void APP_PowerModeSwitch(app_power_mode_t targetPowerMode); static app_power_mode_t APP_GetTargetPowerMode(void); /******************************************************************************* * Variables ******************************************************************************/ char *const g_modeNameArray[] = APP_POWER_MODE_NAME; char *const g_modeDescArray[] = APP_POWER_MODE_DESC; /******************************************************************************* * Code ******************************************************************************/ int main(void) { uint32_t freq; app_power_mode_t targetPowerMode; bool needSetWakeup = false; BOARD_InitHardware(); APP_SetVBATConfiguration(); APP_SetSPCConfiguration(); APP_InitWaketimer(); #if !(defined(APP_NOT_SUPPORT_WAKEUP_BUTTON) && APP_NOT_SUPPORT_WAKEUP_BUTTON) EnableIRQ(APP_WUU_IRQN); #endif /* APP_NOT_SUPPORT_WAKEUP_BUTTON */ EnableIRQ(APP_WAKETIMER_IRQN); PRINTF("\r\nNormal Boot.\r\n"); while (1) { if ((SPC_GetRequestedLowPowerMode(APP_SPC) & (kSPC_PowerDownWithSysClockOff | kSPC_DeepPowerDownWithSysClockOff)) != 0UL) { SPC_ClearPeriphIOIsolationFlag(APP_SPC); } /* Clear CORE domain's low power request flag. */ SPC_ClearPowerDomainLowPowerRequestFlag(APP_SPC, APP_SPC_MAIN_POWER_DOMAIN); SPC_ClearLowPowerRequest(APP_SPC); /* Normal start. */ APP_SetCMCConfiguration(); freq = CLOCK_GetFreq(kCLOCK_CoreSysClk); PRINTF("\r\n########################### Power Mode Switch Demo ###########################\r\n"); PRINTF(" Core Clock = %dHz \r\n", freq); PRINTF(" Power mode: Active\r\n"); targetPowerMode = APP_GetTargetPowerMode(); if ((targetPowerMode > kAPP_PowerModeMin) && (targetPowerMode < kAPP_PowerModeMax)) { /* If target mode is Active mode, don't need to set wakeup source. */ if (targetPowerMode == kAPP_PowerModeActive) { needSetWakeup = false; } else { needSetWakeup = true; } } /* Print description of selected power mode. */ PRINTF("\r\n"); if (needSetWakeup) { APP_GetWakeupConfig(targetPowerMode); APP_PowerPreSwitchHook(); APP_PowerModeSwitch(targetPowerMode); APP_PowerPostSwitchHook(); } PRINTF("\r\nNext loop.\r\n"); } } static void APP_InitWaketimer(void) { waketimer_config_t waketimer_config; WAKETIMER_GetDefaultConfig(&waketimer_config); WAKETIMER_Init(WAKETIMER0, &waketimer_config); } static void APP_SetSPCConfiguration(void) { status_t status; spc_active_mode_regulators_config_t activeModeRegulatorOption; SPC_EnableSRAMLdo(APP_SPC, true); /* Disable analog modules that controlled by SPC in active mode. */ SPC_DisableActiveModeAnalogModules(APP_SPC, (kSPC_controlUsb3vDet | kSPC_controlCmp0 | kSPC_controlCmp1 | kSPC_controlCmp0Dac | kSPC_controlCmp1Dac)); /* Disable LVDs and HVDs in active mode first. */ SPC_EnableActiveModeCoreLowVoltageDetect(APP_SPC, false); SPC_EnableActiveModeSystemHighVoltageDetect(APP_SPC, false); SPC_EnableActiveModeSystemLowVoltageDetect(APP_SPC, false); while (SPC_GetBusyStatusFlag(APP_SPC)) ; activeModeRegulatorOption.bandgapMode = kSPC_BandgapEnabledBufferDisabled; /* DCDC output voltage mid voltage in active mode. */ activeModeRegulatorOption.CoreLDOOption.CoreLDOVoltage = APP_ACTIVE_CFG_LDO_VOLTAGE_LEVEL; activeModeRegulatorOption.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength; status = SPC_SetActiveModeRegulatorsConfig(APP_SPC, &activeModeRegulatorOption); #if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) /* Disable Vdd Core Glitch detector in active mode. */ SPC_DisableActiveModeVddCoreGlitchDetect(APP_SPC, true); #endif if (status != kStatus_Success) { PRINTF("Fail to set regulators in Active mode."); return; } while (SPC_GetBusyStatusFlag(APP_SPC)) ; /* Enable LVDs and HVDs in active mode. */ SPC_EnableActiveModeCoreLowVoltageDetect(APP_SPC, true); SPC_EnableActiveModeSystemHighVoltageDetect(APP_SPC, true); SPC_EnableActiveModeSystemLowVoltageDetect(APP_SPC, true); /* Disable analog modules that controlled by SPC in low power mode. */ SPC_DisableLowPowerModeAnalogModules(APP_SPC, (kSPC_controlUsb3vDet | kSPC_controlCmp0 | kSPC_controlCmp1 | kSPC_controlCmp0Dac | kSPC_controlCmp1Dac)); /* Disable LVDs and HVDs in low power mode to save power. */ SPC_EnableLowPowerModeCoreLowVoltageDetect(APP_SPC, false); SPC_EnableLowPowerModeSystemHighVoltageDetect(APP_SPC, false); SPC_EnableLowPowerModeSystemLowVoltageDetect(APP_SPC, false); spc_lowpower_mode_regulators_config_t lowPowerRegulatorOption; lowPowerRegulatorOption.lpIREF = false; lowPowerRegulatorOption.bandgapMode = kSPC_BandgapDisabled; lowPowerRegulatorOption.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage; lowPowerRegulatorOption.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_LowDriveStrength; status = SPC_SetLowPowerModeRegulatorsConfig(APP_SPC, &lowPowerRegulatorOption); #if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) /* Disable Vdd Core Glitch detector in low power mode. */ SPC_DisableLowPowerModeVddCoreGlitchDetect(APP_SPC, true); #endif if (status != kStatus_Success) { PRINTF("Fail to set regulators in Low Power Mode."); return; } while (SPC_GetBusyStatusFlag(APP_SPC)) ; SPC_SetLowPowerWakeUpDelay(APP_SPC, APP_LDO_LPWKUP_DELAY); } static void APP_SetVBATConfiguration(void) { /* Provide clock for the wake timer which is located in the system domain. */ CLOCK_SetupFRO16KClocking(kCLKE_16K_SYSTEM); } static void APP_SetCMCConfiguration(void) { /* Disable low power debug. */ CMC_EnableDebugOperation(APP_CMC, false); /* Allow all power mode */ CMC_SetPowerModeProtection(APP_CMC, kCMC_AllowAllLowPowerModes); /* Disable flash memory accesses and place flash memory in low-power state whenever the core clock is gated. And an attempt to access the flash memory will cause the flash memory to exit low-power state for the duration of the flash memory access. */ CMC_ConfigFlashMode(APP_CMC, true, true, false); } static app_power_mode_t APP_GetTargetPowerMode(void) { uint8_t ch; app_power_mode_t inputPowerMode; do { PRINTF("\r\nSelect the desired operation \n\r\n"); for (app_power_mode_t modeIndex = kAPP_PowerModeActive; modeIndex <= kAPP_PowerModeDeepPowerDown; modeIndex++) { PRINTF("\tPress %c to enter: %s mode\r\n", modeIndex, g_modeNameArray[(uint8_t)(modeIndex - kAPP_PowerModeActive)]); } PRINTF("\r\nWaiting for power mode select...\r\n\r\n"); ch = GETCHAR(); if ((ch >= 'a') && (ch <= 'z')) { ch -= 'a' - 'A'; } inputPowerMode = (app_power_mode_t)ch; if ((inputPowerMode > kAPP_PowerModeDeepPowerDown) || (inputPowerMode < kAPP_PowerModeActive)) { PRINTF("Wrong Input!"); } } while (inputPowerMode > kAPP_PowerModeDeepPowerDown); PRINTF("\t%s\r\n", g_modeDescArray[(uint8_t)(inputPowerMode - kAPP_PowerModeActive)]); return inputPowerMode; } static app_wakeup_source_t APP_SelectWakeupSource(void) { char ch; PRINTF("Please select wakeup source:\r\n"); PRINTF("\tPress %c to select TIMER as wakeup source;\r\n", kAPP_WakeupSourceWakeupTimer); #if !(defined(APP_NOT_SUPPORT_WAKEUP_BUTTON) && APP_NOT_SUPPORT_WAKEUP_BUTTON) PRINTF("\tPress %c to select WAKE-UP-BUTTON as wakeup source;\r\n", kAPP_WakeupSourceButton); #endif /* APP_NOT_SUPPORT_WAKEUP_BUTTON */ PRINTF("Waiting for wakeup source select...\r\n"); ch = GETCHAR(); if ((ch >= 'a') && (ch <= 'z')) { ch -= 'a' - 'A'; } return (app_wakeup_source_t)ch; } /* Get wakeup timeout and wakeup source. */ static void APP_GetWakeupConfig(app_power_mode_t targetMode) { app_wakeup_source_t wakeupSource; uint8_t timeOutValue; char *isoDomains = NULL; wakeupSource = APP_SelectWakeupSource(); switch (wakeupSource) { case kAPP_WakeupSourceWakeupTimer: { PRINTF("Wakeup Timer Selected As Wakeup Source!\r\n"); timeOutValue = APP_GetWakeupTimeout(); PRINTF("Will wakeup in %d seconds.\r\n", timeOutValue); /* In case of target mode is powerdown/deep power down mode. */ WUU_SetInternalWakeUpModulesConfig(APP_WUU, APP_WUU_WAKEUP_TIMER_IDX, kWUU_InternalModuleInterrupt); WAKETIMER_StartTimer(WAKETIMER0, timeOutValue * 1000); if (targetMode > kAPP_PowerModeSleep) { /* Isolate some power domains that are not used in low power modes, note that in order to save * more power, it is better to not power the isolated domains.*/ SPC_SetExternalVoltageDomainsConfig(APP_SPC, APP_SPC_WAKEUP_TIMER_LPISO_VALUE, APP_SPC_WAKEUP_TIMER_ISO_VALUE); isoDomains = APP_SPC_WAKEUP_TIMER_ISO_DOMAINS; PRINTF("Isolate power domains: %s\r\n", isoDomains); } break; } #if !(defined(APP_NOT_SUPPORT_WAKEUP_BUTTON) && APP_NOT_SUPPORT_WAKEUP_BUTTON) case kAPP_WakeupSourceButton: { PRINTF("Wakeup Button Selected As Wakeup Source.\r\n"); /* Set WUU to detect on rising edge for all power modes. */ wuu_external_wakeup_pin_config_t wakeupButtonConfig; wakeupButtonConfig.edge = kWUU_ExternalPinFallingEdge; wakeupButtonConfig.event = kWUU_ExternalPinInterrupt; wakeupButtonConfig.mode = kWUU_ExternalPinActiveAlways; WUU_SetExternalWakeUpPinsConfig(APP_WUU, APP_WUU_WAKEUP_BUTTON_IDX, &wakeupButtonConfig); PRINTF("Please press %s to wakeup.\r\n", APP_WUU_WAKEUP_BUTTON_NAME); if (targetMode > kAPP_PowerModeSleep) { /* Isolate some power domains that are not used in low power modes, note that in order to save * more power, it is better to not power the isolated domains.*/ SPC_SetExternalVoltageDomainsConfig(APP_SPC, APP_SPC_WAKEUP_BUTTON_LPISO_VALUE, APP_SPC_WAKEUP_BUTTON_ISO_VALUE); isoDomains = APP_SPC_WAKEUP_BUTTON_ISO_DOMAINS; PRINTF("Isolate power domains: %s\r\n", isoDomains); } break; } #endif /* APP_NOT_SUPPORT_WAKEUP_BUTTON */ default: assert(false); break; } } /*! * Get input from user about wakeup timeout */ static uint8_t APP_GetWakeupTimeout(void) { uint8_t timeout; while (1) { PRINTF("Select the wake up timeout in seconds.\r\n"); PRINTF("The allowed range is 1s ~ 9s.\r\n"); PRINTF("Eg. enter 5 to wake up in 5 seconds.\r\n"); PRINTF("\r\nWaiting for input timeout value...\r\n\r\n"); timeout = GETCHAR(); PRINTF("%c\r\n", timeout); if ((timeout > '0') && (timeout <= '9')) { return timeout - '0'; } PRINTF("Wrong value!\r\n"); } } static void APP_PowerPreSwitchHook(void) { /* Wait for debug console output finished. */ while (!(kLPUART_TransmissionCompleteFlag & LPUART_GetStatusFlags((LPUART_Type *)BOARD_DEBUG_UART_BASEADDR))) { } APP_DeinitDebugConsole(); } static void APP_PowerPostSwitchHook(void) { #if !(defined(APP_POST_INIT_CLOCK) && APP_POST_INIT_CLOCK) BOARD_BootClockFRO48M(); #else APP_POST_INIT_CLOCK_FUNCTION(); #endif APP_InitDebugConsole(); } static void APP_PowerModeSwitch(app_power_mode_t targetPowerMode) { if (targetPowerMode != kAPP_PowerModeActive) { switch (targetPowerMode) { case kAPP_PowerModeSleep: APP_EnterSleepMode(); break; case kAPP_PowerModeDeepSleep: APP_EnterDeepSleepMode(); break; case kAPP_PowerModePowerDown: APP_EnterPowerDownMode(); break; case kAPP_PowerModeDeepPowerDown: APP_EnterDeepPowerDownMode(); break; default: assert(false); break; } } } static void APP_EnterSleepMode(void) { cmc_power_domain_config_t config; config.clock_mode = kCMC_GateCoreClock; config.main_domain = kCMC_ActiveOrSleepMode; CMC_EnterLowPowerMode(APP_CMC, &config); } static void APP_EnterDeepSleepMode(void) { cmc_power_domain_config_t config; config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode; config.main_domain = kCMC_DeepSleepMode; CMC_EnterLowPowerMode(APP_CMC, &config); } static void APP_EnterPowerDownMode(void) { cmc_power_domain_config_t config; config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode; config.main_domain = kCMC_PowerDownMode; CMC_EnterLowPowerMode(APP_CMC, &config); } static void APP_EnterDeepPowerDownMode(void) { cmc_power_domain_config_t config; config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode; config.main_domain = kCMC_DeepPowerDown; CMC_EnterLowPowerMode(APP_CMC, &config); }效果
4.总结