-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DRAFT_PR: Add flexspi + SPI Storage support #312
base: main
Are you sure you want to change the base?
DRAFT_PR: Add flexspi + SPI Storage support #312
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be rewritten considerably. Please remember to use the PAC and follow the pattern of the other drivers.
rt = [ | ||
"mimxrt685s-pac?/rt", | ||
"mimxrt633s-pac?/rt", | ||
] | ||
rt = ["mimxrt685s-pac?/rt", "mimxrt633s-pac?/rt"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how but its happening automatically. when I added my change, and saved the file, some of the lines are automatically getting formatted. Maybe because I am using rust-analyzer plugin?
mimxrt685s-pac = { version = "0.2.2", optional = true, features = ["rt", "critical-section", "defmt"] } | ||
mimxrt633s-pac = { version = "0.2.0", optional = true, features = ["rt", "critical-section", "defmt"] } | ||
mimxrt685s-pac = { version = "0.2.2", optional = true, features = [ | ||
"rt", | ||
"critical-section", | ||
"defmt", | ||
] } | ||
mimxrt633s-pac = { version = "0.2.0", optional = true, features = [ | ||
"rt", | ||
"critical-section", | ||
"defmt", | ||
] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary change
examples/rt685s-evk/memory.x
Outdated
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary change
examples/rt685s-evk/memory.x
Outdated
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: one blank line ought to suffice.
examples/rt685s-evk/memory.x
Outdated
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary change
// Copy the Ram code to .flexspi_code partition | ||
copy_flexspi_ramcode_to_ram(); | ||
|
||
unsafe { asm!("cpsid i") } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
cortex_m::asm::dsb(); | ||
|
||
unsafe { asm!("cpsie i") } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/flexspi.rs
Outdated
struct FlexSpi { | ||
MCR0: u32, | ||
/**< Module Control Register 0, offset: 0x0 */ | ||
MCR1: u32, | ||
/**< Module Control Register 1, offset: 0x4 */ | ||
MCR2: u32, | ||
/**< Module Control Register 2, offset: 0x8 */ | ||
AHBCR: u32, | ||
/**< AHB Bus Control Register, offset: 0xC */ | ||
INTEN: u32, | ||
/**< Interrupt Enable Register, offset: 0x10 */ | ||
INTR: u32, | ||
/**< Interrupt Register, offset: 0x14 */ | ||
LUTKEY: u32, | ||
/**< LUT Key Register, offset: 0x18 */ | ||
LUTCR: u32, | ||
/**< LUT Control Register, offset: 0x1C */ | ||
AHBRXBUFCR0: [u32; 8], | ||
/**< AHB RX Buffer 0 Control Register 0..AHB RX Buffer 7 Control Register 0, array offset: 0x20, array step: 0x4 */ | ||
RESERVED_0: [u8; 32], | ||
FLSHCR0: [u32; 4], | ||
/**< Flash Control Register 0, array offset: 0x60, array step: 0x4 */ | ||
FLSHCR1: [u32; 4], | ||
/**< Flash Control Register 1, array offset: 0x70, array step: 0x4 */ | ||
FLSHCR2: [u32; 4], | ||
/**< Flash Control Register 2, array offset: 0x80, array step: 0x4 */ | ||
RESERVED_1: [u8; 4], | ||
FLSHCR4: u32, | ||
/**< Flash Control Register 4, offset: 0x94 */ | ||
RESERVED_2: [u8; 8], | ||
pub IPCR0: u32, | ||
/**< IP Control Register 0, offset: 0xA0 */ | ||
IPCR1: u32, | ||
/**< IP Control Register 1, offset: 0xA4 */ | ||
RESERVED_3: [u8; 8], | ||
IPCMD: u32, | ||
/**< IP Command Register, offset: 0xB0 */ | ||
DLPR: u32, | ||
/**< Data Learn Pattern Register, offset: 0xB4 */ | ||
IPRXFCR: u32, | ||
/**< IP RX FIFO Control Register, offset: 0xB8 */ | ||
IPTXFCR: u32, | ||
/**< IP TX FIFO Control Register, offset: 0xBC */ | ||
DLLCR: [u32; 2], | ||
/**< DLL Control Register 0, array offset: 0xC0, array step: 0x4 */ | ||
RESERVED_4: [u8; 24], | ||
STS0: u32, | ||
/**< Status Register 0, offset: 0xE0 */ | ||
STS1: u32, | ||
/**< Status Register 1, offset: 0xE4 */ | ||
STS2: u32, | ||
/**< Status Register 2, offset: 0xE8 */ | ||
AHBSPNDSTS: u32, | ||
/**< AHB Suspend Status Register, offset: 0xEC */ | ||
IPRXFSTS: u32, | ||
/**< IP RX FIFO Status Register, offset: 0xF0 */ | ||
IPTXFSTS: u32, | ||
/**< IP TX FIFO Status Register, offset: 0xF4 */ | ||
RESERVED_5: [u8; 8], | ||
RFDR: [u32; 32], | ||
/**< IP RX FIFO Data Register 0..IP RX FIFO Data Register 31, array offset: 0x100, array step: 0x4 */ | ||
TFDR: [u32; 32], | ||
/**< IP TX FIFO Data Register 0..IP TX FIFO Data Register 31, array offset: 0x180, array step: 0x4 */ | ||
LUT: [u32; 120], | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/flexspi.rs
Outdated
match config.rx_sample_clock { | ||
FlexspiReadSampleClock::FlexspiReadSampleClkLoopbackInternally => { | ||
regs.mcr0().modify(|_, w| w.rxclksrc().rxclksrc_0()); | ||
} | ||
FlexspiReadSampleClock::FlexspiReadSampleClkLoopbackFromDqsPad => { | ||
regs.mcr0().modify(|_, w| w.rxclksrc().rxclksrc_1()); | ||
} | ||
FlexspiReadSampleClock::FlexspiReadSampleClkLoopbackFromSckPad => { | ||
regs.mcr0().modify(|_, w| w.rxclksrc().rxclksrc_3()); | ||
} | ||
FlexspiReadSampleClock::FlexspiReadSampleClkExternalInputFromDqsPad => { | ||
regs.mcr0().modify(|_, w| w.rxclksrc().rxclksrc_3()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/flexspi.rs
Outdated
if config.enable_doze { | ||
regs.mcr0().modify(|_, w| w.dozeen().set_bit()); | ||
} else { | ||
regs.mcr0().modify(|_, w| w.dozeen().clear_bit()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.rs/mimxrt685s-pac/latest/mimxrt685s_pac/flexspi/mcr0/type.DozeenW.html
Additionally, you can use variant()
:
regs.mcr0().modify(|_, w| w.dozeen().variant(config.enable_doze);
Finally, all of the modify()
to the same register, can be combined into a single block, saving on the amount of read-modify-write cycles needed.
examples/rt685s-evk/memory.x
Outdated
RAM : ORIGIN = 0x20080000, LENGTH = 1536K | ||
FLEXSPIRAM: ORIGIN = 0x0, LENGTH = 10K |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the origin set to 0x0? What VMA does it generate? Can we double check the output with cargo objdump --bin app -- -d --no-show-raw-insn
?
|
||
flexspi.cmdport.erase_sector(ADDR); | ||
|
||
let status = flexspi.cmdport.read_status_register(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add some comments to what this is doing? write enable -> erase -> verify that it is erased -> write -> read back to verify?
src/flexspi.rs
Outdated
|
||
#[repr(C)] | ||
#[allow(non_snake_case)] | ||
struct FlexSpi { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like we talked about, we should assume that PAC is loaded into RAM so let's not shadow these registers in RAM. This will simplify the code a great deal.
src/flexspi.rs
Outdated
panic!("Erase operation is not implemented for Data Port. Please use Command Port for erase operation"); | ||
} | ||
|
||
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can chunk this array into u32s.
src/flexspi.rs
Outdated
const WRITE_SIZE: usize = 512; | ||
const ERASE_SIZE: usize = 4096; | ||
|
||
#[link_section = ".data"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this single function linked to .data
section?
src/flexspi.rs
Outdated
impl FlexSpiCmdPort<Blocking, Ram> { | ||
/// Lock Flash | ||
pub fn lock_flash(&mut self) { | ||
// Lock the command port |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these to be done later? Can we add a TODO comment or something to identify features that are missing?
src/flexspi.rs
Outdated
} | ||
} | ||
|
||
impl BlockingNorFlash for FlexSpiDataPort<Blocking, Ram> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we make the assumption that FlexSpi code will be loaded into RAM and reduce the typestate, this will simplify the code a great deal.
src/flexspi.rs
Outdated
loop { | ||
let mut data = 0; | ||
|
||
data = ((bytes[i + 3] as u32) << 24) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should consider using DMA for these long copy operation.
@felipebalbi @jerrysxie This PR will go through a huge clean up once firmware loading on RAM change is merged |
5c7e03a
to
0b14a86
Compare
src/spinorstorage.rs
Outdated
|
||
impl crate::storage::BlockingNorStorageDriver for SpiStorage<Blocking> { | ||
fn lock(&self) -> Result<(), Self::Error> { | ||
Ok(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kakarimi Please copy all the SPI device related code to this file from Macronix Device Driver as per the design proposed
src/spinorstorage.rs
Outdated
|
||
impl SpiStorage<Blocking> { | ||
pub fn new_blocking<T: Instance>(_spiinstance: T) -> Self { | ||
let info = T::info(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kakarimi This is where we are going to instantiate the SPI device from HAL
|
||
static ADDR: u32 = 0x2F000; | ||
|
||
struct StorageDeviceDriver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kakarimi struct StorageDeviceDriver is an example equivalent to Macronix Device Driver.
pub fn init(&self) { | ||
let bus_ref = self.flexspi_nor_storage_bus.as_ref().unwrap(); | ||
let cmdarr = NorStorageCmdSeq { | ||
fast_read: Some(NorStorageCmd { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kakarimi I have already filled this example from Macronix Datasheet. I believe you should be able to use this code as is.
src/flexspistorage.rs
Outdated
} | ||
|
||
impl<M: Mode> crate::storage::ConfigureCmdSeq for FlexspiStorage<M> { | ||
fn configure_cmd_seq(&self, cmd_seq: &NorStorageCmdSeq) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kakarimi I need to complete this implementation tomorrow. This will make sure that our commands are ready to be used by the bus driver. Similar change need to be done in SPI storage bus driver file "spinorstorage.rs"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Shaibal-Microsoft as discussed offline, please consider adding capacity as part of the configuration structure to pass to the driver as opposed to let Boot ROM determine that.
40dd349
to
65a51fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not looked in depth at flexspi code but from a high-level design perspective. We need to extract the generic traits out of embassy-imxrt first.
src/storage.rs
Outdated
} | ||
|
||
/// Blocking NOR Storage Driver | ||
pub trait BlockingNorStorageDriver: BlockingNorFlash + BlockingReadNorFlash + ConfigureCmdSeq { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This trait does not belong in embassy-imxrt
. We will have other non-NXP MCU and independent flash driver implement these traits so storage service can use them. It does not make sense for client to depend on hardware specific embassy-imxrt
to get these traits.
We should extract these traits into its own crate like embedded-hal
or put these generic trait in embedded-service
for now: https://github.com/OpenDevicePartnership/embedded-services/tree/main/embedded-service/src.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we create a crate like "Embedded-Storage-Bus" to have the traits to be used by all storage busses like FlexSPI, SPI, I2C, etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but the trait as defined feels less like a storage bus, but more like a storage command interface. The new crate can be a separate repo or it can be a part of embedded-service
for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I will move the traits to embedded services for now.
Actually I removed all those commands as I found it not fitting a good bus design. Now it contain only 1 API i.e. "send_command" which fits a good bus API and generic enough to be used with any bus like SPI, FlexSPI, etc
src/spi_nor_storage_bus.rs
Outdated
@@ -0,0 +1,140 @@ | |||
use embassy_hal_internal::Peripheral; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be implemented by the SPI HAL. No need for this file to exist without the SPI HAL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I created it to showcase the design with multiple storage bus drivers. I will remove it.
7e382e0
to
1f45293
Compare
- Flexspi NOR Storage Bus Driver - Example Storage Service
This PR adds NXP flexspi support