Skip to content

Instantly share code, notes, and snippets.

@esden
Last active October 9, 2025 22:02
Show Gist options
  • Select an option

  • Save esden/919f4728471a47db5f63bff3f49e8c12 to your computer and use it in GitHub Desktop.

Select an option

Save esden/919f4728471a47db5f63bff3f49e8c12 to your computer and use it in GitHub Desktop.
#![no_std]
#![no_main]
use blackmagic_rust_firmware::{split_resources, system::preamble::*};
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::{ospi::{self, Ospi}, rcc};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
use embassy_stm32::pac::{OCTOSPI1, octospi::vals};
fn manual_init(
) {
// System configuration
rcc::enable_and_reset::<embassy_stm32::peripherals::OCTOSPI1>();
while OCTOSPI1.sr().read().busy() {}
// Device configuration
OCTOSPI1.dcr1().modify(|v| {
v.set_devsize(5); // 16MBytes (128MBit)
v.set_mtyp(vals::MemType::B_STANDARD);
v.set_csht(2);
v.set_dlybyp(true);
v.set_frck(false);
v.set_ckmode(false);
});
OCTOSPI1.dcr2().modify(|v| {
v.set_wrapsize(0); // None
});
OCTOSPI1.dcr3().modify(|v| {
v.set_csbound(0);
v.set_maxtran(0);
});
OCTOSPI1.dcr4().modify(|v| {
v.set_refresh(0);
});
OCTOSPI1.cr().modify(|v| v.set_fthres(vals::Threshold::_RESERVED_f));
// Wait for the busy flag to clear
while OCTOSPI1.sr().read().busy() {}
OCTOSPI1.dcr2().modify(|v| v.set_prescaler(255));
OCTOSPI1.cr().modify(|v| v.set_dmm(false));
OCTOSPI1.tcr().modify(|v| {
v.set_sshift(vals::SampleShift::NONE);
v.set_dhqc(false);
});
OCTOSPI1.cr().modify(|v| v.set_en(true));
}
fn dump_regs() {
info!("SR {}", OCTOSPI1.sr().read());
info!("DCR1 {}", OCTOSPI1.dcr1().read());
info!("DCR2 {}", OCTOSPI1.dcr2().read());
info!("DCR3 {}", OCTOSPI1.dcr3().read());
info!("DCR4 {}", OCTOSPI1.dcr4().read());
info!("CR {}", OCTOSPI1.cr().read());
info!("TCR {}", OCTOSPI1.tcr().read());
}
fn manual_read() {
let dl = OCTOSPI1.dlr().read().dl();
let cr = OCTOSPI1.cr().read();
let ccr = OCTOSPI1.ccr().read();
let sr = OCTOSPI1.sr().read();
info!("DL {}", dl);
info!("CR {}", cr);
info!("CCR {}", ccr);
info!("SR {}", sr);
OCTOSPI1.cr().modify(|v| {
v.set_dmaen(false);
v.set_fthres(vals::Threshold::_RESERVED_f);
v.set_fmode(vals::FunctionalMode::INDIRECT_READ);
});
OCTOSPI1.dlr().write(|v| v.set_dl(0x2));
OCTOSPI1.tcr().write(|v| {
v.set_dcyc(0);
v.set_dhqc(false);
v.set_sshift(vals::SampleShift::NONE);
});
OCTOSPI1.ccr().write(|v| {
v.set_imode(vals::PhaseMode::ONE_LINE);
v.set_idtr(false);
v.set_isize(vals::SizeInBits::_8BIT);
v.set_admode(vals::PhaseMode::NONE);
v.set_addtr(false);
v.set_adsize(vals::SizeInBits::_8BIT);
v.set_abmode(vals::PhaseMode::NONE);
v.set_abdtr(false);
v.set_absize(vals::SizeInBits::_8BIT);
v.set_dmode(vals::PhaseMode::ONE_LINE);
v.set_ddtr(false);
v.set_dqse(false);
v.set_sioo(false);
});
OCTOSPI1.ir().write(|v| v.set_instruction(0x9F));
let mut status = OCTOSPI1.sr().read();
info!("SR {}", status);
for n in 0..4 {
// while status.busy() {}
while !status.tcf() && !status.ftf() {
status = OCTOSPI1.sr().read();
// info!("SR {}", status);
}
// OCTOSPI1.fcr().write(|v| v.set_ctcf(true));
// let val = OCTOSPI1.dr().read().data();
let val = unsafe { (OCTOSPI1.dr().as_ptr() as *mut u8).read_volatile() };
let new_status = OCTOSPI1.sr().read();
info!("n {} Sr {} val {:#04x} Sr {}", n, status, val, new_status);
status = new_status;
}
while !OCTOSPI1.sr().read().tcf() {}
OCTOSPI1.fcr().write(|v| v.set_ctcf(true));
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
info!("Hello World!");
let p = system::init();
let r = split_resources!(p);
let _flash = system::get_flash_blocking(r.flash);
dump_regs();
manual_init(/*r.flash*/);
dump_regs();
// The flash chip that is connected here over SPI is the Winbond W25Q128
// Refer to the datasheet for protocol details
loop {
manual_read();
Timer::after_millis(10).await;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment