Skip to content
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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Shaibal-Microsoft
Copy link
Contributor

This PR adds NXP flexspi support

Copy link
Contributor

@felipebalbi felipebalbi left a 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"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary change

Copy link
Contributor Author

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?

Comment on lines -95 to +100
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",
] }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary change


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary change

Comment on lines 15 to 9


Copy link
Contributor

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.


Copy link
Contributor

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") }
Copy link
Contributor

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") }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/flexspi.rs Outdated
Comment on lines 18 to 83
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],
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/flexspi.rs Outdated
Comment on lines 1186 to 860
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());
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/flexspi.rs Outdated
Comment on lines 1200 to 865
if config.enable_doze {
regs.mcr0().modify(|_, w| w.dozeen().set_bit());
} else {
regs.mcr0().modify(|_, w| w.dozeen().clear_bit());
}
Copy link
Contributor

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.

@jerrysxie jerrysxie added the enhancement New feature or request label Feb 23, 2025
RAM : ORIGIN = 0x20080000, LENGTH = 1536K
FLEXSPIRAM: ORIGIN = 0x0, LENGTH = 10K
Copy link
Contributor

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();
Copy link
Contributor

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 {
Copy link
Contributor

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> {
Copy link
Contributor

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"]
Copy link
Contributor

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
Copy link
Contributor

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> {
Copy link
Contributor

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)
Copy link
Contributor

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.

@Shaibal-Microsoft
Copy link
Contributor Author

@felipebalbi @jerrysxie This PR will go through a huge clean up once firmware loading on RAM change is merged

@Shaibal-Microsoft Shaibal-Microsoft changed the title DRAFT_PR: Add flexspi support DRAFT_PR: Add flexspi + SPI Storage support Mar 4, 2025
@Shaibal-Microsoft Shaibal-Microsoft force-pushed the main branch 5 times, most recently from 5c7e03a to 0b14a86 Compare March 5, 2025 14:39

impl crate::storage::BlockingNorStorageDriver for SpiStorage<Blocking> {
fn lock(&self) -> Result<(), Self::Error> {
Ok(())
Copy link
Contributor Author

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


impl SpiStorage<Blocking> {
pub fn new_blocking<T: Instance>(_spiinstance: T) -> Self {
let info = T::info();
Copy link
Contributor Author

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 {
Copy link
Contributor Author

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 {
Copy link
Contributor Author

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.

}

impl<M: Mode> crate::storage::ConfigureCmdSeq for FlexspiStorage<M> {
fn configure_cmd_seq(&self, cmd_seq: &NorStorageCmdSeq) {}
Copy link
Contributor Author

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"

Copy link
Contributor

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.

@Shaibal-Microsoft Shaibal-Microsoft force-pushed the main branch 2 times, most recently from 40dd349 to 65a51fa Compare March 7, 2025 18:13
Copy link
Contributor

@jerrysxie jerrysxie left a 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 {
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

@Shaibal-Microsoft Shaibal-Microsoft Mar 10, 2025

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

@@ -0,0 +1,140 @@
use embassy_hal_internal::Peripheral;
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@Shaibal-Microsoft Shaibal-Microsoft force-pushed the main branch 10 times, most recently from 7e382e0 to 1f45293 Compare March 10, 2025 06:38
- Flexspi NOR Storage Bus Driver
- Example Storage Service
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants