mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-30 15:17:25 +00:00
160 lines
5.2 KiB
Rust
160 lines
5.2 KiB
Rust
// Copyright © 2024 William Spinelli <174336620+williams-one@users.noreply.github.com>
|
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
// from embassy/examples/stm32u5/src/bin/hspi_memory_mapped.rs
|
|
|
|
use defmt::info;
|
|
use embassy_stm32::hspi::{AddressSize, DummyCycles, Hspi, HspiWidth, Instance, TransferConfig};
|
|
use embassy_stm32::mode::Async;
|
|
use embassy_stm32::rcc;
|
|
|
|
pub fn rcc_init(config: &mut embassy_stm32::Config) {
|
|
config.rcc.pll2 = Some(rcc::Pll {
|
|
source: rcc::PllSource::HSE,
|
|
prediv: rcc::PllPreDiv::DIV4,
|
|
mul: rcc::PllMul::MUL66,
|
|
divp: None,
|
|
divq: Some(rcc::PllDiv::DIV2),
|
|
divr: None,
|
|
});
|
|
config.rcc.mux.hspi1sel = rcc::mux::Hspisel::PLL2_Q; // 132 MHz
|
|
}
|
|
|
|
// Custom implementation for MX66UW1G45G NOR flash memory from Macronix.
|
|
// Chip commands are hardcoded as they depend on the chip used.
|
|
// This implementation enables Octa I/O (OPI) and Double Transfer Rate (DTR)
|
|
|
|
pub struct OctaDtrFlashMemory<'d, I: Instance> {
|
|
hspi: Hspi<'d, I, Async>,
|
|
}
|
|
|
|
impl<'d, I: Instance> OctaDtrFlashMemory<'d, I> {
|
|
const CMD_READ_OCTA_DTR: u16 = 0xEE11;
|
|
|
|
const CMD_RESET_ENABLE: u8 = 0x66;
|
|
const CMD_RESET_ENABLE_OCTA_DTR: u16 = 0x6699;
|
|
const CMD_RESET: u8 = 0x99;
|
|
const CMD_RESET_OCTA_DTR: u16 = 0x9966;
|
|
|
|
const CMD_WRITE_ENABLE: u8 = 0x06;
|
|
|
|
const CMD_READ_SR: u8 = 0x05;
|
|
|
|
const CMD_WRITE_CR2: u8 = 0x72;
|
|
|
|
const CR2_REG1_ADDR: u32 = 0x00000000;
|
|
const CR2_OCTA_DTR: u8 = 0x02;
|
|
|
|
const CR2_REG3_ADDR: u32 = 0x00000300;
|
|
const CR2_DC_6_CYCLES: u8 = 0x07;
|
|
|
|
pub async fn new(hspi: Hspi<'d, I, Async>) -> Self {
|
|
let mut memory = Self { hspi };
|
|
|
|
memory.reset_memory().await;
|
|
memory.enable_octa_dtr().await;
|
|
memory
|
|
}
|
|
|
|
async fn enable_octa_dtr(&mut self) {
|
|
self.write_enable_spi().await;
|
|
self.write_cr2_spi(Self::CR2_REG3_ADDR, Self::CR2_DC_6_CYCLES);
|
|
self.write_enable_spi().await;
|
|
self.write_cr2_spi(Self::CR2_REG1_ADDR, Self::CR2_OCTA_DTR);
|
|
}
|
|
|
|
pub async fn enable_mm(&mut self) {
|
|
let read_config = TransferConfig {
|
|
iwidth: HspiWidth::OCTO,
|
|
instruction: Some(Self::CMD_READ_OCTA_DTR as u32),
|
|
isize: AddressSize::_16Bit,
|
|
idtr: true,
|
|
adwidth: HspiWidth::OCTO,
|
|
adsize: AddressSize::_32Bit,
|
|
addtr: true,
|
|
dwidth: HspiWidth::OCTO,
|
|
ddtr: true,
|
|
dummy: DummyCycles::_6,
|
|
..Default::default()
|
|
};
|
|
|
|
let write_config = TransferConfig {
|
|
iwidth: HspiWidth::OCTO,
|
|
isize: AddressSize::_16Bit,
|
|
idtr: true,
|
|
adwidth: HspiWidth::OCTO,
|
|
adsize: AddressSize::_32Bit,
|
|
addtr: true,
|
|
dwidth: HspiWidth::OCTO,
|
|
ddtr: true,
|
|
..Default::default()
|
|
};
|
|
self.hspi.enable_memory_mapped_mode(read_config, write_config).unwrap();
|
|
}
|
|
|
|
async fn exec_command_spi(&mut self, cmd: u8) {
|
|
let transaction = TransferConfig {
|
|
iwidth: HspiWidth::SING,
|
|
instruction: Some(cmd as u32),
|
|
..Default::default()
|
|
};
|
|
info!("Excuting command: 0x{:X}", transaction.instruction.unwrap());
|
|
self.hspi.blocking_command(&transaction).unwrap();
|
|
}
|
|
|
|
async fn exec_command_octa_dtr(&mut self, cmd: u16) {
|
|
let transaction = TransferConfig {
|
|
iwidth: HspiWidth::OCTO,
|
|
instruction: Some(cmd as u32),
|
|
isize: AddressSize::_16Bit,
|
|
idtr: true,
|
|
..Default::default()
|
|
};
|
|
info!("Excuting command: 0x{:X}", transaction.instruction.unwrap());
|
|
self.hspi.blocking_command(&transaction).unwrap();
|
|
}
|
|
|
|
fn wait_write_finish_spi(&mut self) {
|
|
while (self.read_sr_spi() & 0x01) != 0 {}
|
|
}
|
|
|
|
pub async fn reset_memory(&mut self) {
|
|
// servono entrambi i comandi?
|
|
self.exec_command_octa_dtr(Self::CMD_RESET_ENABLE_OCTA_DTR).await;
|
|
self.exec_command_octa_dtr(Self::CMD_RESET_OCTA_DTR).await;
|
|
self.exec_command_spi(Self::CMD_RESET_ENABLE).await;
|
|
self.exec_command_spi(Self::CMD_RESET).await;
|
|
self.wait_write_finish_spi();
|
|
}
|
|
|
|
async fn write_enable_spi(&mut self) {
|
|
self.exec_command_spi(Self::CMD_WRITE_ENABLE).await;
|
|
}
|
|
|
|
pub fn read_sr_spi(&mut self) -> u8 {
|
|
let mut buffer = [0; 1];
|
|
let transaction: TransferConfig = TransferConfig {
|
|
iwidth: HspiWidth::SING,
|
|
instruction: Some(Self::CMD_READ_SR as u32),
|
|
dwidth: HspiWidth::SING,
|
|
..Default::default()
|
|
};
|
|
self.hspi.blocking_read(&mut buffer, transaction).unwrap();
|
|
// info!("Read MX66LM1G45G SR register: 0x{:x}", buffer[0]);
|
|
buffer[0]
|
|
}
|
|
|
|
pub fn write_cr2_spi(&mut self, addr: u32, value: u8) {
|
|
let buffer = [value; 1];
|
|
let transaction: TransferConfig = TransferConfig {
|
|
iwidth: HspiWidth::SING,
|
|
instruction: Some(Self::CMD_WRITE_CR2 as u32),
|
|
adwidth: HspiWidth::SING,
|
|
address: Some(addr),
|
|
adsize: AddressSize::_32Bit,
|
|
dwidth: HspiWidth::SING,
|
|
..Default::default()
|
|
};
|
|
self.hspi.blocking_write(&buffer, transaction).unwrap();
|
|
}
|
|
}
|