From d4486eac2bcd018fd73424daade6985cc6b181cf Mon Sep 17 00:00:00 2001 From: Andelf Date: Tue, 2 Jul 2024 10:06:27 +0800 Subject: [PATCH] feat(hpm63): add demo project with raw blinky --- examples/hpm6300evk/.cargo/config.toml | 30 +++ examples/hpm6300evk/Cargo.toml | 24 +++ examples/hpm6300evk/link-fixed.x | 225 ++++++++++++++++++++++ examples/hpm6300evk/memory-ram.x | 35 ++++ examples/hpm6300evk/memory-xip.x | 39 ++++ examples/hpm6300evk/memory.x | 39 ++++ examples/hpm6300evk/src/bin/raw_blinky.rs | 48 +++++ examples/hpm6300evk/src/bin/rtt.rs | 46 +++++ examples/hpm6300evk/src/lib.rs | 1 + 9 files changed, 487 insertions(+) create mode 100644 examples/hpm6300evk/.cargo/config.toml create mode 100644 examples/hpm6300evk/Cargo.toml create mode 100644 examples/hpm6300evk/link-fixed.x create mode 100644 examples/hpm6300evk/memory-ram.x create mode 100644 examples/hpm6300evk/memory-xip.x create mode 100644 examples/hpm6300evk/memory.x create mode 100644 examples/hpm6300evk/src/bin/raw_blinky.rs create mode 100644 examples/hpm6300evk/src/bin/rtt.rs create mode 100644 examples/hpm6300evk/src/lib.rs diff --git a/examples/hpm6300evk/.cargo/config.toml b/examples/hpm6300evk/.cargo/config.toml new file mode 100644 index 0000000..438723d --- /dev/null +++ b/examples/hpm6300evk/.cargo/config.toml @@ -0,0 +1,30 @@ +[build] +target = "riscv32imafc-unknown-none-elf" + +[target.riscv32imafc-unknown-none-elf] +# runner = 'riscv64-unknown-elf-gdb -x ../../openocd.gdb' +runner = "probe-rs run --chip HPM6360 --protocol jtag --chip-description-path ../../HPMicro.yaml" + +rustflags = [ + # +zba,+zbb,+zbc,+zbs are not available + # Linker scripts: + "-C", + "link-arg=-Tmemory.x", + "-C", + "link-arg=-Tdevice.x", # __VECTORED_INTERRUPTS + "-C", + "link-arg=-Tlink-fixed.x", + "-C", + "link-arg=-Tdefmt.x", + "-C", + "link-arg=-nmagic", + + # "--emit", "obj", + # "--emit", "asm", +] + +[unstable] +build-std = ["core"] + +[env] +DEFMT_LOG = "info" diff --git a/examples/hpm6300evk/Cargo.toml b/examples/hpm6300evk/Cargo.toml new file mode 100644 index 0000000..264e1d6 --- /dev/null +++ b/examples/hpm6300evk/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "hpm6300evk" +version = "0.1.0" +edition = "2021" + +[dependencies] +defmt = "0.3.8" +defmt-rtt = "0.4.1" +embedded-hal = "1.0.0" +hpm-metapac = { path = "../../../hpm-data/build/hpm-metapac", features = [ + "hpm6360", + "memory-x", + "rt", +] } +panic-halt = "0.2.0" +riscv = { version = "0.11.1", features = ["critical-section-single-hart"] } +riscv-rt = { version = "0.12.2", features = ["single-hart"] } + + +[profile.release] +strip = false # symbols are not flashed to the microcontroller, so don't strip them. +lto = true +opt-level = "z" # Optimize for size. +debug = 2 diff --git a/examples/hpm6300evk/link-fixed.x b/examples/hpm6300evk/link-fixed.x new file mode 100644 index 0000000..b5a058e --- /dev/null +++ b/examples/hpm6300evk/link-fixed.x @@ -0,0 +1,225 @@ +/* Temp fix for https://github.com/rust-embedded/riscv/issues/196 */ + +/* # Developer notes + +- Symbols that start with a double underscore (__) are considered "private" + +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { + static mut _heap_size }`). + +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a + symbol if not dropped if it appears in or near the front of the linker arguments and "it's not + needed" by any of the preceding objects (linker arguments) + +- `PROVIDE` is used to provide default values that can be overridden by a user linker script + +- In this linker script, you may find symbols that look like `${...}` (e.g., `4`). + These are wildcards used by the `build.rs` script to adapt to different target particularities. + Check `build.rs` for more details about these symbols. + +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* + the LMA of .data are all `4`-byte aligned. These alignments are assumed by the RAM + initialization routine. There's also a second benefit: `4`-byte aligned boundaries + means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`. +*/ + +PROVIDE(_stext = ORIGIN(REGION_TEXT)); +PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)); +PROVIDE(_max_hart_id = 0); +PROVIDE(_hart_stack_size = 2K); +PROVIDE(_heap_size = 0); + +PROVIDE(InstructionMisaligned = ExceptionHandler); +PROVIDE(InstructionFault = ExceptionHandler); +PROVIDE(IllegalInstruction = ExceptionHandler); +PROVIDE(Breakpoint = ExceptionHandler); +PROVIDE(LoadMisaligned = ExceptionHandler); +PROVIDE(LoadFault = ExceptionHandler); +PROVIDE(StoreMisaligned = ExceptionHandler); +PROVIDE(StoreFault = ExceptionHandler);; +PROVIDE(UserEnvCall = ExceptionHandler); +PROVIDE(SupervisorEnvCall = ExceptionHandler); +PROVIDE(MachineEnvCall = ExceptionHandler); +PROVIDE(InstructionPageFault = ExceptionHandler); +PROVIDE(LoadPageFault = ExceptionHandler); +PROVIDE(StorePageFault = ExceptionHandler); + +PROVIDE(SupervisorSoft = DefaultHandler); +PROVIDE(MachineSoft = DefaultHandler); +PROVIDE(SupervisorTimer = DefaultHandler); +PROVIDE(MachineTimer = DefaultHandler); +PROVIDE(SupervisorExternal = DefaultHandler); +PROVIDE(MachineExternal = DefaultHandler); + +PROVIDE(DefaultHandler = DefaultInterruptHandler); +PROVIDE(ExceptionHandler = DefaultExceptionHandler); + +/* # Pre-initialization function */ +/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function, + then the function this points to will be called before the RAM is initialized. */ +PROVIDE(__pre_init = default_pre_init); + +/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ +PROVIDE(_setup_interrupts = default_setup_interrupts); + +/* # Multi-processing hook function + fn _mp_hook() -> bool; + + This function is called from all the harts and must return true only for one hart, + which will perform memory initialization. For other harts it must return false + and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt). +*/ +PROVIDE(_mp_hook = default_mp_hook); + +/* # Start trap function override + By default uses the riscv crates default trap handler + but by providing the `_start_trap` symbol external crates can override. +*/ +PROVIDE(_start_trap = default_start_trap); + +SECTIONS +{ + .text.dummy (NOLOAD) : + { + /* This section is intended to make _stext address work */ + . = ABSOLUTE(_stext); + } > REGION_TEXT + + .text _stext : + { + /* Put reset handler first in .text section so it ends up as the entry */ + /* point of the program. */ + KEEP(*(.init)); + KEEP(*(.init.rust)); + . = ALIGN(4); + *(.trap); + *(.trap.rust); + *(.text.abort); + *(.text .text.*); + } > REGION_TEXT + + /* Fast code section */ + .fast : ALIGN(4) + { + _sifast = LOADADDR(.fast); + _sfast = .; + *(.fast) + *(.fast.*) + . = ALIGN(4); + PROVIDE(_efast= .); /* No idea why `PROVIDE` is needed here */ + } > REGION_FASTTEXT AT > REGION_RODATA + + .rodata : ALIGN(4) + { + *(.srodata .srodata.*); + *(.rodata .rodata.*); + + /* 4-byte align the end (VMA) of this section. + This is required by LLD to ensure the LMA of the following .data + section will have the correct alignment. */ + . = ALIGN(4); + } > REGION_RODATA + + .data : ALIGN(4) + { + _sidata = LOADADDR(.data); + _sdata = .; + /* Must be called __global_pointer$ for linker relaxations to work. */ + PROVIDE(__global_pointer$ = . + 0x800); + *(.sdata .sdata.* .sdata2 .sdata2.*); + *(.data .data.*); + . = ALIGN(4); + _edata = .; + } > REGION_DATA AT > REGION_RODATA + + .bss (NOLOAD) : ALIGN(4) + { + _sbss = .; + *(.sbss .sbss.* .bss .bss.*); + . = ALIGN(4); + _ebss = .; + } > REGION_BSS + + /* fictitious region that represents the memory available for the heap */ + .heap (NOLOAD) : + { + _sheap = .; + . += _heap_size; + . = ALIGN(4); + _eheap = .; + } > REGION_HEAP + + /* fictitious region that represents the memory available for the stack */ + .stack (NOLOAD) : + { + _estack = .; + . = ABSOLUTE(_stack_start); + _sstack = .; + } > REGION_STACK + + /* fake output .got section */ + /* Dynamic relocations are unsupported. This section is only used to detect + relocatable code in the input files and raise an error if relocatable code + is found */ + .got (INFO) : + { + KEEP(*(.got .got.*)); + } + + /*.eh_frame (INFO) : { KEEP(*(.eh_frame)) } + .eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }*/ + .eh_frame : { KEEP(*(.eh_frame)) } > REGION_TEXT + .eh_frame_hdr : { *(.eh_frame_hdr) } > REGION_TEXT +} + +/* Do not exceed this mark in the error messages above | */ +ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_DATA) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_STACK) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned"); + +ASSERT(_stext % 4 == 0, " +ERROR(riscv-rt): `_stext` must be 4-byte aligned"); + +ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, " +BUG(riscv-rt): .data is not 4-byte aligned"); + +ASSERT(_sidata % 4 == 0, " +BUG(riscv-rt): the LMA of .data is not 4-byte aligned"); + +ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, " +BUG(riscv-rt): .bss is not 4-byte aligned"); + +ASSERT(_sheap % 4 == 0, " +BUG(riscv-rt): start of .heap is not 4-byte aligned"); + +ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), " +ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region. +Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'"); + +ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, " +ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts. +Consider changing `_max_hart_id` or `_hart_stack_size`."); + +ASSERT(SIZEOF(.got) == 0, " +.got section detected in the input files. Dynamic relocations are not +supported. If you are linking to C code compiled using the `gcc` crate +then modify your build script to compile the C code _without_ the +-fPIC flag. See the documentation of the `gcc::Config.fpic` method for +details."); + +/* Do not exceed this mark in the error messages above | */ diff --git a/examples/hpm6300evk/memory-ram.x b/examples/hpm6300evk/memory-ram.x new file mode 100644 index 0000000..fb57923 --- /dev/null +++ b/examples/hpm6300evk/memory-ram.x @@ -0,0 +1,35 @@ +MEMORY +{ + ILM0 : ORIGIN = 0x00000000, LENGTH = 128K + DLM0 : ORIGIN = 0x00080000, LENGTH = 128K /* data local memory */ + + AXI_SRAM : ORIGIN = 0x01200000, LENGTH = 512K + AHB_SRAM : ORIGIN = 0xF0300000, LENGTH = 32K +} +REGION_ALIAS("REGION_TEXT", ILM0); +REGION_ALIAS("REGION_RODATA", ILM0); +REGION_ALIAS("REGION_DATA", DLM0); +REGION_ALIAS("REGION_BSS", DLM0) +REGION_ALIAS("REGION_HEAP", DLM0); +REGION_ALIAS("REGION_STACK", DLM0); +REGION_ALIAS("REGION_FASTTEXT", ILM0); + + +/* +SECTIONS +{ + .fast : ALIGN(4) + { + . = ALIGN(8); + __fast_load_addr__ = LOADADDR(.fast); + __fast_start_addr__ = .; + PROVIDE(__ramfunc_start__ = .); + *(.fast) + *(.fast.*) + . = ALIGN(8); + PROVIDE(__ramfunc_end__ = .); + __fast_end_addr__ = .; + } > ILM +} + +*/ diff --git a/examples/hpm6300evk/memory-xip.x b/examples/hpm6300evk/memory-xip.x new file mode 100644 index 0000000..e21bd41 --- /dev/null +++ b/examples/hpm6300evk/memory-xip.x @@ -0,0 +1,39 @@ +MEMORY +{ + XPI0_HEADER : ORIGIN = 0x80000000, LENGTH = 0x3000 /* bootheader */ + XPI0_APP : ORIGIN = 0x80003000, LENGTH = 1024K - 0x3000 /* app firmware */ + + ILM0 : ORIGIN = 0x00000000, LENGTH = 128K + DLM0 : ORIGIN = 0x00080000, LENGTH = 128K /* data local memory */ + + AXI_SRAM : ORIGIN = 0x01200000, LENGTH = 512K + AHB_SRAM : ORIGIN = 0xF0300000, LENGTH = 32K +} + +REGION_ALIAS("REGION_TEXT", XPI0_APP); +REGION_ALIAS("REGION_RODATA", XPI0_APP); +REGION_ALIAS("REGION_DATA", DLM0); +REGION_ALIAS("REGION_BSS", DLM0) +REGION_ALIAS("REGION_HEAP", DLM0); +REGION_ALIAS("REGION_STACK", DLM0); +REGION_ALIAS("REGION_FASTTEXT", ILM0); + + +/* +SECTIONS +{ + .fast : ALIGN(4) + { + . = ALIGN(8); + __fast_load_addr__ = LOADADDR(.fast); + __fast_start_addr__ = .; + PROVIDE(__ramfunc_start__ = .); + *(.fast) + *(.fast.*) + . = ALIGN(8); + PROVIDE(__ramfunc_end__ = .); + __fast_end_addr__ = .; + } > ILM +} + +*/ diff --git a/examples/hpm6300evk/memory.x b/examples/hpm6300evk/memory.x new file mode 100644 index 0000000..48e11a7 --- /dev/null +++ b/examples/hpm6300evk/memory.x @@ -0,0 +1,39 @@ +MEMORY +{ + XPI0_HEADER : ORIGIN = 0x80000000, LENGTH = 0x3000 /* bootheader */ + XPI0_APP : ORIGIN = 0x80003000, LENGTH = 1024K - 0x3000 /* app firmware */ + + ILM0 : ORIGIN = 0x00000000, LENGTH = 128K /* instruction local memory */ + DLM0 : ORIGIN = 0x00080000, LENGTH = 128K /* data local memory */ + + AXI_SRAM : ORIGIN = 0x01200000, LENGTH = 512K + AHB_SRAM : ORIGIN = 0xF0300000, LENGTH = 32K +} + +REGION_ALIAS("REGION_TEXT", XPI0_APP); +REGION_ALIAS("REGION_RODATA", XPI0_APP); +REGION_ALIAS("REGION_DATA", DLM0); +REGION_ALIAS("REGION_BSS", DLM0) +REGION_ALIAS("REGION_HEAP", DLM0); +REGION_ALIAS("REGION_STACK", DLM0); +REGION_ALIAS("REGION_FASTTEXT", ILM0); + + +/* +SECTIONS +{ + .fast : ALIGN(4) + { + . = ALIGN(8); + __fast_load_addr__ = LOADADDR(.fast); + __fast_start_addr__ = .; + PROVIDE(__ramfunc_start__ = .); + *(.fast) + *(.fast.*) + . = ALIGN(8); + PROVIDE(__ramfunc_end__ = .); + __fast_end_addr__ = .; + } > ILM +} + +*/ diff --git a/examples/hpm6300evk/src/bin/raw_blinky.rs b/examples/hpm6300evk/src/bin/raw_blinky.rs new file mode 100644 index 0000000..f2b5e3b --- /dev/null +++ b/examples/hpm6300evk/src/bin/raw_blinky.rs @@ -0,0 +1,48 @@ +#![no_main] +#![no_std] + +use embedded_hal::delay::DelayNs; +use pac::gpiom::vals; +use riscv::delay::McycleDelay; +use {hpm_metapac as pac, panic_halt as _}; + +// defmt_rtt as _, + +#[riscv_rt::entry] +fn main() -> ! { + pac::PCFG.dcdc_mode().modify(|w| w.set_volt(1100)); + + // default clock + let mut delay = McycleDelay::new(480_000_000); + + // ugly but works + pac::SYSCTL.group0(0).set().modify(|w| w.0 = 0xFFFFFFFF); + pac::SYSCTL.group0(1).set().modify(|w| w.0 = 0xFFFFFFFF); + + pac::SYSCTL.affiliate(0).set().write(|w| w.set_link(1)); + + /* + pac::IOC.pad(142).func_ctl().modify(|w| w.set_alt_select(0)); + pac::IOC.pad(142).pad_ctl().write(|w| { + w.set_pe(true); + }); + */ + + const PA: usize = 0; + pac::GPIOM.assign(PA).pin(7).modify(|w| { + w.set_select(vals::PinSelect::CPU0_FGPIO); // FGPIO0 + w.set_hide(0b01); // invisible to GPIO0 + }); + + pac::FGPIO.oe(PA).set().write(|w| w.set_direction(1 << 7)); + + // defmt::info!("Board init!"); + + loop { + // defmt::info!("tick"); + + pac::FGPIO.do_(PA).toggle().write(|w| w.set_output(1 << 7)); + + delay.delay_ms(1000); + } +} diff --git a/examples/hpm6300evk/src/bin/rtt.rs b/examples/hpm6300evk/src/bin/rtt.rs new file mode 100644 index 0000000..2ceb318 --- /dev/null +++ b/examples/hpm6300evk/src/bin/rtt.rs @@ -0,0 +1,46 @@ +#![no_main] +#![no_std] + +use embedded_hal::delay::DelayNs; +use pac::gpiom::vals; +use riscv::delay::McycleDelay; +use {defmt_rtt as _, hpm_metapac as pac, panic_halt as _}; + +#[riscv_rt::entry] +fn main() -> ! { + pac::PCFG.dcdc_mode().modify(|w| w.set_volt(1100)); + + // default clock + let mut delay = McycleDelay::new(480_000_000); + + // ugly but works + pac::SYSCTL.group0(0).set().modify(|w| w.0 = 0xFFFFFFFF); + pac::SYSCTL.group0(1).set().modify(|w| w.0 = 0xFFFFFFFF); + + pac::SYSCTL.affiliate(0).set().write(|w| w.set_link(1)); + + /* + pac::IOC.pad(142).func_ctl().modify(|w| w.set_alt_select(0)); + pac::IOC.pad(142).pad_ctl().write(|w| { + w.set_pe(true); + }); + */ + + const PA: usize = 0; + pac::GPIOM.assign(PA).pin(7).modify(|w| { + w.set_select(vals::PinSelect::CPU0_FGPIO); // FGPIO0 + w.set_hide(0b01); // invisible to GPIO0 + }); + + pac::FGPIO.oe(PA).set().write(|w| w.set_direction(1 << 7)); + + defmt::info!("Board init!"); + + loop { + defmt::info!("tick"); + + pac::FGPIO.do_(PA).toggle().write(|w| w.set_output(1 << 7)); + + delay.delay_ms(1000); + } +} diff --git a/examples/hpm6300evk/src/lib.rs b/examples/hpm6300evk/src/lib.rs new file mode 100644 index 0000000..0c9ac1a --- /dev/null +++ b/examples/hpm6300evk/src/lib.rs @@ -0,0 +1 @@ +#![no_std]