added SDIO example app
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
This commit is contained in:
153
zynq/examples/zedboard/src/bin/sdio.rs
Normal file
153
zynq/examples/zedboard/src/bin/sdio.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use aarch32_cpu::asm::nop;
|
||||
use core::panic::PanicInfo;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use embedded_hal::digital::StatefulOutputPin;
|
||||
use embedded_io::Write;
|
||||
use log::{error, info};
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zynq7000_hal::gpio::Input;
|
||||
use zynq7000_hal::prelude::*;
|
||||
use zynq7000_hal::{
|
||||
BootMode, clocks, gic, gpio, gtc,
|
||||
sdio::{Sdio, SdioClockConfig, SdioLowLevel},
|
||||
uart,
|
||||
};
|
||||
|
||||
use zynq7000_rt as _;
|
||||
|
||||
const INIT_STRING: &str = "-- Zynq 7000 Zedboard GPIO blinky example --\n\r";
|
||||
|
||||
/// 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(zynq7000_hal::InteruptConfig::AllInterruptsToCpu0),
|
||||
})
|
||||
.unwrap();
|
||||
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
|
||||
let clocks = clocks::Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
|
||||
|
||||
let mut gpio_pins = gpio::GpioPins::new(periphs.gpio);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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_for_uart_1(
|
||||
periphs.uart_1,
|
||||
uart::Config::new_with_clk_config(uart_clk_config),
|
||||
(gpio_pins.mio.mio48, gpio_pins.mio.mio49),
|
||||
)
|
||||
.unwrap();
|
||||
uart.write_all(INIT_STRING.as_bytes()).unwrap();
|
||||
// Safety: We are not multi-threaded yet.
|
||||
unsafe {
|
||||
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
|
||||
uart,
|
||||
log::LevelFilter::Trace,
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
let sdio_clock_config =
|
||||
SdioClockConfig::calculate_for_io_clock(clocks.io_clocks(), 100.MHz(), 10.MHz());
|
||||
let sdio = Sdio::new_for_sdio_0(
|
||||
periphs.sdio_0,
|
||||
sdio_clock_config,
|
||||
gpio_pins.mio.mio40,
|
||||
gpio_pins.mio.mio41,
|
||||
(
|
||||
gpio_pins.mio.mio42,
|
||||
gpio_pins.mio.mio43,
|
||||
gpio_pins.mio.mio44,
|
||||
gpio_pins.mio.mio45,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let card_detect = Input::new_for_mio(gpio_pins.mio.mio47).unwrap();
|
||||
let write_protect = Input::new_for_mio(gpio_pins.mio.mio46).unwrap();
|
||||
info!("Card detect state: {:?}", card_detect.is_high());
|
||||
info!("Write protect state: {:?}", write_protect.is_high());
|
||||
|
||||
let capabilities = sdio.ll().capabilities();
|
||||
info!("SDIO Capabilities: {:?}", capabilities);
|
||||
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(200));
|
||||
|
||||
let mut mio_led = gpio::Output::new_for_mio(gpio_pins.mio.mio7, gpio::PinState::Low);
|
||||
loop {
|
||||
mio_led.toggle().unwrap();
|
||||
|
||||
ticker.next().await; // Wait for the next cycle of the ticker
|
||||
}
|
||||
}
|
||||
|
||||
#[zynq7000_rt::irq]
|
||||
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 == 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 {}
|
||||
}
|
||||
@@ -259,6 +259,11 @@ impl SdioLowLevel {
|
||||
Some(Self { id, regs })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn capabilities(&self) -> zynq7000::sdio::Capabilities {
|
||||
self.regs.read_capabilities()
|
||||
}
|
||||
|
||||
/// Common SDIO clock configuration routine which should be called once before using the SDIO.
|
||||
///
|
||||
/// This does NOT disable the clock, which should be done before changing the clock
|
||||
@@ -302,7 +307,15 @@ impl SdioLowLevel {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_clock(&mut self) {
|
||||
pub fn enable_internal_clock(&mut self) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_internal_clock_enable(true);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_sd_clock(&mut self) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_sd_clock_enable(true);
|
||||
val
|
||||
@@ -310,7 +323,7 @@ impl SdioLowLevel {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn disable_clock(&mut self) {
|
||||
pub fn disable_sd_clock(&mut self) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_sd_clock_enable(false);
|
||||
val
|
||||
@@ -400,17 +413,39 @@ impl Sdio {
|
||||
Self { ll }
|
||||
}
|
||||
|
||||
/// Direct access to the low-level SDIO driver.
|
||||
pub fn ll_mut(&mut self) -> &mut SdioLowLevel {
|
||||
&mut self.ll
|
||||
}
|
||||
|
||||
pub fn ll(&self) -> &SdioLowLevel {
|
||||
&self.ll
|
||||
}
|
||||
|
||||
fn initialize(ll: &mut SdioLowLevel, clock_config: &SdioClockConfig) {
|
||||
ll.reset(10);
|
||||
// TODO: SW reset for all?
|
||||
// TODO: Internal clock?
|
||||
ll.disable_clock();
|
||||
ll.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_software_reset_for_all(true);
|
||||
val
|
||||
});
|
||||
ll.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_software_reset_for_all(false);
|
||||
val
|
||||
});
|
||||
// Explicitely clear the clock bit.
|
||||
ll.disable_sd_clock();
|
||||
ll.configure_clock(clock_config);
|
||||
ll.enable_clock();
|
||||
// As specified in the TRM, wait until the internal clock is stable before enabling the
|
||||
// SD clock.
|
||||
ll.enable_internal_clock();
|
||||
while !ll
|
||||
.regs
|
||||
.read_clock_timeout_sw_reset_control()
|
||||
.internal_clock_stable()
|
||||
{}
|
||||
ll.enable_sd_clock();
|
||||
|
||||
// TODO: There is probably some other configuration necessary.. the docs really are not
|
||||
// complete here..
|
||||
unsafe {}
|
||||
// TODO: Perform the regular SDIO setup sequence.
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -390,6 +390,38 @@ pub struct InterruptMask {
|
||||
command_complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Capabilities {
|
||||
#[bit(30, rw)]
|
||||
spi_block_mode: bool,
|
||||
#[bit(29, rw)]
|
||||
spi_mode: bool,
|
||||
#[bit(28, rw)]
|
||||
_64_bit_system_bus_support: bool,
|
||||
#[bit(27, rw)]
|
||||
interrupt_mode: bool,
|
||||
#[bit(26, rw)]
|
||||
voltage_support_1_8v: bool,
|
||||
#[bit(25, rw)]
|
||||
voltage_support_3_0v: bool,
|
||||
#[bit(24, rw)]
|
||||
voltage_support_3_3v: bool,
|
||||
#[bit(23, rw)]
|
||||
suspend_resume_support: bool,
|
||||
#[bit(22, rw)]
|
||||
sdma_support: bool,
|
||||
#[bit(21, rw)]
|
||||
high_speed_support: bool,
|
||||
#[bit(19, rw)]
|
||||
adma2_support: bool,
|
||||
#[bit(18, rw)]
|
||||
extended_media_bus_support: bool,
|
||||
#[bits(16..=17, rw)]
|
||||
max_block_length: u2,
|
||||
#[bit(7, rw)]
|
||||
timeout_clock_unit: bool,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Registers {
|
||||
@@ -411,7 +443,7 @@ pub struct Registers {
|
||||
#[mmio(PureRead)]
|
||||
auto_cmd12_error_status: u32,
|
||||
#[mmio(PureRead)]
|
||||
capabilities: u32,
|
||||
capabilities: Capabilities,
|
||||
_reserved_0: u32,
|
||||
#[mmio(PureRead)]
|
||||
maximum_current_capabilities: u32,
|
||||
|
||||
Reference in New Issue
Block a user