diff --git a/src/libxr/generator_code_mspm0.py b/src/libxr/generator_code_mspm0.py index 35eeac1..458d5ce 100644 --- a/src/libxr/generator_code_mspm0.py +++ b/src/libxr/generator_code_mspm0.py @@ -607,13 +607,15 @@ def _uart_section(uarts: list, extend: set[str]) -> list[str]: tr( f"{instance}: no DMA TX channel in the SysConfig project (UART > DMA " "Configuration: Enable DMA TX with the TX trigger, which also gives the " - f"{instance}_INST_DMA_TRIGGER_n and _CHAN_ID macros); the MSPM0 UART " + f"_CHAN_ID and {instance}_INST_DMA_TRIGGER macros, the latter " + "numbered _0, _1 when the instance has more than one trigger); the MSPM0 UART " "driver constructs only with DMA TX. Enable it and run `libxr parse` again, " "or drop the UART", f"{instance}:SysConfig 工程里没有 DMA TX 通道(UART > DMA Configuration:" - f"启用 DMA TX 并选 TX 触发,SysConfig 随之生成 {instance}_INST_DMA_TRIGGER_n " - "和 <通道>_CHAN_ID 宏);MSPM0 的 UART 驱动只支持带 DMA TX 的构造。请启用后" - "重新运行 `libxr parse`,或删去这个 UART", + f"启用 DMA TX 并选 TX 触发,SysConfig 随之生成 <通道>_CHAN_ID 和 " + f"{instance}_INST_DMA_TRIGGER 宏,实例有多个触发时带编号 _0、_1);MSPM0 的 " + "UART 驱动只支持带 DMA TX 的构造。请启用后重新运行 `libxr parse`,或删去" + "这个 UART", ) ) settings = _instance_settings("UART", name, instance in extend) diff --git a/src/libxr/peripheral_analyzer_mspm0.py b/src/libxr/peripheral_analyzer_mspm0.py index fd18079..3cb5e61 100644 --- a/src/libxr/peripheral_analyzer_mspm0.py +++ b/src/libxr/peripheral_analyzer_mspm0.py @@ -616,16 +616,18 @@ def _gpio_entries( def _header_dma_channel(name: str, direction: str, defines: dict[str, str]) -> str | None: """SysConfig 输出里实例 name 在 direction(TX/RX)方向的 DMA 通道名:每个 - _INST_DMA_TRIGGER_n 前面紧挨着它的通道的 <通道>_CHAN_ID。没有时为 None。 + _INST_DMA_TRIGGER 或 _INST_DMA_TRIGGER_n 前面紧挨着它的通道的 <通道>_CHAN_ID + (一个实例只有一个触发时 SysConfig 不写编号,两个及以上才写 _0、_1)。没有时为 None。 The DMA channel name of the instance name in direction (TX/RX) in the SysConfig output: - every _INST_DMA_TRIGGER_n directly follows the _CHAN_ID of its channel. None - when there is none. + every _INST_DMA_TRIGGER or _INST_DMA_TRIGGER_n directly follows the + _CHAN_ID of its channel (SysConfig writes no number while the instance has one + trigger, and _0, _1 from two on). None when there is none. """ channel = None for macro, value in defines.items(): if macro.endswith("_CHAN_ID"): channel = macro[: -len("_CHAN_ID")] - elif re.fullmatch(rf"{re.escape(name)}_INST_DMA_TRIGGER_\d+", macro): + elif re.fullmatch(rf"{re.escape(name)}_INST_DMA_TRIGGER(?:_\d+)?", macro): trigger = DMA_TRIGGER.fullmatch(value) if trigger and trigger.group(1) == direction and channel: return channel diff --git a/tests/data/mspm0/uart_tx_dma.syscfg b/tests/data/mspm0/uart_tx_dma.syscfg new file mode 100644 index 0000000..9470a09 --- /dev/null +++ b/tests/data/mspm0/uart_tx_dma.syscfg @@ -0,0 +1,57 @@ +/** + * These arguments were used when this file was generated. They will be automatically applied on subsequent loads + * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. + */ +//@cliArgs --device "MSPM0G350X" --package "LQFP-64(PM)" --part "Default" +//@v2CliArgs --device "MSPM0G3507" --package "LQFP-64(PM)" +// @cliArgs --board /ti/boards/LP_MSPM0G3507 --rtos nortos + +/** + * Import the modules used in this configuration. + */ +const UART = scripting.addModule("/ti/driverlib/UART", {}, false); +const UART1 = UART.addInstance(); + +const GPIO = scripting.addModule("/ti/driverlib/GPIO", {}, false); +const GPIO1 = GPIO.addInstance(); + +const SYSCTL = scripting.addModule("/ti/driverlib/SYSCTL"); + +/** + * Write custom configuration values to the imported modules. + */ + +UART1.$name = "UART_0"; +UART1.profile = "CONFIG_PROFILE_1"; +UART1.peripheral.$assign = "UART0"; +UART1.targetBaudRate = 9600; +UART1.enableInternalLoopback = false; +UART1.enabledInterrupts = ["DMA_DONE_TX", "EOT_DONE"]; +UART1.enableFIFO = true; +UART1.txFifoThreshold = "DL_UART_TX_FIFO_LEVEL_ONE_ENTRY"; +UART1.enabledDMATXTriggers = "DL_UART_DMA_INTERRUPT_TX"; +UART1.enableDMATX = true; + +UART1.peripheral.rxPin.$assign = "PA11"; +UART1.peripheral.txPin.$assign = "PA10"; + +UART1.DMA_CHANNEL_TX.peripheral.$assign = "DMA_CH0"; +UART1.DMA_CHANNEL_TX.addressMode = "b2f"; +UART1.DMA_CHANNEL_TX.srcIncDec = "INCREMENT"; +UART1.DMA_CHANNEL_TX.dstLength = "BYTE"; +UART1.DMA_CHANNEL_TX.srcLength = "BYTE"; + +GPIO1.$name = "GPIO_LEDS"; +GPIO1.associatedPins.create(2); +GPIO1.associatedPins[0].$name = "USER_LED_1"; +GPIO1.associatedPins[0].assignedPort = "PORTA"; +GPIO1.associatedPins[0].initialValue = "SET"; +GPIO1.associatedPins[0].assignedPin = "0"; +GPIO1.associatedPins[0].pin.$assign = "PA0"; +GPIO1.associatedPins[1].$name = "USER_TEST"; +GPIO1.associatedPins[1].assignedPort = "PORTA"; +GPIO1.associatedPins[1].assignedPin = "15"; +GPIO1.associatedPins[1].initialValue = "SET"; + +SYSCTL.clockTreeEn = true; +SYSCTL.forceDefaultClkConfig = true; diff --git a/tests/data/mspm0/uart_tx_dma_ti_msp_dl_config.c b/tests/data/mspm0/uart_tx_dma_ti_msp_dl_config.c new file mode 100644 index 0000000..7c1aa00 --- /dev/null +++ b/tests/data/mspm0/uart_tx_dma_ti_msp_dl_config.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2023, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ============ ti_msp_dl_config.c ============= + * Configured MSPM0 DriverLib module definitions + * + * DO NOT EDIT - This file is generated for the LP_MSPM0G3507 + * by the SysConfig tool. + */ + +#include "ti_msp_dl_config.h" + +/* + * ======== SYSCFG_DL_init ======== + * Perform any initialization needed before using any board APIs + */ +SYSCONFIG_WEAK void SYSCFG_DL_init(void) +{ + SYSCFG_DL_initPower(); + SYSCFG_DL_GPIO_init(); + /* Module-Specific Initializations*/ + SYSCFG_DL_SYSCTL_init(); + SYSCFG_DL_UART_0_init(); + SYSCFG_DL_DMA_init(); +} + + + +SYSCONFIG_WEAK void SYSCFG_DL_initPower(void) +{ + DL_GPIO_reset(GPIOA); + DL_GPIO_reset(GPIOB); + DL_UART_Main_reset(UART_0_INST); + + + DL_GPIO_enablePower(GPIOA); + DL_GPIO_enablePower(GPIOB); + DL_UART_Main_enablePower(UART_0_INST); + + delay_cycles(POWER_STARTUP_DELAY); +} + +SYSCONFIG_WEAK void SYSCFG_DL_GPIO_init(void) +{ + + DL_GPIO_initPeripheralOutputFunction( + GPIO_UART_0_IOMUX_TX, GPIO_UART_0_IOMUX_TX_FUNC); + DL_GPIO_initPeripheralInputFunction( + GPIO_UART_0_IOMUX_RX, GPIO_UART_0_IOMUX_RX_FUNC); + + DL_GPIO_initDigitalOutput(GPIO_LEDS_USER_LED_1_IOMUX); + + DL_GPIO_initDigitalOutput(GPIO_LEDS_USER_TEST_IOMUX); + + DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN | + GPIO_LEDS_USER_TEST_PIN); + DL_GPIO_enableOutput(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN | + GPIO_LEDS_USER_TEST_PIN); + +} + + + +SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_init(void) +{ + + //Low Power Mode is configured to be SLEEP0 + DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_0); + + + DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE); + /* Set default configuration */ + DL_SYSCTL_disableHFXT(); + DL_SYSCTL_disableSYSPLL(); + +} + + +static const DL_UART_Main_ClockConfig gUART_0ClockConfig = { + .clockSel = DL_UART_MAIN_CLOCK_BUSCLK, + .divideRatio = DL_UART_MAIN_CLOCK_DIVIDE_RATIO_1 +}; + +static const DL_UART_Main_Config gUART_0Config = { + .mode = DL_UART_MAIN_MODE_NORMAL, + .direction = DL_UART_MAIN_DIRECTION_TX_RX, + .flowControl = DL_UART_MAIN_FLOW_CONTROL_NONE, + .parity = DL_UART_MAIN_PARITY_NONE, + .wordLength = DL_UART_MAIN_WORD_LENGTH_8_BITS, + .stopBits = DL_UART_MAIN_STOP_BITS_ONE +}; + +SYSCONFIG_WEAK void SYSCFG_DL_UART_0_init(void) +{ + DL_UART_Main_setClockConfig(UART_0_INST, (DL_UART_Main_ClockConfig *) &gUART_0ClockConfig); + + DL_UART_Main_init(UART_0_INST, (DL_UART_Main_Config *) &gUART_0Config); + /* + * Configure baud rate by setting oversampling and baud rate divisors. + * Target baud rate: 9600 + * Actual baud rate: 9600.24 + */ + DL_UART_Main_setOversampling(UART_0_INST, DL_UART_OVERSAMPLING_RATE_16X); + DL_UART_Main_setBaudRateDivisor(UART_0_INST, UART_0_IBRD_32_MHZ_9600_BAUD, UART_0_FBRD_32_MHZ_9600_BAUD); + + + /* Configure Interrupts */ + DL_UART_Main_enableInterrupt(UART_0_INST, + DL_UART_MAIN_INTERRUPT_DMA_DONE_TX | + DL_UART_MAIN_INTERRUPT_EOT_DONE); + + /* Configure DMA Transmit Event */ + DL_UART_Main_enableDMATransmitEvent(UART_0_INST); + /* Configure FIFOs */ + DL_UART_Main_enableFIFOs(UART_0_INST); + DL_UART_Main_setRXFIFOThreshold(UART_0_INST, DL_UART_RX_FIFO_LEVEL_ONE_ENTRY); + DL_UART_Main_setTXFIFOThreshold(UART_0_INST, DL_UART_TX_FIFO_LEVEL_ONE_ENTRY); + + DL_UART_Main_enable(UART_0_INST); +} + +static const DL_DMA_Config gDMA_CH0Config = { + .transferMode = DL_DMA_SINGLE_TRANSFER_MODE, + .extendedMode = DL_DMA_NORMAL_MODE, + .destIncrement = DL_DMA_ADDR_UNCHANGED, + .srcIncrement = DL_DMA_ADDR_INCREMENT, + .destWidth = DL_DMA_WIDTH_BYTE, + .srcWidth = DL_DMA_WIDTH_BYTE, + .trigger = UART_0_INST_DMA_TRIGGER, + .triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL, +}; + +SYSCONFIG_WEAK void SYSCFG_DL_DMA_CH0_init(void) +{ + DL_DMA_initChannel(DMA, DMA_CH0_CHAN_ID , (DL_DMA_Config *) &gDMA_CH0Config); +} +SYSCONFIG_WEAK void SYSCFG_DL_DMA_init(void){ + SYSCFG_DL_DMA_CH0_init(); +} + + diff --git a/tests/data/mspm0/uart_tx_dma_ti_msp_dl_config.h b/tests/data/mspm0/uart_tx_dma_ti_msp_dl_config.h new file mode 100644 index 0000000..3655e66 --- /dev/null +++ b/tests/data/mspm0/uart_tx_dma_ti_msp_dl_config.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023, Texas Instruments Incorporated - http://www.ti.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ============ ti_msp_dl_config.h ============= + * Configured MSPM0 DriverLib module declarations + * + * DO NOT EDIT - This file is generated for the LP_MSPM0G3507 + * by the SysConfig tool. + */ +#ifndef ti_msp_dl_config_h +#define ti_msp_dl_config_h + +#define CONFIG_LP_MSPM0G3507 +#define CONFIG_MSPM0G3507 + +#if defined(__ti_version__) || defined(__TI_COMPILER_VERSION__) +#define SYSCONFIG_WEAK __attribute__((weak)) +#elif defined(__IAR_SYSTEMS_ICC__) +#define SYSCONFIG_WEAK __weak +#elif defined(__GNUC__) +#define SYSCONFIG_WEAK __attribute__((weak)) +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ======== SYSCFG_DL_init ======== + * Perform all required MSP DL initialization + * + * This function should be called once at a point before any use of + * MSP DL. + */ + + +/* clang-format off */ + +#define POWER_STARTUP_DELAY (16) + + + +#define CPUCLK_FREQ 32000000 + + + +/* Defines for UART_0 */ +#define UART_0_INST UART0 +#define UART_0_INST_FREQUENCY 32000000 +#define UART_0_INST_IRQHandler UART0_IRQHandler +#define UART_0_INST_INT_IRQN UART0_INT_IRQn +#define GPIO_UART_0_RX_PORT GPIOA +#define GPIO_UART_0_TX_PORT GPIOA +#define GPIO_UART_0_RX_PIN DL_GPIO_PIN_11 +#define GPIO_UART_0_TX_PIN DL_GPIO_PIN_10 +#define GPIO_UART_0_IOMUX_RX (IOMUX_PINCM22) +#define GPIO_UART_0_IOMUX_TX (IOMUX_PINCM21) +#define GPIO_UART_0_IOMUX_RX_FUNC IOMUX_PINCM22_PF_UART0_RX +#define GPIO_UART_0_IOMUX_TX_FUNC IOMUX_PINCM21_PF_UART0_TX +#define UART_0_BAUD_RATE (9600) +#define UART_0_IBRD_32_MHZ_9600_BAUD (208) +#define UART_0_FBRD_32_MHZ_9600_BAUD (21) + + + + + +/* Defines for DMA_CH0 */ +#define DMA_CH0_CHAN_ID (0) +#define UART_0_INST_DMA_TRIGGER (DMA_UART0_TX_TRIG) + + +/* Port definition for Pin Group GPIO_LEDS */ +#define GPIO_LEDS_PORT (GPIOA) + +/* Defines for USER_LED_1: GPIOA.0 with pinCMx 1 on package pin 33 */ +#define GPIO_LEDS_USER_LED_1_PIN (DL_GPIO_PIN_0) +#define GPIO_LEDS_USER_LED_1_IOMUX (IOMUX_PINCM1) +/* Defines for USER_TEST: GPIOA.15 with pinCMx 37 on package pin 8 */ +#define GPIO_LEDS_USER_TEST_PIN (DL_GPIO_PIN_15) +#define GPIO_LEDS_USER_TEST_IOMUX (IOMUX_PINCM37) + + +/* clang-format on */ + +void SYSCFG_DL_init(void); +void SYSCFG_DL_initPower(void); +void SYSCFG_DL_GPIO_init(void); +void SYSCFG_DL_SYSCTL_init(void); +void SYSCFG_DL_UART_0_init(void); +void SYSCFG_DL_DMA_init(void); + + +bool SYSCFG_DL_saveConfiguration(void); +bool SYSCFG_DL_restoreConfiguration(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ti_msp_dl_config_h */ diff --git a/tests/test_generator_code_mspm0.py b/tests/test_generator_code_mspm0.py index 16b2d9c..4964e85 100644 --- a/tests/test_generator_code_mspm0.py +++ b/tests/test_generator_code_mspm0.py @@ -8,16 +8,19 @@ 没有 SysConfig,输出随工程一起提交),以及一个覆盖 BSP 没用到的 SysConfig 写法的 variants 工程 (SPI 用 MFCLK 分频和 RX timeout DMA 触发、外设模式的 SPI、只有目标模式的 I2C、默认实例名且 引脚只有建议值的 PWM、端口加引脚号的 GPIO、默认名 PIN_0 的引脚、收发都有 DMA 的 UART),它的 -输出同样由 SysConfig 1.28.1 生成。测试把固件复制进临时工程,使生成输出的修改时间比 .syscfg 新, -解析直接复用它;测试期间不设置 SYSCONFIG_TOOL 和 MSPM0_SDK_INSTALL_DIR。 +输出同样由 SysConfig 1.28.1 生成,以及 TI SDK 的 uart_tx_multibyte_fifo_dma_interrupts 例程 +(一个实例只有一个 DMA 触发,输出的触发宏不带编号)。测试把固件复制进临时工程,使生成输出的 +修改时间比 .syscfg 新,解析直接复用它;测试期间不设置 SYSCONFIG_TOOL 和 MSPM0_SDK_INSTALL_DIR。 The fixtures are the real project files of the two BSPs: the .syscfg plus the ti_msp_dl_config.h/.c that SysConfig generated (CI has no SysConfig, so the output is committed -with the project), and a variants project with the SysConfig setups the BSPs do not use (an SPI +with the project), a variants project with the SysConfig setups the BSPs do not use (an SPI on MFCLK with a divider and an RX timeout DMA trigger, an SPI in peripheral mode, an I2C in target mode only, a PWM with the default instance name and only suggested pins, GPIO pins given as port plus pin number, a pin with the default name PIN_0, a UART with DMA on both sides), -whose output SysConfig 1.28.1 generated as well. A test copies the fixtures into a temporary -project, so the generated output is newer than the .syscfg and parsing reuses it; +whose output SysConfig 1.28.1 generated as well, and the uart_tx_multibyte_fifo_dma_interrupts +example of the TI SDK (an instance with a single DMA trigger, so its trigger macro carries no +number). A test copies the fixtures into a temporary project, so the generated output is newer +than the .syscfg and parsing reuses it; SYSCONFIG_TOOL and MSPM0_SDK_INSTALL_DIR are unset during the tests. """ @@ -51,6 +54,7 @@ def bsp(name: str) -> str: "g3507": "mspm0g3507_minidb48.syscfg", "g3519": "mspm0g3519_minidb48.syscfg", "variants": "mspm0_variants.syscfg", + "uart_tx_dma": "uart_tx_multibyte_fifo_dma_interrupts.syscfg", }[name] @@ -168,6 +172,17 @@ def test_the_second_uart_of_the_other_board_is_parsed_as_well(self): self.assertEqual(peripherals["UART"]["UART_7"]["DMA_TX"], "DMA_CH_UART7_TX") self.assertEqual(peripherals["UART"]["UART_7"]["PowerDomain"], 0) + def test_a_single_dma_trigger_of_the_output_names_the_channel(self): + # TI 的 uart_tx_multibyte_fifo_dma_interrupts 例程:.syscfg 只写了 + # DMA_CHANNEL_TX.peripheral.$assign,输出里的触发宏只有一个,因而不带编号 + # (UART_0_INST_DMA_TRIGGER)。 + # TI's uart_tx_multibyte_fifo_dma_interrupts example: the .syscfg names only + # DMA_CHANNEL_TX.peripheral.$assign, and the output holds a single trigger macro, + # which therefore carries no number (UART_0_INST_DMA_TRIGGER). + uart = self.parse("uart_tx_dma")["Peripherals"]["UART"]["UART_0"] + self.assertEqual(uart["DMA_TX"], "DMA_CH0") + self.assertEqual(uart["Peripheral"], "UART0") + class ParsingVariants(MSPM0TestCase): """libxr parse 对 BSP 没用到的 SysConfig 写法(variants 工程,审查 2026-10-07 的 H1-H6、 @@ -780,10 +795,24 @@ def test_a_uart_without_dma_tx_names_the_sysconfig_option(self): self.project_yaml(root, lambda data: data["Peripherals"]["UART"]["UART_0"].pop("DMA_TX")) self.assertIn( "UART_0: no DMA TX channel in the SysConfig project (UART > DMA Configuration: " - "Enable DMA TX", + "Enable DMA TX with the TX trigger, which also gives the _CHAN_ID and " + "UART_0_INST_DMA_TRIGGER macros, the latter numbered _0, _1 when the instance has " + "more than one trigger)", self.failure(root), ) + def test_the_ti_example_with_one_dma_trigger_generates(self): + # TI 例程端到端:.syscfg 加 SysConfig 输出解析出 DMA_CH0(触发宏不带编号),生成出来的 + # UART 用它构造。 + # The TI example end to end: its .syscfg and SysConfig output parse to DMA_CH0 (the + # trigger macro carries no number), and the generated UART is constructed with it. + root = self.project("uart_tx_dma") + parse_project(str(root), summary=False) + (root / "User").mkdir() + code = self.regenerate(root) + self.assertIn("MSPM0_UART_MAIN_INIT(UART_0, DMA_CH0,", code) + self.assertIn("#define DMA_CH0_LIBXR_UART_IRQN UART_0_INST_INT_IRQN", code) + def test_different_frequencies_of_one_timer_are_a_warning(self): # L7 root, _code = self.generate("variants") @@ -926,3 +955,39 @@ def test_the_clock_configurations_of_every_kind_are_read(self): sorted(clocks), ["I2C_0", "I2C_TARGET", "PWM_0", "SPI_1", "SPI_PERIPH", "UART_0"] ) self.assertEqual(clocks["UART_0"]["clockSel"], "DL_UART_MAIN_CLOCK_BUSCLK") + + def test_a_dma_trigger_without_a_number_names_the_channel_too(self): + # SysConfig 在一个实例只有一个 DMA 触发时不写编号;通道名是触发宏前面紧挨着的 + # <通道>_CHAN_ID。 + # SysConfig writes no number while an instance has one DMA trigger; the channel is the + # _CHAN_ID directly before the trigger macro. + defines = { + "DMA_CH0_CHAN_ID": "(0)", + "UART_0_INST_DMA_TRIGGER": "(DMA_UART0_TX_TRIG)", + } + self.assertEqual(analyzer._header_dma_channel("UART_0", "TX", defines), "DMA_CH0") + self.assertIsNone(analyzer._header_dma_channel("UART_0", "RX", defines)) + + def test_an_spi_with_one_dma_event_uses_the_same_lookup(self): + # SPI 和 UART 走同一个查找:只开一个 DMA 事件时它的触发宏也不带编号。 + # An SPI uses the same lookup as a UART: with a single DMA event its trigger macro + # carries no number either. + defines = { + "DMA_CH_SPI1_RX_CHAN_ID": "(3)", + "SPI_1_INST_DMA_TRIGGER": "(DMA_SPI1_RX_TRIG)", + } + self.assertEqual(analyzer._header_dma_channel("SPI_1", "RX", defines), "DMA_CH_SPI1_RX") + self.assertIsNone(analyzer._header_dma_channel("SPI_1", "TX", defines)) + + def test_a_numbered_dma_trigger_names_the_channel_as_before(self): + # 两个及以上触发时宏带编号,两个方向各取自己前面的通道。 + # From two triggers on the macros carry numbers, and each direction takes the channel + # before its own trigger. + defines = { + "DMA_CH_UART0_TX_CHAN_ID": "(1)", + "UART_0_INST_DMA_TRIGGER_0": "(DMA_UART0_TX_TRIG)", + "DMA_CH_UART0_RX_CHAN_ID": "(0)", + "UART_0_INST_DMA_TRIGGER_1": "(DMA_UART0_RX_TRIG)", + } + self.assertEqual(analyzer._header_dma_channel("UART_0", "TX", defines), "DMA_CH_UART0_TX") + self.assertEqual(analyzer._header_dma_channel("UART_0", "RX", defines), "DMA_CH_UART0_RX")