Multi Source Translation Content

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Multi Source Translation Content

Discussions

Sort by:
Streaming .SB file via ROM API I am making a USB bootloader. The goal is to stream a SB21 file via USB in 512Byte chunks and stream them to the Bootloader API. But when I stream the SB file, only the ERASE section works, no data in the load section actually gets loaded into flash. I know the SB file is good because I can send the same SB file via blhost directly to the bootloader and it works. Attached to this forum post is my C source code that streams the data to the boot ROM. Is there anything incorrect that might help solve this issue? My bootloader code uses the NXP kb_init, kb_deinit and kb_execute API to stream a SB file.  My sb21 config yaml: # Description: Secure Binary v2.1 section blocks sections:   # --------------------------------------===== SB2.1 Commands [Optional] =====---------------------------------------   # Description: Secure Binary v2.1 commands block, list of all possible options - Modify it according to your   # application   - commands:       # Erase Application space. Keep bottom reserved area for persistent data       - erase:           address: 0x10000           length: 0x6BC00           mem_opt: 0           flags: 0       # Load the signed application MBI to flash       - load:           address: 0x10000           load_opt: 0           # File path is replaced with the generated device-specific MBI.           file: C:\code\Application_SECURE_MBI.bin Notes: 1. I am able to use blhost to send the same exact SB21 file to the Boot ROM and everything works. So I know the SBI is good 2. When I use my bootloader to stream the SB21 file, it does the erase section command, but the load section of the MBI file seems to fail, but I get no error code at all from kb_execute or the init/deinit calls. They all say success.  3. the final SB21 file is 155,568 Bytes total. I am able to stream every byte to the bootloader, all with status_t = 0x00 as a result.  4. My CMPA has SECURE_BOOT disabled, SWD access is enabled, CMPA is not sealed. CFPA also have everything enabled and open.  ISP is enabled LPC55xx 回复: Streaming .SB file via ROM API Hi @guitardenver  Since the same SB2.1 file works correctly with blhost, the SB file itself should be valid. Could you please check the following points in your application? According to the LPC55xx User Manual, the ROM authentication functions use the following RAM regions: 0x30000000–0x30003FFF 0x14005000–0x140059FF Please check your linker map and make sure your workspace, USB buffer, stack, or other application data does not overlap these regions. When kb_init/kb_process/kb_deinit indirectly invoke skboot_authenticate(), the application HASH interrupt vector must call HASH_IRQHandler(). Please also confirm that this interrupt forwarding is correctly configured. These would be the first two areas I recommend checking based on the ROM API requirements.   BR Harry 回复: Streaming .SB file via ROM API The shared RAM regions was indeed the issue. I reserved those within my linker file so my bootloader does not touch them. The file stream succeeded. Thanks!
View full article
通过 ROM API 流式传输 .SB 文件 我正在制作一个USB引导加载程序。目标是通过 USB 将 SB21 文件以 512 字节为单位进行流式传输,并将其传输到 Bootloader API。但是当我播放 SB 文件时,只有擦除部分有效,加载部分的数据实际上并没有加载到闪存中。我知道SB文件没问题,因为我可以通过blhost直接向引导加载程序发送同一个SB文件,而且它能正常工作。本论坛帖子附带了我的 C 源代码,该代码用于将数据流传输到启动 ROM。是否存在任何错误,可以帮助解决这个问题? 我的引导加载程序代码使用 NXP kb_init、kb_deinit 和 kb_execute API 来流式传输 SB 文件。 我的 sb21 配置 yaml 文件: # 描述:安全二进制文件 v2.1 部分块 章节:   # --------------------------------------===== SB2.1 命令 [可选的] =====---------------------------------------   # 说明:Secure 二进制 v2.1 命令块,列出所有可能的选项 - 根据您的需要进行修改   # 应用 -命令:       # 清除应用程序空间。保留底部预留区域用于持久化数据。 -删除:           地址: 0x10000           长度: 0x6BC00           mem_opt : 0           标志: 0       # 将已签名的应用程序 MBI 加载到闪存 -加载:           地址: 0x10000           load_opt : 0           # 文件路径将替换为生成的设备特定 MBI。           文件: C:\code\Application_SECURE_MBI.bin 说明: 1.我可以使用 blhost 将完全相同的 SB21 文件发送到启动 ROM,一切正常。所以我知道SBI不错。 2. 当我使用引导加载程序流式传输 SB21 文件时,它会执行擦除节命令,但 MBI 文件的加载节似乎失败了,但我从 kb_execute 或 init/deinit 调用中完全没有得到任何错误代码。他们都说成功了。 3. 最终的 SB21 文件总大小为 155,568 字节。我能够将每个字节的数据流发送到引导加载程序,所有结果的 status_t 值均为 0x00。 4. 我的 CMPA 已禁用 SECURE_BOOT,已启用 SWD 访问,CMPA 未密封。CFPA的所有功能也都已启用并开放。ISP已启用 LPC55xx 回复: Streaming .SB file via ROM API 嗨@guitardenver 由于同一个 SB2.1 文件在 blhost 中可以正常工作,因此 SB 文件本身应该是有效的。 请您在申请材料中检查以下几点? 根据LPC55xx用户手册,ROM认证功能使用以下RAM区域: 0x30000000–0x30003FFF 0x14005000–0x140059FF 请检查您的链接器映射,并确保您的工作区、USB 缓冲区、堆栈或其他应用程序数据不与这些区域重叠。 当 kb_init/kb_process/kb_deinit 间接调用 skboot_authenticate() 时,应用程序 HASH 中断向量必须调用 HASH_IRQHandler()。请确认中断转发配置是否正确。 根据 ROM API 要求,我建议首先检查这两个方面。   BR 哈里 回复: Streaming .SB file via ROM API 共享内存区域确实是问题所在。我在链接器文件中保留了这些参数,这样引导加载程序就不会触及它们。文件传输成功。谢谢!
View full article
ROM API経由で.SBファイルをストリーミング再生する 私はUSBブートローダーを作成しています。目標は、SB21ファイルをUSB経由で512バイトずつのチャンクに分割してストリーミングし、それをブートローダーAPIに送信することです。しかし、SBファイルをストリーミングすると、ERASEセクションしか機能せず、loadセクションのデータは実際にはフラッシュにロードされません。SBファイルが良いのは、同じSBファイルをblhost経由でブートローダーに直接送って動作するからです。このフォーラム投稿には、ブートROMにデータをストリーミングするC言語のソースコードが添付されています。この問題を解決するのに役立つような、何か誤った情報はありませんか? 私のブートローダーコードは、NXPのkb_init、kb_deinit、kb_execute APIを使用してSBファイルをストリーミングします。 私のsb21設定yamlファイル: # 説明: Secure Binary v2.1 セクションブロック セクション:   # --------------------------------------===== SB2.1 コマンド [オプション] =====---------------------------------------   # 説明: Secure Binary v2.1 コマンドブロック、すべての可能なオプションのリスト - 必要に応じて変更してください   # 応用 -コマンド:       # アプリケーションスペースを消去。永続的なデータ用に下部の部分を予約してください -消去:           アドレス: 0x10000           長さ: 0x6BC00           mem_opt : 0           フラグ: 0       # 署名付きアプリケーションのMBIをフラッシュに読み込む -負荷:           アドレス: 0x10000           load_opt : 0           # ファイルパスは、生成されたデバイス固有の MBI に置き換えられます。           ファイル: C:\code\Application_SECURE_MBI.bin メモ: 1.blhostを使用して全く同じSB21ファイルをブートROMに送信することができ、すべて正常に動作します。SO SBIが良いと知っています 2. ブートローダーを使用して SB21 ファイルをストリーミングすると、セクション消去コマンドは実行されますが、MBI ファイルのセクションのロードが失敗するようです。しかし、kb_execute や init/deinit 呼び出しからはエラーコードがまったく返されません。皆、成功を口にする。 3. 最終的なSB21ファイルは合計155,568バイトです。ブートローダーにすべてのバイトをストリーミングすることができ、結果としてすべてのステータス_tが0x00になります。 4. CMPAはSECURE_BOOT無効化、SWDアクセスは有効、CMPAは封印されていません。CFPAもすべての機能を有効化し、公開している。ISPが有効になっています LPC55xx 回复: Streaming .SB file via ROM API こんにちは、 @guitardenver 同じSB2.1ファイルがblhostで正しく動作することから、SBファイル自体は有効であるはずです。 アプリケーションの以下のポイントをご確認いただけますか? LPC55xxユーザーマニュアルによると、ROM認証機能は以下のRAM領域を使用します。 0x30000000–0x30003FFF 0x14005000–0x140059FF リンカーマップを確認し、ワークスペース、USBバッファ、スタック、その他のアプリケーションデータがこれらの領域と重複していないか確認してください。 kb_init/kb_process/kb_deinitが間接的にskboot_authenticate()を呼び出す場合、アプリケーションのHASH割り込みベクトルはHASH_IRQHandler()を呼び出さなければなりません。また、この割り込み転送が正しく設定されていることを確認してください。 ROM APIの要件に基づくと、まず最初に確認すべき2つの領域はこれらです。   BR ハリー 回复: Streaming .SB file via ROM API 問題は確かに共有RAM領域にあった。それらはリンクファイル内に予約して、ブートローダーが触らないようにしました。ファイルストリームの処理に成功しました。ありがとう!
View full article
I2C_MasterTransferAbort() Getting Hung During I2C Recovery on LPC55S69 Hello Team, I am currently working on an application using the LPC55S69. I have a sensor module that communicates with the LPC55S69 over the I2C interface. I am implementing an I2C recovery mechanism in which I call I2C_MasterTransferAbort() to abort an incomplete non-blocking I2C transfer. However, in some instances, this function appears to get stuck. I have added log messages before and after this function call. However, I can only see the log message printed before the call, and the message after the call is never printed. This indicates that the execution is getting stuck inside I2C_MasterTransferAbort(). Please refer to the logs below. The I2C interface being used is I2C5_MASTER.   PRINTF("%s() -> CFG=0x%08lX, STAT=0x%08lX, MSTCTL=0x%08lX, MSTDAT=0x%08lX, INTSTAT=0x%08lX, INTENSET=0x%08lX, TIMEOUT=0x%08lX\r\n", __func__, (unsigned long)I2C5_MASTER->CFG, (unsigned long)I2C5_MASTER->STAT, (unsigned long)I2C5_MASTER->MSTCTL, (unsigned long)I2C5_MASTER->MSTDAT, (unsigned long)I2C5_MASTER->INTSTAT, (unsigned long)I2C5_MASTER->INTENSET, (unsigned long)I2C5_MASTER->TIMEOUT); /* Capture interrupt state before cleanup. */ PRINTF("%s() -> FLEXCOMM5 IRQ enabled=%d, pending=%d\r\n", __func__, (int)NVIC_GetEnableIRQ(FLEXCOMM5_IRQn), (int)NVIC_GetPendingIRQ(FLEXCOMM5_IRQn)); /* Abort the incomplete non-blocking I2C transfer. */ status_t abortStatus = I2C_MasterTransferAbort(I2C5_MASTER, &g_m_handle); PRINTF("%s() -> I2C_MasterTransferAbort status=%d\r\n", __func__, (int)abortStatus); Observed log output: CFG=0x00000001, STAT=0x00000800, MSTCTL=0x00000002, MSTDAT=0x00000055, INTSTAT=0x00000000, INTENSET=0x03000051, TIMEOUT=0x0000FFFF FLEXCOMM5 IRQ enabled=1, pending=0 As you can see from the above logs, the following message is never printed: I2C_MasterTransferAbort status One thing I noticed is that I2C_RETRY_TIMES is currently set to 0. Based on my investigation, I suspect that the execution is getting stuck inside I2C_PendingStatusWait(). Could someone please help me understand why I2C_MasterTransferAbort() works in some instances but gets stuck in others? In particular, I would like to understand what conditions could cause I2C_PendingStatusWait() to wait indefinitely and whether the I2C_RETRY_TIMES configuration has any impact on this behavior. Thank you. Regards, San
View full article
在 LPC55S69 上,I2C 恢复期间 I2C_MasterTransferAbort() 函数挂起 各位同事好, 我目前正在开发一个使用LPC55S69的应用程序。 我有一个传感器模块,它通过 I2C 接口与 LPC55S69 通信。 我正在实现一个 I2C 恢复机制,其中调用I2C_MasterTransferAbort()来中止未完成的非阻塞 I2C 传输。然而,在某些情况下,该函数似乎会卡住。 我在该函数调用前后都添加了日志信息。但是,我只能看到调用前的日志信息,调用后的日志信息始终没有打印出来。这表明程序执行卡在了I2C_MasterTransferAbort() 函数内部。 请参考以下日志。 所使用的 I2C 接口为I2C5_MASTER 。   PRINTF("%s() -> CFG=0x%08lX, STAT=0x%08lX, MSTCTL=0x%08lX, MSTDAT=0x%08lX, INTSTAT=0x%08lX, INTENSET=0x%08lX, TIMEOUT=0x%08lX\r\n", __func__, (unsigned long)I2C5_MASTER->CFG, (unsigned long)I2C5_MASTER->STAT, (unsigned long)I2C5_MASTER->MSTCTL, (unsigned long)I2C5_MASTER->MSTDAT, (unsigned long)I2C5_MASTER->INTSTAT, (unsigned long)I2C5_MASTER->INTENSET, (unsigned long)I2C5_MASTER->TIMEOUT); /* Capture interrupt state before cleanup. */ PRINTF("%s() -> FLEXCOMM5 IRQ enabled=%d, pending=%d\r\n", __func__, (int)NVIC_GetEnableIRQ(FLEXCOMM5_IRQn), (int)NVIC_GetPendingIRQ(FLEXCOMM5_IRQn)); /* Abort the incomplete non-blocking I2C transfer. */ status_t abortStatus = I2C_MasterTransferAbort(I2C5_MASTER, &g_m_handle); PRINTF("%s() -> I2C_MasterTransferAbort status=%d\r\n", __func__, (int)abortStatus); 观察到的日志输出: CFG=0x00000001, STAT=0x00000800, MSTCTL=0x00000002, MSTDAT=0x00000055, INTSTAT=0x00000000, INTENSET=0x03000051, TIMEOUT=0x0000FFFF FLEXCOMM5 IRQ enabled=1, pending=0 从以上日志可以看出,以下消息从未被打印出来: I2C_MasterTransferAbort status 我注意到的一点是, I2C_RETRY_TIMES当前设置为0 。 根据我的调查,我怀疑执行过程卡在了I2C_PendingStatusWait()函数中。 请问有人能帮我理解一下为什么I2C_MasterTransferAbort()函数在某些情况下可以正常工作,但在另一些情况下却会卡住吗? 我尤其想了解哪些情况会导致I2C_PendingStatusWait()无限期等待,以及I2C_RETRY_TIMES配置是否对此行为有任何影响。 谢谢! 此致, 圣
View full article
[MCX A153] LPSPI Beginner's Guide (Japanese Blog) This article explains the basic concepts of LPSPI ( Low Power Serial Peripheral Interface ) on the MCX A153 and how to implement it using the MCUXpresso SDK , aimed at engineers new to NXP products. First, we will describe the hardware overview, and then, using the FRDM-MCXA153 board as a base, we will explain how to use the MCUXpresso SDK with code snippets. (Reading time: 20 minutes) 1. LPSPI Module Overview   1.1 What is LPSPI ?   LPSPI is a peripheral module used for synchronous serial communication with external devices. Here, "LP (Low Power)" means "designed to operate with low power consumption ."   Differences from a standard SPI (from a low-power perspective) The following are the characteristics of LPSPI compared to a typical SPI module: It can continue operating even in low power consumption mode (Stop / Sleep). By working in conjunction with DMA (eDMA) and reducing CPU intervention, overall system power consumption can be reduced. Hardware triggers (such as HREQ) can be used to initiate communication without waking up the CPU. LPSPI is not simply a module that enables SPI communication; it is designed as a communication module for operating the entire system with low power consumption.   1.2 Configuration in MCX A153 The MCX A153 has multiple LPSPI instances, and signals such as the following are used: CS (P1_3) SCK (P1_1) SDI (P1_2) SDO (P1_0) 2. Basic operation of LPSPI   2.1 Role of Signals SPI communication basically uses the following four wires for communication. SPI communication has four modes depending on polarity and phase, but in mode 0, for example, each signal follows the timing chart below.   2.2 The Role of FIFO LPSPI has an internal FIFO (First-In, First-Out) that can temporarily hold transmitted and received data. This allows the CPU to process data in batches to some extent, without having to perform register operations byte by byte immediately. Furthermore, by combining this with eDMA , the supply and retrieval of data to and from the FIFO can be automated instead of being handled by the CPU . 3. Basic Concepts of DMA ( eDMA ) Transfer   3.1 Why use DMA ? For applications that only require sending a few bytes via SPI , simple polling will suffice, but in actual embedded development, the following requirements are often encountered: I want to continuously transfer sensor data, display data, etc. I don't want the CPU to stop while waiting for communication. I want it to run in parallel with other control processes and RTOS tasks. I want to reduce the load on communication processing.   The key concept here is "non-blocking." Non-blocking refers to a function that returns immediately without waiting for the processing to complete. For example, in the case of SPI communication, there are usually two operating models as follows: Blocking When the send function is called, the CPU waits until the communication is complete. Other processes cannot be performed while communication is in progress. Non-blocking The function only initiates the transmission and immediately returns. Actual communication proceeds in the background (e.g., DMA). The CPU can perform other tasks during that time. Using LPSPI + eDMA allows the hardware to handle most of the data transfer, thus enabling non-blocking communication.   3.2 Concept of DMA Transfer In DMA transfer, the CPU first sets "where to send from," "where to receive from," and "how many bytes to send," and then instructs the system to start the transfer. After that, eDMA automatically proceeds with data transfer in response to LPSPI 's FIFO request. The CPU does not wait and can continue other processes.   3.3 Operation Image The general flow during DMA transfer is as follows: The CPU initializes LPSPI and eDMA . Set send buffer / receive buffer / size The CPU instructs the start of the DMA transfer. eDMA transports data in response to FIFO requests. A callback will be sent to notify you when the transfer is complete. 4. Basic Flow of SDK Drivers To use LPSPI, the following settings are required via software: Set the clock pin LPSPI module initialization eDMA handle definition LPSPI handle generation Transfer buffer settings Transfer execution Confirm completion via callback. This section demonstrates how to use the driver, using a sample project from the MCUXpresso SDK as an example. I will explain using the following project as an example. Reference URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/lpspi/edma_transfer/lpspi_edma_transfer.cc at main · nxp-mcuxpresso/mcuxsdk-examples   4.1 Clock Settings and Pin Settings First, initialize the clock and port to LPSPI0. If you forget to enable the clock, it won't work physically. It's important that the PORT assignment setting (MuxAlt) matches LPSPI0. /* クロック有効化 */ void BOARD_InitHardware(void) { /* Attach peripheral clock */ CLOCK_SetClockDiv(kCLOCK_DivLPSPI0, 1u); CLOCK_AttachClk(kFRO12M_to_LPSPI0); } /* PORT設定 */ /* PORT1: Peripheral clock is enabled */ CLOCK_EnableClock(kCLOCK_GatePORT1); /* PORT3: Peripheral clock is enabled */ CLOCK_EnableClock(kCLOCK_GatePORT3); /* LPSPI0 peripheral is released from reset */ RESET_ReleasePeripheralReset(kLPSPI0_RST_SHIFT_RSTn); /* PORT1 peripheral is released from reset */ RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn); /* LPSPI1 peripheral is released from reset */ RESET_ReleasePeripheralReset(kLPSPI1_RST_SHIFT_RSTn); /* PORT3 peripheral is released from reset */ RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn); const port_pin_config_t port1_0_pin135_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SDO */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_0 (pin 135) is configured as LPSPI0_SDO */ PORT_SetPinConfig(PORT1, 0U, &port1_0_pin135_config); const port_pin_config_t port1_1_pin136_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SCK */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_1 (pin 136) is configured as LPSPI0_SCK */ PORT_SetPinConfig(PORT1, 1U, &port1_1_pin136_config); const port_pin_config_t port1_2_pin137_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SDI */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_2 (pin 137) is configured as LPSPI0_SDI */ PORT_SetPinConfig(PORT1, 2U, &port1_2_pin137_config); const port_pin_config_t port1_3_pin138_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_PCS0 */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_3 (pin 138) is configured as LPSPI0_PCS0 */ PORT_SetPinConfig(PORT1, 3U, &port1_3_pin138_config); const port_pin_config_t port3_10_pin96_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SCK */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_10 (pin 96) is configured as LPSPI1_SCK */ PORT_SetPinConfig(PORT3, 10U, &port3_10_pin96_config); const port_pin_config_t port3_11_pin95_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_PCS0 */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_11 (pin 95) is configured as LPSPI1_PCS0 */ PORT_SetPinConfig(PORT3, 11U, &port3_11_pin95_config); const port_pin_config_t port3_8_pin98_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SDO */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_8 (pin 98) is configured as LPSPI1_SDO */ PORT_SetPinConfig(PORT3, 8U, &port3_8_pin98_config); const port_pin_config_t port3_9_pin97_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SDI */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_9 (pin 97) is configured as LPSPI1_SDI */ PORT_SetPinConfig(PORT3, 9U, &port3_9_pin97_config); }   4.2 LPSPI initialization Initialize the LPSPI module. Obtain the initial values using LPSPI_MasterGetDefaultConfig() and modify them as needed. lpspi_master_config_t masterConfig; LPSPI_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate = 500000U; LPSPI_MasterInit(LPSPI0, &masterConfig, CLOCK_GetFreq(kCLOCK_CoreSysClk));   4.3 Handle Definition A handle is a commonly used term in MCUXpresso SDK drivers, and it refers to an identifier used to indirectly reference and manipulate a resource. When using eDMA, you also need to create a handle for each channel and pass it to the LPSPI driver. You can also set up callbacks (functions that are called when an SPI transfer is completed) by passing a function pointer. edma_handle_t txHandle; edma_handle_t rxHandle; lpspi_master_edma_handle_t lpspiEdmaHandle; EDMA_CreateHandle(&txHandle, DMA0, 0); EDMA_CreateHandle(&rxHandle, DMA0, 1); LPSPI_MasterTransferCreateHandleEDMA( LPSPI0, &lpspiEdmaHandle, lpspi_master_callback, NULL, &txHandle, &rxHandle );   4.4 Transfer Buffers and Transfer Settings Specify the specific transfer details (buffer address, transfer size). /*Start master transfer*/ masterXfer.txData = masterTxData; masterXfer.rxData = NULL; masterXfer.dataSize = TRANSFER_SIZE; isTransferCompleted = false;   4.5 Start SPI transfer The SPI transfer will now begin. This API operates non-blockingly . After the function call, the CPU will immediately recover and be able to continue other processes. LPSPI_MasterTransferEDMALite(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_edma_handle,&masterXfer);   4.6 The Concept of Callbacks DMA transfers are designed to receive completion notifications via callbacks instead of waiting for processing to finish. This allows completion confirmation to be performed on the main loop or task side. In an RTOS environment, this can be replaced with semaphores or event notifications. volatile bool g_transferComplete = false; void lpspi_master_callback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *userData) { if (status == kStatus_Success) { g_transferComplete = true; } }   5. Common stumbling blocks Below is a summary of common stumbling blocks for each item. (1) Data is not returned MOSI/MISO wiring error Incorrect pin assignment settings Timing mismatch with the other device (if the slave device is not ready first, transmission and reception will not work properly). (2) No clock signal LPSPI module clock disabled PCS is not being controlled as expected. (3) DMA transfer does not complete DMA channel configuration error Callback registration missed Transfer size mismatch (4) CS cannot be controlled PCS configuration flags (configFlags) are incorrect. Incompatible polarity settings on the other device. (5) Received data is corrupted The clock setting is too fast. FIFO/DMA/ buffer size is not consistent. There are problems with the wiring quality or signal waveform.   6. Summary   LPSPI is the primary serial communication module for implementing SPI communication in the MCX A153, and is designed with low power consumption and DMA integration in mind. When actually using it, it is important to correctly configure not only the LPSPI settings but also the pin settings and clock settings. Furthermore, by using the MCUXpresso SDK, non-blocking communication using eDMA can be easily implemented. This allows the CPU to perform other tasks without being constrained by communication processing, leading to improved overall system efficiency. ========================= We are currently unable to respond to comments left in the "Comment" section of this post. We apologize for the inconvenience, but please refer to " Technical Questions to NXP - How to Contact Us( Japanese Blog) " when making an inquiry. (If you are already an NXP distributor or have a relationship with NXP, you may ask your representative directly.) This article explains the basic concepts of LPSPI ( Low Power Serial Peripheral Interface ) on the MCX A153 and how to implement it using the MCUXpresso SDK , aimed at engineers new to NXP products. First, we will describe the hardware overview, and then, using the FRDM-MCXA153 board as a base, we will explain how to use the MCUXpresso SDK with code snippets. (Reading time: 20 minutes) MCX Japanese Blog
View full article
[MCX A153] LPUART 入门指南(日语博客) 本文旨在为NXP产品新手工程师介绍MCX A153上的LPUART(低功耗通用异步收发器)的基本概念以及如何将其与MCUXpresso SDK配合使用。首先,我们将概述硬件,然后以FRDM-MCXA153开发板为基础,通过代码示例讲解如何使用MCUXpresso SDK API。 (阅读时间:20分钟) 1. LPUART 模块概述 LPUART 是一个用于实现异步串行通信的模块。接下来,我们将依次介绍它的主要特性。   异步通信(起始位/停止位) LPUART 不使用时钟线;它通过数据中包含的起始位和停止位来确定时序。由于它只需要两根线(TX 和 RX),因此被广泛用于轻松连接各种设备,例如与 PC 通信、连接传感器以及输出调试日志。 中断/DMA 支持 LPUART 采用了一种硬件自动辅助数据传输的机制,而非由 CPU 逐字节处理数据。它利用中断,仅在事件发生时才处理数据;并利用 DMA 技术,无需 CPU 干预即可在内存和数据之间进行传输。由于其设计充分考虑了 DMA 集成,即使在高速通信期间也能最大限度地降低 CPU 负载。 内置FIFO(缓冲区) LPUART 内部有一个用于发送和接收数据的缓冲区,也称为 FIFO(先进先出)。由于它可以临时存储数据,因此可以弥补通信速度与 CPU 或 DMA 处理速度之间的差异。与 DMA 结合使用时,更容易实现不间断的连续通信。 低功耗运行 它采用比标准UART更低的功耗设计,有时甚至在睡眠模式下也能继续运行。由于它与时钟控制紧密配合,因此特别适用于电池供电设备和物联网应用。 支持多实例 该MCU具有多个LPUART,允许多个设备同时通信。这使您可以为每个实例分配不同的角色,例如将调试和传感器通信分开。 2. 软件配置(MCUXpresso SDK) MCUXpresso SDK 提供了三种类型的驱动程序来处理 LPUART:轮询、中断和 eDMA。 在实际应用中,基于中断的通信足以满足小规模通信的需求,但高速、连续通信则通常使用 eDMA。对于不希望增加 CPU 负担的应用,从一开始就考虑使用 eDMA 进行设计可以最大限度地减少未来的修改。因此,本文将假设使用 DMA 进行讨论。 3. 先进先出(FIFO)和直接内存访问(DMA)的作用 要正确使用DMA,首先必须了解FIFO的工作原理。LPUART内部有一个FIFO(先进先出缓冲区),它的作用是临时保存发送的数据、临时存储接收到的数据,并吸收LPUART和DMA之间可能存在的速度差异。 在DMA集成中,接收端LPUART接收到的数据存储在RX FIFO中,当达到阈值时,DMA将数据从RX FIFO传输到内存。发送端DMA将数据从内存写入TX FIFO,LPUART依次从TX FIFO中读取并发送数据。这种机制允许硬件端进行连续数据传输,无需等待DMA传输完成,从而实现不间断的通信。 DMA 的工作原理可以描述如下: 当 LPUART 与 DMA 一起使用时,需要配置通道 MUX 以确定 LPUART 的 TX/RX 请求应该通过哪个 eDMA 通道进行路由。 MCX A153 没有像其他系列那样配备独立的 DMAMUX 外设。相反,eDMA 控制器的每个通道都内置了一个通道多路复用器(CHn_MUX 寄存器),用于选择要接受哪个外设功能的 DMA 请求源。SDK 使用 EDMA_SetChannelMux() API 为每个通道分配请求源(具体调用方法请参见第 4 章)。通道号不是固定的,可以根据应用程序的需要自由切换。 下图说明了外围功能侧的多个 DMA 请求源如何通过每个 eDMA 通道中内置的通道 MUX 选择器连接到通道主体。 在上图中,实线表示使用 EDMA_SetChannelMux 将 LPUART0 TX 分配给通道 0,LPUART0 RX 分配给通道 1 的示例。虚线表示可用的连接选项,通过在调用 API 时重写参数,可以更改其他分配,例如将 LPUART0 TX 分配给通道 2。 4. SDK驱动程序的基本流程 接下来,我们将以 MCUXpresso SDK 示例项目“lpuart_edma_transfer”为例,演示如何使用该驱动程序。 参考网址: 硬件要求 — MCUXpresso SDK 文档 mcuxsdk-examples/driver_examples/lpuart/edma_transfer/lpuart_edma_transfer.c 以下是同时使用 LPUART 和 DMA 的基本步骤: 启用时钟。 配置引脚多路复用器 初始化LPUART。 配置 eDMA 通道 MUX。 生成 DMA 句柄 开始发送/接收 下一个过程由回调函数控制。 接下来的章节中,我们将详细解释每个步骤,并提供代码片段。 4.1 时钟端口设置 首先,启用 LPUART 模块上的时钟。 CLOCK_EnableClock(kCLOCK_Lpuart0); 接下来,我们配置用于 TX 和 RX 的 MUX 引脚。 PORT_SetPinMux(PORTA, 1U, kPORT_MuxAlt2); // TX PORT_SetPinMux(PORTA, 2U, kPORT_MuxAlt2); // RX 除了 GND 之外,UART 的接线仅包含两根线:发送线和接收线。在 FRDM-MCXA153 电路图中,LPUART0 的 TXD 和 RXD 连接到 MCU-LINK 的虚拟 COM 口,通过 USB 将 MCU-LINK 连接到 PC,即可实现 UART 通信调试。 flowchart LR PC[PC] <-->|USB| MCULINK[MCU-LINK Virtual COM] MCULINK <-->|UART| LPUART0[MCXA153 LPUART0]   4.2 LPUART 初始化 初始化 LPUART 包括先获取默认设置,然后修改必要的项目。 lpuart_config_t config; LPUART_GetDefaultConfig(&config); config.baudRate_Bps = 115200; config.enableTx = true; config.enableRx = true; LPUART_Init(LPUART0, &config, CLOCK_GetFreq(kCLOCK_CoreSysClk)); 波特率取决于提供给 LPUART 的时钟频率,因此您需要在 CLOCK_GetFreq() 中传递正确的时钟源频率。根据需要启用 TX 和 RX。 4.3 eDMA通道复用器配置 在生成句柄之前,您需要使用 EDMA_SetChannelMux 指定要将 LPUART TX/RX 请求路由到的 eDMA 通道。如第 3 章所述,MCX A153 没有独立的 DMAMUX,此 API 会在每个通道的 CHn_MUX 寄存器中设置请求源。 /* LPUART0 TX を eDMA の任意チャネル(例: CH0)に割り当てる */ EDMA_SetChannelMux(DMA0, LPUART_TX_DMA_CHANNEL, kDma0RequestMuxLPUART0Tx); /* LPUART0 RX を eDMA の任意チャネル(例: CH1)に割り当てる */ EDMA_SetChannelMux(DMA0, LPUART_RX_DMA_CHANNEL, kDma0RequestMuxLPUART0Rx); 此处指定的通道号必须与生成后续 DMA 句柄时传递给 txEdmaHandle / rxEdmaHandle 通道号匹配。 4.4 DMA句柄生成 创建一个句柄来连接 LPUART 和 DMA,并在此处注册一个回调函数,以便在通信完成后调用。 lpuart_edma_handle_t g_lpuartEdmaHandle; LPUART_TransferCreateHandleEDMA(LPUART0, &g_lpuartEdmaHandle, lpuart_callback, userData, &txEdmaHandle, &rxEdmaHandle); 该句柄关联 LPUART 和 DMA TX/RX 通道,然后由后续的发送和接收 API 使用这些通道。 4.5 传输(DMA) 发送操作非常简单,只需调用 API,并将发送缓冲区和大小设置为 lpuart_transfer_t 。 lpuart_transfer_t xfer; xfer.data = txBuffer; xfer.dataSize = txSize; LPUART_TransferSendEDMA(LPUART0, &g_lpuartEdmaHandle, &xfer);   4.6 接收(DMA) 同样,接收也是通过在调用函数时指定接收缓冲区和大小来完成的。 lpuart_transfer_t xfer; xfer.data = rxBuffer; xfer.dataSize = rxSize; LPUART_TransferReceiveEDMA(LPUART0, &g_lpuartEdmaHandle, &xfer);   4.7 回调实现 通信完成后,应用程序会收到回调函数的通知。 void lpuart_callback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData) { if (status == kStatus_LPUART_TxIdle) { // 送信完了処理 } else if (status == kStatus_LPUART_RxIdle) { // 受信完了処理 } } kStatus_LPUART_TxIdle kStatus_LPUART_RxIdle 表示通过 DMA 传输完成, 表示通过 DMA 接收完成。如果要继续连续接收,可以在此回调函数中再次调用 LPUART_TransferReceiveEDMA() 以继续不间断接收。   4.8 关键设计要点 当实际将 LPUART 和 DMA 结合使用时,需要注意以下几个设计方面的考虑因素。 首先,我们来考虑传输大小。如果传输大小太小,中断次数会增加,降低 CPU 效率;如果传输大小太大,传输完成的延迟会很高。你需要根据应用程序的需求,同时考虑 FIFO 的大小,选择一个合适的传输大小。 接下来是接收缓冲区的设计。如果接收长度是预先确定的,则固定长度的缓冲区就足够了;但如果要连续接收长度不确定的数据,通常使用环形缓冲区。 最后,还有回调过程。回调不仅通知应用程序传输已完成,还会触发下一次DMA传输的重新配置。实现这一部分对于确保稳定连续的通信至关重要。 5. 常见问题   5.1 DMA 功能无法正常工作 可能的原因包括DMA时钟未启用、 EDMA_SetChannelMux 中指定的请求源与LPUART的TX/RX不匹配,或者传递给LPUART驱动程序的通道号与 EDMA_SetChannelMux 中设置的通道号不匹配。最快的解决方法是先启用时钟,然后检查通道MUX分配是否匹配。 5.2 数据丢失 常见问题包括 FIFO 溢出和传输大小设置与实际数据量不匹配。请检查 FIFO 阈值和 DMA 传输单元之间的关系。 5.3 高速通信导致的故障 随着波特率的提高,FIFO 欠载、缓冲器设计不足、波形质量下降和时钟错误等因素会变得尤为明显。因此,必须从硬件端信号质量和软件端缓冲器供电能力两方面来探究问题的根源。 6. 总结 LPUART 实际应用中最重要的是正确理解 FIFO 的作用,并考虑其与 DMA 的交互来设计数据缓冲区。牢记这些要点,即可实现低功耗、低 CPU 负载的稳定 UART 通信。 ========================= 我们目前无法回复此帖“评论”区的评论。由此给您带来的不便,我们深表歉意。如有任何疑问,请参阅“ NXP技术问题咨询 - 如何联系我们(日语博客) ”。(如果您已经是NXP的分销商或与NXP有合作关系,您可以直接联系您的代表。) 本文旨在为NXP产品新手工程师介绍MCX A153上的LPUART(低功耗通用异步收发器)的基本概念以及如何将其与MCUXpresso SDK配合使用。首先,我们将概述硬件,然后以FRDM-MCXA153开发板为基础,通过代码示例讲解如何使用MCUXpresso SDK API。 (阅读时间:20分钟) MCUXpresso SDK MCX 日本博客
View full article
[MCX A153] eDMA入門ガイド(日本語ブログ) 本記事では、MCX A153 に搭載されている eDMA(Enhanced Direct Memory Access)の基本概念と、MCUXpresso SDK を用いた使用方法を、初めてNXP製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後FRDM-MCXA153ボードをベースに、MCUXpresso SDKの使い方をコードスニペットとともに説明します。 (読了時間: 20分)   1. eDMAとは   eDMAはCPUを介さずにメモリとペリフェラル間、またはメモリ同士でデータを転送するハードウェアです。 CPUでデータ転送を行う場合、CPU自身が転送元のデータを読み出し、転送先へ書き込む処理を繰り返す必要があります。そのため、転送量が増えるほどCPU負荷が高くなります。 一方、eDMAを使用する場合は、CPUは転送条件(転送元アドレス、転送先アドレス、転送サイズなど)を設定してeDMAを起動するだけです。実際のデータ転送はeDMAハードウェアが実行するため、CPUは通信処理やアプリケーション処理など他のタスクを並行して実行できます。特にUARTやSPIなど連続的なデータ転送を伴うアプリケーションでは、CPU負荷の低減とリアルタイム性能の向上に大きな効果があります。 eDMAの代表的な用途としては、以下のようなものが挙げられます。 ADC変換結果をRAMへ自動格納 LPUART受信データをRAMに格納 LPSPI送信データをFIFOに転送 外部FlashからTCM(Tightly Coupled Memory)へのコピー PWMやタイマと組み合わせた周期転送 2. MCX A153のeDMA構成   MCXA153は4チャネルのeDMAを搭載しており、各チャネルは独立して動作します。 各チャネルへの転送要求は例えば以下から発行できます。 LPUART LPSPI LPI2C ADC CTIMER FlexPWM ソフトウェア要求 3. eDMAの基本概念   3.1 TCD   eDMAの設定を理解する上で重要なのがTCD(Transfer Control Descriptor)です。 TCDは「どこから・どこへ・何バイト・何回転送するか」を定義する転送記述子です。 eDMAは、TCDにしたがって動作します。TCDの代表的なパラメータを以下に示します。   項目 意味 SADDR ソースアドレス DADDR デスティネーションアドレス SOFF 転送毎ソースアドレス加算値 DOFF 転送毎デスティネーション加算値 NBYTES Minor Loopサイズ CITER 残りMajor Loop回数 BITER 初期Major Loop回数 SLAST 転送終了後ソース補正値 DLASTSGA 転送終了後宛先補正値 3.2. Minor LoopとMajor Loop   eDMAを初めて利用する方が最も混乱する部分です。   Minor Loop   1回のDMA要求で実施する転送量を意味します。例えば NBYTES を 4 に設定した場合、DMA要求が1回発生するたびに4バイトのデータが転送されます。つまり Minor Loop は「DMA要求1回あたりの転送量」を表すパラメータです。   Major Loop   Minor Loopを何回繰り返すかを意味します。例えば NBYTES を 4、BITER を 100 に設定した場合、DMAは4バイトの転送を100回繰り返します。その結果、合計400バイトのデータが転送されます。つまり Major Loop は「Minor Loopを何回繰り返すか」を表すパラメータです。   3.3. 擬似コードで理解するeDMA eDMAの動作は以下のように考えると理解しやすくなります。 以下のポイントを押さえて下さい。 NBYTES/SIZEがMinor Loop回数 BITERがMajor Loop回数 SOFF/DOFFが転送毎のアドレス更新 SLAST/DLASTで転送完了後に元へ戻せる(この仕組みを利用することで、リングバッファが実現可能) size_t *src,*dst; src=saddr; dst = daddr; for(citer = biter; citer>0; citer--) // major loop { for(i = 0; i 4. SDKドライバの基本フロー   eDMAを使用するためには、ソフトウェアによって以下の設定が必要となります。 eDMAモジュール初期化 eDMAハンドル定義 TCD設定 転送実行 MCUXpresso SDKのサンプルプロジェクトを例に、ドライバの使用方法を紹介します。 参考URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/edma4/memory_to_memory/edma_memory_to_memory.c at main · nxp-mcuxpresso/mcuxsdk-examples   4.1 eDMA初期化 eDMAモジュールの初期化を行います。EDMA_GetDefaultConfig() で初期値を取得して、用途に応じて変更してください。 edma_config_t config; EDMA_GetDefaultConfig(&config); EDMA_Init(DMA0, &config); 4.2 転送設定   SDKサンプルで最も重要なAPIです。 edma_transfer_config_t transferConfig; EDMA_PrepareTransfer(&transferConfig, srcAddr, sizeof(srcAddr[0]), destAddr, sizeof(destAddr[0]), sizeof(destAddr), sizeof(destAddr), kEDMA_MemoryToMemory); EDMA_SetTransferConfig(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, &transferConfig, NULL); EnableIRQ(DMA_CH0_IRQn); 引数の意味:   引数 意味 srcBuffer 転送元 srcWidth 転送単位 dstBuffer 転送先 dstWidth 転送単位 minorBytes Minor Loopサイズ totalBytes 総転送量 type 転送種別 4.3 転送開始 EDMA_TriggerChannelStart(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0); これでDMAが動作開始します。   4.4 コールバック DMA 転送では、処理完了を待つ代わりにコールバックで完了を受け取る設計にします。これにより、メインループ側やタスク側で完了確認が可能です。RTOS 環境ならセマフォやイベント通知に置き換え可能です。 /* EDMA transfer channel 0 IRQ handler */ void DMA_CH0_IRQHandler(void) { if ((EDMA_GetChannelStatusFlags(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0) & kEDMA_InterruptFlag) != 0U) { EDMA_ClearChannelStatusFlags(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, kEDMA_InterruptFlag); g_Transfer_Done = true; } }     5. よくあるつまずき 以下に各項目ごとに、つまずきがちなポイントをまとめました。 転送が始まらない DMA初期化済みか チャネル番号が正しいか 転送途中で停止 NBYTES設定 BITER設定 アライメント違反   データ化け 転送サイズ(8/16/32bit) SOFF/DOFF設定 バッファサイズ 6. まとめ   MCXA153のeDMAは4チャネル構成の高機能DMAです。TCDのパラメータの意味を理解することが重要です。他の入門ガイドでも、eDMAを使用したプロジェクトを数多く紹介しているので、是非ご一読ください。     ========================= 本投稿の「Comment」欄にコメントをいただいても、現在返信に対応しておりません。 お手数をおかけしますが、お問い合わせの際には「NXPへの技術質問 - 問い合わせ方法 (日本語ブログ)」をご参照ください。 (既に弊社NXP代理店、もしくはNXPとお付き合いのある方は、直接担当者へご質問いただいてもかまいません。) 本記事では、MCX A153 に搭載されている eDMA(Enhanced Direct Memory Access)の基本概念と、MCUXpresso SDK を用いた使用方法を、初めてNXP製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後FRDM-MCXA153ボードをベースに、MCUXpresso SDKの使い方をコードスニペットとともに説明します。 MCX 日本語ブログ
View full article
[MCX A153] GPIO 入门指南(日语博客) 本文阐述了MCX A153上GPIO(通用输入/输出)的基本概念。此外,本文还针对NXP产品新手,讲解了如何使用基于FRDM-MCXA153开发板的MCUXpresso SDK进行软件开发。首先,本文概述了硬件,然后解释了如何使用MCUXpresso SDK,并提供了代码示例。 (阅读时间:20分钟) 1. GPIO模块概述   1.1 GPIO 的作用 GPIO是控制微控制器引脚的最基本接口,可以将引脚作为“输入”或“输出”。 例如,在 FRDM-MCXA153 中,三个 RGB LED 连接到以下 GPIO ,因此可以通过控制 GPIO 来打开/关闭 LED。 红色:P3_12 绿色:P3_13 蓝色:P3_0 1.2 MCX A153中的引脚控制功能 在MCX A153中,引脚控制功能由以下两个模块管理: (1)端口模块 它主要发挥以下作用。由于一个引脚具有多种功能,因此需要进行端口配置才能将其用作GPIO。 引脚功能选择( GPIO/UART/SPI/I2C/PWM等) 上拉/下拉设置 驱动能力设置   (2)GPIO模块 它主要发挥以下作用: 输入/输出数据控制 引脚的高/低输出 读取输入状态 “ PORT =引脚配置”和“ GPIO =实际输入/输出操作”,等等。   2. GPIO的基本操作 GPIO 模块具有输出模式和输入模式,每种模式下均可进行以下操作: (1)输出模式 以下流程是可行的: 高输出 低输出 切换(反转当前输出) (2)输入模式 以下流程是可行的: 读取引脚电压状态(高电平或低电平) 中断检测(上升沿/下降沿)   3. SDK驱动程序的基本流程   要使用 GPIO,软件需要进行以下设置。 - 时钟设置 - 引脚设置(端口设置) - 输入或输出设置( GPIO设置) - 中断设置(如有必要) 本指南将以MCUXpresso SDK中的示例项目为例,演示如何使用该驱动程序。    3.1输出模式 我将以以下项目为例进行解释。 参考网址: 硬件要求 — MCUXpresso SDK 文档 mcuxsdk-examples/driver_examples/gpio/led_output/gpio_led_output.c 在 main · nxp-mcuxpresso...   3.1.1初始化 首先,初始化红色 LED 的时钟、端口和 GPIO。 #include "fsl_gpio.h" #include "fsl_port.h" // 赤色LEDに配線されたピンのパラメータ #define BOARD_INITPINS_LED_RED_PORT PORT3 #define BOARD_INITPINS_LED_RED_GPIO GPIO3 #define BOARD_INITPINS_LED_RED_PIN 12 void init_gpio(void) { // クロック有効化 CLOCK_EnableClock(kCLOCK_GateGPIO3); // PORT設定 const port_pin_config_t LED_RED = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as P3_12 */ kPORT_MuxAlt0, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; PORT_SetPinConfig(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, &LED_RED); // GPIO設定 gpio_pin_config_t LED_RED_config = { .pinDirection = kGPIO_DigitalOutput, .outputLogic = 0U }; GPIO_PinInit(BOARD_INITPINS_LED_RED_GPIO, BOARD_INITPINS_LED_RED_PIN, &LED_RED_config); }   3.1.2输出控制( LED开/关/切换) 可以使用以下 API 修改输出值。 GPIO_PinWrite(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, 1); // High GPIO_PinWrite(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, 0); // Low GPIO_PortToggle(BOARD_INITPINS_LED_RED_PORT, 1U << BOARD_INITPINS_LED_RED_PIN); // Toggle   3.2输入模式 我将以以下项目为例进行解释。 参考网址: 硬件要求 — MCUXpresso SDK 文档 mcuxsdk-examples/driver_examples/gpio/input_interrupt/gpio_input_interrupt.c 在 main · nxp-mcuxpresso...   3.2.1 初始化 除了输出模式和参数之外,其他都相同,因此我将省略细节。   3.2.2输入读取 可以使用以下 API 读取输入值。 uint32_t value = GPIO_PinRead(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN); if (value == 0) { // スイッチ押下(プルアップの場合) }   3.2.3中断设置 要将下降沿信号设置为GPIO中断,请使用以下 API。EnableIRQ 是 Cortex-M 端的中断使能设置。 GPIO_SetPinInterruptConfig(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, kGPIO_InterruptFallingEdge); EnableIRQ(BOARD_SW_IRQ); 处理中断需要定义一个函数作为中断处理程序。 如果不清除中断标志,中断将无限期地持续发生,所以要小心。 void BOARD_SW_IRQ_HANDLER(void) { /* 割り込みフラグをクリア */ GPIO_GpioClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN); // 処理 SDK_ISR_EXIT_BARRIER; } 下面显示的是导致中断的过程。 以上说明了如何将 GPIO 驱动程序与 MCUXpresso SDK 一起使用。   4. 常见陷阱 如果修改源代码后 GPIO 没有按预期工作,请检查以下项目。 引脚被设置为不同的功能 → 检查端口设置,看看引脚是否分配给了 GPIO。 时钟未启用→ 检查是否正在调用 CLOCK_EnableClock。 引脚编号错误 →检查是否与硬件引脚编号匹配。 未收到 GPIO 中断 → 检查 Cortex-M 端是否已启用中断,请使用 EnableIRQ。 GPIO中断循环 → 检查中断标志是否已清除。   5.总结   MCX A153 上的 GPIO 引脚采用两级配置:通过 PORT 模块进行引脚配置,并通过 GPIO 模块进行输入/输出控制。 因此,当使用引脚作为 GPIO 时,必须先在 PORT 模块中配置引脚分配设置并选择 GPIO 功能。之后,可以使用 GPIO 模块将其初始化为输入或输出,并执行诸如打开/关闭 LED 或读取开关状态等操作。 使用 MCUXpresso SDK,可以通过库 API 简洁地实现这些设置和控制。 此外,利用 GPIO 中断功能,可以高效地检测诸如开关按下之类的事件。如果 GPIO 工作异常,请检查端口设置是否已启用、目标端口的时钟是否已启用以及引脚编号设置是否正确。   ========================= 即使您在本文的“评论”栏留言,我们目前也无法回复。 给您带来不便,我们深感抱歉。请在询问时参阅“NXP技术问题-联系方式(日本博客)”。 (如果您已经是NXP的代理商或与其有合作关系,可以直接向负责人咨询。) 本文阐述了MCX A153上GPIO(通用输入/输出)的基本概念。此外,本文还针对NXP产品新手,讲解了如何使用基于FRDM-MCXA153开发板的MCUXpresso SDK进行软件开发。首先,本文概述了硬件,然后解释了如何使用MCUXpresso SDK,并提供了代码示例。 (阅读时间:20分钟) MCX 日本博客
View full article
使用 ND/LD 模式启动 i.MX95 的快速指南 在 i.MX95 上,OD、ND 和 LD 代表不同的系统运行模式,用于平衡性能和功耗。OD(OverDrive)模式以最高性能为目标,允许在更高的 SoC 电源电压下实现更高的时钟频率。ND(标称驱动)模式为正常性能和功率效率提供了标准工作点。LD(低驱动)模式用于低功耗运行,通过降低电压和限制时钟频率来节能。实际上,在这些模式之间切换涉及 VDD_SOC、系统时钟和 DDR 工作频率的协调变化,这样设备就可以安全、高效地在高性能和低功耗状态之间移动。 以下是不同模式模块的最大频率表。 超速模式 标称模式 低速驱动模式 VDD_SOC (典型值) 0.9 V 0.85 V 0.8 V VDD_ARM (典型值) 0.9 V 0.85 V 0.8 V A55 频率 1800 兆赫 1400 兆赫 900 兆赫 NPU 频率 1000 兆赫 800 兆赫 500 兆赫 ISI 频率 667 兆赫 500 兆赫 333 兆赫 GPU 频率 500 兆赫 500 兆赫 500 兆赫 显示频率 800 兆赫 666 兆赫 400 兆赫 VPU 频率 666 兆赫 500 兆赫 333 兆赫 要实现不同模式下的相应状态,需要采取三项行动 在系统管理器中更改 SoC 驱动模式 在 OEI 图像中设置 ddr 速率 在 mkimage 中编译引导加载程序 1.1 在系统管理器中更改 SoC 驱动模式 1。首先,将存储库克隆到本地计算机并版本 m33_image.bin。有关详细的编译说明和其他信息,请参阅存储库中的 README.md 文件。 git clone https://github.com/nxp-imx/imx-sm.git export TOOLS=~/tools  # toolchain download link here, export your own path: make config=mx95evk cfg​ make config=mx95evk all​ 2.以下是系统管理器中 ND 模式和 LD 模式的代码更改 ND: Diff --git a/boards/mcimx95evk/sm/brd_sm.c b/boards/mcimx95evk/sm/brd_sm.c​ --- a/boards/mcimx95evk/sm/brd_sm.c​ +++ b/boards/mcimx95evk/sm/brd_sm.c​ @@ -104,7 +104,7 @@​ BRD_SM_REC_VLD_MASK)​ /* Performance parameters */​ -#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_ODV /* Target perf level */​ +#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_NOM /* Target perf level */​ diff --git a/devices/MIMX95/sm/dev_sm_perf.c b/devices/MIMX95/sm/dev_sm_perf.c index 8aafdce9..26d6da11 100644 --- a/devices/MIMX95/sm/dev_sm_perf.c +++ b/devices/MIMX95/sm/dev_sm_perf.c @@ -2704,7 +2704,8 @@ static void DEV_SM_PerfCfgInit(void)      else      {          /* All other devices support PRK, LOW, NOM, ODV setpoints */ -        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 1U; +        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 2U;      }      /* Check for LPDDR4X */ LD: diff --git a/boards/mcimx95evk/sm/brd_sm.c b/boards/mcimx95evk/sm/brd_sm.c​ --- a/boards/mcimx95evk/sm/brd_sm.c​ +++ b/boards/mcimx95evk/sm/brd_sm.c​ @@ -104,7 +104,7 @@​ BRD_SM_REC_VLD_MASK)​ /* Performance parameters */​ -#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_ODV /* Target perf level */​ +#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_LOW /* Target perf level */ diff --git a/devices/MIMX95/sm/dev_sm_perf.c b/devices/MIMX95/sm/dev_sm_perf.c index 8aafdce9..26d6da11 100644 --- a/devices/MIMX95/sm/dev_sm_perf.c +++ b/devices/MIMX95/sm/dev_sm_perf.c @@ -2704,7 +2704,8 @@ static void DEV_SM_PerfCfgInit(void)      else      {          /* All other devices support PRK, LOW, NOM, ODV setpoints */ -        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 1U; +        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 3U;      }      /* Check for LPDDR4X */ 编译 SM 二进制文件以生成 build/mx95lp5/ddr/m33_image.bin,然后将其复制到 imx-mkimage/iMX95/m33_image.bin。 1.2. 在系统管理器中更改 SoC 驱动模式 1. 首先,将存储库克隆到本地计算机上,然后构建 m33-oei-ddr.bin。有关详细的编译说明和其他信息,请参阅存储库中的 README.md 文件。 git clone https://github.com/nxp-imx/imx-oei.git export TOOLS=~/tools make board=mx95lp5 oei=ddr DEBUG=1 r=B0 2。请更换 a/boards/ mx95lp5/ddr/ cmimx95_lpddr5_evk_19x19_6400mts_fw2024.09_timing.c文件和对应不同 DDR 数据速率的文件。 对于 ND 模式,文件为lpddr5_4800_timing.c(见附件)。 对于 LD 模式,文件为lpddr5_3200_timing.c(见附件)。 编译 OEI 二进制文件以生成 build/mx95lp5/ddr/m33_image.bin,然后将其复制到 imx-mkimage/iMX95/m33_image.bin。 1.3.在 mkimage 中编译引导加载程序 1.imx-mkimage 的设置 mkdir imx-mkimage​ cd imx-mkimage/​ git clone https://github.com/nxp-imx/imx-mkimage.git git checkout 2.编译 flash.bin 参考 UG10163第 4.5.13 节,编译 mkimage 所需的文件。将所有生成的文件复制到 imx-mkimage/iMX95 目录。替换 oei-m33-ddr.bin 和 m33_image.bin、然后运行以下命令生成 flash.bin: make SOC=iMX95 OEI=YES flash_all 该表描述了相应的二进制文件: OEI 图像 系统管理员(M33_image) 超速模式 Oei-m33-ddr-6400.bin​ M33_image_OD.bin 标称模式 Oei-m33-ddr-4800.bin​ M33_image_ND.bin 低速驱动模式 Oei-m33-ddr-3200.bin​ M33_image_LD.bin 3. 使用以下命令将不同的 flash.bin 文件闪存到主板上: ./uuu.exe –b emmc flash.bin​ 4.打开 BCU工具,检查VDD_SOC和VDD_ARM电压。然后运行mhz命令,就会看到当前 CPU 频率受到限制。 在 i.MX95 上,OD、ND 和 LD 代表不同的系统运行模式,用于平衡性能和功耗。OD(OverDrive)模式以最高性能为目标,允许在更高的 SoC 电源电压下实现更高的时钟频率。ND(标称驱动)模式为正常性能和功率效率提供了标准工作点。LD(低驱动)模式用于低功耗运行,通过降低电压和限制时钟频率来节能。实际上,在这些模式之间切换涉及 VDD_SOC、系统时钟和 DDR 工作频率的协调变化,这样设备就可以安全、高效地在高性能和低功耗状态之间移动。 以下是不同模式模块的最大频率表。 超速模式 标称模式 低速驱动模式 VDD_SOC (典型值) 0.9 V 0.85 V 0.8 V VDD_ARM (典型值) 0.9 V 0.85 V 0.8 V A55 频率 1800 兆赫 1400 兆赫 900 兆赫 NPU 频率 1000 兆赫 800 兆赫 500 兆赫 ISI 频率 667 兆赫 500 兆赫 333 兆赫 GPU 频率 500 兆赫 500 兆赫 500 兆赫 显示频率 800 兆赫 666 兆赫 400 兆赫 VPU 频率 666 兆赫 500 兆赫 333 兆赫 i.MX 处理器 Re: Quick Guide on Booting i.MX95 with ND/LD Mode 还有另一种更改 ARM 工作模式的方法:(不包括 SoC 模式) mx95evk.cfg msel 0/1/2 OD>LD PERF_A55=3/3-> PERF_A55 =3/1
View full article
[MCX A153] eDMA 入门指南(日语博客) 本文 旨在为 NXP 产品 新手工程师 介绍 MCX A153 上的 eDMA ( 增强型 直接 内存 访问 )基本概念 以及 如何将其与 MCUXpresso SDK 配合使用。 首先,我们将概述硬件,然后以 FRDM-MCXA153 开发板为基础,通过代码示例讲解如何使用MCUXpresso SDK。 (阅读时间:20分钟)   1. 什么是eDMA?   eDMA是一种硬件,它无需 CPU 参与即可在内存和外围设备之间或内存设备之间传输数据。 当数据传输由CPU执行时,CPU本身需要反复从源端读取数据并将其写入目标端。因此,随着数据传输量的增加,CPU负载也会增加。 另一方面,使用eDMA时,CPU只需设置传输条件(源地址、目标地址、传输大小等)并启动eDMA即可。由于实际的数据传输由eDMA硬件完成,CPU可以并行执行其他任务,例如通信处理和应用程序处理。这显著降低了CPU负载,提高了实时性能,尤其是在UART和SPI等涉及连续数据传输的应用中。 eDMA的典型用途包括以下几种: ADC转换结果会自动存储在RAM中。 LPUART 接收到的数据存储在 RAM 中。 将LPSPI传输数据传输到FIFO 从外部闪存复制到TCM(紧耦合存储器) 周期性传输结合 PWM 或定时器 2. MCX A153 的 eDMA 配置   MCXA153 具有四个 eDMA 通道,每个通道独立运行。 例如,可以通过以下方式向各个通道发出转发请求: LPUART LPSPI LPI2C ADC 计时器 FlexPWM 软件需求 3. eDMA的基本概念   3.1 TCD   在考虑eDMA设置时,了解 TCD(传输控制描述符)至关重要。 TCD 是传输描述符,它定义了“从哪里传输、从哪里传输、传输多少字节以及传输多少次”。 eDMA 的工作原理基于 TCD。典型的 TCD 参数如下所示。   项目 意义 萨德 源地址 DADDR 目的地地址 索夫 每次传输的源地址增量 脱 每次转账的目的地增量 字节 小环尺寸 西特 剩余主要环路 咬人者 初始主要循环计数 SLAST 传输完成后的源校正值 DLASTSGA 转账完成后的目的地更正值 3.2.小环和大环   这是初次使用eDMA的人最容易感到困惑的部分。   小环   这指的是单次 DMA 请求中传输的数据量。例如,如果 NBYTES 设置为 4,则每次 DMA 请求都会传输 4 字节的数据。换句话说,Minor Loop 是一个表示“每次 DMA 请求传输的数据量”的参数。   主环   这指的是次循环重复的次数。例如,如果 NBYTES 设置为 4,BITER 设置为 100,则 DMA 将重复传输 4 个字节 100 次。因此,总共将传输 400 字节的数据。简而言之,主循环是一个表示“次循环重复次数”的参数。   3.3.通过伪代码理解 eDMA 如果这样理解,就更容易理解eDMA的工作原理了: 请记住以下几点。 字节/大小是小环的数量 BITER 是主要循环的数量 SOFF/DOFF 会更新每次转账的地址。 SLAST/DLAST 允许在传输完成后恢复数据(此机制实现了环形缓冲区)。 size_t *src,*dst; src=saddr; dst = daddr; for(citer = biter; citer>0; citer--) // major loop { for(i = 0; i 4. SDK驱动程序的基本流程   要使用 eDMA,软件需要进行以下设置: eDMA 模块初始化 eDMA句柄定义 TCD设置 转账执行 本指南将演示如何使用驱动程序,并以 MCUXpresso SDK 中的示例项目为例进行说明。 参考网址: 硬件要求 — MCUXpresso SDK 文档 mcuxsdk-examples/driver_examples/edma4/memory_to_memory/edma_memory_to_memory.c 位于 main · nxp-mcuxpresso/mcuxsdk-examples   4.1 eDMA初始化 这将初始化 eDMA 模块。使用 EDMA_GetDefaultConfig() 获取初始值,并根据需要进行修改。 edma_config_t config; EDMA_GetDefaultConfig(&config); EDMA_Init(DMA0, &config); 4.2传输设置   这是 SDK 示例中最重要的 API。 edma_transfer_config_t transferConfig; EDMA_PrepareTransfer(&transferConfig, srcAddr, sizeof(srcAddr[0]), destAddr, sizeof(destAddr[0]), sizeof(destAddr), sizeof(destAddr), kEDMA_MemoryToMemory); EDMA_SetTransferConfig(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, &transferConfig, NULL); EnableIRQ(DMA_CH0_IRQn); 论证的含义:   争论 意义 srcBuffer 来源 srcWidth 传输单元 目标缓冲区 转发目的地 目标宽度 传输单元 次要字节 小环尺寸 总字节数 总传输量 类型 转账类型 4.3 转会开始 EDMA_TriggerChannelStart(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0); 这将启动DMA操作。   4.4 回调 DMA传输设计为通过回调接收完成通知,而不是等待处理完成。这使得可以在主循环或任务端执行完成确认。在RTOS环境中,这可以用信号量或事件通知来替代。 /* EDMA transfer channel 0 IRQ handler */ void DMA_CH0_IRQHandler(void) { if ((EDMA_GetChannelStatusFlags(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0) & kEDMA_InterruptFlag) != 0U) { EDMA_ClearChannelStatusFlags(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, kEDMA_InterruptFlag); g_Transfer_Done = true; } }     5.常见的绊脚石 以下是每个项目常见障碍的总结。 转账未开始 DMA 是否已初始化? 频道号正确吗? 转移过程中停止 字节设置 BITER 设置 对齐违规   数据损坏 传输大小(8/16/32 位) SOFF/DOFF 设置 缓冲区大小 6. 总结   MCXA153 的 eDMA 是一种高性能的 4 通道 DMA。理解 TCD 参数的含义至关重要。许多其他入门指南也介绍了使用 eDMA 的项目,因此请务必阅读它们。     ========================= 我们目前无法回复此帖子“评论”部分留下的评论。 由此给您带来的不便,我们深表歉意。如有任何疑问,请在邮件主题栏填写“NXP 技术问题”。 - 如何联系我们 请参阅“( 日语博客 ) ”部分。 (如果您已经是恩智浦的分销商或与恩智浦有合作关系,您可以直接咨询您的代表。) 本文 旨在为 NXP 产品 新手工程师 介绍 MCX A153 上的 eDMA ( 增强型 直接 内存 访问 )基本概念 以及 如何将其与 MCUXpresso SDK 配合使用。 首先,我们将概述硬件,然后以 FRDM-MCXA153 开发板为基础,通过代码示例讲解如何使用MCUXpresso SDK。 MCX 日本博客
View full article
i.MX95をND/LDモードで起動するためのクイックガイド i.MX95では、OD、ND、LDは、パフォーマンスと消費電力のバランスを取るために使用される異なるシステム動作モードを表します。OD(オーバードライブ)モードは最高のパフォーマンスを目指しており、より高いSoC供給電圧でより高いクロック周波数を可能にします。ND(公称駆動)モードは、通常の性能と電力効率を実現するための標準動作点を提供します。LD(低駆動)モードは、低消費電力動作を目的としており、電圧を下げ、クロック周波数を制限することでエネルギーを節約します。実際には、これらのモードを切り替えるには、VDD_SOC、システムクロック、DDR動作周波数の協調的な変更が必要となり、デバイスが高性能状態と低消費電力状態の間を安全かつ効率的に移行できるようになります。 以下は、異なるモードのモジュールの最大周波数に関する表です。 オーバードライブモード 公称モード ロードライブモード VDD_SOC(標準値) 0.9V 0.85V 0.8V VDD_ARM(標準値) 0.9V 0.85V 0.8V A55周波数 1800MHz 1400MHz 900MHz NPU周波数 1000MHz 800MHz 500MHz ISI周波数 667MHz 500MHz 333MHz GPU周波数 500MHz 500MHz 500MHz 表示周波数 800MHz 666MHz 400MHz VPU周波数 666MHz 500MHz 333MHz 異なるモードで対応する状態を達成するには、3つの行動を取る必要があった。 システムマネージャでSoCの駆動モードを変更する OEIイメージでDDRレートを設定します mkimageでブートローダーをコンパイル 1.1システムマネージャでSoCの駆動モードを変更する 1. まず、リポジトリをローカルマシンにクローンし、m33_image.bin をビルドします。詳細なビルド手順および追加情報については、リポジトリ内のREADME.mdファイルを参照してください。 git clone https://github.com/nxp-imx/imx-sm.git export TOOLS=~/tools  # toolchain download link here, export your own path: make config=mx95evk cfg​ make config=mx95evk all​ 2. システムマネージャにおけるNDモードとLDモードのコード変更点は以下のとおりです。 ND: Diff --git a/boards/mcimx95evk/sm/brd_sm.c b/boards/mcimx95evk/sm/brd_sm.c​ --- a/boards/mcimx95evk/sm/brd_sm.c​ +++ b/boards/mcimx95evk/sm/brd_sm.c​ @@ -104,7 +104,7 @@​ BRD_SM_REC_VLD_MASK)​ /* Performance parameters */​ -#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_ODV /* Target perf level */​ +#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_NOM /* Target perf level */​ diff --git a/devices/MIMX95/sm/dev_sm_perf.c b/devices/MIMX95/sm/dev_sm_perf.c index 8aafdce9..26d6da11 100644 --- a/devices/MIMX95/sm/dev_sm_perf.c +++ b/devices/MIMX95/sm/dev_sm_perf.c @@ -2704,7 +2704,8 @@ static void DEV_SM_PerfCfgInit(void)      else      {          /* All other devices support PRK, LOW, NOM, ODV setpoints */ -        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 1U; +        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 2U;      }      /* Check for LPDDR4X */ LD: diff --git a/boards/mcimx95evk/sm/brd_sm.c b/boards/mcimx95evk/sm/brd_sm.c​ --- a/boards/mcimx95evk/sm/brd_sm.c​ +++ b/boards/mcimx95evk/sm/brd_sm.c​ @@ -104,7 +104,7 @@​ BRD_SM_REC_VLD_MASK)​ /* Performance parameters */​ -#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_ODV /* Target perf level */​ +#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_LOW /* Target perf level */ diff --git a/devices/MIMX95/sm/dev_sm_perf.c b/devices/MIMX95/sm/dev_sm_perf.c index 8aafdce9..26d6da11 100644 --- a/devices/MIMX95/sm/dev_sm_perf.c +++ b/devices/MIMX95/sm/dev_sm_perf.c @@ -2704,7 +2704,8 @@ static void DEV_SM_PerfCfgInit(void)      else      {          /* All other devices support PRK, LOW, NOM, ODV setpoints */ -        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 1U; +        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 3U;      }      /* Check for LPDDR4X */ SMバイナリをコンパイルしてbuild/mx95lp5/ddr/m33_image.binを生成し、それをimx-mkimage/iMX95/m33_image.binにコピーします。 1. 2 .システムマネージャでSoCの駆動モードを変更する 1.まず、リポジトリをローカルマシンにクローンし、m33-oei-ddr.bin をビルドします。詳細なビルド手順および追加情報については、リポジトリ内のREADME.mdファイルを参照してください。 git clone https://github.com/nxp-imx/imx-oei.git export TOOLS=~/tools make board=mx95lp5 oei=ddr DEBUG=1 r=B0 2. a/boards/mx95lp5/ddr/ cMIMX95_LPDDR5_EVK_19X19_6400MTS_FW2024.09_timing.cを置き換えてください。異なるDDRデータレートに対応するファイルを含むファイル。 NDモードの場合、ファイルはlpddr5_4800_timing.cです(添付ファイルを参照)。 LDモードの場合、ファイルはlpddr5_3200_timing.cです(添付ファイルを参照)。 OEIバイナリをコンパイルしてbuild/mx95lp5/ddr/m33_image.binを生成し、それをimx-mkimage/iMX95/m33_image.binにコピーします。 1. 3. mkimag eでブートローダーをコンパイルする 1. imx-mkimage をセットアップします mkdir imx-mkimage​ cd imx-mkimage/​ git clone https://github.com/nxp-imx/imx-mkimage.git git checkout 2. flash.binをコンパイルする mkimageに必要なファイルをコンパイルするには、 UG10163のセクション4.5.13を参照してください。生成されたすべてのファイルをimx-mkimage/iMX95ディレクトリにコピーしてください。oei-m33-ddr.bin と m33_image.bin を置き換えます。次に、以下のコマンドを実行して flash.bin を生成します。 make SOC=iMX95 OEI=YES flash_all 表には、対応するバイナリが示されています。 OEI画像 システムマネージャ(M33_image) オーバードライブモード Oei-m33-ddr-6400.bin​ M33_image_OD.bin 公称モード Oei-m33-ddr-4800.bin​ M33_image_ND.bin ロードライブモード Oei-m33-ddr-3200.bin​ M33_image_LD.bin 3.以下のコマンドを使用して、異なるflash.binファイルをボードに書き込みます。 ./uuu.exe –b emmc flash.bin​ 4. BCUツールを開いて、 VDD_SOCとVDD_ARMの電圧を確認します。次にmhzコマンドを実行すると、現在のCPU周波数が制限されていることが確認できます。 i.MX95では、OD、ND、LDは、パフォーマンスと消費電力のバランスを取るために使用される異なるシステム動作モードを表します。OD(オーバードライブ)モードは最高のパフォーマンスを目指しており、より高いSoC供給電圧でより高いクロック周波数を可能にします。ND(公称駆動)モードは、通常の性能と電力効率を実現するための標準動作点を提供します。LD(低駆動)モードは、低消費電力動作を目的としており、電圧を下げ、クロック周波数を制限することでエネルギーを節約します。実際には、これらのモードを切り替えるには、VDD_SOC、システムクロック、DDR動作周波数の協調的な変更が必要となり、デバイスが高性能状態と低消費電力状態の間を安全かつ効率的に移行できるようになります。 以下は、異なるモードのモジュールの最大周波数に関する表です。 オーバードライブモード 公称モード ロードライブモード VDD_SOC(標準値) 0.9V 0.85V 0.8V VDD_ARM(標準値) 0.9V 0.85V 0.8V A55周波数 1800MHz 1400MHz 900MHz NPU周波数 1000MHz 800MHz 500MHz ISI周波数 667MHz 500MHz 333MHz GPU周波数 500MHz 500MHz 500MHz 表示周波数 800MHz 666MHz 400MHz VPU周波数 666MHz 500MHz 333MHz i.MXプロセッサ Re: Quick Guide on Booting i.MX95 with ND/LD Mode ARMの動作モードを変更する別の方法があります:(SoCモードを含まない) mx95evk.cfg msel 0/1/2 OD->LD PERF_A55 =3/3 - > PERF_A55 =3/1
View full article
[MCX A153] LPSPI 入门指南(日语博客) 本文 旨在为 NXP 产品新手工程师介绍 MCX A153 上的 LPSPI( 低 功耗 串行 外设 接口 ) 基本概念 以及 如何使用 MCUXpresso SDK 实现该接口。 首先,我们将概述硬件,然后以 FRDM-MCXA153 开发板为基础,通过代码示例讲解如何使用MCUXpresso SDK。 (阅读时间:20分钟) 1. LPSPI模块概述   1.1 什么是LPSPI ?   LPSPI 是一种用于与外部设备进行同步串行通信的外围模块。 这里, “LP(低功耗)”是指“设计用于低功耗运行”。   与标准SPI的区别(从低功耗角度来看) 以下是LPSPI与典型SPI模块相比的特点: 即使在低功耗模式(停止/睡眠)下,它也能继续运行。 通过与 DMA(eDMA)协同工作并减少 CPU 干预,可以降低系统整体功耗。 可以使用硬件触发器(例如 HREQ)来启动通信,而无需唤醒 CPU。 LPSPI 不仅仅是一个实现 SPI 通信的模块;它被设计成一个低功耗的通信模块,用于运行整个系统。   1.2 MCX A153 的配置 MCX A153具有多个LPSPI实例,并使用以下信号: CS(P1_3) SCK (P1_1) SDI(P1_2) SDO(P1_0) 2. LPSPI的基本操作   2.1信号的作用 SPI 通信主要使用以下四根线进行通信。 SPI 通信根据极性和相位有四种模式,但例如在模式 0 中,每个信号都遵循以下时序图。   2.2 先进先出原则的作用 LPSPI具有内部FIFO (先进先出),可以临时保存已发送和已接收的数据。 这使得CPU能够在一定程度上分批处理数据,而无需立即逐字节执行寄存器操作。此外,通过将其与eDMA结合使用,可以实现FIFO的数据供取和检索自动化,而无需由CPU处理。 3. DMA( eDMA )传输的基本概念   3.1为什么要使用DMA ? 对于只需要通过SPI发送几个字节的应用来说,简单的轮询就足够了,但在实际的嵌入式开发中,经常会遇到以下要求: 我希望能够持续传输传感器数据、显示数据等等。 我不希望CPU在等待通信时停止运行。 我希望它能与其他控制进程和RTOS任务并行运行。 我想减轻通信处理的负担。   这里的关键概念是“非阻塞”。 非阻塞函数是指不等待处理完成就立即返回的函数。 例如,对于SPI通信,通常有两种工作模式,如下所示: 阻塞 当调用发送函数时,CPU 会等待通信完成。 通信进行期间,其他操作无法执行。 非阻塞式 该函数仅启动传输并立即返回。 实际通信在后台进行(例如,DMA)。 CPU 在此期间可以执行其他任务。 使用 LPSPI + eDMA 可以让硬件处理大部分数据传输,从而实现无阻塞通信。   3.2 DMA传输的概念 在DMA传输中, CPU首先设置“从哪里发送”、“从哪里接收”和“要发送多少字节”,然后指示系统开始传输。 之后, eDMA会根据LPSPI的FIFO请求自动进行数据传输。CPU 无需等待,可以继续执行其他进程。   3.3操作图像 DMA传输的一般流程如下: CPU初始化LPSPI和eDMA 。 设置发送缓冲区/接收缓冲区/大小 CPU指示开始DMA传输。 eDMA根据FIFO请求传输数据。 转账完成后,我们会回拨电话通知您。 4. SDK驱动程序的基本流程 要使用 LPSPI,需要通过软件进行以下设置: 设置时钟引脚 LPSPI模块初始化 eDMA句柄定义 LPSPI句柄生成 传输缓冲区设置 转账执行 通过回拨确认完成。 本节演示如何使用驱动程序,并以 MCUXpresso SDK 中的示例项目为例进行说明。 我将以以下项目为例进行解释。 参考网址: 硬件要求 — MCUXpresso SDK 文档 mcuxsdk-examples/driver_examples/lpspi/edma_transfer/lpspi_edma_transfer.cc 在 main · nxp-mcuxpresso/mcuxsdk-examples   4.1 时钟设置和引脚设置 首先,初始化时钟并将端口连接到 LPSPI0。 如果忘记启用时钟,设备将无法正常工作。端口分配设置 (MuxAlt) 必须与 LPSPI0 匹配,这一点非常重要。 /* クロック有効化 */ void BOARD_InitHardware(void) { /* Attach peripheral clock */ CLOCK_SetClockDiv(kCLOCK_DivLPSPI0, 1u); CLOCK_AttachClk(kFRO12M_to_LPSPI0); } /* PORT設定 */ /* PORT1: Peripheral clock is enabled */ CLOCK_EnableClock(kCLOCK_GatePORT1); /* PORT3: Peripheral clock is enabled */ CLOCK_EnableClock(kCLOCK_GatePORT3); /* LPSPI0 peripheral is released from reset */ RESET_ReleasePeripheralReset(kLPSPI0_RST_SHIFT_RSTn); /* PORT1 peripheral is released from reset */ RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn); /* LPSPI1 peripheral is released from reset */ RESET_ReleasePeripheralReset(kLPSPI1_RST_SHIFT_RSTn); /* PORT3 peripheral is released from reset */ RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn); const port_pin_config_t port1_0_pin135_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SDO */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_0 (pin 135) is configured as LPSPI0_SDO */ PORT_SetPinConfig(PORT1, 0U, &port1_0_pin135_config); const port_pin_config_t port1_1_pin136_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SCK */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_1 (pin 136) is configured as LPSPI0_SCK */ PORT_SetPinConfig(PORT1, 1U, &port1_1_pin136_config); const port_pin_config_t port1_2_pin137_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SDI */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_2 (pin 137) is configured as LPSPI0_SDI */ PORT_SetPinConfig(PORT1, 2U, &port1_2_pin137_config); const port_pin_config_t port1_3_pin138_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_PCS0 */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_3 (pin 138) is configured as LPSPI0_PCS0 */ PORT_SetPinConfig(PORT1, 3U, &port1_3_pin138_config); const port_pin_config_t port3_10_pin96_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SCK */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_10 (pin 96) is configured as LPSPI1_SCK */ PORT_SetPinConfig(PORT3, 10U, &port3_10_pin96_config); const port_pin_config_t port3_11_pin95_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_PCS0 */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_11 (pin 95) is configured as LPSPI1_PCS0 */ PORT_SetPinConfig(PORT3, 11U, &port3_11_pin95_config); const port_pin_config_t port3_8_pin98_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SDO */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_8 (pin 98) is configured as LPSPI1_SDO */ PORT_SetPinConfig(PORT3, 8U, &port3_8_pin98_config); const port_pin_config_t port3_9_pin97_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SDI */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_9 (pin 97) is configured as LPSPI1_SDI */ PORT_SetPinConfig(PORT3, 9U, &port3_9_pin97_config); }   4.2 LPSPI初始化 初始化 LPSPI 模块。使用 LPSPI_MasterGetDefaultConfig() 获取初始值,并根据需要进行修改。 lpspi_master_config_t masterConfig; LPSPI_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate = 500000U; LPSPI_MasterInit(LPSPI0, &masterConfig, CLOCK_GetFreq(kCLOCK_CoreSysClk));   4.3句柄定义 在 MCUXpresso SDK 驱动程序中,“句柄”是一个常用术语,指的是用于间接引用和操作资源的标识符。使用 eDMA 时,还需要为每个通道创建一个句柄,并将其传递给 LPSPI 驱动程序。此外,还可以通过传递函数指针来设置回调函数(SPI 传输完成后调用的函数)。 edma_handle_t txHandle; edma_handle_t rxHandle; lpspi_master_edma_handle_t lpspiEdmaHandle; EDMA_CreateHandle(&txHandle, DMA0, 0); EDMA_CreateHandle(&rxHandle, DMA0, 1); LPSPI_MasterTransferCreateHandleEDMA( LPSPI0, &lpspiEdmaHandle, lpspi_master_callback, NULL, &txHandle, &rxHandle );   4.4传输缓冲区和传输设置 指定具体的传输细节(缓冲区地址、传输大小)。 /*Start master transfer*/ masterXfer.txData = masterTxData; masterXfer.rxData = NULL; masterXfer.dataSize = TRANSFER_SIZE; isTransferCompleted = false;   4.5 开始 SPI传输 SPI 数据传输即将开始。此API以非阻塞方式运行。函数调用结束后, CPU将立即恢复并能够继续执行其他进程。 LPSPI_MasterTransferEDMALite(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_edma_handle,&masterXfer);   4.6回调的概念 DMA传输设计为通过回调接收完成通知,而不是等待处理完成。这使得可以在主循环或任务端执行完成确认。在RTOS环境中,这可以用信号量或事件通知来替代。 volatile bool g_transferComplete = false; void lpspi_master_callback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *userData) { if (status == kStatus_Success) { g_transferComplete = true; } }   5.常见的绊脚石 以下是每个项目常见障碍的总结。 (1)未返回数据 MOSI/MISO接线错误 引脚分配设置错误 与其他设备时序不匹配(如果从设备未先准备就绪,则传输和接收将无法正常工作)。 (2)无时钟信号 LPSPI模块时钟已禁用 PCS 的管控未达到预期效果。 (3)DMA传输未完成 DMA通道配置错误 回调注册失败 传输尺寸不匹配 (4)CS无法控制 PCS配置标志(configFlags)不正确。 另一台设备的极性设置不兼容。 (5)接收到的数据已损坏 时钟设置太快了。 FIFO/DMA/缓冲区大小不一致。 线路质量或信号波形存在问题。   6.总结   LPSPI 是 MCX A153 中实现 SPI 通信的主要串行通信模块,其设计注重低功耗和 DMA 集成。实际使用时,不仅需要正确配置 LPSPI 设置,还需要正确配置引脚设置和时钟设置。 此外,借助 MCUXpresso SDK,可以轻松实现基于 eDMA 的非阻塞通信。这使得 CPU 可以执行其他任务而无需受通信处理的限制,从而提高系统整体效率。 ========================= 即使您在本文的“评论”栏留言,我们目前也无法回复。 给您带来不便,我们深感抱歉。请在询问时参阅“NXP技术问题-联系方式(日本博客)”。 (如果您已经是NXP的代理商或与其有合作关系,可以直接向负责人咨询。) 本文 旨在为 NXP 产品新手工程师介绍 MCX A153 上的 LPSPI( 低 功耗 串行 外设 接口 ) 基本概念 以及 如何使用 MCUXpresso SDK 实现该接口。 首先,我们将概述硬件,然后以 FRDM-MCXA153 开发板为基础,通过代码示例讲解如何使用MCUXpresso SDK。 (阅读时间:20分钟) MCX 日本博客
View full article
[MCX A153] GPIO入門ガイド(日本語ブログ) 本記事では、MCX A153 に搭載されている GPIO (General Purpose Input/Output) の基本概念を解説します。またFRDM-MCXA153ボードをベースに、MCUXpresso SDK を用いたソフトウェアの実装方法を、初めてNXP製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後MCUXpresso SDKの使い方をコードスニペットとともに説明します。 (読了時間:20分) 1. GPIOモジュールの概要   1.1 GPIOの役割 GPIOは、マイコンのピンを「入力」または「出力」として制御するための最も基本的なインターフェースです。 例えば、FRDM-MCXA153においては、3色RGB LEDが以下のGPIOにそれぞれ配線されているため、GPIOを制御することで、LEDのON/OFFを切り替えることが可能です。   赤 : P3_12 緑 : P3_13 青 : P3_0 1.2 MCX A153におけるピンの制御機能 MCX A153では、ピンの制御機能は以下の2つのモジュールに分かれて管理されます。 (1) PORTモジュール 主に以下の役割を持ちます。1つのピンは複数の機能を持つため、GPIOとして使うにはPORT設定が必要です。 ピンの機能選択(GPIO / UART / SPI / I2C / PWM など) プルアップ/プルダウン設定 ドライブ能力設定   (2) GPIOモジュール 主に以下の役割を持ちます。 入出力データの制御 ピンのHigh/Low出力 入力状態の読み取り 「PORT = ピン設定」「GPIO = 実際の入出力操作」といった具合です。   2. GPIOの基本動作 GPIOモジュールには、出力モードと入力モードがあり、それぞれ以下の動作が可能です。 (1) 出力モード 以下の処理が可能 High出力 Low出力 トグル(現在の出力を反転) (2) 入力モード 以下の処理が可能 ピン電圧状態の読み取り(High or Low) 割り込み検知(立ち上がり/立ち下がり)   3. SDKドライバの基本フロー   GPIOを使用するためには、ソフトウェアによって以下の設定が必要となります。 - クロック設定 - ピン設定(PORTの設定) - 入力、または出力設定(GPIOの設定) - 割り込み設定(必要に応じて) MCUXpresso SDKのサンプルプロジェクトを例に、ドライバの使用方法を紹介します。    3.1 出力モード 以下のプロジェクトを参考に、説明します。 参考URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/gpio/led_output/gpio_led_output.c at main · nxp-mcuxpresso...   3.1.1 初期化 まず、クロック、PORT、GPIOを赤色LED向けに初期化します。 #include "fsl_gpio.h" #include "fsl_port.h" // 赤色LEDに配線されたピンのパラメータ #define BOARD_INITPINS_LED_RED_PORT PORT3 #define BOARD_INITPINS_LED_RED_GPIO GPIO3 #define BOARD_INITPINS_LED_RED_PIN 12 void init_gpio(void) { // クロック有効化 CLOCK_EnableClock(kCLOCK_GateGPIO3); // PORT設定 const port_pin_config_t LED_RED = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as P3_12 */ kPORT_MuxAlt0, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; PORT_SetPinConfig(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, &LED_RED); // GPIO設定 gpio_pin_config_t LED_RED_config = { .pinDirection = kGPIO_DigitalOutput, .outputLogic = 0U }; GPIO_PinInit(BOARD_INITPINS_LED_RED_GPIO, BOARD_INITPINS_LED_RED_PIN, &LED_RED_config); }   3.1.2 出力操作(LED点灯/消灯/トグル) 出力値は以下のAPIによって、変更可能です。 GPIO_PinWrite(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, 1); // High GPIO_PinWrite(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, 0); // Low GPIO_PortToggle(BOARD_INITPINS_LED_RED_PORT, 1U << BOARD_INITPINS_LED_RED_PIN); // Toggle   3.2 入力モード 以下のプロジェクトを参考に、説明します。 参考URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/gpio/input_interrupt/gpio_input_interrupt.c at main · nxp-mcuxpresso...   3.2.1 初期化 出力モードと引数以外同じなので、省略します。    3.2.2 入力読み取り 入力値は以下のAPIによって、読み取り可能です。 uint32_t value = GPIO_PinRead(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN); if (value == 0) { // スイッチ押下(プルアップの場合) }   3.2.3 割り込み設定 立ち下り信号を、GPIO割り込みとして設定する場合は、以下のAPIを使用します。EnableIRQは、Cortex-M側の割り込み許可設定です。 GPIO_SetPinInterruptConfig(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, kGPIO_InterruptFallingEdge); EnableIRQ(BOARD_SW_IRQ); 割り込み発生時の処理は、割り込みハンドラとして、関数定義が必要です。 割り込みフラグをクリアしないと、割り込みが永久に入り続けるので、注意が必要です。 void BOARD_SW_IRQ_HANDLER(void) { /* 割り込みフラグをクリア */ GPIO_GpioClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN); // 処理 SDK_ISR_EXIT_BARRIER; } 割り込みが発生するまでの流れを以下に示します。 以上が、MCUXpresso SDKを用いた、GPIOドライバの使用方法となります。   4. よくあるつまづき もしソースコードを変更して、GPIOが期待通りに動作しない場合は、以下の項目を確認してみてください。 ピンが他の役割として設定されている → ピンがGPIOに割り当てられているかPORT設定確認 クロック未有効 → CLOCK_EnableClockを呼び出しているか確認 ピン番号の間違い → ハードウェアのピン番号と一致しているか確認 GPIO割り込みが入らない → EnableIRQでCortex-M側でも、割り込みを許可している確認 GPIO割り込みがループする → 割り込みフラグがクリアされているか確認   5. まとめ   MCX A153のGPIOは、PORTモジュールによるピン設定とGPIOモジュールによる入出力制御の2段構成で動作します。 そのため、GPIOとしてピンを使用する場合は、まずPORTモジュールでピンの割り当て設定を行い、GPIO機能を選択する必要があります。その後、GPIOモジュールを用いて入力または出力として初期化し、LEDの点灯・消灯やスイッチの状態読み取りといった操作を行います。 MCUXpresso SDKを利用すると、これらの設定や制御をライブラリAPI経由で簡潔に実装できます。 また、GPIO割り込み機能を利用することで、スイッチ押下などのイベントを効率よく検出することも可能です。GPIOが期待どおりに動作しない場合は、PORT設定の有無、対象PORTのクロック有効化、そしてピン番号の設定が正しいかを確認して下さい。   ========================= 本投稿の「Comment」欄にコメントをいただいても、現在返信に対応しておりません。 お手数をおかけしますが、お問い合わせの際には「NXPへの技術質問 - 問い合わせ方法 (日本語ブログ)」をご参照ください。 (既に弊社NXP代理店、もしくはNXPとお付き合いのある方は、直接担当者へご質問いただいてもかまいません。) 本記事では、MCX A153 に搭載されている GPIO (General Purpose Input/Output) の基本概念を解説します。またFRDM-MCXA153ボードをベースに、MCUXpresso SDK を用いたソフトウェアの実装方法を、初めてNXP製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後MCUXpresso SDKの使い方をコードスニペットとともに説明します。 (読了時間:20分) MCX 日本語ブログ
View full article
[MCX A153] LPUART入門ガイド(日本語ブログ) 本記事では、MCX A153 に搭載されている LPUART(Low Power Universal Asynchronous Receiver/Transmitter) の基本概念と、MCUXpresso SDK を用いた使用方法を、初めて NXP 製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後FRDM-MCXA153ボードをベースに、MCUXpresso SDK API の使い方をコードスニペットとともに説明します。 (読了:20分) 1. LPUART モジュール概要 LPUART は、非同期シリアル通信を実現するためのモジュールです。ここでは代表的な特徴を順に見ていきます。   非同期通信(スタートビット/ストップビット) LPUART はクロック線を使わず、データに含まれるスタートビットとストップビットでタイミングを判断します。配線が TX と RX の 2 本だけで済むため、PC との通信、センサーとの接続、デバッグログの出力など、異なる機器同士を簡単につなぐ用途に広く使われています。 割り込み/DMA対応 LPUART は、CPU が 1 バイトずつデータを処理するのではなく、ハードウェアが自動でデータ転送を補助する仕組みを備えています。割り込みを使えばイベント発生時にのみ CPU が処理を行い、DMA を使えば CPU を介さずにメモリとの間でデータを転送できます。DMA 連携を前提とした設計になっているため、高速な通信でも CPU 負荷を最小限に抑えることができます。 FIFO(バッファ)内蔵 LPUART は内部に送受信用のバッファ、いわゆる FIFO を持っています。データを一時的に蓄積できるため、通信速度と CPU や DMA の処理速度との差を吸収することができます。DMA と組み合わせることで、途切れのない連続通信が実現しやすくなります。 低消費電力動作 通常の UART よりも低消費電力で動作するよう設計されており、スリープ中でも動作を継続できるケースがあります。クロック制御と密接に連携しているため、バッテリー駆動の機器や IoT 用途で特に有用です。 複数インスタンス対応 MCU 内に LPUART を複数搭載しており、同時に複数の通信を行うことができます。デバッグ用途とセンサー通信用途を分けるなど、インスタンスごとに役割を切り分けて利用できます。 2. ソフトウェア構成(MCUXpresso SDK) MCUXpresso SDK では、LPUART を扱うドライバとしてポーリング、割り込み、eDMA の 3 種類が提供されています。 実務では、小規模な通信であれば割り込み方式で十分ですが、高速かつ連続的な通信を扱う場合は eDMA を利用します。CPU に負荷を与えたくないアプリケーションでは、最初から eDMA を使う前提で設計しておくと後々の変更が少なくて済みます。したがって、本記事では、DMAを使用する前提で話を進めます。 3. FIFO の役割と DMA DMA を正しく使うためには、まず FIFO の動作を理解することが重要です。LPUART は内部に FIFO(First-In First-Out バッファ)を持っており、送信データの一時保持、受信データの一時蓄積、そして LPUART と DMA の間に生じる速度差の吸収という役割を担っています。 DMA との連携では、受信側では LPUART が受け取ったデータが RX FIFO に蓄積され、しきい値に達したタイミングで DMA が RX FIFO からメモリへデータを転送します。送信側では、DMA がメモリから TX FIFO へデータを書き込み、LPUART が TX FIFO から順次取り出して送信します。こうした仕組みによって、DMA 転送の完了を待たずにハードウェア側で連続的にデータを受け渡すことができ、スループットを止めずに通信を継続できます。 DMA の動きを図解すると、以下のようになります。 LPUART を DMA で使う際には、LPUART の TX/RX 要求を eDMA のどのチャネルに流し込むかを決めるために、チャネル MUX の設定が必要になります。 MCX A153 では、他ファミリーで見られるような独立した DMAMUX ペリフェラルは存在せず、eDMA コントローラの各チャネルが内蔵するチャネル MUX(CHn_MUX レジスタ)で、どの周辺機能の DMA 要求ソースを受け付けるかを選択します。SDK からは EDMA_SetChannelMux() API を使ってチャネルごとに要求ソースを割り当てます(具体的な呼び出し方は 4 章で紹介します)。チャネル番号は固定ではなく、アプリケーションの用途に応じて自由に切り替えられます。 下図は、周辺機能側の多数の DMA 要求ソースが、eDMA 各チャネルに内蔵されたチャネル MUX セレクタを介してチャネル本体に接続される様子を示したものです。 上図では、 EDMA_SetChannelMux によって LPUART0 TX を Channel 0、LPUART0 RX を Channel 1 に割り当てた例を実線で示しています。点線は選択肢として存在する接続候補で、API 呼び出し時の引数を書き換えることで、たとえば LPUART0 TX を Channel 2 に割り当てるといった変更も可能です。 4. SDK ドライバの基本フロー 次に、MCUXpresso SDK のサンプルプロジェクト “lpuart_edma_transfer” を例に、ドライバの使用方法を紹介します。 参考URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/lpuart/edma_transfer/lpuart_edma_transfer.c LPUART と DMA を組み合わせて使う際の基本ステップは、次の 7 つです。 クロックを有効化する ピン MUX を設定する LPUART を初期化する eDMA のチャネル MUX を設定する DMA ハンドルを生成する 送信/受信を開始する コールバックで次の処理を制御する 以降では、コードスニペットを交えながら、各ステップを具体的に説明していきます。 4.1 クロック・ポート設定 まず LPUART モジュールのクロックを有効化します。 CLOCK_EnableClock(kCLOCK_Lpuart0); 続いて、TX と RX に使用するピンの MUX を設定します。 PORT_SetPinMux(PORTA, 1U, kPORT_MuxAlt2); // TX PORT_SetPinMux(PORTA, 2U, kPORT_MuxAlt2); // RX GND を除くと、UART の配線は送信と受信の 2 本だけです。FRDM-MCXA153 の回路図では、LPUART0 の TXD と RXD が MCU-LINK の Virtual COM に接続されており、MCU-Link を PC と USB で接続することで、UART 通信を経由したデバッグが可能になります。 flowchart LR PC[PC] <-->|USB| MCULINK[MCU-LINK Virtual COM] MCULINK <-->|UART| LPUART0[MCXA153 LPUART0]   4.2 LPUART 初期化 LPUART の初期化は、まずデフォルト設定を取得してから必要な項目を変更する流れになります。 lpuart_config_t config; LPUART_GetDefaultConfig(&config); config.baudRate_Bps = 115200; config.enableTx = true; config.enableRx = true; LPUART_Init(LPUART0, &config, CLOCK_GetFreq(kCLOCK_CoreSysClk)); ボーレートは LPUART に供給されるクロック周波数に依存して決まるため、 CLOCK_GetFreq() で正しいクロックソースの周波数を渡す必要があります。TX と RX の有効化は、用途に応じて変更してください。 4.3 eDMA チャネル MUX 設定 ハンドルを生成する前に、LPUART の TX/RX 要求を eDMA のどのチャネルに流し込むかを EDMA_SetChannelMux で指定しておきます。3 章で説明したとおり、MCX A153 では独立 DMAMUX は存在せず、この API で各チャネルの CHn_MUX レジスタに要求ソースを設定します。 /* LPUART0 TX を eDMA の任意チャネル(例: CH0)に割り当てる */ EDMA_SetChannelMux(DMA0, LPUART_TX_DMA_CHANNEL, kDma0RequestMuxLPUART0Tx); /* LPUART0 RX を eDMA の任意チャネル(例: CH1)に割り当てる */ EDMA_SetChannelMux(DMA0, LPUART_RX_DMA_CHANNEL, kDma0RequestMuxLPUART0Rx); ここで指定するチャネル番号は、後続の DMA ハンドル生成時に txEdmaHandle / rxEdmaHandle に渡すチャネル番号と一致している必要があります。 4.4 DMA ハンドル生成 LPUART と DMA を結びつけるハンドルを生成し、通信完了時に呼び出されるコールバック関数をここで登録します。 lpuart_edma_handle_t g_lpuartEdmaHandle; LPUART_TransferCreateHandleEDMA(LPUART0, &g_lpuartEdmaHandle, lpuart_callback, userData, &txEdmaHandle, &rxEdmaHandle); このハンドルによって LPUART と DMA の TX/RX チャネルが関連付けられ、以降の送受信 API で利用されます。 4.5 送信(DMA) 送信は、送信バッファとサイズを lpuart_transfer_t に設定して API を呼び出すだけです。 lpuart_transfer_t xfer; xfer.data = txBuffer; xfer.dataSize = txSize; LPUART_TransferSendEDMA(LPUART0, &g_lpuartEdmaHandle, &xfer);   4.6 受信(DMA) 受信も同様に、受信バッファとサイズを指定して呼び出します。 lpuart_transfer_t xfer; xfer.data = rxBuffer; xfer.dataSize = rxSize; LPUART_TransferReceiveEDMA(LPUART0, &g_lpuartEdmaHandle, &xfer);   4.7 コールバック実装 コールバック関数を介して、通信の完了がアプリケーションに通知されます。 void lpuart_callback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData) { if (status == kStatus_LPUART_TxIdle) { // 送信完了処理 } else if (status == kStatus_LPUART_RxIdle) { // 受信完了処理 } } kStatus_LPUART_TxIdle は DMA による送信の完了、 kStatus_LPUART_RxIdle は DMA による受信の完了を示します。連続して受信を続けたい場合は、このコールバック内で再度 LPUART_TransferReceiveEDMA() を呼び出すことで、受信を途切れさせずに継続できます。   4.8 重要な設計ポイント 実際に LPUART と DMA を組み合わせて使う際には、いくつか押さえておきたい設計上の観点があります。 まず転送サイズです。1 回の転送サイズが小さすぎると割り込み回数が増えて CPU 効率が低下し、大きすぎると転送完了までのレイテンシが大きくなります。FIFO のサイズを意識しながら、アプリケーションの要求に合わせて適切な値を選ぶ必要があります。 次に受信バッファの設計です。受信長があらかじめ決まっている場合は固定長バッファで十分ですが、不定長のデータを受け続ける場合はリングバッファを用いるのが一般的です。 最後にコールバック処理です。コールバックは転送完了をアプリケーションに通知するだけでなく、次の DMA 転送を再設定するトリガーにもなります。連続通信を安定して回すうえで、ここの実装が最も重要な部分になります。 5. よくあるトラブル   5.1 DMA が動かない DMA クロックが有効化されていない、 EDMA_SetChannelMux で指定した要求ソースが LPUART の TX/RX と合っていない、あるいは LPUART ドライバに渡したチャネル番号と EDMA_SetChannelMux で設定したチャネル番号が一致していない、といった原因が考えられます。まずクロックの有効化と、チャネル MUX の割り当ての一致を確認するのが近道です。 5.2 データ欠落 FIFO のオーバーランや、転送サイズの設定が実際のデータ量に合っていないケースが典型的です。FIFO しきい値と DMA の転送単位の関係を見直してください。 5.3 高速通信で破綻 ボーレートを上げていくと、FIFO のアンダーラン、バッファ設計の不足、波形品質の低下、クロック誤差といった要因が顕在化してきます。ハードウェア側の信号品質と、ソフトウェア側のバッファ供給能力の両面から原因を切り分ける必要があります。 6. まとめ LPUART を実務で使いこなすうえで最も重要なのは、FIFO の役割を正しく理解し、DMA との連携を踏まえてデータバッファを設計することです。これらを押さえておけば、低消費電力かつ CPU 負荷の小さい、安定した UART 通信を実現することができます。 ========================= 本投稿の「Comment」欄にコメントをいただいても、現在返信に対応しておりません。 お手数をおかけしますが、お問い合わせの際には「NXPへの技術質問 - 問い合わせ方法 (日本語ブログ)」をご参照ください。 (既に弊社 NXP 代理店、もしくは NXP とお付き合いのある方は、直接担当者へご質問いただいてもかまいません。) 本記事では、MCX A153 に搭載されている LPUART(Low Power Universal Asynchronous Receiver/Transmitter) の基本概念と、MCUXpresso SDK を用いた使用方法を、初めて NXP 製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後FRDM-MCXA153ボードをベースに、MCUXpresso SDK API の使い方をコードスニペットとともに説明します。 (読了:20分) MCUXpresso SDK MCX 日本語ブログ
View full article
[MCX A153] eDMA Introduction Guide (Japanese Blog) This article explains the basic concepts of eDMA( Enhanced Direct Memory Access ) on the MCX A153 and how to use it with the MCUXpresso SDK , aimed at engineers who are new to NXP products. First, we will explain the hardware overview, and then, using the FRDM-MCXA153 board as a base, we will explain how to use the MCUXpresso SDK with code snippets. (Reading time: 20 minutes)   1. What is eDMA?   eDMA is hardware that transfers data between memory and peripherals, or between memory devices, without involving the CPU. When data transfer is performed by the CPU, the CPU itself needs to repeatedly read the data from the source and write it to the destination. Therefore, the CPU load increases as the amount of data transferred increases. On the other hand, when using eDMA, the CPU only needs to set the transfer conditions (source address, destination address, transfer size, etc.) and start eDMA. Since the actual data transfer is performed by the eDMA hardware, the CPU can perform other tasks in parallel, such as communication processing and application processing. This has a significant effect on reducing CPU load and improving real-time performance, especially in applications that involve continuous data transfer such as UART and SPI. Typical uses of eDMA include the following: ADC conversion results are automatically stored in RAM. LPUART received data is stored in RAM. Transfer LPSPI transmission data to FIFO Copying from external Flash to TCM (Tightly Coupled Memory) Periodic transfer combined with PWM or timer 2. eDMA configuration of MCX A153   The MCXA153 features four eDMA channels , each operating independently. Forwarding requests to each channel can be issued, for example, from the following: LPUART LPSPI LPI2C ADC CTIMER FlexPWM Software Requirements 3. Basic Concepts of eDMA   3.1 TCD   Understanding the TCD (Transfer Control Descriptor) is crucial when considering eDMA settings . A TCD is a transfer descriptor that defines "where to transfer from, where to transfer from, how many bytes to transfer, and how many times to transfer." eDMA operates according to the TCD. Typical TCD parameters are shown below.   item meaning SADDR Source address DADDR Destination Address SOFF Source address increment per transfer DOFF Destination increment per transfer NBYTES Minor Loop Size CITER Remaining Major Loops BITER Initial Major Loop Count SLAST Source correction value after transfer is complete DLASTSGA Destination correction value after transfer is complete 3.2.Minor Loop and Major Loop   This is the part that causes the most confusion for people using eDMA for the first time.   Minor Loop   This refers to the amount of data transferred in a single DMA request. For example, if NBYTES is set to 4, 4 bytes of data will be transferred each time a DMA request occurs. In other words, Minor Loop is a parameter that represents the "amount of data transferred per DMA request".   Major Loop   This refers to the number of times the Minor Loop is repeated. For example, if NBYTES is set to 4 and BITER to 100, the DMA will repeat the transfer of 4 bytes 100 times. As a result, a total of 400 bytes of data will be transferred. In short, Major Loop is a parameter that represents "how many times the Minor Loop is repeated".   3.3.Understanding eDMA through pseudocode The operation of eDMA can be easier to understand if you think of it as follows: Please keep the following points in mind. NBYTES/SIZE is the number of Minor Loops BITER is the number of Major Loops SOFF/DOFF updates the address for each transfer. SLAST/DLAST allows data to be restored after transfer is complete ( this mechanism enables the implementation of a ring buffer). size_t *src,*dst; src=saddr; dst = daddr; for(citer = biter; citer>0; citer--) // major loop { for(i = 0; i 4. Basic Flow of SDK Drivers   To use eDMA, the following settings are required by the software: eDMA module initialization eDMA handle definition TCD settings Transfer execution This guide will demonstrate how to use the driver , using a sample project from the MCUXpresso SDK as an example . Reference URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/edma4/memory_to_memory/edma_memory_to_memory.c at main · nxp-mcuxpresso/mcuxsdk-examples   4.1 eDMA initialization This initializes the eDMA module. Obtain the initial values using EDMA_GetDefaultConfig() and modify them as needed. edma_config_t config; EDMA_GetDefaultConfig(&config); EDMA_Init(DMA0, &config); 4.2 Transfer Settings   This is the most important API in the SDK sample. edma_transfer_config_t transferConfig; EDMA_PrepareTransfer(&transferConfig, srcAddr, sizeof(srcAddr[0]), destAddr, sizeof(destAddr[0]), sizeof(destAddr), sizeof(destAddr), kEDMA_MemoryToMemory); EDMA_SetTransferConfig(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, &transferConfig, NULL); EnableIRQ(DMA_CH0_IRQn); Meaning of arguments:   argument meaning srcBuffer Source srcWidth Transfer unit dstBuffer Forwarding destination dstWidth Transfer unit minorBytes Minor Loop Size totalBytes Total transfer volume Type Transfer type 4.3 Transfer Start EDMA_TriggerChannelStart(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0); This will start the DMA operation.   4.4 Callback DMA transfers are designed to receive completion notifications via callbacks instead of waiting for processing to finish. This allows completion confirmation to be performed on the main loop or task side. In an RTOS environment, this can be replaced with semaphores or event notifications. /* EDMA transfer channel 0 IRQ handler */ void DMA_CH0_IRQHandler(void) { if ((EDMA_GetChannelStatusFlags(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0) & kEDMA_InterruptFlag) != 0U) { EDMA_ClearChannelStatusFlags(EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, kEDMA_InterruptFlag); g_Transfer_Done = true; } }     5. Common stumbling blocks Below is a summary of common stumbling blocks for each item. Transfer not starting Is the DMA initialized? Is the channel number correct? Stopped during transfer NBYTES settings BITER settings Alignment violation   Data corruption Transfer size (8/16/32bit) SOFF/DOFF setting Buffer size 6. Summary   The MCXA153's eDMA is a high-performance 4-channel DMA. Understanding the meaning of the TCD parameters is crucial. Many other introductory guides also introduce projects using eDMA , so please be sure to read them.     ========================= We are currently unable to respond to comments left in the "Comment" section of this post. We apologize for the inconvenience, but when making an inquiry, please use the subject line " Technical Questions to NXP". - How to contact us Please refer to the "( Japanese blog) " section. (If you are already an NXP distributor or have a relationship with NXP, you may ask your representative directly.) This article explains the basic concepts of eDMA( Enhanced Direct Memory Access ) on the MCX A153 and how to use it with the MCUXpresso SDK , aimed at engineers who are new to NXP products. First, we will explain the hardware overview, and then, using the FRDM-MCXA153 board as a base, we will explain how to use the MCUXpresso SDK with code snippets. MCX Japanese Blog
View full article
[MCX A153] LPSPI入門ガイド(日本語ブログ) 本記事では、MCX A153 に搭載されている LPSPI(Low Power Serial Peripheral Interface)の基本概念と、MCUXpresso SDK を用いた実装方法を、初めてNXP製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後FRDM-MCXA153ボードをベースに、MCUXpresso SDKの使い方をコードスニペットとともに説明します。 (読了:20分) 1. LPSPIモジュール概要   1.1 LPSPIとは   LPSPI は、外部デバイスとの同期シリアル通信を行うための周辺モジュールです。 ここでの "LP(Low Power)" とは「低消費電力で動作できる設計」 を意味します。   通常のSPIとの違い(Low Powerの視点) 一般的なSPIモジュールと比較したときの LPSPI の特徴は以下です。 低消費電力モード(Stop / Sleep)でも動作継続可能 DMA(eDMA)と連携し、CPU介在を減らすことでシステム全体の電力削減 ハードウェアトリガ(HREQなど)でCPUを起こさず通信開始が可能 LPSPI は「単にSPI通信ができる」だけではなく、 「システム全体を低消費電力で運用するための通信モジュール」として設計されています。   1.2 MCX A153における構成 MCX A153 には複数の LPSPI インスタンスがあり、例えば、以下のような信号が使用されます: CS (P1_3) SCK (P1_1) SDI (P1_2) SDO (P1_0) 2. LPSPIの基本動作   2.1 信号の役割 SPI通信では、基本的に以下の4線を使用して、通信します。 SPI通信には極性と位相によって、4つのモードがありますが、例えばモード0の場合、それぞれの信号は、以下のタイミングチャートに従います。   2.2 FIFOの役割 LPSPI は内部に FIFO を持っており、送信データ・受信データを一時的に保持できます。 これにより、CPU が 1 バイトずつ即時にレジスタ操作しなくても、ある程度まとめてデータを処理できます。さらに eDMA を組み合わせることで、FIFO へのデータ供給/取り出しを CPU の代わりに自動化できます。 3. DMA(eDMA)転送の基本概念   3.1 なぜ DMA を使うのか SPI で数バイトだけ送る用途なら単純なポーリングでも動作しますが、実際の組み込み開発では以下の要求が多くあります。 センサデータや表示データなどを連続転送したい CPU を通信待ちで止めたくない 他の制御処理や RTOS タスクと並行動作したい 通信処理の負荷を下げたい   ここで重要になる考え方が「ノンブロッキング(Non-blocking)」です。 ノンブロッキングとは、「処理の完了を待たずにすぐに関数が戻る動作」のことです。 例えば SPI 通信の場合、通常は以下のような2つの動作モデルがあります。 ブロッキング(Blocking) 送信関数を呼ぶと、通信が終わるまでCPUが待ち続ける 通信中は他の処理ができない ノンブロッキング(Non-blocking) 送信開始だけ行い、すぐに関数が戻る 実際の通信はバックグラウンド(DMAなど)で進む CPUはその間に他の処理を実行できる LPSPI + eDMA を使うと、データ転送の大部分をハードウェア側に任せることができるため、ノンブロッキング通信を実現する事が可能となります。   3.2 DMA転送の考え方 DMA 転送では、CPU は最初に「どこから送るか」「どこへ受けるか」「何バイト送るか」を設定し、転送開始を指示します。 その後は、LPSPI の FIFO 要求に応じて eDMA が自動的にデータ転送を進めます。CPU は待機せず、他の処理を続けることができます。   3.3 動作イメージ DMA転送時の流れは概ね以下の通りです。 CPU が LPSPI と eDMA を初期化 送信バッファ / 受信バッファ / サイズを設定 CPU が DMA転送開始を指示 eDMA が FIFO 要求に応じてデータを搬送 転送完了時にコールバックで通知  4. SDKドライバの基本フロー LPSPIを使用するためには、ソフトウェアによって以下の設定が必要となります。 クロック・ピンを設定 LPSPIモジュール初期化 eDMAハンドル定義 LPSPIハンドル生成 転送バッファ設定 転送実行 コールバックで完了確認 MCUXpresso SDKのサンプルプロジェクトを例に、ドライバの使用方法を紹介します。  以下のプロジェクトを参考に、説明します。 参考URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/lpspi/edma_transfer/lpspi_edma_transfer.cc at main · nxp-mcuxpresso/mcuxsdk-examples   4.1 クロック設定・ピン設定 まず、クロック、PORTをLPSPI0に初期化します。 クロック有効化を忘れると物理的に動きません。PORTの割り当て設定(MuxAlt)がLPSPI0に一致している事が重要です。 /* クロック有効化 */ void BOARD_InitHardware(void) { /* Attach peripheral clock */ CLOCK_SetClockDiv(kCLOCK_DivLPSPI0, 1u); CLOCK_AttachClk(kFRO12M_to_LPSPI0); } /* PORT設定 */ /* PORT1: Peripheral clock is enabled */ CLOCK_EnableClock(kCLOCK_GatePORT1); /* PORT3: Peripheral clock is enabled */ CLOCK_EnableClock(kCLOCK_GatePORT3); /* LPSPI0 peripheral is released from reset */ RESET_ReleasePeripheralReset(kLPSPI0_RST_SHIFT_RSTn); /* PORT1 peripheral is released from reset */ RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn); /* LPSPI1 peripheral is released from reset */ RESET_ReleasePeripheralReset(kLPSPI1_RST_SHIFT_RSTn); /* PORT3 peripheral is released from reset */ RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn); const port_pin_config_t port1_0_pin135_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SDO */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_0 (pin 135) is configured as LPSPI0_SDO */ PORT_SetPinConfig(PORT1, 0U, &port1_0_pin135_config); const port_pin_config_t port1_1_pin136_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SCK */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_1 (pin 136) is configured as LPSPI0_SCK */ PORT_SetPinConfig(PORT1, 1U, &port1_1_pin136_config); const port_pin_config_t port1_2_pin137_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_SDI */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_2 (pin 137) is configured as LPSPI0_SDI */ PORT_SetPinConfig(PORT1, 2U, &port1_2_pin137_config); const port_pin_config_t port1_3_pin138_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI0_PCS0 */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT1_3 (pin 138) is configured as LPSPI0_PCS0 */ PORT_SetPinConfig(PORT1, 3U, &port1_3_pin138_config); const port_pin_config_t port3_10_pin96_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SCK */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_10 (pin 96) is configured as LPSPI1_SCK */ PORT_SetPinConfig(PORT3, 10U, &port3_10_pin96_config); const port_pin_config_t port3_11_pin95_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_PCS0 */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_11 (pin 95) is configured as LPSPI1_PCS0 */ PORT_SetPinConfig(PORT3, 11U, &port3_11_pin95_config); const port_pin_config_t port3_8_pin98_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SDO */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_8 (pin 98) is configured as LPSPI1_SDO */ PORT_SetPinConfig(PORT3, 8U, &port3_8_pin98_config); const port_pin_config_t port3_9_pin97_config = {/* Internal pull-up/down resistor is disabled */ .pullSelect = kPORT_PullDisable, /* Low internal pull resistor value is selected. */ .pullValueSelect = kPORT_LowPullResistor, /* Fast slew rate is configured */ .slewRate = kPORT_FastSlewRate, /* Passive input filter is disabled */ .passiveFilterEnable = kPORT_PassiveFilterDisable, /* Open drain output is disabled */ .openDrainEnable = kPORT_OpenDrainDisable, /* Low drive strength is configured */ .driveStrength = kPORT_LowDriveStrength, /* Normal drive strength is configured */ .driveStrength1 = kPORT_NormalDriveStrength, /* Pin is configured as LPSPI1_SDI */ .mux = kPORT_MuxAlt2, /* Digital input enabled */ .inputBuffer = kPORT_InputBufferEnable, /* Digital input is not inverted */ .invertInput = kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ .lockRegister = kPORT_UnlockRegister}; /* PORT3_9 (pin 97) is configured as LPSPI1_SDI */ PORT_SetPinConfig(PORT3, 9U, &port3_9_pin97_config); }   4.2 LPSPI 初期化 LPSPIモジュールの初期化を行います。LPSPI_MasterGetDefaultConfig() で初期値を取得して、用途に応じて変更してください。 lpspi_master_config_t masterConfig; LPSPI_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate = 500000U; LPSPI_MasterInit(LPSPI0, &masterConfig, CLOCK_GetFreq(kCLOCK_CoreSysClk));   4.3 ハンドル定義 ハンドルは、MCUXpresso SDKのドライバではよく使われる単語であり、あるリソースを間接的に参照・操作するための識別子のことです。eDMAを使用する場合もチャンネルごとにハンドルを作り、それをLPSPIのドライバに渡す必要があります。関数ポインタを渡すことで、コールバック(SPI転送終了時に呼び出される関数)を設定することも出来ます。 edma_handle_t txHandle; edma_handle_t rxHandle; lpspi_master_edma_handle_t lpspiEdmaHandle; EDMA_CreateHandle(&txHandle, DMA0, 0); EDMA_CreateHandle(&rxHandle, DMA0, 1); LPSPI_MasterTransferCreateHandleEDMA( LPSPI0, &lpspiEdmaHandle, lpspi_master_callback, NULL, &txHandle, &rxHandle );   4.4 転送バッファと転送設定 具体的な転送内容(バッファのアドレス、転送サイズ)を指定します。 /*Start master transfer*/ masterXfer.txData = masterTxData; masterXfer.rxData = NULL; masterXfer.dataSize = TRANSFER_SIZE; isTransferCompleted = false;   4.5 SPI転送開始 SPI転送を開始します。この API はノンブロッキングで動作します。関数呼び出し後、CPU はすぐに復帰し、他の処理を継続できます。 LPSPI_MasterTransferEDMALite(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_edma_handle,&masterXfer);   4.6 コールバックの考え方 DMA 転送では、処理完了を待つ代わりにコールバックで完了を受け取る設計にします。これにより、メインループ側やタスク側で完了確認が可能です。RTOS 環境ならセマフォやイベント通知に置き換え可能です。 volatile bool g_transferComplete = false; void lpspi_master_callback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *userData) { if (status == kStatus_Success) { g_transferComplete = true; } }   5. よくあるつまずき 以下に各項目ごとに、つまずきがちなポイントをまとめました。 (1) データが返らない MOSI / MISO の配線ミス ピン割り当て設定ミス 相手デバイスとのタイミングミスマッチ(スレーブが先に待機しないと、正常に送受信できません) (2) クロックが出ない LPSPI モジュールクロック未有効 PCS が期待どおり制御されていない (3) DMA転送が完了しない DMA チャネル設定ミス コールバック登録漏れ 転送サイズ不一致 (4) CS が制御できない PCS 設定フラグ(configFlags)不備 相手デバイス側の極性設定と不一致 (5) 受信データが崩れる クロック設定が速すぎる FIFO / DMA / バッファサイズの整合が取れていない 配線品質や信号波形に問題がある   6. まとめ   LPSPI は、MCX A153 における SPI 通信を実現するための主要なシリアル通信モジュールであり、低消費電力動作や DMA 連携を考慮して設計されています。実際に使用する際には、LPSPI の設定だけでなく、ピン設定、やクロック設定を正しく行うことが重要です。 また、MCUXpresso SDKを利用することで、eDMA を用いたノンブロッキング通信を容易に実装できます。これにより、CPU は通信処理に拘束されることなく他の処理を実行でき、システム全体の効率向上につながります。 ========================= 本投稿の「Comment」欄にコメントをいただいても、現在返信に対応しておりません。 お手数をおかけしますが、お問い合わせの際には「NXPへの技術質問 - 問い合わせ方法 (日本語ブログ)」をご参照ください。 (既に弊社NXP代理店、もしくはNXPとお付き合いのある方は、直接担当者へご質問いただいてもかまいません。) 本記事では、MCX A153 に搭載されている LPSPI(Low Power Serial Peripheral Interface)の基本概念と、MCUXpresso SDK を用いた実装方法を、初めてNXP製品を扱うエンジニア向けに解説します。まずハードウェアの概要を説明し、その後FRDM-MCXA153ボードをベースに、MCUXpresso SDKの使い方をコードスニペットとともに説明します。 (読了:20分) MCX 日本語ブログ
View full article
Quick Guide on Booting i.MX95 with ND/LD Mode On i.MX95, OD, ND, and LD represent different system operating modes used to balance performance and power consumption. OD (OverDrive) mode targets the highest performance, allowing higher clock frequencies with a higher SoC supply voltage. ND (Nominal Drive) mode provides the standard operating point for normal performance and power efficiency. LD (Low Drive) mode is intended for lower-power operation, reducing voltage and limiting clock frequencies to save energy. In practice, switching between these modes involves coordinated changes of VDD_SOC, system clocks, and DDR operating frequency so that the device can move between high-performance and low-power states safely and efficiently. Here is a table about the Maximum frequency of modules of different modes. OverDrive Mode Nominal Mode LowDrive Mode VDD_SOC (typical) 0.9 V 0.85 V 0.8 V VDD_ARM (typical) 0.9 V 0.85 V 0.8 V A55 frequency 1800 MHz 1400 MHz 900 MHz NPU frequency 1000 MHz 800 MHz 500 MHz ISI frequency 667 MHz 500 MHz 333 MHz GPU frequency 500 MHz 500 MHz 500 MHz Display frequency 800 MHz 666 MHz 400 MHz VPU frequency 666 MHz 500 MHz 333 MHz To achieve the corresponding status in different modes, three actions needed to be taken Change SoC driving mode in system manager Set ddr rate in OEI image Compile bootloader in mkimage 1.1 Change the SoC driving mode in system manager 1. First, clone the repository to your local machine and build the m33_image.bin. Refer to the README.md file in the repository for detailed build instructions and additional information. git clone https://github.com/nxp-imx/imx-sm.git export TOOLS=~/tools  # toolchain download link here, export your own path: make config=mx95evk cfg​ make config=mx95evk all​ 2.Here are the code changes for ND mode​ and LD mode in system manager ND: Diff --git a/boards/mcimx95evk/sm/brd_sm.c b/boards/mcimx95evk/sm/brd_sm.c​ --- a/boards/mcimx95evk/sm/brd_sm.c​ +++ b/boards/mcimx95evk/sm/brd_sm.c​ @@ -104,7 +104,7 @@​ BRD_SM_REC_VLD_MASK)​ /* Performance parameters */​ -#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_ODV /* Target perf level */​ +#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_NOM /* Target perf level */​ diff --git a/devices/MIMX95/sm/dev_sm_perf.c b/devices/MIMX95/sm/dev_sm_perf.c index 8aafdce9..26d6da11 100644 --- a/devices/MIMX95/sm/dev_sm_perf.c +++ b/devices/MIMX95/sm/dev_sm_perf.c @@ -2704,7 +2704,8 @@ static void DEV_SM_PerfCfgInit(void)      else      {          /* All other devices support PRK, LOW, NOM, ODV setpoints */ -        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 1U; +        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 2U;      }      /* Check for LPDDR4X */ LD: diff --git a/boards/mcimx95evk/sm/brd_sm.c b/boards/mcimx95evk/sm/brd_sm.c​ --- a/boards/mcimx95evk/sm/brd_sm.c​ +++ b/boards/mcimx95evk/sm/brd_sm.c​ @@ -104,7 +104,7 @@​ BRD_SM_REC_VLD_MASK)​ /* Performance parameters */​ -#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_ODV /* Target perf level */​ +#define BOARD_PERF_LEVEL DEV_SM_PERF_LVL_LOW /* Target perf level */ diff --git a/devices/MIMX95/sm/dev_sm_perf.c b/devices/MIMX95/sm/dev_sm_perf.c index 8aafdce9..26d6da11 100644 --- a/devices/MIMX95/sm/dev_sm_perf.c +++ b/devices/MIMX95/sm/dev_sm_perf.c @@ -2704,7 +2704,8 @@ static void DEV_SM_PerfCfgInit(void)      else      {          /* All other devices support PRK, LOW, NOM, ODV setpoints */ -        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 1U; +        s_perfNumLevels[PS_VDD_ARM] = DEV_SM_NUM_PERF_LVL_ARM - 3U;      }      /* Check for LPDDR4X */ Compile the SM binary to generate build/mx95lp5/ddr/m33_image.bin, then copy it to imx-mkimage/iMX95/m33_image.bin. 1.2. Change the SoC driving mode in system manager 1.First, clone the repository to your local machine and build the m33-oei-ddr.bin. Refer to the README.md file in the repository for detailed build instructions and additional information. git clone https://github.com/nxp-imx/imx-oei.git export TOOLS=~/tools make board=mx95lp5 oei=ddr DEBUG=1 r=B0 2. Please replace the a/boards/mx95lp5/ddr/ cMIMX95_LPDDR5_EVK_19X19_6400MTS_FW2024.09_timing.c file with a file corresponding to a different DDR data rate. For ND mode, the file is lpddr5_4800_timing.c (See in attachment) For LD mode, the file is lpddr5_3200_timing.c (See in attachment) Compile the OEI binary to generate build/mx95lp5/ddr/m33_image.bin, then copy it to imx-mkimage/iMX95/m33_image.bin. 1.3. Compile bootloader in mkimage 1.Setup the imx-mkimage​ mkdir imx-mkimage​ cd imx-mkimage/​ git clone https://github.com/nxp-imx/imx-mkimage.git git checkout 2. Compile flash.bin Refer to UG10163, section 4.5.13, to compile the files required by mkimage. Copy all the generated files to the imx-mkimage/iMX95 directory. Replace oei-m33-ddr.bin and m33_image.bin, then run the following command to generate flash.bin: make SOC=iMX95 OEI=YES flash_all ​ ​ The table describes the corresponding binaries: OEI image System manager (M33_image) OverDrive Mode Oei-m33-ddr-6400.bin​ M33_image_OD.bin​ Nominal Mode Oei-m33-ddr-4800.bin​ M33_image_ND.bin​ LowDrive Mode Oei-m33-ddr-3200.bin​ M33_image_LD.bin​ 3 .Flash the different flash.bin file to board with following command:​ ./uuu.exe –b emmc flash.bin​ 4. Open the BCU tool to check the VDD_SOC and VDD_ARM voltages. Then run the mhz command, and you will see that the current CPU frequency is being limited. On i.MX95, OD, ND, and LD represent different system operating modes used to balance performance and power consumption. OD (OverDrive) mode targets the highest performance, allowing higher clock frequencies with a higher SoC supply voltage. ND (Nominal Drive) mode provides the standard operating point for normal performance and power efficiency. LD (Low Drive) mode is intended for lower-power operation, reducing voltage and limiting clock frequencies to save energy. In practice, switching between these modes involves coordinated changes of VDD_SOC, system clocks, and DDR operating frequency so that the device can move between high-performance and low-power states safely and efficiently. Here is a table about the Maximum frequency of modules of different modes. OverDrive Mode Nominal Mode LowDrive Mode VDD_SOC (typical) 0.9 V 0.85 V 0.8 V VDD_ARM (typical) 0.9 V 0.85 V 0.8 V A55 frequency 1800 MHz 1400 MHz 900 MHz NPU frequency 1000 MHz 800 MHz 500 MHz ISI frequency 667 MHz 500 MHz 333 MHz GPU frequency 500 MHz 500 MHz 500 MHz Display frequency 800 MHz 666 MHz 400 MHz VPU frequency 666 MHz 500 MHz 333 MHz i.MX Processors Re: Quick Guide on Booting i.MX95 with ND/LD Mode There is another way to change ARM working mode: ( NOT include SoC Mode) mx95evk.cfg msel 0/1/2 OD->LD  PERF_A55 =3/3 - > PERF_A55 =3/1
View full article
[MCX A153] LPUART Introduction Guide (Japanese Blog) This article explains the basic concepts of LPUART ( Low Power Universal Asynchronous Receiver / Transmitter ) on the MCX A153 and how to use it with the MCUXpresso SDK, aimed at engineers who are new to NXP products. First, we will explain the hardware overview, and then, using the FRDM-MCXA153 board as a base, we will explain how to use the MCUXpresso SDK API with code snippets. (Reading time: 20 minutes) 1. LPUART Module Overview LPUART is a module for implementing asynchronous serial communication. Here, we will look at its key features in order.   Asynchronous communication (start bit/stop bit) LPUART does not use a clock line; instead, it determines timing using start and stop bits included in the data. Because it only requires two wires, TX and RX, it is widely used for easily connecting different devices, such as communicating with a PC, connecting to sensors, and outputting debug logs. Interrupt/DMA compatible LPUART features a mechanism where hardware automatically assists with data transfer, rather than the CPU processing data byte by byte. Using interrupts, the CPU only processes data when an event occurs, and using DMA, data can be transferred to and from memory without CPU intervention. Because it's designed with DMA integration in mind, CPU load can be minimized even during high-speed communication. Built-in FIFO (buffer) LPUART has an internal buffer for sending and receiving data, also known as a FIFO. Because it can temporarily store data, it can absorb the difference between the communication speed and the processing speed of the CPU or DMA. When combined with DMA, it makes it easier to achieve uninterrupted, continuous communication. Low power operation Designed to operate with lower power consumption than a standard UART, it can sometimes continue operating even while in sleep mode. Because it works closely with clock control, it is particularly useful for battery-powered devices and IoT applications. Supports multiple instances The MCU has multiple LPUARTs, allowing for simultaneous communication of multiple devices. This enables you to separate roles for each instance, such as separating debugging and sensor communication. 2. Software Configuration (MCUXpresso SDK) The MCUXpresso SDK provides three types of drivers for handling LPUART: polling, interrupt, and eDMA. In practical applications, interrupt-based communication is sufficient for small-scale communications, but eDMA is used for high-speed, continuous communications. For applications where you don't want to burden the CPU, designing with eDMA in mind from the start will minimize future changes. Therefore, this article will proceed on the assumption that DMA is being used. 3. The role of FIFO and DMA To use DMA correctly, it's essential to first understand how FIFOs work. LPUART has an internal FIFO (First-In First-Out buffer) that plays the role of temporarily holding transmitted data, temporarily storing received data, and absorbing the speed difference that occurs between LPUART and DMA. In DMA integration, on the receiving side, data received by the LPUART is stored in the RX FIFO, and when a threshold is reached, the DMA transfers the data from the RX FIFO to memory. On the transmitting side, the DMA writes data from memory to the TX FIFO, and the LPUART sequentially retrieves and transmits the data from the TX FIFO. This mechanism allows for continuous data transfer on the hardware side without waiting for the DMA transfer to complete, enabling continuous communication without interrupting throughput. The operation of DMA can be illustrated as follows: When using LPUART with DMA, you need to configure the channel MUX to determine which eDMA channel the LPUART's TX/RX requests should be routed through. In the MCX A153, there is no separate DMAMUX peripheral as seen in other families. Instead, each channel of the eDMA controller has a built-in channel MUX (CHn_MUX register) that selects which peripheral function's DMA request source it will accept. The SDK assigns request sources to each channel using the EDMA_SetChannelMux() API (the specific calling method is described in Chapter 4). The channel number is not fixed and can be freely switched depending on the application's use. The diagram below illustrates how multiple DMA request sources on the peripheral function side are connected to the channel body via a channel MUX selector built into each eDMA channel. In the diagram above, the solid lines show an example where LPUART0 TX is assigned to Channel 0 and LPUART0 RX to Channel 1 using EDMA_SetChannelMux . The dotted lines represent available connection options, and by rewriting the arguments when calling the API, it is possible to change other assignments, such as assigning LPUART0 TX to Channel 2. 4. Basic Flow of SDK Drivers Next, we will demonstrate how to use the driver using the MCUXpresso SDK sample project "lpuart_edma_transfer" as an example. Reference URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/lpuart/edma_transfer/lpuart_edma_transfer.c The following seven steps are the basic steps when using LPUART and DMA together: Enable the clock. Configure pin MUX Initialize the LPUART. Configure the eDMA channel MUX. Generate a DMA handle Start sending/receiving The next process is controlled by the callback. In the following sections, we will explain each step in detail, including code snippets. 4.1 Clock Port Settings First, enable the clock on the LPUART module. CLOCK_EnableClock(kCLOCK_Lpuart0); Next, we configure the MUX pins used for TX and RX. PORT_SetPinMux(PORTA, 1U, kPORT_MuxAlt2); // TX PORT_SetPinMux(PORTA, 2U, kPORT_MuxAlt2); // RX Aside from GND, the UART wiring consists of only two wires: transmit and receive. In the FRDM-MCXA153 circuit diagram, the TXD and RXD of LPUART0 are connected to the MCU-LINK's Virtual COM, and by connecting the MCU-Link to a PC via USB, debugging via UART communication becomes possible. flowchart LR PC[PC] <-->|USB| MCULINK[MCU-LINK Virtual COM] MCULINK <-->|UART| LPUART0[MCXA153 LPUART0]   4.2 LPUART initialization Initializing the LPUART involves first obtaining the default settings and then modifying the necessary items. lpuart_config_t config; LPUART_GetDefaultConfig(&config); config.baudRate_Bps = 115200; config.enableTx = true; config.enableRx = true; LPUART_Init(LPUART0, &config, CLOCK_GetFreq(kCLOCK_CoreSysClk)); The baud rate depends on the clock frequency supplied to the LPUART, so you need to pass the correct clock source frequency in CLOCK_GetFreq() . Enable TX and RX as needed. 4.3 eDMA Channel MUX Settings Before generating the handle, you specify with EDMA_SetChannelMux which eDMA channel to route the LPUART TX/RX requests to. As explained in Chapter 3, the MCX A153 does not have an independent DMAMUX, and this API sets the request source in the CHn_MUX register for each channel. /* LPUART0 TX を eDMA の任意チャネル(例: CH0)に割り当てる */ EDMA_SetChannelMux(DMA0, LPUART_TX_DMA_CHANNEL, kDma0RequestMuxLPUART0Tx); /* LPUART0 RX を eDMA の任意チャネル(例: CH1)に割り当てる */ EDMA_SetChannelMux(DMA0, LPUART_RX_DMA_CHANNEL, kDma0RequestMuxLPUART0Rx); The channel number specified here must match the channel number passed to txEdmaHandle / rxEdmaHandle when generating the subsequent DMA handle. 4.4 DMA Handle Generation A handle is created to link LPUART and DMA, and a callback function is registered here to be called when communication is complete. lpuart_edma_handle_t g_lpuartEdmaHandle; LPUART_TransferCreateHandleEDMA(LPUART0, &g_lpuartEdmaHandle, lpuart_callback, userData, &txEdmaHandle, &rxEdmaHandle); This handle associates the LPUART and DMA TX/RX channels, which are then used by subsequent transmit and receive APIs. 4.5 Transmission (DMA) Sending is as simple as calling the API with the send buffer and size set to lpuart_transfer_t . lpuart_transfer_t xfer; xfer.data = txBuffer; xfer.dataSize = txSize; LPUART_TransferSendEDMA(LPUART0, &g_lpuartEdmaHandle, &xfer);   4.6 Receiving (DMA) Similarly, receiving is also done by specifying the receive buffer and size when calling the function. lpuart_transfer_t xfer; xfer.data = rxBuffer; xfer.dataSize = rxSize; LPUART_TransferReceiveEDMA(LPUART0, &g_lpuartEdmaHandle, &xfer);   4.7 Callback Implementation The application is notified of the completion of the communication via a callback function. void lpuart_callback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData) { if (status == kStatus_LPUART_TxIdle) { // 送信完了処理 } else if (status == kStatus_LPUART_RxIdle) { // 受信完了処理 } } kStatus_LPUART_TxIdle kStatus_LPUART_RxIdle indicates completion of transmission via DMA, and indicates completion of reception via DMA. If you want to continue receiving continuously, you can call LPUART_TransferReceiveEDMA() again within this callback to continue receiving without interruption.   4.8 Key Design Points When actually using LPUART and DMA in combination, there are several design considerations that you should keep in mind. First, let's consider the transfer size . If the transfer size is too small, the number of interrupts will increase, reducing CPU efficiency. If it's too large, the latency until the transfer is complete will be high. You need to choose an appropriate value that matches the application's requirements while keeping the FIFO size in mind. Next is the design of the receive buffer . If the receive length is predetermined, a fixed-length buffer is sufficient, but if you are continuously receiving data of an unspecified length, it is common to use a ring buffer. Finally, there's the callback process . Callbacks not only notify the application that the transfer is complete, but they also trigger the reconfiguration of the next DMA transfer. Implementing this part is the most crucial for ensuring stable continuous communication. 5. Common problems   5.1 DMA is not working Possible causes include the DMA clock not being enabled, the request source specified in EDMA_SetChannelMux not matching the LPUART's TX/RX, or the channel number passed to the LPUART driver not matching the channel number set in EDMA_SetChannelMux . The quickest solution is to first enable the clock and check that the channel MUX assignments match. 5.2 Data Loss Typical issues include FIFO overruns and transfer size settings that don't match the actual data volume. Review the relationship between the FIFO threshold and the DMA transfer unit. 5.3 Failure due to high-speed communication As the baud rate increases, factors such as FIFO underrun, insufficient buffer design, degraded waveform quality, and clock errors become apparent. It is necessary to isolate the cause from both the hardware-side signal quality and the software-side buffer supply capability. 6. Summary The most important thing for effectively using LPUART in practice is to correctly understand the role of FIFO and design the data buffer in consideration of its interaction with DMA. By keeping these points in mind, you can achieve stable UART communication with low power consumption and low CPU load. ========================= We are currently unable to respond to comments left in the "Comment" section of this post. We apologize for the inconvenience, but please refer to " Technical Questions to NXP - How to Contact Us (Japanese Blog) " when making inquiries. (If you are already an NXP distributor or have a relationship with NXP, you may contact your representative directly.) This article explains the basic concepts of LPUART (Low Power Universal Asynchronous Receiver/Transmitter) on the MCX A153 and how to use it with the MCUXpresso SDK, aimed at engineers who are new to NXP products. First, we will explain the hardware overview, and then, using the FRDM-MCXA153 board as a base, we will explain how to use the MCUXpresso SDK API with code snippets. (Reading time: 20 minutes) MCUXpresso SDK MCX Japanese Blog
View full article
[MCX A153] GPIO Beginner's Guide (Japanese Blog) This article explains the basic concepts of GPIO ( General Purpose Input / Output ) on the MCX A153 . It also explains how to implement software using the MCUXpresso SDK , based on the FRDM-MCXA153 board, for engineers new to NXP products. First, an overview of the hardware is provided, followed by an explanation of how to use the MCUXpresso SDK, along with code snippets. (Reading time: 20 minutes) 1. Overview of the GPIO module   1.1 Role of GPIO GPIO is the most basic interface for controlling microcontroller pins as either "inputs" or "outputs". For example, in the FRDM-MCXA153 , the three RGB LEDs are wired to the following GPIOs , so it is possible to switch the LEDs ON/OFF by controlling the GPIOs. Red : P3_12 Green : P3_13 Blue : P3_0 1.2 Pin control function in MCX A153 In the MCX A153 , pin control functions are managed by the following two modules: (1) PORT module It primarily serves the following roles. Since one pin has multiple functions, PORT configuration is required to use it as a GPIO. Pin function selection ( GPIO / UART / SPI / I2C / PWM , etc. ) Pull-up / Pull-down settings Drive capability settings   (2) GPIO module It primarily serves the following roles: Input/Output Data Control High/Low output of the pin Reading the input state " PORT = pin configuration" and " GPIO = actual input/output operation," and so on.   2. Basic operation of GPIO GPIO modules have output and input modes, and the following operations are possible with each mode: (1) Output mode The following processes are possible: High output Low output Toggle (inverts the current output) (2) Input mode The following processes are possible: Read the pin voltage status (High or Low) Interrupt detection (rising / falling edge)   3. Basic Flow of SDK Drivers   To use GPIO, the following settings are required by the software. - Clock settings - Pin settings (PORT settings) - Input or output settings ( GPIO settings) - Interrupt settings (if necessary) This guide will demonstrate how to use the driver, using a sample project from the MCUXpresso SDK as an example.    3.1 Output Modes I will explain using the following project as an example. Reference URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/gpio/led_output/gpio_led_output.c at main · nxp-mcuxpresso...   3.1.1Initialization First, initialize the clock, port, and GPIO for the red LED. #include "fsl_gpio.h" #include "fsl_port.h" // 赤色LEDに配線されたピンのパラメータ #define BOARD_INITPINS_LED_RED_PORT PORT3 #define BOARD_INITPINS_LED_RED_GPIO GPIO3 #define BOARD_INITPINS_LED_RED_PIN 12 void init_gpio(void) { // クロック有効化 CLOCK_EnableClock(kCLOCK_GateGPIO3); // PORT設定 const port_pin_config_t LED_RED = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as P3_12 */ kPORT_MuxAlt0, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; PORT_SetPinConfig(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, &LED_RED); // GPIO設定 gpio_pin_config_t LED_RED_config = { .pinDirection = kGPIO_DigitalOutput, .outputLogic = 0U }; GPIO_PinInit(BOARD_INITPINS_LED_RED_GPIO, BOARD_INITPINS_LED_RED_PIN, &LED_RED_config); }   3.1.2Output control ( LED on / off / toggle) The output values can be modified using the following API. GPIO_PinWrite(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, 1); // High GPIO_PinWrite(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, 0); // Low GPIO_PortToggle(BOARD_INITPINS_LED_RED_PORT, 1U << BOARD_INITPINS_LED_RED_PIN); // Toggle   3.2 Input Mode I will explain using the following project as an example. Reference URL: Hardware requirements — MCUXpresso SDK Documentation mcuxsdk-examples/driver_examples/gpio/input_interrupt/gpio_input_interrupt.c at main · nxp-mcuxpresso...   3.2.1 Initialization Since it's the same except for the output mode and arguments, I'll omit the details.   3.2.2Input reading The input values can be read using the following API. uint32_t value = GPIO_PinRead(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN); if (value == 0) { // スイッチ押下(プルアップの場合) }   3.2.3Interrupt settings To set the falling edge signal as a GPIO interrupt, use the following API. EnableIRQ is the interrupt enable setting on the Cortex-M side. GPIO_SetPinInterruptConfig(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, kGPIO_InterruptFallingEdge); EnableIRQ(BOARD_SW_IRQ); Handling interrupts requires a function definition as an interrupt handler. If you don't clear the interrupt flag, the interrupt will continue to occur indefinitely, so be careful. void BOARD_SW_IRQ_HANDLER(void) { /* 割り込みフラグをクリア */ GPIO_GpioClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN); // 処理 SDK_ISR_EXIT_BARRIER; } The process leading up to an interrupt is shown below. The above explains how to use the GPIO driver with the MCUXpresso SDK.   4. Common pitfalls If you modify the source code and the GPIO doesn't work as expected, please check the following items. The pin is set to a different function → Check the PORT settings to see if the pin is assigned to GPIO. Clock not enabled → Check if CLOCK_EnableClock is being called. Incorrect pin number → Check if it matches the hardware pin number. GPIO interrupts are not being received → Check that interrupts are enabled on the Cortex-M side using EnableIRQ. GPIO interrupts are looping → Check if the interrupt flag has been cleared.   5. Summary   The GPIO pins on the MCX A153 operate in a two-stage configuration: pin configuration via the PORT module and input/output control via the GPIO module. Therefore, when using a pin as a GPIO, you must first configure the pin assignment settings in the PORT module and select the GPIO function. After that, you use the GPIO module to initialize it as an input or output and perform operations such as turning LEDs on and off or reading the state of switches. Using the MCUXpresso SDK, these settings and controls can be implemented concisely via the library API. Furthermore, by utilizing the GPIO interrupt function, it is possible to efficiently detect events such as switch presses. If the GPIO does not work as expected, check whether the PORT setting is enabled, whether the clock is enabled for the target PORT, and whether the pin number setting is correct.   ========================= We are currently unable to respond to comments left in the "Comment" section of this post. We apologize for the inconvenience, but please refer to " Technical Questions to NXP - How to Contact Us( Japanese Blog) " when making an inquiry. (If you are already an NXP distributor or have a relationship with NXP, you may ask your representative directly.) This article explains the basic concepts of GPIO ( General Purpose Input / Output ) on the MCX A153 . It also explains how to implement software using the MCUXpresso SDK , based on the FRDM-MCXA153 board, for engineers new to NXP products. First, an overview of the hardware is provided, followed by an explanation of how to use the MCUXpresso SDK, along with code snippets. (Reading time: 20 minutes) MCX Japanese Blog
View full article