Initial implementation of ram proc macro (#6)
* Add .iram section for ESP32C3, make it possible to use direct-boot or normal-boot * Add ram proc-macro
This commit is contained in:
parent
9bbe5e0987
commit
70109ffe36
@ -17,6 +17,7 @@ paste = "1.0"
|
||||
riscv = { version = "0.7", optional = true }
|
||||
void = { version = "1.0", default-features = false }
|
||||
xtensa-lx = { version = "0.4", optional = true }
|
||||
procmacros = { path = "../esp-hal-procmacros", package = "esp-hal-procmacros" }
|
||||
# IMPORTANT:
|
||||
# Each supported device MUST have its PAC included below along with a
|
||||
# corresponding feature.
|
||||
@ -26,7 +27,7 @@ esp32s2_pac = { package = "esp32s2", git = "https://github.com/jessebraham/esp32
|
||||
esp32s3_pac = { package = "esp32s3", git = "https://github.com/jessebraham/esp32s3.git", branch = "develop", optional = true }
|
||||
|
||||
[features]
|
||||
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6"]
|
||||
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"]
|
||||
esp32c3 = ["esp32c3_pac", "esp32c3_pac/rt", "riscv"]
|
||||
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6"] # FIXME
|
||||
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6"] # FIXME
|
||||
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME
|
||||
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME
|
||||
|
||||
@ -37,3 +37,6 @@ pub use delay::Delay;
|
||||
pub use gpio::*;
|
||||
pub use serial::Serial;
|
||||
pub use timer::Timer;
|
||||
|
||||
use procmacros;
|
||||
pub use procmacros::ram;
|
||||
|
||||
24
esp-hal-procmacros/Cargo.toml
Normal file
24
esp-hal-procmacros/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "esp-hal-procmacros"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Jesse Braham <jesse@beta7.io>",
|
||||
"Björn Quentin <bjoern.quentin@mobile-j.de>",
|
||||
]
|
||||
edition = "2021"
|
||||
description = "Procedural macros for ESP-HAL"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
darling = "0.10"
|
||||
syn = {version = "1.0", features = ["extra-traits", "full"]}
|
||||
proc-macro-error = "1.0.4"
|
||||
|
||||
[features]
|
||||
rtc_slow = []
|
||||
91
esp-hal-procmacros/src/lib.rs
Normal file
91
esp-hal-procmacros/src/lib.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use darling::FromMeta;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro::{self, Span};
|
||||
use proc_macro_error::{abort, proc_macro_error};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, AttributeArgs};
|
||||
|
||||
#[derive(Debug, Default, FromMeta)]
|
||||
#[darling(default)]
|
||||
struct RamArgs {
|
||||
rtc_fast: bool,
|
||||
rtc_slow: bool,
|
||||
uninitialized: bool,
|
||||
zeroed: bool,
|
||||
}
|
||||
|
||||
/// This attribute allows placing statics and functions into ram.
|
||||
///
|
||||
/// Options that can be specified are rtc_slow or rtc_fast to use the
|
||||
/// RTC slow or RTC fast ram instead of the normal SRAM.
|
||||
///
|
||||
/// The uninitialized option will skip initialization of the memory
|
||||
/// (e.g. to persist it across resets or deep sleep mode for the RTC RAM)
|
||||
///
|
||||
/// Not all targets support RTC slow ram.
|
||||
|
||||
#[proc_macro_attribute]
|
||||
#[proc_macro_error]
|
||||
pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let attr_args = parse_macro_input!(args as AttributeArgs);
|
||||
|
||||
let RamArgs {
|
||||
rtc_fast,
|
||||
rtc_slow,
|
||||
uninitialized,
|
||||
zeroed,
|
||||
} = match FromMeta::from_list(&attr_args) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return e.write_errors().into();
|
||||
}
|
||||
};
|
||||
|
||||
let item: syn::Item = syn::parse(input).expect("failed to parse input");
|
||||
|
||||
#[cfg(not(feature = "rtc_slow"))]
|
||||
if rtc_slow {
|
||||
abort!(
|
||||
Span::call_site(),
|
||||
"rtc_slow is not available for this target"
|
||||
);
|
||||
}
|
||||
|
||||
let is_fn = matches!(item, syn::Item::Fn(_));
|
||||
let section_name = match (is_fn, rtc_fast, rtc_slow, uninitialized, zeroed) {
|
||||
(true, false, false, false, false) => Ok(".rwtext"),
|
||||
(true, true, false, false, false) => Ok(".rtc_fast.text"),
|
||||
(true, false, true, false, false) => Ok(".rtc_slow.text"),
|
||||
|
||||
(false, false, false, false, false) => Ok(".data"),
|
||||
|
||||
(false, true, false, false, false) => Ok(".rtc_fast.data"),
|
||||
(false, true, false, true, false) => Ok(".rtc_fast.noinit"),
|
||||
(false, true, false, false, true) => Ok(".rtc_fast.bss"),
|
||||
|
||||
(false, false, true, false, false) => Ok(".rtc_slow.data"),
|
||||
(false, false, true, true, false) => Ok(".rtc_slow.noinit"),
|
||||
(false, false, true, false, true) => Ok(".rtc_slow.bss"),
|
||||
|
||||
_ => Err(()),
|
||||
};
|
||||
|
||||
let section = match (is_fn, section_name) {
|
||||
(true, Ok(section_name)) => quote! {
|
||||
#[link_section = #section_name]
|
||||
#[inline(never)] // make certain function is not inlined
|
||||
},
|
||||
(false, Ok(section_name)) => quote! {
|
||||
#[link_section = #section_name]
|
||||
},
|
||||
(_, Err(_)) => {
|
||||
abort!(Span::call_site(), "Invalid combination of ram arguments");
|
||||
}
|
||||
};
|
||||
|
||||
let output = quote! {
|
||||
#section
|
||||
#item
|
||||
};
|
||||
output.into()
|
||||
}
|
||||
91
esp32-hal/examples/ram.rs
Normal file
91
esp32-hal/examples/ram.rs
Normal file
@ -0,0 +1,91 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
use esp32_hal::{
|
||||
pac::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
ram,
|
||||
Serial,
|
||||
Timer,
|
||||
};
|
||||
use nb::block;
|
||||
use panic_halt as _;
|
||||
use xtensa_lx_rt::entry;
|
||||
|
||||
#[ram(rtc_fast)]
|
||||
static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
|
||||
|
||||
#[ram(rtc_fast, uninitialized)]
|
||||
static mut SOME_UNINITED_DATA: [u8; 2] = [0; 2];
|
||||
|
||||
#[ram(rtc_fast, zeroed)]
|
||||
static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||
|
||||
// Disable watchdog timer
|
||||
timer0.disable();
|
||||
|
||||
timer0.start(10_000_000u64);
|
||||
|
||||
writeln!(
|
||||
serial0,
|
||||
"IRAM function located at {:p}",
|
||||
function_in_ram as *const ()
|
||||
)
|
||||
.unwrap();
|
||||
unsafe {
|
||||
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
|
||||
|
||||
SOME_INITED_DATA[0] = 0xff;
|
||||
SOME_ZEROED_DATA[0] = 0xff;
|
||||
|
||||
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
|
||||
|
||||
if SOME_UNINITED_DATA[0] != 0 {
|
||||
SOME_UNINITED_DATA[0] = 0;
|
||||
SOME_UNINITED_DATA[1] = 0;
|
||||
}
|
||||
|
||||
if SOME_UNINITED_DATA[1] == 0xff {
|
||||
SOME_UNINITED_DATA[1] = 0;
|
||||
}
|
||||
|
||||
writeln!(serial0, "Counter {}", SOME_UNINITED_DATA[1]).unwrap();
|
||||
SOME_UNINITED_DATA[1] += 1;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
serial0,
|
||||
"RTC_FAST function located at {:p}",
|
||||
function_in_rtc_ram as *const ()
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(serial0, "Result {}", function_in_rtc_ram()).unwrap();
|
||||
|
||||
loop {
|
||||
function_in_ram(&mut serial0);
|
||||
block!(timer0.wait()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn function_in_ram(serial0: &mut Serial<UART0>) {
|
||||
writeln!(serial0, "Hello world!").unwrap();
|
||||
}
|
||||
|
||||
#[ram(rtc_fast)]
|
||||
fn function_in_rtc_ram() -> u32 {
|
||||
42
|
||||
}
|
||||
@ -78,16 +78,16 @@ SECTIONS {
|
||||
|
||||
.rtc_fast.data :
|
||||
{
|
||||
_rtc_fast_data_start = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_rtc_fast_data_start = ABSOLUTE(.);
|
||||
*(.rtc_fast.data .rtc_fast.data.*)
|
||||
_rtc_fast_data_end = ABSOLUTE(.);
|
||||
} > rtc_fast_dram_seg AT > RODATA
|
||||
|
||||
.rtc_fast.bss (NOLOAD) :
|
||||
{
|
||||
_rtc_fast_bss_start = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_rtc_fast_bss_start = ABSOLUTE(.);
|
||||
*(.rtc_fast.bss .rtc_fast.bss.*)
|
||||
_rtc_fast_bss_end = ABSOLUTE(.);
|
||||
} > rtc_fast_dram_seg
|
||||
@ -106,16 +106,16 @@ SECTIONS {
|
||||
|
||||
.rtc_slow.data :
|
||||
{
|
||||
_rtc_slow_data_start = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_rtc_slow_data_start = ABSOLUTE(.);
|
||||
*(.rtc_slow.data .rtc_slow.data.*)
|
||||
_rtc_slow_data_end = ABSOLUTE(.);
|
||||
} > rtc_slow_seg AT > RODATA
|
||||
|
||||
.rtc_slow.bss (NOLOAD) :
|
||||
{
|
||||
_rtc_slow_bss_start = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_rtc_slow_bss_start = ABSOLUTE(.);
|
||||
*(.rtc_slow.bss .rtc_slow.bss.*)
|
||||
_rtc_slow_bss_end = ABSOLUTE(.);
|
||||
} > rtc_slow_seg
|
||||
|
||||
@ -7,6 +7,8 @@ pub use self::gpio::IO;
|
||||
|
||||
pub mod gpio;
|
||||
|
||||
pub use esp_hal_common::ram;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
[target.riscv32imc-unknown-none-elf]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tesp32c3-link.x",
|
||||
]
|
||||
|
||||
[build]
|
||||
|
||||
@ -32,6 +32,7 @@ embedded-hal = { version = "0.2", features = ["unproven"] }
|
||||
nb = "1.0"
|
||||
riscv = "0.7"
|
||||
void = { version = "1.0", default-features = false }
|
||||
r0 = "1.0.0"
|
||||
|
||||
[dependencies.esp-hal-common]
|
||||
path = "../esp-hal-common"
|
||||
@ -48,3 +49,4 @@ panic-halt = "0.2"
|
||||
[features]
|
||||
default = ["rt"]
|
||||
rt = ["riscv-rt"]
|
||||
normalboot = []
|
||||
|
||||
44
esp32c3-hal/bl-esp32c3-memory.x
Normal file
44
esp32c3-hal/bl-esp32c3-memory.x
Normal file
@ -0,0 +1,44 @@
|
||||
MEMORY
|
||||
{
|
||||
/*
|
||||
https://github.com/espressif/esptool/blob/master/esptool.py#L1919
|
||||
MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x3C000000, 0x3C800000, "DROM"],
|
||||
[0x3FC80000, 0x3FCE0000, "DRAM"],
|
||||
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
|
||||
[0x3FF00000, 0x3FF20000, "DROM_MASK"],
|
||||
[0x40000000, 0x40060000, "IROM_MASK"],
|
||||
[0x42000000, 0x42800000, "IROM"],
|
||||
[0x4037C000, 0x403E0000, "IRAM"],
|
||||
[0x50000000, 0x50002000, "RTC_IRAM"],
|
||||
[0x50000000, 0x50002000, "RTC_DRAM"],
|
||||
[0x600FE000, 0x60100000, "MEM_INTERNAL2"]]
|
||||
*/
|
||||
/* 400K of on soc RAM, 16K reserved for cache */
|
||||
ICACHE : ORIGIN = 0x4037C000, LENGTH = 0x4000
|
||||
/* Instruction RAM */
|
||||
IRAM : ORIGIN = 0x4037C000 + 0x4000, LENGTH = 400K - 0x4000
|
||||
/* Data RAM */
|
||||
DRAM : ORIGIN = 0x3FC80000, LENGTH = 0x50000
|
||||
|
||||
|
||||
/* External flash */
|
||||
/* Instruction ROM */
|
||||
IROM : ORIGIN = 0x42000000 + 0x20, LENGTH = 0x400000 - 0x20
|
||||
/* Data ROM */
|
||||
DROM : ORIGIN = 0x3C000000, LENGTH = 0x400000
|
||||
|
||||
/* RTC fast memory (executable). Persists over deep sleep. */
|
||||
RTC_FAST : ORIGIN = 0x50000000, LENGTH = 0x2000 /*- ESP_BOOTLOADER_RESERVE_RTC*/
|
||||
}
|
||||
|
||||
REGION_ALIAS("REGION_TEXT", IROM);
|
||||
REGION_ALIAS("REGION_RODATA", DROM);
|
||||
|
||||
REGION_ALIAS("REGION_DATA", DRAM);
|
||||
REGION_ALIAS("REGION_BSS", DRAM);
|
||||
REGION_ALIAS("REGION_HEAP", DRAM);
|
||||
REGION_ALIAS("REGION_STACK", DRAM);
|
||||
|
||||
REGION_ALIAS("REGION_RWTEXT", IRAM);
|
||||
REGION_ALIAS("REGION_RTC_FAST", RTC_FAST);
|
||||
221
esp32c3-hal/bl-riscv-link.x
Normal file
221
esp32c3-hal/bl-riscv-link.x
Normal file
@ -0,0 +1,221 @@
|
||||
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(UserSoft = DefaultHandler);
|
||||
PROVIDE(SupervisorSoft = DefaultHandler);
|
||||
PROVIDE(MachineSoft = DefaultHandler);
|
||||
PROVIDE(UserTimer = DefaultHandler);
|
||||
PROVIDE(SupervisorTimer = DefaultHandler);
|
||||
PROVIDE(MachineTimer = DefaultHandler);
|
||||
PROVIDE(UserExternal = 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 :
|
||||
{
|
||||
_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 .text.*);
|
||||
_etext = .;
|
||||
} > REGION_TEXT
|
||||
|
||||
/**
|
||||
* This dummy section represents the .text section but in rodata.
|
||||
* Thus, it must have its alignement and (at least) its size.
|
||||
*/
|
||||
.text_dummy (NOLOAD):
|
||||
{
|
||||
/* Start at the same alignement constraint than .text */
|
||||
. = ALIGN(ALIGNOF(.text));
|
||||
/* Create an empty gap as big as .text section */
|
||||
. = . + SIZEOF(.text);
|
||||
/* Prepare the alignement of the section above. Few bytes (0x20) must be
|
||||
* added for the mapping header. */
|
||||
. = ALIGN(0x10000) + 0x20;
|
||||
} > REGION_RODATA
|
||||
|
||||
.rodata : ALIGN(4)
|
||||
{
|
||||
_srodata = .;
|
||||
*(.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);
|
||||
_erodata = .;
|
||||
} > REGION_RODATA
|
||||
|
||||
.rwtext : ALIGN(4) {
|
||||
_irwtext = LOADADDR(.rwtext);
|
||||
_srwtext = .;
|
||||
*(.rwtext);
|
||||
. = ALIGN(4);
|
||||
_erwtext = .;
|
||||
} > REGION_RWTEXT
|
||||
|
||||
/* similar as text_dummy */
|
||||
.ram_dummy (NOLOAD) : {
|
||||
. = ALIGN(ALIGNOF(.rwtext));
|
||||
. = . + SIZEOF(.rwtext);
|
||||
} > REGION_DATA
|
||||
|
||||
.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
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_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
|
||||
|
||||
.rtc_fast.text : ALIGN(4) {
|
||||
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
|
||||
} > REGION_RTC_FAST AT > REGION_RODATA
|
||||
|
||||
.rtc_fast.data : ALIGN(4)
|
||||
{
|
||||
_rtc_fast_data_start = ABSOLUTE(.);
|
||||
*(.rtc_fast.data .rtc_fast.data.*)
|
||||
_rtc_fast_data_end = ABSOLUTE(.);
|
||||
} > REGION_RTC_FAST AT > REGION_RODATA
|
||||
|
||||
.rtc_fast.bss (NOLOAD) : ALIGN(4)
|
||||
{
|
||||
_rtc_fast_bss_start = ABSOLUTE(.);
|
||||
*(.rtc_fast.bss .rtc_fast.bss.*)
|
||||
_rtc_fast_bss_end = ABSOLUTE(.);
|
||||
} > REGION_RTC_FAST
|
||||
|
||||
.rtc_fast.noinit (NOLOAD) : ALIGN(4)
|
||||
{
|
||||
*(.rtc_fast.noinit .rtc_fast.noinit.*)
|
||||
} > REGION_RTC_FAST
|
||||
|
||||
.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
|
||||
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
|
||||
}
|
||||
|
||||
/* 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 | */
|
||||
@ -1,27 +1,52 @@
|
||||
use std::{env, fs::File, io::Write, path::PathBuf};
|
||||
|
||||
#[cfg(not(feature = "normalboot"))]
|
||||
fn main() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("esp32c3-memory.x"))
|
||||
.write_all(include_bytes!("db-esp32c3-memory.x"))
|
||||
.unwrap();
|
||||
|
||||
File::create(out.join("esp32c3-link.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("esp32c3-link.x"))
|
||||
.write_all(include_bytes!("db-esp32c3-link.x"))
|
||||
.unwrap();
|
||||
|
||||
File::create(out.join("riscv-link.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("riscv-link.x"))
|
||||
.unwrap();
|
||||
.write_all(include_bytes!("db-riscv-link.x"))
|
||||
.unwrap();
|
||||
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
println!("cargo:rustc-link-arg=-Tesp32c3-link.x");
|
||||
}
|
||||
|
||||
#[cfg(feature = "normalboot")]
|
||||
fn main() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("bl-esp32c3-memory.x"))
|
||||
.unwrap();
|
||||
|
||||
File::create(out.join("bl-riscv-link.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("bl-riscv-link.x"))
|
||||
.unwrap();
|
||||
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
println!("cargo:rustc-link-arg=-Tmemory.x");
|
||||
println!("cargo:rustc-link-arg=-Tbl-riscv-link.x");
|
||||
}
|
||||
|
||||
@ -27,6 +27,9 @@ MEMORY
|
||||
IROM : ORIGIN = 0x42000000, LENGTH = 0x400000
|
||||
/* Data ROM */
|
||||
DROM : ORIGIN = 0x3C000000, LENGTH = 0x400000
|
||||
|
||||
/* RTC fast memory (executable). Persists over deep sleep. */
|
||||
RTC_FAST : ORIGIN = 0x50000000, LENGTH = 0x2000 /*- ESP_BOOTLOADER_RESERVE_RTC*/
|
||||
}
|
||||
|
||||
|
||||
@ -36,4 +39,7 @@ REGION_ALIAS("REGION_RODATA", DROM);
|
||||
REGION_ALIAS("REGION_DATA", DRAM);
|
||||
REGION_ALIAS("REGION_BSS", DRAM);
|
||||
REGION_ALIAS("REGION_HEAP", DRAM);
|
||||
REGION_ALIAS("REGION_STACK", DRAM);
|
||||
REGION_ALIAS("REGION_STACK", DRAM);
|
||||
|
||||
REGION_ALIAS("REGION_RWTEXT", IRAM);
|
||||
REGION_ALIAS("REGION_RTC_FAST", RTC_FAST);
|
||||
@ -73,7 +73,6 @@ SECTIONS
|
||||
_rodata_size = _erodata - _srodata + 8;
|
||||
.data ORIGIN(DRAM) : AT(_text_size + _rodata_size)
|
||||
{
|
||||
_sidata = LOADADDR(.data);
|
||||
_sdata = .;
|
||||
/* Must be called __global_pointer$ for linker relaxations to work. */
|
||||
PROVIDE(__global_pointer$ = . + 0x800);
|
||||
@ -83,6 +82,7 @@ SECTIONS
|
||||
_edata = .;
|
||||
} > REGION_DATA
|
||||
|
||||
_data_size = _edata - _sdata + 8;
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_sbss = .;
|
||||
@ -91,6 +91,14 @@ SECTIONS
|
||||
_ebss = .;
|
||||
} > REGION_BSS
|
||||
|
||||
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
|
||||
_srwtext = .;
|
||||
*(.rwtext);
|
||||
. = ALIGN(4);
|
||||
_erwtext = .;
|
||||
} > REGION_RWTEXT
|
||||
_rwtext_size = _erwtext - _srwtext + 8;
|
||||
|
||||
/* fictitious region that represents the memory available for the heap */
|
||||
.heap (NOLOAD) :
|
||||
{
|
||||
@ -108,6 +116,36 @@ SECTIONS
|
||||
_sstack = .;
|
||||
} > REGION_STACK
|
||||
|
||||
.rtc_fast.text : AT(_text_size + _rodata_size + _data_size + _rwtext_size) {
|
||||
_srtc_fast_text = .;
|
||||
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
|
||||
. = ALIGN(4);
|
||||
_ertc_fast_text = .;
|
||||
} > REGION_RTC_FAST
|
||||
_fast_text_size = _ertc_fast_text - _srtc_fast_text + 8;
|
||||
|
||||
.rtc_fast.data : AT(_text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size)
|
||||
{
|
||||
_rtc_fast_data_start = ABSOLUTE(.);
|
||||
*(.rtc_fast.data .rtc_fast.data.*)
|
||||
. = ALIGN(4);
|
||||
_rtc_fast_data_end = ABSOLUTE(.);
|
||||
} > REGION_RTC_FAST
|
||||
_rtc_fast_data_size = _rtc_fast_data_end - _rtc_fast_data_start + 8;
|
||||
|
||||
.rtc_fast.bss (NOLOAD) : ALIGN(4)
|
||||
{
|
||||
_rtc_fast_bss_start = ABSOLUTE(.);
|
||||
*(.rtc_fast.bss .rtc_fast.bss.*)
|
||||
. = ALIGN(4);
|
||||
_rtc_fast_bss_end = ABSOLUTE(.);
|
||||
} > REGION_RTC_FAST
|
||||
|
||||
.rtc_fast.noinit (NOLOAD) : ALIGN(4)
|
||||
{
|
||||
*(.rtc_fast.noinit .rtc_fast.noinit.*)
|
||||
} > REGION_RTC_FAST
|
||||
|
||||
/* 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
|
||||
@ -121,6 +159,11 @@ SECTIONS
|
||||
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
|
||||
}
|
||||
|
||||
PROVIDE(_sidata = _erodata + 8);
|
||||
PROVIDE(_irwtext = ORIGIN(DROM) + _text_size + _rodata_size + _data_size);
|
||||
PROVIDE(_irtc_fast_text = ORIGIN(DROM) + _text_size + _rodata_size + _data_size + _rwtext_size);
|
||||
PROVIDE(_irtc_fast_data = ORIGIN(DROM) + _text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size);
|
||||
|
||||
/* 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");
|
||||
@ -29,4 +29,4 @@ fn main() -> ! {
|
||||
writeln!(serial0, "Hello world!").unwrap();
|
||||
block!(timer0.wait()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
91
esp32c3-hal/examples/ram.rs
Normal file
91
esp32c3-hal/examples/ram.rs
Normal file
@ -0,0 +1,91 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
use esp32c3_hal::{
|
||||
pac::{self, UART0},
|
||||
prelude::*,
|
||||
ram,
|
||||
Serial,
|
||||
Timer,
|
||||
};
|
||||
use nb::block;
|
||||
use panic_halt as _;
|
||||
use riscv_rt::entry;
|
||||
|
||||
#[ram(rtc_fast)]
|
||||
static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
|
||||
|
||||
#[ram(rtc_fast, uninitialized)]
|
||||
static mut SOME_UNINITED_DATA: [u8; 2] = [0; 2];
|
||||
|
||||
#[ram(rtc_fast, zeroed)]
|
||||
static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = pac::Peripherals::take().unwrap();
|
||||
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||
|
||||
// don't disable WDTs ... we actually want it getting triggered in this example
|
||||
|
||||
timer0.disable();
|
||||
|
||||
timer0.start(10_000_000u64);
|
||||
|
||||
writeln!(
|
||||
serial0,
|
||||
"IRAM function located at {:p}",
|
||||
function_in_ram as *const ()
|
||||
)
|
||||
.unwrap();
|
||||
unsafe {
|
||||
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
|
||||
|
||||
SOME_INITED_DATA[0] = 0xff;
|
||||
SOME_ZEROED_DATA[0] = 0xff;
|
||||
|
||||
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
|
||||
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
|
||||
|
||||
if SOME_UNINITED_DATA[0] != 0 {
|
||||
SOME_UNINITED_DATA[0] = 0;
|
||||
SOME_UNINITED_DATA[1] = 0;
|
||||
}
|
||||
|
||||
if SOME_UNINITED_DATA[1] == 0xff {
|
||||
SOME_UNINITED_DATA[1] = 0;
|
||||
}
|
||||
|
||||
writeln!(serial0, "Counter {}", SOME_UNINITED_DATA[1]).unwrap();
|
||||
SOME_UNINITED_DATA[1] += 1;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
serial0,
|
||||
"RTC_FAST function located at {:p}",
|
||||
function_in_rtc_ram as *const ()
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(serial0, "Result {}", function_in_rtc_ram()).unwrap();
|
||||
|
||||
loop {
|
||||
function_in_ram(&mut serial0);
|
||||
block!(timer0.wait()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn function_in_ram(serial0: &mut Serial<UART0>) {
|
||||
writeln!(serial0, "Hello world!").unwrap();
|
||||
}
|
||||
|
||||
#[ram(rtc_fast)]
|
||||
fn function_in_rtc_ram() -> u32 {
|
||||
42
|
||||
}
|
||||
@ -2,8 +2,70 @@
|
||||
|
||||
pub use embedded_hal as ehal;
|
||||
pub use esp_hal_common::{pac, prelude, Delay, Serial, Timer};
|
||||
#[cfg(not(feature = "normalboot"))]
|
||||
use riscv_rt::pre_init;
|
||||
|
||||
pub mod gpio;
|
||||
pub mod rtc_cntl;
|
||||
|
||||
pub use esp_hal_common::ram;
|
||||
|
||||
pub use self::{gpio::IO, rtc_cntl::RtcCntl};
|
||||
|
||||
extern "C" {
|
||||
// Boundaries of the .iram section
|
||||
static mut _srwtext: u32;
|
||||
static mut _erwtext: u32;
|
||||
static mut _irwtext: u32;
|
||||
|
||||
// Boundaries of the .bss section
|
||||
static mut _ebss: u32;
|
||||
static mut _sbss: u32;
|
||||
|
||||
// Boundaries of the rtc .bss section
|
||||
static mut _rtc_fast_bss_start: u32;
|
||||
static mut _rtc_fast_bss_end: u32;
|
||||
|
||||
// Boundaries of the .rtc_fast.text section
|
||||
static mut _srtc_fast_text: u32;
|
||||
static mut _ertc_fast_text: u32;
|
||||
static mut _irtc_fast_text: u32;
|
||||
|
||||
// Boundaries of the .rtc_fast.data section
|
||||
static mut _rtc_fast_data_start: u32;
|
||||
static mut _rtc_fast_data_end: u32;
|
||||
static mut _irtc_fast_data: u32;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "normalboot"))]
|
||||
#[pre_init]
|
||||
#[cfg(not(feature = "normalboot"))]
|
||||
unsafe fn init() {
|
||||
r0::init_data(&mut _srwtext, &mut _erwtext, &_irwtext);
|
||||
|
||||
r0::init_data(
|
||||
&mut _rtc_fast_data_start,
|
||||
&mut _rtc_fast_data_end,
|
||||
&_irtc_fast_data,
|
||||
);
|
||||
|
||||
r0::init_data(&mut _srtc_fast_text, &mut _ertc_fast_text, &_irtc_fast_text);
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
#[export_name = "_mp_hook"]
|
||||
pub fn mp_hook() -> bool {
|
||||
unsafe {
|
||||
r0::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "normalboot"))]
|
||||
return true;
|
||||
|
||||
// no init data when using normal boot - but we need to zero out BSS
|
||||
unsafe {
|
||||
r0::zero_bss(&mut _sbss, &mut _ebss);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user