diff --git a/build.rs b/build.rs index 42f258d..605963d 100644 --- a/build.rs +++ b/build.rs @@ -177,6 +177,64 @@ fn main() { (("uart", "RX"), quote!(crate::uart::RxDma)), (("uart", "TX"), quote!(crate::uart::TxDma)), (("i2c", "GLOBAL"), quote!(crate::i2c::I2cDma)), + // FEMC + (("femc", "A00"), quote!(crate::femc::A00Pin)), + (("femc", "A01"), quote!(crate::femc::A01Pin)), + (("femc", "A02"), quote!(crate::femc::A02Pin)), + (("femc", "A03"), quote!(crate::femc::A03Pin)), + (("femc", "A04"), quote!(crate::femc::A04Pin)), + (("femc", "A05"), quote!(crate::femc::A05Pin)), + (("femc", "A06"), quote!(crate::femc::A06Pin)), + (("femc", "A07"), quote!(crate::femc::A07Pin)), + (("femc", "A08"), quote!(crate::femc::A08Pin)), + (("femc", "A09"), quote!(crate::femc::A09Pin)), + (("femc", "A10"), quote!(crate::femc::A10Pin)), + (("femc", "A11"), quote!(crate::femc::A11Pin)), + (("femc", "A12"), quote!(crate::femc::A12Pin)), + (("femc", "BA0"), quote!(crate::femc::BA0Pin)), + (("femc", "BA1"), quote!(crate::femc::BA1Pin)), + (("femc", "CAS"), quote!(crate::femc::CASPin)), + (("femc", "CKE"), quote!(crate::femc::CKEPin)), + (("femc", "CLK"), quote!(crate::femc::CLKPin)), + (("femc", "CS0"), quote!(crate::femc::CS0Pin)), + (("femc", "CS1"), quote!(crate::femc::CS1Pin)), + (("femc", "DM0"), quote!(crate::femc::DM0Pin)), + (("femc", "DM1"), quote!(crate::femc::DM1Pin)), + (("femc", "DQS"), quote!(crate::femc::DQSPin)), + (("femc", "DQ00"), quote!(crate::femc::DQ00Pin)), + (("femc", "DQ01"), quote!(crate::femc::DQ01Pin)), + (("femc", "DQ02"), quote!(crate::femc::DQ02Pin)), + (("femc", "DQ03"), quote!(crate::femc::DQ03Pin)), + (("femc", "DQ04"), quote!(crate::femc::DQ04Pin)), + (("femc", "DQ05"), quote!(crate::femc::DQ05Pin)), + (("femc", "DQ06"), quote!(crate::femc::DQ06Pin)), + (("femc", "DQ07"), quote!(crate::femc::DQ07Pin)), + (("femc", "DQ08"), quote!(crate::femc::DQ08Pin)), + (("femc", "DQ09"), quote!(crate::femc::DQ09Pin)), + (("femc", "DQ10"), quote!(crate::femc::DQ10Pin)), + (("femc", "DQ11"), quote!(crate::femc::DQ11Pin)), + (("femc", "DQ12"), quote!(crate::femc::DQ12Pin)), + (("femc", "DQ13"), quote!(crate::femc::DQ13Pin)), + (("femc", "DQ14"), quote!(crate::femc::DQ14Pin)), + (("femc", "DQ15"), quote!(crate::femc::DQ15Pin)), + (("femc", "DQ16"), quote!(crate::femc::DQ16Pin)), + (("femc", "DQ17"), quote!(crate::femc::DQ17Pin)), + (("femc", "DQ18"), quote!(crate::femc::DQ18Pin)), + (("femc", "DQ19"), quote!(crate::femc::DQ19Pin)), + (("femc", "DQ20"), quote!(crate::femc::DQ20Pin)), + (("femc", "DQ21"), quote!(crate::femc::DQ21Pin)), + (("femc", "DQ22"), quote!(crate::femc::DQ22Pin)), + (("femc", "DQ23"), quote!(crate::femc::DQ23Pin)), + (("femc", "DQ24"), quote!(crate::femc::DQ24Pin)), + (("femc", "DQ25"), quote!(crate::femc::DQ25Pin)), + (("femc", "DQ26"), quote!(crate::femc::DQ26Pin)), + (("femc", "DQ27"), quote!(crate::femc::DQ27Pin)), + (("femc", "DQ28"), quote!(crate::femc::DQ28Pin)), + (("femc", "DQ29"), quote!(crate::femc::DQ29Pin)), + (("femc", "DQ30"), quote!(crate::femc::DQ30Pin)), + (("femc", "DQ31"), quote!(crate::femc::DQ31Pin)), + (("femc", "RAS"), quote!(crate::femc::RASPin)), + (("femc", "WE"), quote!(crate::femc::WEPin)), ] .into(); diff --git a/examples/hpm6e00evk/Cargo.toml b/examples/hpm6e00evk/Cargo.toml index ebe7c73..bde01a5 100644 --- a/examples/hpm6e00evk/Cargo.toml +++ b/examples/hpm6e00evk/Cargo.toml @@ -5,12 +5,9 @@ edition = "2021" resolver = "2" [dependencies] -hpm-hal = { path = "../../", features = ["hpm6e80"] } +hpm-hal = { path = "../../", features = ["hpm6e80", "rt", "embassy"] } -# TODO -# hpm-hal = { path = "../../", features = ["hpm6e80"]} panic-halt = "0.2.0" -riscv-rt = { version = "0.12.2", features = ["single-hart"] } defmt = "0.3.8" defmt-rtt = "0.4.1" @@ -25,6 +22,7 @@ embassy-executor = { version = "0.5.0", features = [ "arch-riscv32", "executor-thread", ] } +embedded-io = "0.6.1" [profile.release] strip = false # symbols are not flashed to the microcontroller, so don't strip them. diff --git a/examples/hpm6e00evk/memory.x b/examples/hpm6e00evk/memory.x index 647f719..0b542d4 100644 --- a/examples/hpm6e00evk/memory.x +++ b/examples/hpm6e00evk/memory.x @@ -4,7 +4,7 @@ MEMORY XPI0_APP : ORIGIN = 0x80003000, LENGTH = 1024K - 0x3000 /* app firmware */ DLM0 : ORIGIN = 0x00200000, LENGTH = 256K /* data local memory */ ILM0 : ORIGIN = 0x00000000, LENGTH = 256K /* instruction local memory */ - AAXI_SRAM : ORIGIN = 0x01200000, LENGTH = 1M + AXI_SRAM : ORIGIN = 0x01200000, LENGTH = 1M } REGION_ALIAS("REGION_TEXT", XPI0_APP); REGION_ALIAS("REGION_RODATA", XPI0_APP); diff --git a/examples/hpm6e00evk/src/bin/BANNER b/examples/hpm6e00evk/src/bin/BANNER new file mode 100644 index 0000000..decf9fd --- /dev/null +++ b/examples/hpm6e00evk/src/bin/BANNER @@ -0,0 +1,10 @@ +---------------------------------------------------------------------- +$$\ $$\ $$$$$$$\ $$\ $$\ $$\ +$$ | $$ |$$ __$$\ $$$\ $$$ |\__| +$$ | $$ |$$ | $$ |$$$$\ $$$$ |$$\ $$$$$$$\ $$$$$$\ $$$$$$\ +$$$$$$$$ |$$$$$$$ |$$\$$\$$ $$ |$$ |$$ _____|$$ __$$\ $$ __$$\ +$$ __$$ |$$ ____/ $$ \$$$ $$ |$$ |$$ / $$ | \__|$$ / $$ | +$$ | $$ |$$ | $$ |\$ /$$ |$$ |$$ | $$ | $$ | $$ | +$$ | $$ |$$ | $$ | \_/ $$ |$$ |\$$$$$$$\ $$ | \$$$$$$ | +\__| \__|\__| \__| \__|\__| \_______|\__| \______/ +---------------------------------------------------------------------- diff --git a/examples/hpm6e00evk/src/bin/blinky.rs b/examples/hpm6e00evk/src/bin/blinky.rs index 5ab18ad..69f2e30 100644 --- a/examples/hpm6e00evk/src/bin/blinky.rs +++ b/examples/hpm6e00evk/src/bin/blinky.rs @@ -2,10 +2,9 @@ #![no_std] use embedded_hal::delay::DelayNs; -use hal::pac; use hpm_hal::gpio::{Level, Output}; use riscv::delay::McycleDelay; -use {defmt_rtt as _, hpm_hal as hal, panic_halt as _, riscv_rt as _}; +use {defmt_rtt as _, hpm_hal as hal, panic_halt as _}; #[hal::entry] fn main() -> ! { diff --git a/examples/hpm6e00evk/src/bin/embassy_blinky.rs b/examples/hpm6e00evk/src/bin/embassy_blinky.rs index 86a428d..85fa4d7 100644 --- a/examples/hpm6e00evk/src/bin/embassy_blinky.rs +++ b/examples/hpm6e00evk/src/bin/embassy_blinky.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_time::Timer; use hal::gpio::Pin as _; use hpm_hal::gpio::{AnyPin, Level, Output}; -use {defmt_rtt as _, hpm_hal as hal, riscv_rt as _}; +use {defmt_rtt as _, hpm_hal as hal}; #[embassy_executor::task(pool_size = 3)] async fn blink(pin: AnyPin, interval_ms: u32) { diff --git a/examples/hpm6e00evk/src/bin/embassy_femc.rs b/examples/hpm6e00evk/src/bin/embassy_femc.rs new file mode 100644 index 0000000..1ed7103 --- /dev/null +++ b/examples/hpm6e00evk/src/bin/embassy_femc.rs @@ -0,0 +1,466 @@ +#![no_main] +#![no_std] +#![feature(type_alias_impl_trait)] + +use core::mem; + +use embassy_executor::Spawner; +use embassy_time::Timer; +use embedded_io::Write as _; +use hal::gpio::{AnyPin, Level, Output, Pin as _}; +use hal::mode::Blocking; +use hal::pac; +use {defmt_rtt as _, hpm_hal as hal}; + +const BANNER: &str = include_str!("./BANNER"); + +static mut UART: Option> = None; + +macro_rules! println { + ($($arg:tt)*) => { + #[allow(unused_unsafe)] + unsafe { + if let Some(uart) = UART.as_mut() { + let _ = writeln!(uart, $($arg)*); + } + } + }; +} + +fn init_femc_pins() { + use pac::IOC; + + IOC.pad(pac::pins::PD02) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD02_FUNC_CTL_FEMC_A_00)); + IOC.pad(pac::pins::PD03) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD03_FUNC_CTL_FEMC_A_01)); + IOC.pad(pac::pins::PD00) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD00_FUNC_CTL_FEMC_A_02)); + IOC.pad(pac::pins::PD01) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD01_FUNC_CTL_FEMC_A_03)); + IOC.pad(pac::pins::PC18) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC18_FUNC_CTL_FEMC_A_04)); + IOC.pad(pac::pins::PC19) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC19_FUNC_CTL_FEMC_A_05)); + IOC.pad(pac::pins::PC20) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC20_FUNC_CTL_FEMC_A_06)); + IOC.pad(pac::pins::PC21) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC21_FUNC_CTL_FEMC_A_07)); + IOC.pad(pac::pins::PC23) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC23_FUNC_CTL_FEMC_A_08)); + IOC.pad(pac::pins::PC24) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC24_FUNC_CTL_FEMC_A_09)); + IOC.pad(pac::pins::PD04) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD04_FUNC_CTL_FEMC_A_10)); + IOC.pad(pac::pins::PC25) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC25_FUNC_CTL_FEMC_A_11)); /* SRAM: NWE */ + IOC.pad(pac::pins::PC26) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC26_FUNC_CTL_FEMC_A_12)); /* SRAM: NOE */ + + IOC.pad(pac::pins::PD31) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD31_FUNC_CTL_FEMC_DQ_00)); + IOC.pad(pac::pins::PD30) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD30_FUNC_CTL_FEMC_DQ_01)); + IOC.pad(pac::pins::PD29) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD29_FUNC_CTL_FEMC_DQ_02)); + IOC.pad(pac::pins::PD28) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD28_FUNC_CTL_FEMC_DQ_03)); + IOC.pad(pac::pins::PD27) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD27_FUNC_CTL_FEMC_DQ_04)); + IOC.pad(pac::pins::PD26) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD26_FUNC_CTL_FEMC_DQ_05)); + IOC.pad(pac::pins::PD24) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD24_FUNC_CTL_FEMC_DQ_06)); + IOC.pad(pac::pins::PD25) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD25_FUNC_CTL_FEMC_DQ_07)); + IOC.pad(pac::pins::PD14) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD14_FUNC_CTL_FEMC_DQ_08)); + IOC.pad(pac::pins::PD17) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD17_FUNC_CTL_FEMC_DQ_09)); + IOC.pad(pac::pins::PD16) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD16_FUNC_CTL_FEMC_DQ_10)); + IOC.pad(pac::pins::PD19) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD19_FUNC_CTL_FEMC_DQ_11)); + IOC.pad(pac::pins::PD18) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD18_FUNC_CTL_FEMC_DQ_12)); + IOC.pad(pac::pins::PD21) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD21_FUNC_CTL_FEMC_DQ_13)); + IOC.pad(pac::pins::PD20) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD20_FUNC_CTL_FEMC_DQ_14)); + IOC.pad(pac::pins::PD22) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD22_FUNC_CTL_FEMC_DQ_15)); + IOC.pad(pac::pins::PC16) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC16_FUNC_CTL_FEMC_DQ_16)); + IOC.pad(pac::pins::PC17) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC17_FUNC_CTL_FEMC_DQ_17)); + IOC.pad(pac::pins::PC13) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC13_FUNC_CTL_FEMC_DQ_18)); + IOC.pad(pac::pins::PC14) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC14_FUNC_CTL_FEMC_DQ_19)); + IOC.pad(pac::pins::PC10) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC10_FUNC_CTL_FEMC_DQ_20)); + IOC.pad(pac::pins::PC11) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC11_FUNC_CTL_FEMC_DQ_21)); + IOC.pad(pac::pins::PC02) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC02_FUNC_CTL_FEMC_DQ_22)); + IOC.pad(pac::pins::PC09) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC09_FUNC_CTL_FEMC_DQ_23)); + IOC.pad(pac::pins::PC00) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC00_FUNC_CTL_FEMC_DQ_24)); + IOC.pad(pac::pins::PC01) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC01_FUNC_CTL_FEMC_DQ_25)); + IOC.pad(pac::pins::PC03) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC03_FUNC_CTL_FEMC_DQ_26)); + IOC.pad(pac::pins::PC04) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC04_FUNC_CTL_FEMC_DQ_27)); + IOC.pad(pac::pins::PC05) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC05_FUNC_CTL_FEMC_DQ_28)); + IOC.pad(pac::pins::PC06) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC06_FUNC_CTL_FEMC_DQ_29)); + IOC.pad(pac::pins::PC07) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC07_FUNC_CTL_FEMC_DQ_30)); + IOC.pad(pac::pins::PC08) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC08_FUNC_CTL_FEMC_DQ_31)); + + IOC.pad(pac::pins::PD23) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD23_FUNC_CTL_FEMC_DM_0)); /* SRAM: NLB */ + IOC.pad(pac::pins::PD15) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD15_FUNC_CTL_FEMC_DM_1)); /* SRAM: NUB */ + IOC.pad(pac::pins::PC12) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC12_FUNC_CTL_FEMC_DM_2)); + IOC.pad(pac::pins::PC15) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC15_FUNC_CTL_FEMC_DM_3)); + + IOC.pad(pac::pins::PX07).func_ctl().write(|w| { + w.set_alt_select(pac::iomux::IOC_PX07_FUNC_CTL_FEMC_DQS); + w.set_loop_back(true); + }); + + /* SDRAM */ + IOC.pad(pac::pins::PD05) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD05_FUNC_CTL_FEMC_BA0)); + IOC.pad(pac::pins::PD06) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD06_FUNC_CTL_FEMC_BA1)); /* SRAM: NADV */ + IOC.pad(pac::pins::PD10) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD10_FUNC_CTL_FEMC_RAS)); + IOC.pad(pac::pins::PD13) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD13_FUNC_CTL_FEMC_CAS)); + IOC.pad(pac::pins::PC28) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC28_FUNC_CTL_FEMC_CKE)); + IOC.pad(pac::pins::PC27) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC27_FUNC_CTL_FEMC_CLK_0)); + IOC.pad(pac::pins::PD12) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD12_FUNC_CTL_FEMC_WE)); + IOC.pad(pac::pins::PD11) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD11_FUNC_CTL_FEMC_CS_0)); + IOC.pad(pac::pins::PD08) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD08_FUNC_CTL_FEMC_CS_1)); + + /* SRAM */ + IOC.pad(pac::pins::PC29) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC29_FUNC_CTL_FEMC_SCLK_0)); + IOC.pad(pac::pins::PD07) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PD07_FUNC_CTL_FEMC_SCLK_1)); + IOC.pad(pac::pins::PC30) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC30_FUNC_CTL_FEMC_SCS_0)); + IOC.pad(pac::pins::PC31) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC31_FUNC_CTL_FEMC_SCS_1)); + IOC.pad(pac::pins::PC22) + .func_ctl() + .write(|w| w.set_alt_select(pac::iomux::IOC_PC22_FUNC_CTL_FEMC_SRDY)); +} + +fn init_ext_ram() { + use hal::femc::*; + + init_femc_pins(); + + let clk_in = hal::sysctl::clocks().get_clock_freq(pac::clocks::FEMC); + + let femc_config = FemcConfig::default(); + + let mut femc = unsafe { Femc::new_raw(hal::peripherals::FEMC::steal()) }; + + femc.init(femc_config); + + let mut sdram_config = FemcSdramConfig::default(); + + sdram_config.bank_num = Bank2Sel::BANK_NUM_4; + sdram_config.prescaler = 0x3; + sdram_config.burst_len = BurstLen::_8; + sdram_config.auto_refresh_count_in_one_burst = 1; + // Column address: A0-A8 + sdram_config.col_addr_bits = ColAddrBits::_9BIT; + sdram_config.cas_latency = CasLatency::_3; + + // AC Characteristics and Operating Condition + sdram_config.refresh_to_refresh_in_ns = 60; /* Trc */ + sdram_config.refresh_recover_in_ns = 60; /* Trc */ + sdram_config.act_to_precharge_in_ns = 42; /* Tras */ + sdram_config.act_to_rw_in_ns = 18; /* Trcd */ + sdram_config.precharge_to_act_in_ns = 18; /* Trp */ + sdram_config.act_to_act_in_ns = 12; /* Trrd */ + sdram_config.write_recover_in_ns = 12; /* Twr/Tdpl */ + sdram_config.self_refresh_recover_in_ns = 72; /* Txsr */ + + sdram_config.cs = 0; // BOARD_SDRAM_CS; = FEMC_SDRAM_CS0 = 0 + sdram_config.base_address = 0x40000000; // BOARD_SDRAM_ADDRESS; + sdram_config.size = MemorySize::_32MB; + sdram_config.port_size = SdramPortSize::_16BIT; + sdram_config.refresh_count = 8192; // BOARD_SDRAM_REFRESH_COUNT; + sdram_config.refresh_in_ms = 64; // Tref, BOARD_SDRAM_REFRESH_IN_MS; + + sdram_config.delay_cell_disable = true; + sdram_config.delay_cell_value = 0; + + let _ = femc.configure_sdram(clk_in.0, sdram_config).unwrap(); + pac::FEMC.sdrctrl0().modify(|w| w.set_highband(true)); + + // pac::FEMC.sdrctrl0().modify(|w| w.set_highband(true)); +} + +#[embassy_executor::task(pool_size = 3)] +async fn blink(pin: AnyPin, interval_ms: u32) { + // all leds are active low + let mut led = Output::new(pin, Level::Low, Default::default()); + + loop { + led.toggle(); + + Timer::after_millis(interval_ms as u64).await; + } +} + +const MEM_START: usize = 0x40000000; // Start address for memory test +const MEM_SIZE: usize = 0x2000000; // 32MB + +#[link_section = ".fast"] +fn memtest_operation(addr: *mut u32, data: u32, operation: u8) -> bool { + unsafe { + match operation { + 0 => { + // Write operation + core::ptr::write_volatile(addr, data); + return true; + } + 1 => { + // Read and verify operation + let read_data = core::ptr::read_volatile(addr); + if read_data != data { + println!( + "Memory test failed at address 0x{:08X} (expected: 0x{:08X}, found: 0x{:08X})", + addr as usize, data, read_data + ); + return false; + } + return true; + } + _ => unreachable!(), + } + } +} + +#[link_section = ".fast"] +fn memtest() { + let mem_start = MEM_START as *mut u32; + let pattern = 0x12345678; + + println!( + "Starting memory test from 0x{:08X} to 0x{:08X}", + MEM_START, + MEM_START + MEM_SIZE - 1 + ); + + // Write pattern + // Write pattern + let mut start = riscv::register::mcycle::read64(); + for i in 0..(MEM_SIZE / mem::size_of::()) { + let addr = unsafe { mem_start.offset(i as isize) }; + if !memtest_operation(addr, pattern, 0) { + println!("Memory test failed!"); + return; + } + if i % 0x100000 == 0 { + if i != 0 { + let elapsed = riscv::register::mcycle::read64() - start; + let elapsed_ms = elapsed * 1000 / (hal::sysctl::clocks().cpu0.0 as u64); + let byte_per_sec = 0x100000 * mem::size_of::() as u64 * 1000 / elapsed_ms; + println!( + "Memory test: 0x{:08X} of 0x{:08X} written, elapsed {}ms, {} bytes/s", + i, + MEM_SIZE / mem::size_of::(), + elapsed_ms, + byte_per_sec + ); + } + start = riscv::register::mcycle::read64(); + } + } + + // Read and verify pattern + for i in 0..(MEM_SIZE / mem::size_of::()) { + let addr = unsafe { mem_start.offset(i as isize) }; + if !memtest_operation(addr, pattern, 1) { + println!("Memory test failed!"); + return; + } + if i % 0x100000 == 0 { + if i != 0 { + let elapsed = riscv::register::mcycle::read64() - start; + let elapsed_ms = elapsed * 1000 / (hal::sysctl::clocks().cpu0.0 as u64); + let byte_per_sec = 0x100000 * mem::size_of::() as u64 * 1000 / elapsed_ms; + println!( + "Memory test: 0x{:08X} of 0x{:08X} read, elapsed {}ms, {} bytes/s", + i, + MEM_SIZE / mem::size_of::(), + elapsed_ms, + byte_per_sec + ); + } + start = riscv::register::mcycle::read64(); + } + } + + println!("Memory test completed successfully!"); +} + +#[embassy_executor::main(entry = "hpm_hal::entry")] +async fn main(spawner: Spawner) -> ! { + let p = hal::init(Default::default()); + + defmt::info!("Board init!"); + + //let key_a = p.PB24; + //let key_b = p.PB25; + + let led_r = p.PE14; + let led_g = p.PE15; + let led_b = p.PE04; + + spawner.spawn(blink(led_r.degrade(), 1000)).unwrap(); + spawner.spawn(blink(led_g.degrade(), 2000)).unwrap(); + spawner.spawn(blink(led_b.degrade(), 3000)).unwrap(); + defmt::info!("Tasks init!"); + + let uart = hal::uart::Uart::new_blocking(p.UART0, p.PA01, p.PA00, Default::default()).unwrap(); + unsafe { + UART = Some(uart); + } + + println!("{}", BANNER); + + println!("Clocks: {:?}", hal::sysctl::clocks()); + println!( + "XPI0: {}Hz (noinit if running from ram)", + hal::sysctl::clocks().get_clock_freq(pac::clocks::XPI0).0 + ); + println!("MCT0: {}Hz", hal::sysctl::clocks().get_clock_freq(pac::clocks::MCT0).0); + + println!("Hello, world!"); + + { + pac::SYSCTL.monitor(0).control().modify(|w| { + w.set_accuracy(true); // 1Hz + w.set_reference(true); // 24M + w.set_mode(true); // save to min and max + w.set_selection(pac::sysctl::vals::MonitorSelection::CLK_TOP_FEMC); // pll0 clk0 + w.set_start(true); + }); + while !pac::SYSCTL.monitor(0).control().read().valid() {} + println!( + "Monitor 0 measure: {} min={} max={}!", + pac::SYSCTL.monitor(0).current().read().frequency(), + pac::SYSCTL.monitor(0).low_limit().read().frequency(), + pac::SYSCTL.monitor(0).high_limit().read().frequency() + ); + } + + init_ext_ram(); + + println!("Memory init done!"); + println!("Memory test start!"); + + memtest(); + + loop { + defmt::info!("tick"); + + Timer::after_millis(1000).await; + + println!("Hello, world! xxx"); + } +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + let mut err = heapless::String::<1024>::new(); + + use core::fmt::Write as _; + + write!(err, "panic: {}", _info).ok(); + + defmt::info!("{}", err.as_str()); + loop {} +} diff --git a/examples/hpm6e00evk/src/bin/raw_blinky.rs b/examples/hpm6e00evk/src/bin/raw_blinky.rs index d7f22bc..68f6cea 100644 --- a/examples/hpm6e00evk/src/bin/raw_blinky.rs +++ b/examples/hpm6e00evk/src/bin/raw_blinky.rs @@ -5,9 +5,9 @@ use embedded_hal::delay::DelayNs; use hal::pac; use pac::gpiom::vals; use riscv::delay::McycleDelay; -use {defmt_rtt as _, hpm_hal as hal, panic_halt as _, riscv_rt as _}; +use {defmt_rtt as _, hpm_hal as hal, panic_halt as _}; -#[riscv_rt::entry] +#[hal::entry] fn main() -> ! { // default clock let mut delay = McycleDelay::new(600_000_000); diff --git a/openocd.gdb b/openocd.gdb index 560f669..75b863f 100644 --- a/openocd.gdb +++ b/openocd.gdb @@ -13,3 +13,5 @@ set confirm off load continue + +# quit diff --git a/run-openocd.sh b/run-openocd.sh index dc91c18..173e1d9 100755 --- a/run-openocd.sh +++ b/run-openocd.sh @@ -7,9 +7,17 @@ export HPM_SDK_BASE=`pwd`/../hpm_sdk # openocd -f $OPENOCD_CFG/probes/ft2232.cfg -f $OPENOCD_CFG/soc/hpm5300.cfg -f $OPENOCD_CFG/boards/hpm5300evk.cfg +export FAMILY=hpm6e00 +export BOARD=hpm6e00evk +export PROBE=ft2232 + # export BOARD=hpm5301evklite -export BOARD=hpm5300evk +# export BOARD=hpm5300evk # export PROBE=cmsis_dap export PROBE=ft2232 +# export PROBE=cmsis_dap + +#export FAMILY=hpm5300 +export FAMILY=hpm6e00 -openocd -c "set HPM_SDK_BASE ${HPM_SDK_BASE}; set BOARD ${BOARD}; set PROBE ${PROBE};" -f ${HPM_SDK_BASE}/boards/openocd/hpm5300_all_in_one.cfg +openocd -c "set HPM_SDK_BASE ${HPM_SDK_BASE}; set BOARD ${BOARD}; set PROBE ${PROBE};" -f ${HPM_SDK_BASE}/boards/openocd/${FAMILY}_all_in_one.cfg diff --git a/src/embassy/time_driver_mchtmr.rs b/src/embassy/time_driver_mchtmr.rs index eb5af7a..d0bf8a8 100644 --- a/src/embassy/time_driver_mchtmr.rs +++ b/src/embassy/time_driver_mchtmr.rs @@ -63,7 +63,7 @@ impl MachineTimerDriver { self.period.store(cnt_per_tick as u32, Ordering::Relaxed); // make sure mchtmr will not be gated on "wfi" - SYSCTL.cpu(0).lp().modify(|w| w.set_mode(vals::LpMode::WAIT)); + SYSCTL.cpu(0).lp().modify(|w| w.set_mode(vals::LpMode::RUN)); // 4 * 32 = 128 bits // enable wake up from all interrupts SYSCTL.cpu(0).wakeup_enable(0).write(|w| w.set_enable(0xFFFFFFFF)); diff --git a/src/femc.rs b/src/femc.rs new file mode 100644 index 0000000..4763449 --- /dev/null +++ b/src/femc.rs @@ -0,0 +1,474 @@ +//! FEMC(Flexible External Memory Controller) +//! +//! Available on: +//! hpm6e, hpm67, hpm68, hpm63 + +use core::marker::PhantomData; +use core::mem; + +use embassy_hal_internal::Peripheral; +pub use hpm_metapac::femc::vals::{ + Bank2Sel, BurstLen, CasLatency, ColAddrBits, DataSize, Dqs, MemorySize, SdramCmd, SdramPortSize, +}; + +const HPM_FEMC_DRV_RETRY_COUNT: usize = 5000; +const FEMC_CMD_KEY: u16 = 0x5AA5; +const HPM_FEMC_DRV_DEFAULT_PRESCALER: u8 = 3; + +/// Structure for specifying the configuration of AXI queue weight +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(C)] +pub struct FemcAxiQWeight { + /// Enable AXI weight setting flag + pub enable: bool, + pub qos: u8, + pub age: u8, + pub slave_hit_wo_rw: u8, + /// Only available for queue A + pub slave_hit: u8, + /// Only available for queue B + pub page_hit: u8, + /// Only available for queue B + pub bank_rotation: u8, +} + +/// Structure for specifying the configuration of FEMC +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub struct FemcConfig { + /// DQS setting + pub dqs: Dqs, + /// Command timeout + pub cmd_timeout: u8, + /// Bus timeout + pub bus_timeout: u8, + /// AXI queue weight + pub axi_q_weight_a: FemcAxiQWeight, + /// AXI queue weight + pub axi_q_weight_b: FemcAxiQWeight, +} + +impl Default for FemcConfig { + // femc_default_config + fn default() -> Self { + let mut config: Self = unsafe { mem::zeroed() }; + + config.dqs = Dqs::FROM_PAD; + config.cmd_timeout = 0; + config.bus_timeout = 0x10; + + config.axi_q_weight_a.enable = true; + config.axi_q_weight_a.qos = 4; + config.axi_q_weight_a.age = 2; + config.axi_q_weight_a.slave_hit = 0x5; + config.axi_q_weight_a.slave_hit_wo_rw = 0x3; + + config.axi_q_weight_b.enable = true; + config.axi_q_weight_b.qos = 4; + config.axi_q_weight_b.age = 2; + config.axi_q_weight_b.page_hit = 0x5; + config.axi_q_weight_b.slave_hit_wo_rw = 0x3; + config.axi_q_weight_b.bank_rotation = 0x6; + + config + } +} + +/// Structure for specifying the configuration of SDRAM +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub struct FemcSdramConfig { + /// External SDRAM base address + pub base_address: u32, + /// External SDRAM size in bytes + pub size: MemorySize, + /// Referesh count + pub refresh_count: u32, + /// Column address bit count + pub col_addr_bits: ColAddrBits, + /// CAS latency, Choices are 1, 2, 3 + pub cas_latency: CasLatency, + /// Chip select + pub cs: u8, + // /// Chip select mux + // pub cs_mux_pin: u8, + /// Bank number + pub bank_num: Bank2Sel, + /// Prescaler + pub prescaler: u8, + /// SDRAM port size + pub port_size: SdramPortSize, + /// 1/2/4/8 bytes + pub burst_len: BurstLen, + pub cke_off_in_ns: u8, + /// Tras + pub act_to_precharge_in_ns: u8, + /// Trp + pub precharge_to_act_in_ns: u8, + /// Trcd + pub act_to_rw_in_ns: u8, + /// Trrd + pub act_to_act_in_ns: u8, + /// Trc + pub refresh_to_refresh_in_ns: u8, + /// Twr + pub write_recover_in_ns: u8, + /// Txsr + pub self_refresh_recover_in_ns: u8, + /// Trc + pub refresh_recover_in_ns: u8, + /// Tref + pub refresh_in_ms: u8, + pub idle_timeout_in_ns: u8, + pub cmd_data_width: DataSize, + pub auto_refresh_count_in_one_burst: u8, + /// Delay cell disable + pub delay_cell_disable: bool, + /// Delay cell value + pub delay_cell_value: u8, +} + +impl Default for FemcSdramConfig { + fn default() -> Self { + let mut config: Self = unsafe { mem::zeroed() }; + + config.col_addr_bits = ColAddrBits::_9BIT; + config.cas_latency = CasLatency::_3; + config.bank_num = Bank2Sel::BANK_NUM_4; + config.prescaler = HPM_FEMC_DRV_DEFAULT_PRESCALER; + config.burst_len = BurstLen::_8; + + config.auto_refresh_count_in_one_burst = 1; + config.precharge_to_act_in_ns = 18; + config.act_to_rw_in_ns = 18; + config.refresh_recover_in_ns = 60; + config.write_recover_in_ns = 12; + config.cke_off_in_ns = 42; + config.act_to_precharge_in_ns = 42; + + config.self_refresh_recover_in_ns = 72; + config.refresh_to_refresh_in_ns = 60; + config.act_to_act_in_ns = 12; + config.idle_timeout_in_ns = 6; + + // cs_mux_pin not used + + config.cmd_data_width = DataSize::_32BIT; + + config + } +} + +/// FEMC driver +pub struct Femc<'d, T: Instance> { + peri: PhantomData<&'d mut T>, +} + +unsafe impl<'d, T> Send for Femc<'d, T> where T: Instance {} + +impl<'d, T> Femc<'d, T> +where + T: Instance, +{ + pub fn new_raw(_instance: impl Peripheral

+ 'd) -> Self { + T::add_resource_group(0); + + Self { peri: PhantomData } + } + + pub fn enable(&mut self) { + T::REGS.ctrl().modify(|w| w.set_dis(false)); + } + + pub fn disable(&mut self) { + while !T::REGS.stat0().read().idle() {} + + T::REGS.ctrl().modify(|w| w.set_dis(true)); + } + + pub fn reset(&mut self) { + T::REGS.ctrl().write(|w| w.set_rst(true)); + + while T::REGS.ctrl().read().rst() {} + } + + fn check_ip_cmd_done(&mut self) -> Result<(), Error> { + let r = T::REGS; + + let mut retry = 0; + let mut intr; + loop { + intr = r.intr().read(); + if intr.ipcmddone() || intr.ipcmderr() { + break; + } + retry += 1; + if retry >= HPM_FEMC_DRV_RETRY_COUNT { + return Err(Error::Timeout); + } + } + + // W1C + r.intr().write(|w| { + w.set_ipcmddone(true); + w.set_ipcmderr(true); + }); + + if intr.ipcmderr() { + return Err(Error::FemcCmd); + } + + Ok(()) + } + + pub fn issue_ip_cmd(&mut self, base_address: u32, cmd: SdramCmd, data: u32) -> Result { + let r = T::REGS; + + // SDK-BUG: logic of femc_is_write_cmd + let read_data = cmd == SdramCmd::READ; + + r.saddr().write(|w| w.0 = base_address); + if !read_data { + r.iptx().write(|w| w.0 = data); + } + r.ipcmd().write(|w| { + w.set_cmd(cmd); + w.set_key(FEMC_CMD_KEY); + }); + + self.check_ip_cmd_done()?; + + if read_data { + Ok(r.iprx().read().0) + } else { + Ok(0) + } + } + + pub fn init(&mut self, config: FemcConfig) { + let r = T::REGS; + r.br(0).write(|w| w.0 = 0x0); // BASE0, SDRAM0 + r.br(1).write(|w| w.0 = 0x0); // BASE1, SDMRA1 + + self.reset(); + self.disable(); + + r.ctrl().modify(|w| { + w.set_bto(config.bus_timeout); + w.set_cto(config.cmd_timeout); + w.set_dqs(config.dqs); + }); + + let q = config.axi_q_weight_a; + if q.enable { + r.bmw0().write(|w| { + w.set_qos(q.qos); + w.set_age(q.age); + w.set_sh(q.slave_hit); + w.set_rws(q.slave_hit_wo_rw); + }); + } else { + r.bmw0().write(|w| w.0 = 0); + } + + let q = config.axi_q_weight_b; + if q.enable { + r.bmw1().write(|w| { + w.set_qos(q.qos); + w.set_age(q.age); + w.set_ph(q.page_hit); + w.set_rws(q.slave_hit_wo_rw); + w.set_br(q.bank_rotation); + }); + } else { + r.bmw1().write(|w| w.0 = 0); + } + + self.enable(); + } + + pub fn configure_sdram(&mut self, clk_in_hz: u32, config: FemcSdramConfig) -> Result<(), Error> { + let r = T::REGS; + + let clk_in_khz = clk_in_hz / 1000; + + let prescaler = if config.prescaler == 0 { + 256 + } else { + config.prescaler as u32 + }; + let refresh_cycle = + clk_in_khz * (config.refresh_in_ms as u32) / config.refresh_count / ((prescaler as u32) << 4); + + if refresh_cycle == 0 || refresh_cycle > 256 { + return Err(Error::InvalidConfig); + } + + r.br(config.cs as usize).write(|w| { + w.set_base(config.base_address >> 12); // base is high 20 bits + w.set_size(config.size); + w.set_vld(true); + }); + + r.sdrctrl0().write(|w| { + w.set_portsz(config.port_size); + w.set_burstlen(config.burst_len); + // COL and COL8 are merged into one + w.set_col(config.col_addr_bits); + w.set_cas(config.cas_latency); + w.set_bank2(config.bank_num); + }); + + r.sdrctrl1().write(|w| { + w.set_pre2act(ns2cycle(clk_in_hz, config.precharge_to_act_in_ns as _, 0xF) as u8); + w.set_act2rw(ns2cycle(clk_in_hz, config.act_to_rw_in_ns as _, 0xF) as u8); + w.set_rfrc(ns2cycle(clk_in_hz, config.refresh_to_refresh_in_ns as _, 0x1F) as u8); + w.set_wrc(ns2cycle(clk_in_hz, config.write_recover_in_ns as _, 7) as u8); + w.set_ckeoff(ns2cycle(clk_in_hz, config.cke_off_in_ns as _, 0xF) as u8); + w.set_act2pre(ns2cycle(clk_in_hz, config.act_to_precharge_in_ns as _, 0xF) as u8); + }); + + r.sdrctrl2().write(|w| { + w.set_srrc(ns2cycle(clk_in_hz, config.self_refresh_recover_in_ns as _, 0xFF) as u8); + w.set_ref2ref(ns2cycle(clk_in_hz, config.refresh_recover_in_ns as _, 0xFF) as u8); + w.set_act2act(ns2cycle(clk_in_hz, config.act_to_act_in_ns as _, 0xFF) as u8); + w.set_ito(ns2cycle(clk_in_hz, config.idle_timeout_in_ns as _, 0xFF) as u8); + }); + + let prescaler = if prescaler == 256 { 0 } else { config.prescaler as u8 }; + let refresh_cycle = if refresh_cycle == 256 { 0 } else { refresh_cycle }; + r.sdrctrl3().write(|w| { + w.set_prescale(prescaler as u8); + w.set_rt(refresh_cycle as u8); + w.set_ut(refresh_cycle as u8); + w.set_rebl(config.auto_refresh_count_in_one_burst - 1); + }); + + // config delay cell + { + r.dlycfg().modify(|w| w.set_oe(false)); + r.dlycfg().write(|w| { + w.set_dlysel(config.delay_cell_value); + w.set_dlyen(!config.delay_cell_disable); + }); + r.dlycfg().modify(|w| w.set_oe(true)); + } + + r.datsz().write(|w| w.set_datsz(config.cmd_data_width)); + // SDK-BUG: what's the meaning of 0x3 as mask? + // r.datsz().write(|w| w.0 = (config.cmd_data_width as u32) & 0x3); //???? + r.bytemsk().write(|w| w.0 = 0); + + self.issue_ip_cmd(config.base_address, SdramCmd::PRECHARGE_ALL, 0)?; + + self.issue_ip_cmd(config.base_address, SdramCmd::AUTO_REFRESH, 0)?; + self.issue_ip_cmd(config.base_address, SdramCmd::AUTO_REFRESH, 0)?; + + let cmd_data = (config.burst_len as u32) | ((config.cas_latency as u32) << 4); + self.issue_ip_cmd(config.base_address, SdramCmd::MODE_SET, cmd_data)?; + + // enable refresh + r.sdrctrl3().modify(|w| w.set_ren(true)); + + Ok(()) + } +} + +fn ns2cycle(freq_in_hz: u32, ns: u32, max_cycle: u32) -> u32 { + let ns_per_cycle = 1_000_000_000 / freq_in_hz; + let mut cycle = ns / ns_per_cycle; + if cycle > max_cycle { + cycle = max_cycle; + } + cycle +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + InvalidConfig, + FemcCmd, + Timeout, +} + +trait SealedInstance: crate::sysctl::ClockPeripheral { + const REGS: crate::pac::femc::Femc; +} + +/// FMC instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} + +foreach_peripheral!( + (femc, $inst:ident) => { + impl crate::femc::SealedInstance for crate::peripherals::$inst { + const REGS: crate::pac::femc::Femc = crate::pac::$inst; + } + impl crate::femc::Instance for crate::peripherals::$inst {} + }; +); + +pin_trait!(A00Pin, Instance); +pin_trait!(A01Pin, Instance); +pin_trait!(A02Pin, Instance); +pin_trait!(A03Pin, Instance); +pin_trait!(A04Pin, Instance); +pin_trait!(A05Pin, Instance); +pin_trait!(A06Pin, Instance); +pin_trait!(A07Pin, Instance); +pin_trait!(A08Pin, Instance); +pin_trait!(A09Pin, Instance); +pin_trait!(A10Pin, Instance); +pin_trait!(A11Pin, Instance); // NWE for SRAM +pin_trait!(A12Pin, Instance); // NOE for SRAM + +pin_trait!(BA0Pin, Instance); +pin_trait!(BA1Pin, Instance); // NADV for SRAM + +pin_trait!(CASPin, Instance); +pin_trait!(CKEPin, Instance); +pin_trait!(CLKPin, Instance); + +pin_trait!(CS0Pin, Instance); +pin_trait!(CS1Pin, Instance); // NCE for SRAM + +pin_trait!(DM0Pin, Instance); +pin_trait!(DM1Pin, Instance); + +pin_trait!(DQSPin, Instance); + +pin_trait!(DQ00Pin, Instance); // D0, AD0 +pin_trait!(DQ01Pin, Instance); +pin_trait!(DQ02Pin, Instance); +pin_trait!(DQ03Pin, Instance); +pin_trait!(DQ04Pin, Instance); +pin_trait!(DQ05Pin, Instance); +pin_trait!(DQ06Pin, Instance); +pin_trait!(DQ07Pin, Instance); +pin_trait!(DQ08Pin, Instance); +pin_trait!(DQ09Pin, Instance); +pin_trait!(DQ10Pin, Instance); +pin_trait!(DQ11Pin, Instance); +pin_trait!(DQ12Pin, Instance); +pin_trait!(DQ13Pin, Instance); +pin_trait!(DQ14Pin, Instance); +pin_trait!(DQ15Pin, Instance); +pin_trait!(DQ16Pin, Instance); // A8 +pin_trait!(DQ17Pin, Instance); +pin_trait!(DQ18Pin, Instance); +pin_trait!(DQ19Pin, Instance); +pin_trait!(DQ20Pin, Instance); +pin_trait!(DQ21Pin, Instance); +pin_trait!(DQ22Pin, Instance); +pin_trait!(DQ23Pin, Instance); +pin_trait!(DQ24Pin, Instance); +pin_trait!(DQ25Pin, Instance); +pin_trait!(DQ26Pin, Instance); +pin_trait!(DQ27Pin, Instance); +pin_trait!(DQ28Pin, Instance); +pin_trait!(DQ29Pin, Instance); +pin_trait!(DQ30Pin, Instance); +pin_trait!(DQ31Pin, Instance); // A23 + +pin_trait!(RASPin, Instance); +pin_trait!(WEPin, Instance); diff --git a/src/lib.rs b/src/lib.rs index 988dc35..b8288e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,9 @@ pub mod dma; pub mod i2c; pub mod uart; +#[cfg(femc)] +pub mod femc; + #[cfg(feature = "rt")] pub mod rt; #[cfg(feature = "rt")] diff --git a/src/macros.rs b/src/macros.rs index e448f68..225233f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -109,6 +109,7 @@ impl TxDma for C { macro_rules! dma_trait_impl { (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $request:expr) => { impl crate::$mod::$trait for C { + #[inline(always)] fn request(&self) -> crate::dma::Request { $request } diff --git a/src/sysctl/v6e.rs b/src/sysctl/v6e.rs index 0f1f1dc..b13eabd 100644 --- a/src/sysctl/v6e.rs +++ b/src/sysctl/v6e.rs @@ -173,7 +173,7 @@ pub(crate) unsafe fn init(config: Config) { // Connect Group0 to CPU0 SYSCTL.affiliate(0).set().write(|w| w.set_link(1 << 0)); - clock_and_to_group(pac::resources::CPU1, 1); + clock_and_to_group(pac::resources::CPU1, 0); clock_and_to_group(pac::resources::MCT1, 1); SYSCTL.affiliate(1).set().write(|w| w.set_link(1 << 1));