diff --git a/README.md b/README.md index 4b6e89e..9228add 100644 --- a/README.md +++ b/README.md @@ -8,25 +8,25 @@ family of SoCs. This project contains the following crates: -## Zynq Workspace +## [Zynq Workspace](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq) This workspace contains libraries and application which can only be run on the target system. -- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-rt) +- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-rt) run-time crate containing basic low-level startup code necessary to boot a Rust app on the Zynq7000. -- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000) PAC +- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000) PAC crate containing basic low-level register definitions. -- The [`zynq7000-mmu`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-hal) +- The [`zynq7000-mmu`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-hal) crate containing common MMU abstractions used by both the HAL and the run-time crate. -- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-hal) +- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-hal) HAL crate containing higher-level abstractions on top of the PAC register crate. -- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-embassy) +- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-embassy) crate containing support for running the embassy-rs asynchronous run-time. It also contains the following helper crates: -- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples) +- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples) folder contains various example applications crates using the HAL and the PAC. This folder also contains dedicated example applications using the [`embassy`](https://github.com/embassy-rs/embassy) native Rust RTOS. diff --git a/tools/zynq7000-ps7init-extract/src/main.rs b/tools/zynq7000-ps7init-extract/src/main.rs index 49e62f9..db195c2 100644 --- a/tools/zynq7000-ps7init-extract/src/main.rs +++ b/tools/zynq7000-ps7init-extract/src/main.rs @@ -149,7 +149,7 @@ fn generate_ddrc_config( let ctrl_reg6 = reg_to_values.val_as_token("CTRL Reg 6", 0xF800_607C); let che_t_zq = reg_to_values.val_as_token("CHE T ZQ", 0xF800_60A4); let che_t_zq_short_interval_reg = - reg_to_values.val_as_token("CHE T ZQ Short Interval", 0xF800_60A4); + reg_to_values.val_as_token("CHE T ZQ Short Interval", 0xF800_60A8); let deep_powerdown = reg_to_values.val_as_token("Deep Powerdown", 0xF800_60AC); let reg_2c = reg_to_values.val_as_token("Reg 2C", 0xF800_60B0); let reg_2d = reg_to_values.val_as_token("Reg 2D", 0xF800_60B4); diff --git a/zynq/examples/embassy/src/bin/embassy-hello.rs b/zynq/examples/embassy/src/bin/embassy-hello.rs new file mode 100644 index 0000000..1047373 --- /dev/null +++ b/zynq/examples/embassy/src/bin/embassy-hello.rs @@ -0,0 +1,123 @@ +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use log::{error, info}; +use zynq7000_hal::{BootMode, InteruptConfig, clocks, gic, gpio, gtc, time::Hertz, uart}; + +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(_spawner: Spawner) -> ! { + let periphs = zynq7000_hal::init(zynq7000_hal::Config { + init_l2_cache: true, + level_shifter_config: Some(zynq7000_hal::LevelShifterConfig::EnableAll), + interrupt_config: Some(InteruptConfig::AllInterruptsToCpu0), + }) + .unwrap(); + let clocks = clocks::Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + + // Set up global timer counter and embassy time driver. + let gtc = gtc::GlobalTimerCounter::new(periphs.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + let mio_pins = gpio::mio::Pins::new(periphs.gpio); + + // Set up the UART, we are logging with it. + let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let mut uart = uart::Uart::new_with_mio( + periphs.uart_1, + uart::Config::new_with_clk_config(uart_clk_config), + (mio_pins.mio48, mio_pins.mio49), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") + .unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let boot_mode = BootMode::new_from_regs(); + info!("Boot mode: {:?}", boot_mode); + + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut led = gpio::Output::new_for_mio(mio_pins.mio7, gpio::PinState::Low); + loop { + info!("Hello, world!"); + led.toggle().unwrap(); + ticker.next().await; + } +} + +#[zynq7000_rt::irq] +pub fn irq_handler() { + let mut gic_helper = gic::GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + gic::Interrupt::Sgi(_) => (), + gic::Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + gic::Interrupt::Spi(_spi_interrupt) => (), + gic::Interrupt::Invalid(_) => (), + gic::Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[zynq7000_rt::exception(DataAbort)] +fn data_abort_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +#[zynq7000_rt::exception(Undefined)] +fn undefined_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +#[zynq7000_rt::exception(PrefetchAbort)] +fn prefetch_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {info:?}"); + loop {} +} diff --git a/zynq/examples/embassy/src/main.rs b/zynq/examples/embassy/src/main.rs index 1047373..8840657 100644 --- a/zynq/examples/embassy/src/main.rs +++ b/zynq/examples/embassy/src/main.rs @@ -6,9 +6,8 @@ use cortex_ar::asm::nop; use embassy_executor::Spawner; use embassy_time::{Duration, Ticker}; use embedded_hal::digital::StatefulOutputPin; -use embedded_io::Write; -use log::{error, info}; -use zynq7000_hal::{BootMode, InteruptConfig, clocks, gic, gpio, gtc, time::Hertz, uart}; +use log::error; +use zynq7000_hal::{InteruptConfig, clocks, gic, gpio, gtc, time::Hertz}; use zynq7000_rt as _; @@ -38,37 +37,10 @@ async fn main(_spawner: Spawner) -> ! { // Set up global timer counter and embassy time driver. let gtc = gtc::GlobalTimerCounter::new(periphs.gtc, clocks.arm_clocks()); zynq7000_embassy::init(clocks.arm_clocks(), gtc); - let mio_pins = gpio::mio::Pins::new(periphs.gpio); - - // Set up the UART, we are logging with it. - let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) - .unwrap() - .0; - let mut uart = uart::Uart::new_with_mio( - periphs.uart_1, - uart::Config::new_with_clk_config(uart_clk_config), - (mio_pins.mio48, mio_pins.mio49), - ) - .unwrap(); - uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") - .unwrap(); - // Safety: We are not multi-threaded yet. - unsafe { - zynq7000_hal::log::uart_blocking::init_unsafe_single_core( - uart, - log::LevelFilter::Trace, - false, - ) - }; - - let boot_mode = BootMode::new_from_regs(); - info!("Boot mode: {:?}", boot_mode); - let mut ticker = Ticker::every(Duration::from_millis(1000)); let mut led = gpio::Output::new_for_mio(mio_pins.mio7, gpio::PinState::Low); loop { - info!("Hello, world!"); led.toggle().unwrap(); ticker.next().await; } diff --git a/zynq/examples/simple/Cargo.toml b/zynq/examples/simple/Cargo.toml index fdec76d..8edfe4c 100644 --- a/zynq/examples/simple/Cargo.toml +++ b/zynq/examples/simple/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "blinky" +name = "simple" version = "0.1.0" authors = ["Robin Mueller "] edition = "2024" diff --git a/zynq/examples/simple/src/bin/blinky.rs b/zynq/examples/simple/src/bin/blinky.rs new file mode 100644 index 0000000..9c822f0 --- /dev/null +++ b/zynq/examples/simple/src/bin/blinky.rs @@ -0,0 +1,103 @@ +//! Simple blinky app, showing a PAC variant and a HAL variant. +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin}; +use zynq7000::Peripherals; +use zynq7000_hal::{ + clocks::Clocks, + gpio::{Output, PinState, mio}, + l2_cache, + priv_tim::CpuPrivateTimer, + time::Hertz, +}; +use zynq7000_rt as _; + +pub const LIB: Lib = Lib::Hal; + +/// One user LED is MIO7 +const ZEDBOARD_LED_MASK: u32 = 1 << 7; + +// Define the clock frequency as a constant. +// +// Not required for the PAC mode, is required for clean delays in HAL mode. +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333); + +#[derive(Debug)] +pub enum Lib { + Pac, + Hal, +} + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[unsafe(export_name = "main")] +pub fn main() -> ! { + l2_cache::init_with_defaults(&mut unsafe { zynq7000::l2_cache::L2Cache::new_mmio_fixed() }); + match LIB { + Lib::Pac => { + let mut gpio = unsafe { zynq7000::gpio::Gpio::new_mmio_fixed() }; + gpio.bank_0().modify_dirm(|v| v | ZEDBOARD_LED_MASK); + gpio.bank_0().modify_out_en(|v| v | ZEDBOARD_LED_MASK); + loop { + gpio.modify_out_0(|v| v ^ ZEDBOARD_LED_MASK); + for _ in 0..5_000_000 { + nop(); + } + } + } + Lib::Hal => { + let dp = Peripherals::take().unwrap(); + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Unwrap okay, we only call this once on core 0 here. + let mut cpu_tim = CpuPrivateTimer::take(clocks.arm_clocks()).unwrap(); + let mio_pins = mio::Pins::new(dp.gpio); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::High); + loop { + led.toggle().unwrap(); + cpu_tim.delay_ms(1000); + } + } + } +} + +#[zynq7000_rt::irq] +pub fn irq_handler() {} + +#[zynq7000_rt::exception(DataAbort)] +fn data_abort_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +#[zynq7000_rt::exception(Undefined)] +fn undefined_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +#[zynq7000_rt::exception(PrefetchAbort)] +fn prefetch_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop { + nop(); + } +} diff --git a/zynq/examples/simple/src/main.rs b/zynq/examples/simple/src/main.rs index 9c822f0..be92ace 100644 --- a/zynq/examples/simple/src/main.rs +++ b/zynq/examples/simple/src/main.rs @@ -4,33 +4,8 @@ use core::panic::PanicInfo; use cortex_ar::asm::nop; -use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin}; -use zynq7000::Peripherals; -use zynq7000_hal::{ - clocks::Clocks, - gpio::{Output, PinState, mio}, - l2_cache, - priv_tim::CpuPrivateTimer, - time::Hertz, -}; use zynq7000_rt as _; -pub const LIB: Lib = Lib::Hal; - -/// One user LED is MIO7 -const ZEDBOARD_LED_MASK: u32 = 1 << 7; - -// Define the clock frequency as a constant. -// -// Not required for the PAC mode, is required for clean delays in HAL mode. -const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333); - -#[derive(Debug)] -pub enum Lib { - Pac, - Hal, -} - /// Entry point (not called like a normal main function) #[unsafe(no_mangle)] pub extern "C" fn boot_core(cpu_id: u32) -> ! { @@ -42,31 +17,8 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! { #[unsafe(export_name = "main")] pub fn main() -> ! { - l2_cache::init_with_defaults(&mut unsafe { zynq7000::l2_cache::L2Cache::new_mmio_fixed() }); - match LIB { - Lib::Pac => { - let mut gpio = unsafe { zynq7000::gpio::Gpio::new_mmio_fixed() }; - gpio.bank_0().modify_dirm(|v| v | ZEDBOARD_LED_MASK); - gpio.bank_0().modify_out_en(|v| v | ZEDBOARD_LED_MASK); - loop { - gpio.modify_out_0(|v| v ^ ZEDBOARD_LED_MASK); - for _ in 0..5_000_000 { - nop(); - } - } - } - Lib::Hal => { - let dp = Peripherals::take().unwrap(); - let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); - // Unwrap okay, we only call this once on core 0 here. - let mut cpu_tim = CpuPrivateTimer::take(clocks.arm_clocks()).unwrap(); - let mio_pins = mio::Pins::new(dp.gpio); - let mut led = Output::new_for_mio(mio_pins.mio7, PinState::High); - loop { - led.toggle().unwrap(); - cpu_tim.delay_ms(1000); - } - } + loop { + cortex_ar::asm::nop(); } } diff --git a/zynq/zedboard-bsp/src/ddrc_config_autogen.rs b/zynq/zedboard-bsp/src/ddrc_config_autogen.rs index e1edb93..22670cb 100644 --- a/zynq/zedboard-bsp/src/ddrc_config_autogen.rs +++ b/zynq/zedboard-bsp/src/ddrc_config_autogen.rs @@ -98,4 +98,3 @@ pub const DDRC_CONFIG_ZEDBOARD: DdrcConfigSet = DdrcConfigSet { lpddr_ctrl_2: regs::LpddrControl2::new_with_raw_value(0x00005125), lpddr_ctrl_3: regs::LpddrControl3::new_with_raw_value(0x000012a8), }; - diff --git a/zynq/zedboard-bsp/src/ddriob_config_autogen.rs b/zynq/zedboard-bsp/src/ddriob_config_autogen.rs index 74f1ea1..b1aebdd 100644 --- a/zynq/zedboard-bsp/src/ddriob_config_autogen.rs +++ b/zynq/zedboard-bsp/src/ddriob_config_autogen.rs @@ -13,4 +13,3 @@ pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet { diff1: regs::DdriobConfig::new_with_raw_value(0x00000674), clock: regs::DdriobConfig::new_with_raw_value(0x00000600), }; - diff --git a/zynq/zynq7000/src/ddrc.rs b/zynq/zynq7000/src/ddrc.rs index fd4e1cc..d1fe31c 100644 --- a/zynq/zynq7000/src/ddrc.rs +++ b/zynq/zynq7000/src/ddrc.rs @@ -1,8 +1,8 @@ pub const DDRC_BASE_ADDR: usize = 0xF800_6000; pub mod regs { - use arbitrary_int::{u2, u3, u4, u5, u6, u7, u9, u10, u11, u12, u20}; pub use crate::slcr::ddriob::DdriobConfig; + use arbitrary_int::{u2, u3, u4, u5, u6, u7, u9, u10, u11, u12, u20}; #[bitbybit::bitenum(u2)] #[derive(Debug, PartialEq, Eq)]