Introduce Rust FSBL
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:
31
examples/embassy/build.rs
Normal file
31
examples/embassy/build.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put `memory.x` in our output directory and ensure it's
|
||||
// on the linker search path.
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// By default, Cargo will re-run a build script whenever
|
||||
// any file in the project changes. By specifying `memory.x`
|
||||
// here, we ensure the build script is only re-run when
|
||||
// `memory.x` is changed.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
}
|
||||
22
examples/embassy/memory.x
Normal file
22
examples/embassy/memory.x
Normal file
@@ -0,0 +1,22 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Uncached memory */
|
||||
.uncached (NOLOAD) : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
_sbss_uncached = .;
|
||||
*(.uncached .uncached.*);
|
||||
. = ALIGN(4);
|
||||
_ebss_uncached = .;
|
||||
} > UNCACHED
|
||||
}
|
||||
@@ -137,7 +137,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Flex Pin 0 state (should be low): {}", flex_pin_0.is_high());
|
||||
}
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(1000));
|
||||
|
||||
@@ -75,7 +75,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
|
||||
zynq7000_hal::log::rb::init(log::LevelFilter::Trace);
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let led = Output::new_for_mio(mio_pins.mio7, PinState::Low);
|
||||
|
||||
@@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(1000));
|
||||
|
||||
@@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(1000));
|
||||
|
||||
31
examples/simple/build.rs
Normal file
31
examples/simple/build.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put `memory.x` in our output directory and ensure it's
|
||||
// on the linker search path.
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// By default, Cargo will re-run a build script whenever
|
||||
// any file in the project changes. By specifying `memory.x`
|
||||
// here, we ensure the build script is only re-run when
|
||||
// `memory.x` is changed.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
}
|
||||
22
examples/simple/memory.x
Normal file
22
examples/simple/memory.x
Normal file
@@ -0,0 +1,22 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Uncached memory */
|
||||
.uncached (NOLOAD) : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
_sbss_uncached = .;
|
||||
*(.uncached .uncached.*);
|
||||
. = ALIGN(4);
|
||||
_ebss_uncached = .;
|
||||
} > UNCACHED
|
||||
}
|
||||
@@ -21,7 +21,7 @@ use zynq7000_hal::{
|
||||
use zynq7000_rt as _;
|
||||
|
||||
// Define the clock frequency as a constant
|
||||
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
|
||||
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333);
|
||||
|
||||
static MS_TICKS: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ pub fn main() -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {boot_mode:?}");
|
||||
|
||||
let mut led = Output::new_for_mio(mio_pins.mio7, PinState::Low);
|
||||
|
||||
@@ -4,25 +4,33 @@
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use cortex_ar::asm::nop;
|
||||
use embedded_hal::digital::StatefulOutputPin;
|
||||
use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin};
|
||||
use zynq7000::PsPeripherals;
|
||||
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,
|
||||
}
|
||||
|
||||
const LIB: Lib = Lib::Hal;
|
||||
|
||||
/// Entry point (not called like a normal main function)
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
|
||||
@@ -49,13 +57,14 @@ pub fn main() -> ! {
|
||||
}
|
||||
Lib::Hal => {
|
||||
let dp = PsPeripherals::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();
|
||||
for _ in 0..5_000_000 {
|
||||
nop();
|
||||
}
|
||||
cpu_tim.delay_ms(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,22 +73,22 @@ pub fn main() -> ! {
|
||||
#[zynq7000_rt::irq]
|
||||
pub fn irq_handler() {}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn _abort_handler() {
|
||||
#[zynq7000_rt::exception(DataAbort)]
|
||||
fn data_abort_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn _undefined_handler() {
|
||||
#[zynq7000_rt::exception(Undefined)]
|
||||
fn undefined_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn _prefetch_handler() {
|
||||
#[zynq7000_rt::exception(PrefetchAbort)]
|
||||
fn prefetch_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
nop();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
zynq7000-embassy = { path = "../../zynq7000-embassy" }
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
l3gd20 = { git = "https://github.com/us-irs/l3gd20.git", branch = "add-async-if" }
|
||||
embedded-io = "0.6"
|
||||
bitbybit = "1.3"
|
||||
|
||||
31
examples/zedboard/build.rs
Normal file
31
examples/zedboard/build.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put `memory.x` in our output directory and ensure it's
|
||||
// on the linker search path.
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// By default, Cargo will re-run a build script whenever
|
||||
// any file in the project changes. By specifying `memory.x`
|
||||
// here, we ensure the build script is only re-run when
|
||||
// `memory.x` is changed.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
}
|
||||
22
examples/zedboard/memory.x
Normal file
22
examples/zedboard/memory.x
Normal file
@@ -0,0 +1,22 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Uncached memory */
|
||||
.uncached (NOLOAD) : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
_sbss_uncached = .;
|
||||
*(.uncached .uncached.*);
|
||||
. = ALIGN(4);
|
||||
_ebss_uncached = .;
|
||||
} > UNCACHED
|
||||
}
|
||||
@@ -249,7 +249,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
// Safety: We are not multi-threaded yet.
|
||||
unsafe { zynq7000_hal::log::uart_blocking::init_unsafe_single_core(uart, LOG_LEVEL, false) };
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
static ETH_RX_BUFS: static_cell::ConstStaticCell<[AlignedBuffer; NUM_RX_SLOTS]> =
|
||||
|
||||
@@ -93,7 +93,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let pin_sel = match I2C_ADDR_SEL {
|
||||
|
||||
@@ -96,7 +96,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
.unwrap();
|
||||
zynq7000_hal::log::rb::init(log::LevelFilter::Trace);
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
if DEBUG_SPI_CLK_CONFIG {
|
||||
|
||||
@@ -160,7 +160,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(1000));
|
||||
|
||||
@@ -254,7 +254,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![no_std]
|
||||
use zynq7000_hal::time::Hertz;
|
||||
pub mod phy_marvell;
|
||||
pub mod qspi_spansion;
|
||||
|
||||
// Define the clock frequency as a constant
|
||||
pub const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333);
|
||||
|
||||
@@ -79,7 +79,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
)
|
||||
};
|
||||
|
||||
let boot_mode = BootMode::new();
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(200));
|
||||
|
||||
161
examples/zedboard/src/qspi_spansion.rs
Normal file
161
examples/zedboard/src/qspi_spansion.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
use core::cell::RefCell;
|
||||
|
||||
use zynq7000_hal::qspi::QspiIoMode;
|
||||
|
||||
pub enum RegisterId {
|
||||
/// PP
|
||||
PageProgram = 0x02,
|
||||
/// READ
|
||||
Read = 0x03,
|
||||
/// WRDI
|
||||
WriteDisable = 0x04,
|
||||
/// RDSR1
|
||||
ReadStatus1 = 0x05,
|
||||
/// RDSR2
|
||||
ReadStatus2 = 0x07,
|
||||
/// WREN
|
||||
WriteEnable = 0x06,
|
||||
/// SE
|
||||
SectorErase = 0xD8,
|
||||
/// RDID
|
||||
ReadId = 0x9F,
|
||||
}
|
||||
|
||||
pub struct QspiSpansionS25Fl256S {
|
||||
pub qspi: RefCell<QspiIoMode>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum MemoryInterfaceType {
|
||||
_128Mb = 0x20,
|
||||
_256Mb = 0x02,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Density {
|
||||
_128Mb = 0x18,
|
||||
_256Mb = 0x19,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BaseDeviceId {
|
||||
manufacturer_id: u8,
|
||||
device_id: u16,
|
||||
}
|
||||
|
||||
impl BaseDeviceId {
|
||||
#[inline]
|
||||
pub const fn new(manufacturer_id: u8, device_id: u16) -> Self {
|
||||
BaseDeviceId {
|
||||
manufacturer_id,
|
||||
device_id,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_raw(raw: u32) -> Self {
|
||||
let manufacturer_id = ((raw >> 16) & 0xff) as u8;
|
||||
let device_id = (raw & 0xffff) as u16;
|
||||
BaseDeviceId::new(manufacturer_id, device_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn manufacturer_id(&self) -> u8 {
|
||||
self.manufacturer_id
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn device_id_raw(&self) -> u16 {
|
||||
self.device_id
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn memory_interface_type(&self) -> Result<MemoryInterfaceType, u8> {
|
||||
MemoryInterfaceType::try_from((self.device_id & 0xff) as u8).map_err(|e| e.number as u8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn density(&self) -> Result<Density, u8> {
|
||||
Density::try_from((self.device_id) as u8).map_err(|e| e.number as u8)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExtendedDeviceId {
|
||||
base: BaseDeviceId,
|
||||
id_cfi_len: u8,
|
||||
sector_arch: u8,
|
||||
familiy_id: u8,
|
||||
model_number: [u8; 2],
|
||||
}
|
||||
|
||||
impl ExtendedDeviceId {
|
||||
#[inline]
|
||||
pub fn base_id(&self) -> BaseDeviceId {
|
||||
self.base
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u8)]
|
||||
pub struct StatusRegister1 {
|
||||
#[bit(7, rw)]
|
||||
status_register_write_disable: bool,
|
||||
#[bit(6, r)]
|
||||
programming_error: bool,
|
||||
#[bit(5, r)]
|
||||
erase_error: bool,
|
||||
#[bit(4, r)]
|
||||
bp_2: bool,
|
||||
#[bit(3, r)]
|
||||
bp_1: bool,
|
||||
#[bit(2, r)]
|
||||
bp_0: bool,
|
||||
#[bit(1, r)]
|
||||
write_enable_latch: bool,
|
||||
#[bit(0, r)]
|
||||
write_in_progress: bool,
|
||||
}
|
||||
|
||||
impl QspiSpansionS25Fl256S {
|
||||
pub fn new(qspi: QspiIoMode) -> Self {
|
||||
QspiSpansionS25Fl256S {
|
||||
qspi: RefCell::new(qspi),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_enable(&mut self) {
|
||||
let qspi = self.qspi.get_mut();
|
||||
qspi.clear_rx_fifo();
|
||||
qspi.transfer_init();
|
||||
qspi.regs().write_tx_data_01(0x06);
|
||||
qspi.transfer_start();
|
||||
while !qspi.read_status().rx_not_empty() {}
|
||||
qspi.read_rx_data();
|
||||
qspi.transfer_done();
|
||||
}
|
||||
|
||||
pub fn read_rdsr1(&self) -> StatusRegister1 {
|
||||
let mut qspi = self.qspi.borrow_mut();
|
||||
qspi.clear_rx_fifo();
|
||||
qspi.transfer_init();
|
||||
qspi.regs().write_tx_data_10(0x05);
|
||||
qspi.transfer_start();
|
||||
while !qspi.read_status().rx_not_empty() {}
|
||||
let reply = qspi.read_rx_data();
|
||||
qspi.transfer_done();
|
||||
StatusRegister1::new_with_raw_value(((reply >> 24) & 0xff) as u8)
|
||||
}
|
||||
|
||||
pub fn read_rdid_base(&self) -> BaseDeviceId {
|
||||
let mut qspi = self.qspi.borrow_mut();
|
||||
qspi.clear_rx_fifo();
|
||||
qspi.transfer_init();
|
||||
qspi.regs().write_tx_data_00(0x9F);
|
||||
qspi.transfer_start();
|
||||
while !qspi.read_status().rx_not_empty() {}
|
||||
let reply = qspi.read_rx_data();
|
||||
qspi.transfer_done();
|
||||
BaseDeviceId::from_raw(reply)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user