Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -723,12 +723,14 @@ Active Peripherals:

缓冲区大小等设置在 `libxr_config.yaml` 中。GPIO 以引脚标签命名(`LED1`),UART、I2C、SPI 以小写的外设名
命名(`uart0`、`i2c0`),PWM 为 `pwm_tima1_c0`;`terminal_source` 指定终端使用的串口,未设置时用第一个 UART。
生成总是包含 `static MSPM0PowerManager power_manager;`,使用 XRobot 时把它登记为 `PowerManager`。
流程、设置与约束的完整说明见 [MSPM0 代码生成](https://xrobot.work/docs/code_gen/mspm0)。

The settings such as the buffer sizes live in `libxr_config.yaml`. GPIO objects are named after
the pin labels (`LED1`), UART, I2C and SPI after their lowercase peripheral names (`uart0`, `i2c0`),
and a PWM is `pwm_tima1_c0`; `terminal_source` names the UART the terminal uses, the first one when it is not
set. The flow, the settings and their constraints are described in
set. The generation always emits `static MSPM0PowerManager power_manager;`, registered as a
`PowerManager` with XRobot. The flow, the settings and their constraints are described in
[MSPM0 code generation](https://xrobot.work/en/docs/code_gen/mspm0).

---
Expand Down Expand Up @@ -782,11 +784,13 @@ Active Peripherals:
```

支持 HPM5301(QFN48)和 HPM5361(LQFP100、LQFP64、QFN48)。UART、SPI 等外设目前只识别,生成时列入
Other。流程、命名与设置的完整说明见 [HPM 代码生成](https://xrobot.work/docs/code_gen/hpm)。
Other。生成总是包含 `static HPMPowerManager power_manager;`,使用 XRobot 时把它登记为
`PowerManager`。流程、命名与设置的完整说明见 [HPM 代码生成](https://xrobot.work/docs/code_gen/hpm)。

HPM5301 (QFN48) and HPM5361 (LQFP100, LQFP64, QFN48) are supported. Peripherals such as UART and
SPI are recognized for now and listed under Other in the generation. The flow, the naming and the
settings are described in [HPM code generation](https://xrobot.work/en/docs/code_gen/hpm).
SPI are recognized for now and listed under Other in the generation. The generation always emits
`static HPMPowerManager power_manager;`, registered as a `PowerManager` with XRobot. The flow, the
naming and the settings are described in [HPM code generation](https://xrobot.work/en/docs/code_gen/hpm).

---

Expand Down
17 changes: 12 additions & 5 deletions src/libxr/generator_code_hpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@
"app_main",
"main",
"timebase",
"power_manager",
"PlatformInit",
"LibXR",
"Thread",
"UINT32_MAX",
"HPMTimebase",
"HPMPowerManager",
"HPMGPIO",
"HPMI2C",
"HPMPWM",
Expand Down Expand Up @@ -522,6 +524,7 @@ def _sections(
f"{INDENT}// Timebase and platform",
f"{INDENT}static HPMTimebase timebase;",
f"{INDENT}PlatformInit();",
f"{INDENT}static HPMPowerManager power_manager;",
],
_gpio_section(project_data, gpio),
_i2c_section(peripherals.get("I2C", [])),
Expand Down Expand Up @@ -578,7 +581,7 @@ def _includes(project_data: dict, use_xrobot: bool) -> list[str]:
and, with XRobot, xrobot_main.hpp; all in alphabetical order.
"""
peripherals = project_data.get("Peripherals", {})
drivers = ["hpm_soc.h", "hpm_timebase.hpp"]
drivers = ["hpm_soc.h", "hpm_timebase.hpp", "hpm_power.hpp"]
if project_data.get("GPIO"):
drivers.append("hpm_gpio.hpp")
for kind in ("I2C", "PWM"):
Expand Down Expand Up @@ -655,14 +658,18 @@ def _check_soc(project_data: dict) -> None:
_fail(str(error))


def initialize_registry() -> None:
"""清空生成对象的登记表,使同一次进程中的下一次生成不带上次的对象。
def initialize_registry(use_xrobot: bool) -> None:
"""清空生成对象的登记表,使同一次进程中的下一次生成不带上次的对象;use_xrobot 为真时先
登记 power_manager(PowerManager)。
Clear the registry of generated objects, so the next generation in the same process
carries no objects over.
carries no objects over; with use_xrobot, power_manager (PowerManager) is registered
first.
"""
stm32.registered_devices.clear()
stm32.registered_origins.clear()
stm32.used_headers.clear()
if use_xrobot:
stm32._register_device("power_manager", "PowerManager", tr("power manager", "电源管理器"))


def reset_settings() -> None:
Expand Down Expand Up @@ -708,7 +715,7 @@ def generate(
stm32._settings("I2C")
stm32._settings("PWM")
stm32._settings("GPIO")
initialize_registry()
initialize_registry(use_xrobot)

existing_code = ""
if os.path.exists(output_path):
Expand Down
15 changes: 10 additions & 5 deletions src/libxr/generator_code_mspm0.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ def _includes(project_data: dict, use_xrobot: bool) -> list[str]:
XRobot, xrobot_main.hpp; all in alphabetical order.
"""
peripherals = project_data.get("Peripherals", {})
drivers = ["mspm0_timebase.hpp"]
drivers = ["mspm0_timebase.hpp", "mspm0_power.hpp"]
if project_data.get("GPIO"):
drivers.append("mspm0_gpio.hpp")
for kind in ("I2C", "PWM", "SPI", "UART"):
Expand Down Expand Up @@ -853,6 +853,7 @@ def _sections(
f"{INDENT}// Timebase and platform",
f"{INDENT}static MSPM0Timebase timebase;",
f"{INDENT}PlatformInit();",
f"{INDENT}static MSPM0PowerManager power_manager;",
],
_gpio_section(gpio),
_uart_section(peripherals.get("UART", []), extend),
Expand Down Expand Up @@ -999,14 +1000,18 @@ def _warn_hand_written(path: str, existing_code: str, generated_code: str) -> No
)


def initialize_registry() -> None:
"""清空生成对象的登记表和本次生成用到的头文件,使同一次进程中的下一次生成不带上次的对象。
def initialize_registry(use_xrobot: bool) -> None:
"""清空生成对象的登记表和本次生成用到的头文件,使同一次进程中的下一次生成不带上次的对象;
use_xrobot 为真时先登记 power_manager(PowerManager)。
Clear the registry of generated objects and the headers of this generation, so the next
generation in the same process carries no objects over.
generation in the same process carries no objects over; with use_xrobot, power_manager
(PowerManager) is registered first.
"""
stm32.registered_devices.clear()
stm32.registered_origins.clear()
stm32.used_headers.clear()
if use_xrobot:
stm32._register_device("power_manager", "PowerManager", tr("power manager", "电源管理器"))


def reset_settings() -> None:
Expand Down Expand Up @@ -1049,7 +1054,7 @@ def generate(
stm32.libxr_settings.pop("SYSTEM", None)
stm32._settings("UART")
stm32._settings("PWM")
initialize_registry()
initialize_registry(use_xrobot)

existing_code = ""
if os.path.exists(output_path):
Expand Down
4 changes: 4 additions & 0 deletions tests/data/hpm/hpm5301evklite_expected_app_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "libxr.hpp"
#include "hpm_gpio.hpp"
#include "hpm_i2c.hpp"
#include "hpm_power.hpp"
#include "hpm_pwm.hpp"
#include "hpm_soc.h"
#include "hpm_timebase.hpp"
Expand All @@ -25,6 +26,7 @@ extern "C" void app_main(void)
// Timebase and platform
static HPMTimebase timebase;
PlatformInit();
static HPMPowerManager power_manager;

// GPIO: init_bsp_pins() configured pa10 (PA10) as an output pin, pa3 (PA03) as an input
// pin with a pull-down. The interrupt edge comes from the pinmux and every object
Expand All @@ -43,6 +45,8 @@ extern "C" void app_main(void)
clock_gptmr0, 1, 0, HPMPWM::Polarity::NORMAL);

// Hardware registration
XR_REGISTER(power_manager, LibXR::PowerManager);

XR_REGISTER(pa10, LibXR::GPIO);
XR_REGISTER(pa3, LibXR::GPIO);

Expand Down
4 changes: 4 additions & 0 deletions tests/data/hpm/rmcs_slave_lite_expected_app_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "libxr.hpp"
#include "hpm_gpio.hpp"
#include "hpm_power.hpp"
#include "hpm_soc.h"
#include "hpm_timebase.hpp"
#include "xrobot_main.hpp"
Expand All @@ -23,6 +24,7 @@ extern "C" void app_main(void)
// Timebase and platform
static HPMTimebase timebase;
PlatformInit();
static HPMPowerManager power_manager;

// GPIO: init_bsp_pins() configured pb11 (PB11) as an output pin, pb13 (PB13) as an
// output pin, pb12 (PB12) as an input pin, pb10 (PB10) as an input pin, pa31 (PA31) as
Expand All @@ -36,6 +38,8 @@ extern "C" void app_main(void)
static HPMGPIO pa31(HPM_GPIO0, GPIO_DI_GPIOA, 31, IRQn_GPIO0_A);

// Hardware registration
XR_REGISTER(power_manager, LibXR::PowerManager);

XR_REGISTER(pb11, LibXR::GPIO);
XR_REGISTER(pb13, LibXR::GPIO);
XR_REGISTER(pb12, LibXR::GPIO);
Expand Down
4 changes: 4 additions & 0 deletions tests/data/mspm0/g3507_expected_app_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "libxr.hpp"
#include "mspm0_gpio.hpp"
#include "mspm0_i2c.hpp"
#include "mspm0_power.hpp"
#include "mspm0_pwm.hpp"
#include "mspm0_spi.hpp"
#include "mspm0_timebase.hpp"
Expand Down Expand Up @@ -63,6 +64,7 @@ extern "C" void app_main(void)
// Timebase and platform
static MSPM0Timebase timebase;
PlatformInit();
static MSPM0PowerManager power_manager;

// GPIO: SysConfig configured LED1 (PB8), LED2 (PA16) as output pins and KEY1 (PB24),
// KEY2 (PB20) as input pins. The interrupt edge comes from SysConfig; RegisterCallback
Expand Down Expand Up @@ -105,6 +107,8 @@ extern "C" void app_main(void)
Timer::Start(terminal_task);

// Hardware registration
XR_REGISTER(power_manager, LibXR::PowerManager);

XR_REGISTER(LED1, LibXR::GPIO);
XR_REGISTER(LED2, LibXR::GPIO);
XR_REGISTER(KEY1, LibXR::GPIO);
Expand Down
4 changes: 4 additions & 0 deletions tests/data/mspm0/g3519_expected_app_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "libxr.hpp"
#include "mspm0_gpio.hpp"
#include "mspm0_i2c.hpp"
#include "mspm0_power.hpp"
#include "mspm0_pwm.hpp"
#include "mspm0_spi.hpp"
#include "mspm0_timebase.hpp"
Expand Down Expand Up @@ -66,6 +67,7 @@ extern "C" void app_main(void)
// Timebase and platform
static MSPM0Timebase timebase;
PlatformInit();
static MSPM0PowerManager power_manager;

// GPIO: SysConfig configured LED1 (PA25), LED2 (PA16) as output pins and KEY1 (PB24),
// KEY2 (PB20) as input pins. The interrupt edge comes from SysConfig; RegisterCallback
Expand Down Expand Up @@ -108,6 +110,8 @@ extern "C" void app_main(void)
Timer::Start(terminal_task);

// Hardware registration
XR_REGISTER(power_manager, LibXR::PowerManager);

XR_REGISTER(LED1, LibXR::GPIO);
XR_REGISTER(LED2, LibXR::GPIO);
XR_REGISTER(KEY1, LibXR::GPIO);
Expand Down
4 changes: 4 additions & 0 deletions tests/data/mspm0/variants_expected_app_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "libxr.hpp"
#include "mspm0_gpio.hpp"
#include "mspm0_i2c.hpp"
#include "mspm0_power.hpp"
#include "mspm0_pwm.hpp"
#include "mspm0_spi.hpp"
#include "mspm0_timebase.hpp"
Expand Down Expand Up @@ -55,6 +56,7 @@ extern "C" void app_main(void)
// Timebase and platform
static MSPM0Timebase timebase;
PlatformInit();
static MSPM0PowerManager power_manager;

// GPIO: SysConfig configured USER_LED_1 (PA26), USER_LED_2 (PA27) as output pins and
// gpio_btn_pin_0 (PA7) as input pins. The interrupt edge comes from SysConfig;
Expand Down Expand Up @@ -96,6 +98,8 @@ extern "C" void app_main(void)
Timer::Start(terminal_task);

// Hardware registration
XR_REGISTER(power_manager, LibXR::PowerManager);

XR_REGISTER(USER_LED_1, LibXR::GPIO);
XR_REGISTER(USER_LED_2, LibXR::GPIO);
XR_REGISTER(gpio_btn_pin_0, LibXR::GPIO);
Expand Down
35 changes: 28 additions & 7 deletions tests/test_generator_code_hpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class Generation(TestCase):

def setUp(self):
super().setUp()
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()

def generate(self, name: str, use_xrobot: bool = True) -> tuple[Path, str]:
Expand Down Expand Up @@ -233,6 +233,27 @@ def test_without_xrobot_the_entry_sleeps_and_registers_nothing(self):
# The objects are still generated.
self.assertIn("static HPMPWM pwm_gptmr0_ch1(", code)

def test_power_manager_is_generated_always_and_registered_only_with_xrobot(self):
# power_manager 对象总是生成,登记只在使用 XRobot 时;GPIO 不能改叫 power_manager。
# The power_manager object is always generated; it is registered only with XRobot, and
# a GPIO cannot be renamed to power_manager.
root, code = self.generate("hpm5301evklite", use_xrobot=False)
self.assertIn('#include "hpm_power.hpp"', code)
self.assertIn("static HPMPowerManager power_manager;", code)
self.assertNotIn("XR_REGISTER", code)
output = root / "User" / "app_main.cpp"
generator.generate(str(root / ".config.yaml"), str(output), True, "")
self.assertIn(
"XR_REGISTER(power_manager, LibXR::PowerManager);",
output.read_text(encoding="utf-8"),
)
(root / "User" / "libxr_config.yaml").write_text(
"GPIO:\n pa10: power_manager\n", encoding="utf-8"
)
with self.assertLogs(level="ERROR") as logs, self.assertRaises(SystemExit):
generator.generate(str(root / ".config.yaml"), str(output), True, "")
self.assertIn("a name of the HPM SDK or of the generated code", "\n".join(logs.output))


class Notices(TestCase):
"""解析的两条提示(P3 遗留):main.c 不调用 pinmux 函数,两个活动函数选中同一个 pad。
Expand Down Expand Up @@ -478,7 +499,7 @@ class GenerationChecks(TestCase):

def setUp(self):
super().setUp()
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()

def generate(self, config: str | None = None, root: Path | None = None) -> tuple[Path, str]:
Expand Down Expand Up @@ -546,7 +567,7 @@ def test_unusable_gpio_names_are_listed_together(self):
("1led", "not a valid C++ identifier"),
):
with self.subTest(name=name):
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()
self.assertGenerationFails(f"GPIO:\n pa10: '{name}'\n", problem)

Expand All @@ -555,13 +576,13 @@ def test_sdk_macros_and_generated_names_are_refused_and_plain_names_pass(self):
# Review C1: function-like macros and names the generated code uses (NORMAL is the
# polarity of the PWM) are refused; gpio_led is fine.
self.assertGenerationFails("GPIO:\n pa10: MAX\n", "GPIO.pa10 'MAX'")
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()
self.assertGenerationFails(
"GPIO:\n pa10: NORMAL\n",
"the generated code uses the names for something else: NORMAL",
)
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()
_root, code = self.generate("GPIO:\n pa10: gpio_led\n pa3: board_key\n")
self.assertIn("static HPMGPIO gpio_led(", code)
Expand All @@ -571,7 +592,7 @@ def test_a_null_or_literal_speed_is_read_as_on_the_other_platforms(self):
# Review C3: null takes the default, a string is read as an integer literal.
_root, code = self.generate("I2C:\n i2c3:\n speed:\n")
self.assertIn("{100000U}", code)
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()
_root, code = self.generate("I2C:\n i2c3:\n speed: '0x61A80'\n")
self.assertIn("{400000U}", code)
Expand All @@ -582,7 +603,7 @@ def test_a_gpio_rename_must_be_a_name(self):
def test_a_pwm_frequency_must_be_a_positive_integer(self):
for value in ("0", "-5", "abc", "1.5", "true"):
with self.subTest(value=value):
generator.initialize_registry()
generator.initialize_registry(False)
generator.reset_settings()
self.assertGenerationFails(
f"PWM:\n pwm_gptmr0_ch1:\n frequency: {value}\n",
Expand Down
Loading
Loading