commit
						bdeeb388ff
					
				| @ -73,7 +73,7 @@ rand_core = "0.6.3" | |||||||
| sdio-host = "0.5.0" | sdio-host = "0.5.0" | ||||||
| critical-section = "1.1" | critical-section = "1.1" | ||||||
| #stm32-metapac = { version = "16" } | #stm32-metapac = { version = "16" } | ||||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609" } | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db" } | ||||||
| 
 | 
 | ||||||
| vcell = "0.1.3" | vcell = "0.1.3" | ||||||
| nb = "1.0.0" | nb = "1.0.0" | ||||||
| @ -102,7 +102,7 @@ proc-macro2 = "1.0.36" | |||||||
| quote = "1.0.15" | quote = "1.0.15" | ||||||
| 
 | 
 | ||||||
| #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} | #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} | ||||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609", default-features = false, features = ["metadata"] } | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db", default-features = false, features = ["metadata"] } | ||||||
| 
 | 
 | ||||||
| [features] | [features] | ||||||
| default = ["rt"] | default = ["rt"] | ||||||
|  | |||||||
| @ -62,7 +62,13 @@ fn main() { | |||||||
|     // generate one singleton per peripheral (with many exceptions...)
 |     // generate one singleton per peripheral (with many exceptions...)
 | ||||||
|     for p in METADATA.peripherals { |     for p in METADATA.peripherals { | ||||||
|         if let Some(r) = &p.registers { |         if let Some(r) = &p.registers { | ||||||
|             if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" || r.kind == "octospi" { |             if r.kind == "adccommon" | ||||||
|  |                 || r.kind == "sai" | ||||||
|  |                 || r.kind == "ucpd" | ||||||
|  |                 || r.kind == "otg" | ||||||
|  |                 || r.kind == "octospi" | ||||||
|  |                 || r.kind == "xspi" | ||||||
|  |             { | ||||||
|                 // TODO: should we emit this for all peripherals? if so, we will need a list of all
 |                 // TODO: should we emit this for all peripherals? if so, we will need a list of all
 | ||||||
|                 // possible peripherals across all chips, so that we can declare the configs
 |                 // possible peripherals across all chips, so that we can declare the configs
 | ||||||
|                 // (replacing the hard-coded list of `peri_*` cfgs below)
 |                 // (replacing the hard-coded list of `peri_*` cfgs below)
 | ||||||
| @ -116,6 +122,7 @@ fn main() { | |||||||
|         "peri_usb_otg_fs", |         "peri_usb_otg_fs", | ||||||
|         "peri_usb_otg_hs", |         "peri_usb_otg_hs", | ||||||
|         "peri_octospi2", |         "peri_octospi2", | ||||||
|  |         "peri_xspi2", | ||||||
|     ]); |     ]); | ||||||
|     cfgs.declare_all(&["mco", "mco1", "mco2"]); |     cfgs.declare_all(&["mco", "mco1", "mco2"]); | ||||||
| 
 | 
 | ||||||
| @ -1098,6 +1105,72 @@ fn main() { | |||||||
|         (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)), |         (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)), | ||||||
|         (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)), |         (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)), | ||||||
|         (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)), |         (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)), | ||||||
|  |         (("xspi", "IO0"), quote!(crate::xspi::D0Pin)), | ||||||
|  |         (("xspi", "IO1"), quote!(crate::xspi::D1Pin)), | ||||||
|  |         (("xspi", "IO2"), quote!(crate::xspi::D2Pin)), | ||||||
|  |         (("xspi", "IO3"), quote!(crate::xspi::D3Pin)), | ||||||
|  |         (("xspi", "IO4"), quote!(crate::xspi::D4Pin)), | ||||||
|  |         (("xspi", "IO5"), quote!(crate::xspi::D5Pin)), | ||||||
|  |         (("xspi", "IO6"), quote!(crate::xspi::D6Pin)), | ||||||
|  |         (("xspi", "IO7"), quote!(crate::xspi::D7Pin)), | ||||||
|  |         (("xspi", "IO8"), quote!(crate::xspi::D8Pin)), | ||||||
|  |         (("xspi", "IO9"), quote!(crate::xspi::D9Pin)), | ||||||
|  |         (("xspi", "IO10"), quote!(crate::xspi::D10Pin)), | ||||||
|  |         (("xspi", "IO11"), quote!(crate::xspi::D11Pin)), | ||||||
|  |         (("xspi", "IO12"), quote!(crate::xspi::D12Pin)), | ||||||
|  |         (("xspi", "IO13"), quote!(crate::xspi::D13Pin)), | ||||||
|  |         (("xspi", "IO14"), quote!(crate::xspi::D14Pin)), | ||||||
|  |         (("xspi", "IO15"), quote!(crate::xspi::D15Pin)), | ||||||
|  |         (("xspi", "DQS0"), quote!(crate::xspi::DQS0Pin)), | ||||||
|  |         (("xspi", "DQS1"), quote!(crate::xspi::DQS1Pin)), | ||||||
|  |         (("xspi", "NCS1"), quote!(crate::xspi::NCSPin)), | ||||||
|  |         (("xspi", "NCS2"), quote!(crate::xspi::NCSPin)), | ||||||
|  |         (("xspi", "CLK"), quote!(crate::xspi::CLKPin)), | ||||||
|  |         (("xspi", "NCLK"), quote!(crate::xspi::NCLKPin)), | ||||||
|  |         (("xspim", "P1_IO0"), quote!(crate::xspi::D0Pin)), | ||||||
|  |         (("xspim", "P1_IO1"), quote!(crate::xspi::D1Pin)), | ||||||
|  |         (("xspim", "P1_IO2"), quote!(crate::xspi::D2Pin)), | ||||||
|  |         (("xspim", "P1_IO3"), quote!(crate::xspi::D3Pin)), | ||||||
|  |         (("xspim", "P1_IO4"), quote!(crate::xspi::D4Pin)), | ||||||
|  |         (("xspim", "P1_IO5"), quote!(crate::xspi::D5Pin)), | ||||||
|  |         (("xspim", "P1_IO6"), quote!(crate::xspi::D6Pin)), | ||||||
|  |         (("xspim", "P1_IO7"), quote!(crate::xspi::D7Pin)), | ||||||
|  |         (("xspim", "P1_IO8"), quote!(crate::xspi::D8Pin)), | ||||||
|  |         (("xspim", "P1_IO9"), quote!(crate::xspi::D9Pin)), | ||||||
|  |         (("xspim", "P1_IO10"), quote!(crate::xspi::D10Pin)), | ||||||
|  |         (("xspim", "P1_IO11"), quote!(crate::xspi::D11Pin)), | ||||||
|  |         (("xspim", "P1_IO12"), quote!(crate::xspi::D12Pin)), | ||||||
|  |         (("xspim", "P1_IO13"), quote!(crate::xspi::D13Pin)), | ||||||
|  |         (("xspim", "P1_IO14"), quote!(crate::xspi::D14Pin)), | ||||||
|  |         (("xspim", "P1_IO15"), quote!(crate::xspi::D15Pin)), | ||||||
|  |         (("xspim", "P1_DQS0"), quote!(crate::xspi::DQS0Pin)), | ||||||
|  |         (("xspim", "P1_DQS1"), quote!(crate::xspi::DQS1Pin)), | ||||||
|  |         (("xspim", "P1_NCS1"), quote!(crate::xspi::NCSPin)), | ||||||
|  |         (("xspim", "P1_NCS2"), quote!(crate::xspi::NCSPin)), | ||||||
|  |         (("xspim", "P1_CLK"), quote!(crate::xspi::CLKPin)), | ||||||
|  |         (("xspim", "P1_NCLK"), quote!(crate::xspi::NCLKPin)), | ||||||
|  |         (("xspim", "P2_IO0"), quote!(crate::xspi::D0Pin)), | ||||||
|  |         (("xspim", "P2_IO1"), quote!(crate::xspi::D1Pin)), | ||||||
|  |         (("xspim", "P2_IO2"), quote!(crate::xspi::D2Pin)), | ||||||
|  |         (("xspim", "P2_IO3"), quote!(crate::xspi::D3Pin)), | ||||||
|  |         (("xspim", "P2_IO4"), quote!(crate::xspi::D4Pin)), | ||||||
|  |         (("xspim", "P2_IO5"), quote!(crate::xspi::D5Pin)), | ||||||
|  |         (("xspim", "P2_IO6"), quote!(crate::xspi::D6Pin)), | ||||||
|  |         (("xspim", "P2_IO7"), quote!(crate::xspi::D7Pin)), | ||||||
|  |         (("xspim", "P2_IO8"), quote!(crate::xspi::D8Pin)), | ||||||
|  |         (("xspim", "P2_IO9"), quote!(crate::xspi::D9Pin)), | ||||||
|  |         (("xspim", "P2_IO10"), quote!(crate::xspi::D10Pin)), | ||||||
|  |         (("xspim", "P2_IO11"), quote!(crate::xspi::D11Pin)), | ||||||
|  |         (("xspim", "P2_IO12"), quote!(crate::xspi::D12Pin)), | ||||||
|  |         (("xspim", "P2_IO13"), quote!(crate::xspi::D13Pin)), | ||||||
|  |         (("xspim", "P2_IO14"), quote!(crate::xspi::D14Pin)), | ||||||
|  |         (("xspim", "P2_IO15"), quote!(crate::xspi::D15Pin)), | ||||||
|  |         (("xspim", "P2_DQS0"), quote!(crate::xspi::DQS0Pin)), | ||||||
|  |         (("xspim", "P2_DQS1"), quote!(crate::xspi::DQS1Pin)), | ||||||
|  |         (("xspim", "P2_NCS1"), quote!(crate::xspi::NCSPin)), | ||||||
|  |         (("xspim", "P2_NCS2"), quote!(crate::xspi::NCSPin)), | ||||||
|  |         (("xspim", "P2_CLK"), quote!(crate::xspi::CLKPin)), | ||||||
|  |         (("xspim", "P2_NCLK"), quote!(crate::xspi::NCLKPin)), | ||||||
|         (("hspi", "IO0"), quote!(crate::hspi::D0Pin)), |         (("hspi", "IO0"), quote!(crate::hspi::D0Pin)), | ||||||
|         (("hspi", "IO1"), quote!(crate::hspi::D1Pin)), |         (("hspi", "IO1"), quote!(crate::hspi::D1Pin)), | ||||||
|         (("hspi", "IO2"), quote!(crate::hspi::D2Pin)), |         (("hspi", "IO2"), quote!(crate::hspi::D2Pin)), | ||||||
| @ -1190,6 +1263,29 @@ fn main() { | |||||||
|                         peri = format_ident!("{}", "OCTOSPI1"); |                         peri = format_ident!("{}", "OCTOSPI1"); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|  |                     // XSPIM  is special
 | ||||||
|  |                     if p.name == "XSPIM" { | ||||||
|  |                         if pin.signal.starts_with("P1") { | ||||||
|  |                             peri = format_ident!("{}", "XSPI1"); | ||||||
|  |                         } else if pin.signal.starts_with("P2") { | ||||||
|  |                             peri = format_ident!("{}", "XSPI2"); | ||||||
|  |                         } else { | ||||||
|  |                             panic! {"malformed XSPIM pin: {:?}", pin} | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     // XSPI NCS pin to CSSEL mapping
 | ||||||
|  |                     if pin.signal.ends_with("NCS1") { | ||||||
|  |                         g.extend(quote! { | ||||||
|  |                             sel_trait_impl!(crate::xspi::NCSEither, #peri, #pin_name, 0); | ||||||
|  |                         }) | ||||||
|  |                     } | ||||||
|  |                     if pin.signal.ends_with("NCS2") { | ||||||
|  |                         g.extend(quote! { | ||||||
|  |                             sel_trait_impl!(crate::xspi::NCSEither, #peri, #pin_name, 1); | ||||||
|  |                         }) | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     g.extend(quote! { |                     g.extend(quote! { | ||||||
|                         pin_trait_impl!(#tr, #peri, #pin_name, #af); |                         pin_trait_impl!(#tr, #peri, #pin_name, #af); | ||||||
|                     }) |                     }) | ||||||
|  | |||||||
| @ -127,6 +127,8 @@ pub mod usart; | |||||||
| pub mod usb; | pub mod usb; | ||||||
| #[cfg(iwdg)] | #[cfg(iwdg)] | ||||||
| pub mod wdg; | pub mod wdg; | ||||||
|  | #[cfg(xspi)] | ||||||
|  | pub mod xspi; | ||||||
| 
 | 
 | ||||||
| // This must go last, so that it sees all the impl_foo! macros defined earlier.
 | // This must go last, so that it sees all the impl_foo! macros defined earlier.
 | ||||||
| pub(crate) mod _generated { | pub(crate) mod _generated { | ||||||
|  | |||||||
| @ -60,6 +60,17 @@ macro_rules! pin_trait_impl { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[allow(unused_macros)] | ||||||
|  | macro_rules! sel_trait_impl { | ||||||
|  |     (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $sel:expr) => { | ||||||
|  |         impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin { | ||||||
|  |             fn sel(&self) -> u8 { | ||||||
|  |                 $sel | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // ====================
 | // ====================
 | ||||||
| 
 | 
 | ||||||
| macro_rules! dma_trait { | macro_rules! dma_trait { | ||||||
|  | |||||||
							
								
								
									
										364
									
								
								embassy-stm32/src/xspi/enums.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										364
									
								
								embassy-stm32/src/xspi/enums.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,364 @@ | |||||||
|  | //! Enums used in Xspi configuration.
 | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub(crate) enum XspiMode { | ||||||
|  |     IndirectWrite, | ||||||
|  |     IndirectRead, | ||||||
|  |     #[expect(dead_code)] | ||||||
|  |     AutoPolling, | ||||||
|  |     #[expect(dead_code)] | ||||||
|  |     MemoryMapped, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for XspiMode { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             XspiMode::IndirectWrite => 0b00, | ||||||
|  |             XspiMode::IndirectRead => 0b01, | ||||||
|  |             XspiMode::AutoPolling => 0b10, | ||||||
|  |             XspiMode::MemoryMapped => 0b11, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Xspi lane width
 | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum XspiWidth { | ||||||
|  |     /// None
 | ||||||
|  |     NONE, | ||||||
|  |     /// Single lane
 | ||||||
|  |     SING, | ||||||
|  |     /// Dual lanes
 | ||||||
|  |     DUAL, | ||||||
|  |     /// Quad lanes
 | ||||||
|  |     QUAD, | ||||||
|  |     /// Eight lanes
 | ||||||
|  |     OCTO, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for XspiWidth { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             XspiWidth::NONE => 0b00, | ||||||
|  |             XspiWidth::SING => 0b01, | ||||||
|  |             XspiWidth::DUAL => 0b10, | ||||||
|  |             XspiWidth::QUAD => 0b11, | ||||||
|  |             XspiWidth::OCTO => 0b100, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Wrap Size
 | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum WrapSize { | ||||||
|  |     None, | ||||||
|  |     _16Bytes, | ||||||
|  |     _32Bytes, | ||||||
|  |     _64Bytes, | ||||||
|  |     _128Bytes, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for WrapSize { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             WrapSize::None => 0x00, | ||||||
|  |             WrapSize::_16Bytes => 0x02, | ||||||
|  |             WrapSize::_32Bytes => 0x03, | ||||||
|  |             WrapSize::_64Bytes => 0x04, | ||||||
|  |             WrapSize::_128Bytes => 0x05, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Memory Type
 | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum MemoryType { | ||||||
|  |     Micron, | ||||||
|  |     Macronix, | ||||||
|  |     Standard, | ||||||
|  |     MacronixRam, | ||||||
|  |     HyperBusMemory, | ||||||
|  |     HyperBusRegister, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for MemoryType { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             MemoryType::Micron => 0x00, | ||||||
|  |             MemoryType::Macronix => 0x01, | ||||||
|  |             MemoryType::Standard => 0x02, | ||||||
|  |             MemoryType::MacronixRam => 0x03, | ||||||
|  |             MemoryType::HyperBusMemory => 0x04, | ||||||
|  |             MemoryType::HyperBusRegister => 0x04, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Xspi memory size.
 | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum MemorySize { | ||||||
|  |     _1KiB, | ||||||
|  |     _2KiB, | ||||||
|  |     _4KiB, | ||||||
|  |     _8KiB, | ||||||
|  |     _16KiB, | ||||||
|  |     _32KiB, | ||||||
|  |     _64KiB, | ||||||
|  |     _128KiB, | ||||||
|  |     _256KiB, | ||||||
|  |     _512KiB, | ||||||
|  |     _1MiB, | ||||||
|  |     _2MiB, | ||||||
|  |     _4MiB, | ||||||
|  |     _8MiB, | ||||||
|  |     _16MiB, | ||||||
|  |     _32MiB, | ||||||
|  |     _64MiB, | ||||||
|  |     _128MiB, | ||||||
|  |     _256MiB, | ||||||
|  |     _512MiB, | ||||||
|  |     _1GiB, | ||||||
|  |     _2GiB, | ||||||
|  |     _4GiB, | ||||||
|  |     Other(u8), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for MemorySize { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             MemorySize::_1KiB => 9, | ||||||
|  |             MemorySize::_2KiB => 10, | ||||||
|  |             MemorySize::_4KiB => 11, | ||||||
|  |             MemorySize::_8KiB => 12, | ||||||
|  |             MemorySize::_16KiB => 13, | ||||||
|  |             MemorySize::_32KiB => 14, | ||||||
|  |             MemorySize::_64KiB => 15, | ||||||
|  |             MemorySize::_128KiB => 16, | ||||||
|  |             MemorySize::_256KiB => 17, | ||||||
|  |             MemorySize::_512KiB => 18, | ||||||
|  |             MemorySize::_1MiB => 19, | ||||||
|  |             MemorySize::_2MiB => 20, | ||||||
|  |             MemorySize::_4MiB => 21, | ||||||
|  |             MemorySize::_8MiB => 22, | ||||||
|  |             MemorySize::_16MiB => 23, | ||||||
|  |             MemorySize::_32MiB => 24, | ||||||
|  |             MemorySize::_64MiB => 25, | ||||||
|  |             MemorySize::_128MiB => 26, | ||||||
|  |             MemorySize::_256MiB => 27, | ||||||
|  |             MemorySize::_512MiB => 28, | ||||||
|  |             MemorySize::_1GiB => 29, | ||||||
|  |             MemorySize::_2GiB => 30, | ||||||
|  |             MemorySize::_4GiB => 31, | ||||||
|  |             MemorySize::Other(val) => val, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Xspi Address size
 | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum AddressSize { | ||||||
|  |     /// 8-bit address
 | ||||||
|  |     _8bit, | ||||||
|  |     /// 16-bit address
 | ||||||
|  |     _16bit, | ||||||
|  |     /// 24-bit address
 | ||||||
|  |     _24bit, | ||||||
|  |     /// 32-bit address
 | ||||||
|  |     _32bit, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for AddressSize { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             AddressSize::_8bit => 0b00, | ||||||
|  |             AddressSize::_16bit => 0b01, | ||||||
|  |             AddressSize::_24bit => 0b10, | ||||||
|  |             AddressSize::_32bit => 0b11, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Time the Chip Select line stays high.
 | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum ChipSelectHighTime { | ||||||
|  |     _1Cycle, | ||||||
|  |     _2Cycle, | ||||||
|  |     _3Cycle, | ||||||
|  |     _4Cycle, | ||||||
|  |     _5Cycle, | ||||||
|  |     _6Cycle, | ||||||
|  |     _7Cycle, | ||||||
|  |     _8Cycle, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for ChipSelectHighTime { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             ChipSelectHighTime::_1Cycle => 0, | ||||||
|  |             ChipSelectHighTime::_2Cycle => 1, | ||||||
|  |             ChipSelectHighTime::_3Cycle => 2, | ||||||
|  |             ChipSelectHighTime::_4Cycle => 3, | ||||||
|  |             ChipSelectHighTime::_5Cycle => 4, | ||||||
|  |             ChipSelectHighTime::_6Cycle => 5, | ||||||
|  |             ChipSelectHighTime::_7Cycle => 6, | ||||||
|  |             ChipSelectHighTime::_8Cycle => 7, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// FIFO threshold.
 | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum FIFOThresholdLevel { | ||||||
|  |     _1Bytes, | ||||||
|  |     _2Bytes, | ||||||
|  |     _3Bytes, | ||||||
|  |     _4Bytes, | ||||||
|  |     _5Bytes, | ||||||
|  |     _6Bytes, | ||||||
|  |     _7Bytes, | ||||||
|  |     _8Bytes, | ||||||
|  |     _9Bytes, | ||||||
|  |     _10Bytes, | ||||||
|  |     _11Bytes, | ||||||
|  |     _12Bytes, | ||||||
|  |     _13Bytes, | ||||||
|  |     _14Bytes, | ||||||
|  |     _15Bytes, | ||||||
|  |     _16Bytes, | ||||||
|  |     _17Bytes, | ||||||
|  |     _18Bytes, | ||||||
|  |     _19Bytes, | ||||||
|  |     _20Bytes, | ||||||
|  |     _21Bytes, | ||||||
|  |     _22Bytes, | ||||||
|  |     _23Bytes, | ||||||
|  |     _24Bytes, | ||||||
|  |     _25Bytes, | ||||||
|  |     _26Bytes, | ||||||
|  |     _27Bytes, | ||||||
|  |     _28Bytes, | ||||||
|  |     _29Bytes, | ||||||
|  |     _30Bytes, | ||||||
|  |     _31Bytes, | ||||||
|  |     _32Bytes, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for FIFOThresholdLevel { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             FIFOThresholdLevel::_1Bytes => 0, | ||||||
|  |             FIFOThresholdLevel::_2Bytes => 1, | ||||||
|  |             FIFOThresholdLevel::_3Bytes => 2, | ||||||
|  |             FIFOThresholdLevel::_4Bytes => 3, | ||||||
|  |             FIFOThresholdLevel::_5Bytes => 4, | ||||||
|  |             FIFOThresholdLevel::_6Bytes => 5, | ||||||
|  |             FIFOThresholdLevel::_7Bytes => 6, | ||||||
|  |             FIFOThresholdLevel::_8Bytes => 7, | ||||||
|  |             FIFOThresholdLevel::_9Bytes => 8, | ||||||
|  |             FIFOThresholdLevel::_10Bytes => 9, | ||||||
|  |             FIFOThresholdLevel::_11Bytes => 10, | ||||||
|  |             FIFOThresholdLevel::_12Bytes => 11, | ||||||
|  |             FIFOThresholdLevel::_13Bytes => 12, | ||||||
|  |             FIFOThresholdLevel::_14Bytes => 13, | ||||||
|  |             FIFOThresholdLevel::_15Bytes => 14, | ||||||
|  |             FIFOThresholdLevel::_16Bytes => 15, | ||||||
|  |             FIFOThresholdLevel::_17Bytes => 16, | ||||||
|  |             FIFOThresholdLevel::_18Bytes => 17, | ||||||
|  |             FIFOThresholdLevel::_19Bytes => 18, | ||||||
|  |             FIFOThresholdLevel::_20Bytes => 19, | ||||||
|  |             FIFOThresholdLevel::_21Bytes => 20, | ||||||
|  |             FIFOThresholdLevel::_22Bytes => 21, | ||||||
|  |             FIFOThresholdLevel::_23Bytes => 22, | ||||||
|  |             FIFOThresholdLevel::_24Bytes => 23, | ||||||
|  |             FIFOThresholdLevel::_25Bytes => 24, | ||||||
|  |             FIFOThresholdLevel::_26Bytes => 25, | ||||||
|  |             FIFOThresholdLevel::_27Bytes => 26, | ||||||
|  |             FIFOThresholdLevel::_28Bytes => 27, | ||||||
|  |             FIFOThresholdLevel::_29Bytes => 28, | ||||||
|  |             FIFOThresholdLevel::_30Bytes => 29, | ||||||
|  |             FIFOThresholdLevel::_31Bytes => 30, | ||||||
|  |             FIFOThresholdLevel::_32Bytes => 31, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Dummy cycle count
 | ||||||
|  | #[allow(missing_docs)] | ||||||
|  | #[derive(Copy, Clone)] | ||||||
|  | pub enum DummyCycles { | ||||||
|  |     _0, | ||||||
|  |     _1, | ||||||
|  |     _2, | ||||||
|  |     _3, | ||||||
|  |     _4, | ||||||
|  |     _5, | ||||||
|  |     _6, | ||||||
|  |     _7, | ||||||
|  |     _8, | ||||||
|  |     _9, | ||||||
|  |     _10, | ||||||
|  |     _11, | ||||||
|  |     _12, | ||||||
|  |     _13, | ||||||
|  |     _14, | ||||||
|  |     _15, | ||||||
|  |     _16, | ||||||
|  |     _17, | ||||||
|  |     _18, | ||||||
|  |     _19, | ||||||
|  |     _20, | ||||||
|  |     _21, | ||||||
|  |     _22, | ||||||
|  |     _23, | ||||||
|  |     _24, | ||||||
|  |     _25, | ||||||
|  |     _26, | ||||||
|  |     _27, | ||||||
|  |     _28, | ||||||
|  |     _29, | ||||||
|  |     _30, | ||||||
|  |     _31, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<u8> for DummyCycles { | ||||||
|  |     fn into(self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             DummyCycles::_0 => 0, | ||||||
|  |             DummyCycles::_1 => 1, | ||||||
|  |             DummyCycles::_2 => 2, | ||||||
|  |             DummyCycles::_3 => 3, | ||||||
|  |             DummyCycles::_4 => 4, | ||||||
|  |             DummyCycles::_5 => 5, | ||||||
|  |             DummyCycles::_6 => 6, | ||||||
|  |             DummyCycles::_7 => 7, | ||||||
|  |             DummyCycles::_8 => 8, | ||||||
|  |             DummyCycles::_9 => 9, | ||||||
|  |             DummyCycles::_10 => 10, | ||||||
|  |             DummyCycles::_11 => 11, | ||||||
|  |             DummyCycles::_12 => 12, | ||||||
|  |             DummyCycles::_13 => 13, | ||||||
|  |             DummyCycles::_14 => 14, | ||||||
|  |             DummyCycles::_15 => 15, | ||||||
|  |             DummyCycles::_16 => 16, | ||||||
|  |             DummyCycles::_17 => 17, | ||||||
|  |             DummyCycles::_18 => 18, | ||||||
|  |             DummyCycles::_19 => 19, | ||||||
|  |             DummyCycles::_20 => 20, | ||||||
|  |             DummyCycles::_21 => 21, | ||||||
|  |             DummyCycles::_22 => 22, | ||||||
|  |             DummyCycles::_23 => 23, | ||||||
|  |             DummyCycles::_24 => 24, | ||||||
|  |             DummyCycles::_25 => 25, | ||||||
|  |             DummyCycles::_26 => 26, | ||||||
|  |             DummyCycles::_27 => 27, | ||||||
|  |             DummyCycles::_28 => 28, | ||||||
|  |             DummyCycles::_29 => 29, | ||||||
|  |             DummyCycles::_30 => 30, | ||||||
|  |             DummyCycles::_31 => 31, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1425
									
								
								embassy-stm32/src/xspi/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1425
									
								
								embassy-stm32/src/xspi/mod.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										448
									
								
								examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										448
									
								
								examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,448 @@ | |||||||
|  | #![no_main] | ||||||
|  | #![no_std] | ||||||
|  | 
 | ||||||
|  | //! For Nucleo STM32H7S3L8 MB1737, has MX25UW25645GXDI00
 | ||||||
|  | //!
 | ||||||
|  | //! TODO: Currently this only uses single SPI, pending flash chip documentation for octo SPI.
 | ||||||
|  | 
 | ||||||
|  | use defmt::info; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::gpio::{Level, Output, Speed}; | ||||||
|  | use embassy_stm32::mode::Blocking; | ||||||
|  | use embassy_stm32::time::Hertz; | ||||||
|  | use embassy_stm32::xspi::{ | ||||||
|  |     AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, TransferConfig, | ||||||
|  |     WrapSize, Xspi, XspiWidth, | ||||||
|  | }; | ||||||
|  | use embassy_stm32::Config; | ||||||
|  | use embassy_time::Timer; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     // RCC config
 | ||||||
|  |     let mut config = Config::default(); | ||||||
|  |     { | ||||||
|  |         use embassy_stm32::rcc::*; | ||||||
|  |         config.rcc.hse = Some(Hse { | ||||||
|  |             freq: Hertz(24_000_000), | ||||||
|  |             mode: HseMode::Oscillator, | ||||||
|  |         }); | ||||||
|  |         config.rcc.pll1 = Some(Pll { | ||||||
|  |             source: PllSource::HSE, | ||||||
|  |             prediv: PllPreDiv::DIV3, | ||||||
|  |             mul: PllMul::MUL150, | ||||||
|  |             divp: Some(PllDiv::DIV2), | ||||||
|  |             divq: None, | ||||||
|  |             divr: None, | ||||||
|  |         }); | ||||||
|  |         config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
 | ||||||
|  |         config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
 | ||||||
|  |         config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz
 | ||||||
|  |         config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz
 | ||||||
|  |         config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz
 | ||||||
|  |         config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz
 | ||||||
|  |         config.rcc.voltage_scale = VoltageScale::HIGH; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Initialize peripherals
 | ||||||
|  |     let p = embassy_stm32::init(config); | ||||||
|  | 
 | ||||||
|  |     let spi_config = embassy_stm32::xspi::Config { | ||||||
|  |         fifo_threshold: FIFOThresholdLevel::_4Bytes, | ||||||
|  |         memory_type: MemoryType::Macronix, | ||||||
|  |         delay_hold_quarter_cycle: true, | ||||||
|  |         // memory_type: MemoryType::Micron,
 | ||||||
|  |         // delay_hold_quarter_cycle: false,
 | ||||||
|  |         device_size: MemorySize::_32MiB, | ||||||
|  |         chip_select_high_time: ChipSelectHighTime::_2Cycle, | ||||||
|  |         free_running_clock: false, | ||||||
|  |         clock_mode: false, | ||||||
|  |         wrap_size: WrapSize::None, | ||||||
|  |         // 300mhz / (4+1) = 60mhz. Unsure the limit, need to find a MX25UW25645GXDI00 datasheet.
 | ||||||
|  |         clock_prescaler: 3, | ||||||
|  |         sample_shifting: false, | ||||||
|  |         chip_select_boundary: 0, | ||||||
|  |         max_transfer: 0, | ||||||
|  |         refresh: 0, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let mut cor = cortex_m::Peripherals::take().unwrap(); | ||||||
|  | 
 | ||||||
|  |     // Not necessary, but recommended if using XIP
 | ||||||
|  |     cor.SCB.enable_icache(); | ||||||
|  |     cor.SCB.enable_dcache(&mut cor.CPUID); | ||||||
|  | 
 | ||||||
|  |     let xspi = embassy_stm32::xspi::Xspi::new_blocking_xspi( | ||||||
|  |         p.XSPI2, p.PN6, p.PN2, p.PN3, p.PN4, p.PN5, p.PN8, p.PN9, p.PN10, p.PN11, p.PN1, spi_config, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     let mut flash = FlashMemory::new(xspi).await; | ||||||
|  | 
 | ||||||
|  |     let flash_id = flash.read_id(); | ||||||
|  |     info!("FLASH ID: {=[u8]:x}", flash_id); | ||||||
|  | 
 | ||||||
|  |     let mut wr_buf = [0u8; 8]; | ||||||
|  |     for i in 0..8 { | ||||||
|  |         wr_buf[i] = 0x90 + i as u8; | ||||||
|  |     } | ||||||
|  |     let mut rd_buf = [0u8; 8]; | ||||||
|  |     flash.erase_sector(0).await; | ||||||
|  |     flash.write_memory(0, &wr_buf, true).await; | ||||||
|  |     flash.read_memory(0, &mut rd_buf, true); | ||||||
|  |     info!("WRITE BUF: {=[u8]:#X}", wr_buf); | ||||||
|  |     info!("READ BUF: {=[u8]:#X}", rd_buf); | ||||||
|  |     flash.enable_mm().await; | ||||||
|  |     info!("Enabled memory mapped mode"); | ||||||
|  | 
 | ||||||
|  |     let first_u32 = unsafe { *(0x70000000 as *const u32) }; | ||||||
|  |     assert_eq!(first_u32, 0x93929190); | ||||||
|  |     info!("first_u32 {:08x}", first_u32); | ||||||
|  | 
 | ||||||
|  |     let second_u32 = unsafe { *(0x70000004 as *const u32) }; | ||||||
|  |     assert_eq!(second_u32, 0x97969594); | ||||||
|  |     info!("second_u32 {:08x}", first_u32); | ||||||
|  | 
 | ||||||
|  |     flash.disable_mm().await; | ||||||
|  |     info!("Disabled memory mapped mode"); | ||||||
|  | 
 | ||||||
|  |     info!("DONE"); | ||||||
|  |     // Output pin PE3
 | ||||||
|  |     let mut led = Output::new(p.PE3, Level::Low, Speed::Low); | ||||||
|  | 
 | ||||||
|  |     loop { | ||||||
|  |         led.toggle(); | ||||||
|  |         Timer::after_millis(1000).await; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const MEMORY_PAGE_SIZE: usize = 8; | ||||||
|  | 
 | ||||||
|  | const CMD_READ: u8 = 0x0B; | ||||||
|  | const _CMD_QUAD_READ: u8 = 0x6B; | ||||||
|  | 
 | ||||||
|  | const CMD_WRITE_PG: u8 = 0x02; | ||||||
|  | const _CMD_QUAD_WRITE_PG: u8 = 0x32; | ||||||
|  | 
 | ||||||
|  | const CMD_READ_ID: u8 = 0x9F; | ||||||
|  | const CMD_READ_ID_OCTO: u16 = 0x9F60; | ||||||
|  | 
 | ||||||
|  | const CMD_ENABLE_RESET: u8 = 0x66; | ||||||
|  | const CMD_RESET: u8 = 0x99; | ||||||
|  | 
 | ||||||
|  | const CMD_WRITE_ENABLE: u8 = 0x06; | ||||||
|  | 
 | ||||||
|  | const CMD_CHIP_ERASE: u8 = 0xC7; | ||||||
|  | const CMD_SECTOR_ERASE: u8 = 0x20; | ||||||
|  | const CMD_BLOCK_ERASE_32K: u8 = 0x52; | ||||||
|  | const CMD_BLOCK_ERASE_64K: u8 = 0xD8; | ||||||
|  | 
 | ||||||
|  | const CMD_READ_SR: u8 = 0x05; | ||||||
|  | const CMD_READ_CR: u8 = 0x35; | ||||||
|  | 
 | ||||||
|  | const CMD_WRITE_SR: u8 = 0x01; | ||||||
|  | const CMD_WRITE_CR: u8 = 0x31; | ||||||
|  | 
 | ||||||
|  | /// Implementation of access to flash chip.
 | ||||||
|  | ///
 | ||||||
|  | /// Chip commands are hardcoded as it depends on used chip.
 | ||||||
|  | /// This targets a MX25UW25645GXDI00.
 | ||||||
|  | pub struct FlashMemory<I: Instance> { | ||||||
|  |     xspi: Xspi<'static, I, Blocking>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<I: Instance> FlashMemory<I> { | ||||||
|  |     pub async fn new(xspi: Xspi<'static, I, Blocking>) -> Self { | ||||||
|  |         let mut memory = Self { xspi }; | ||||||
|  | 
 | ||||||
|  |         memory.reset_memory().await; | ||||||
|  |         memory.enable_octo(); | ||||||
|  |         memory | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn qpi_mode(&mut self) { | ||||||
|  |         // Enter qpi mode
 | ||||||
|  |         self.exec_command(0x38).await; | ||||||
|  | 
 | ||||||
|  |         // Set read param
 | ||||||
|  |         let transaction = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::QUAD, | ||||||
|  |             dwidth: XspiWidth::QUAD, | ||||||
|  |             instruction: Some(0xC0), | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.enable_write().await; | ||||||
|  |         self.xspi.blocking_write(&[0x30_u8], transaction).unwrap(); | ||||||
|  |         self.wait_write_finish(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn disable_mm(&mut self) { | ||||||
|  |         self.xspi.disable_memory_mapped_mode(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn enable_mm(&mut self) { | ||||||
|  |         self.qpi_mode().await; | ||||||
|  | 
 | ||||||
|  |         let read_config = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             isize: AddressSize::_8bit, | ||||||
|  |             adwidth: XspiWidth::SING, | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             instruction: Some(CMD_READ as u32), | ||||||
|  |             dummy: DummyCycles::_8, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let write_config = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             isize: AddressSize::_8bit, | ||||||
|  |             adwidth: XspiWidth::SING, | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             instruction: Some(CMD_WRITE_PG as u32), | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.xspi.enable_memory_mapped_mode(read_config, write_config).unwrap(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn enable_octo(&mut self) { | ||||||
|  |         let cr = self.read_cr(); | ||||||
|  |         // info!("Read cr: {:x}", cr);
 | ||||||
|  |         self.write_cr(cr | 0x02); | ||||||
|  |         // info!("Read cr after writing: {:x}", cr);
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn disable_octo(&mut self) { | ||||||
|  |         let cr = self.read_cr(); | ||||||
|  |         self.write_cr(cr & (!(0x02))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn exec_command_4(&mut self, cmd: u8) { | ||||||
|  |         let transaction = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::QUAD, | ||||||
|  |             adwidth: XspiWidth::NONE, | ||||||
|  |             // adsize: AddressSize::_24bit,
 | ||||||
|  |             dwidth: XspiWidth::NONE, | ||||||
|  |             instruction: Some(cmd as u32), | ||||||
|  |             address: None, | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.xspi.blocking_command(&transaction).unwrap(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn exec_command(&mut self, cmd: u8) { | ||||||
|  |         let transaction = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             adwidth: XspiWidth::NONE, | ||||||
|  |             // adsize: AddressSize::_24bit,
 | ||||||
|  |             dwidth: XspiWidth::NONE, | ||||||
|  |             instruction: Some(cmd as u32), | ||||||
|  |             address: None, | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         // info!("Excuting command: {:x}", transaction.instruction);
 | ||||||
|  |         self.xspi.blocking_command(&transaction).unwrap(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn reset_memory(&mut self) { | ||||||
|  |         self.exec_command_4(CMD_ENABLE_RESET).await; | ||||||
|  |         self.exec_command_4(CMD_RESET).await; | ||||||
|  |         self.exec_command(CMD_ENABLE_RESET).await; | ||||||
|  |         self.exec_command(CMD_RESET).await; | ||||||
|  |         self.wait_write_finish(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn enable_write(&mut self) { | ||||||
|  |         self.exec_command(CMD_WRITE_ENABLE).await; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_id(&mut self) -> [u8; 3] { | ||||||
|  |         let mut buffer = [0; 3]; | ||||||
|  |         let transaction: TransferConfig = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             isize: AddressSize::_8bit, | ||||||
|  |             adwidth: XspiWidth::NONE, | ||||||
|  |             // adsize: AddressSize::_24bit,
 | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             instruction: Some(CMD_READ_ID as u32), | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         // info!("Reading id: 0x{:X}", transaction.instruction);
 | ||||||
|  |         self.xspi.blocking_read(&mut buffer, transaction).unwrap(); | ||||||
|  |         buffer | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_id_8(&mut self) -> [u8; 3] { | ||||||
|  |         let mut buffer = [0; 3]; | ||||||
|  |         let transaction: TransferConfig = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::OCTO, | ||||||
|  |             isize: AddressSize::_16bit, | ||||||
|  |             adwidth: XspiWidth::OCTO, | ||||||
|  |             address: Some(0), | ||||||
|  |             adsize: AddressSize::_32bit, | ||||||
|  |             dwidth: XspiWidth::OCTO, | ||||||
|  |             instruction: Some(CMD_READ_ID_OCTO as u32), | ||||||
|  |             dummy: DummyCycles::_4, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         info!("Reading id: {:#X}", transaction.instruction); | ||||||
|  |         self.xspi.blocking_read(&mut buffer, transaction).unwrap(); | ||||||
|  |         buffer | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { | ||||||
|  |         let transaction = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             adwidth: XspiWidth::SING, | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             instruction: Some(CMD_READ as u32), | ||||||
|  |             dummy: DummyCycles::_8, | ||||||
|  |             // dwidth: XspiWidth::QUAD,
 | ||||||
|  |             // instruction: Some(CMD_QUAD_READ as u32),
 | ||||||
|  |             // dummy: DummyCycles::_8,
 | ||||||
|  |             address: Some(addr), | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         if use_dma { | ||||||
|  |             self.xspi.blocking_read(buffer, transaction).unwrap(); | ||||||
|  |         } else { | ||||||
|  |             self.xspi.blocking_read(buffer, transaction).unwrap(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn wait_write_finish(&mut self) { | ||||||
|  |         while (self.read_sr() & 0x01) != 0 {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn perform_erase(&mut self, addr: u32, cmd: u8) { | ||||||
|  |         let transaction = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             adwidth: XspiWidth::SING, | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             dwidth: XspiWidth::NONE, | ||||||
|  |             instruction: Some(cmd as u32), | ||||||
|  |             address: Some(addr), | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.enable_write().await; | ||||||
|  |         self.xspi.blocking_command(&transaction).unwrap(); | ||||||
|  |         self.wait_write_finish(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn erase_sector(&mut self, addr: u32) { | ||||||
|  |         self.perform_erase(addr, CMD_SECTOR_ERASE).await; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn erase_block_32k(&mut self, addr: u32) { | ||||||
|  |         self.perform_erase(addr, CMD_BLOCK_ERASE_32K).await; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn erase_block_64k(&mut self, addr: u32) { | ||||||
|  |         self.perform_erase(addr, CMD_BLOCK_ERASE_64K).await; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn erase_chip(&mut self) { | ||||||
|  |         self.exec_command(CMD_CHIP_ERASE).await; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { | ||||||
|  |         assert!( | ||||||
|  |             (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, | ||||||
|  |             "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", | ||||||
|  |             len, | ||||||
|  |             addr | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         let transaction = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             adwidth: XspiWidth::SING, | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             instruction: Some(CMD_WRITE_PG as u32), | ||||||
|  |             // dwidth: XspiWidth::QUAD,
 | ||||||
|  |             // instruction: Some(CMD_QUAD_WRITE_PG as u32),
 | ||||||
|  |             address: Some(addr), | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.enable_write().await; | ||||||
|  |         if use_dma { | ||||||
|  |             self.xspi.blocking_write(buffer, transaction).unwrap(); | ||||||
|  |         } else { | ||||||
|  |             self.xspi.blocking_write(buffer, transaction).unwrap(); | ||||||
|  |         } | ||||||
|  |         self.wait_write_finish(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { | ||||||
|  |         let mut left = buffer.len(); | ||||||
|  |         let mut place = addr; | ||||||
|  |         let mut chunk_start = 0; | ||||||
|  | 
 | ||||||
|  |         while left > 0 { | ||||||
|  |             let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; | ||||||
|  |             let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; | ||||||
|  |             let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; | ||||||
|  |             self.write_page(place, chunk, chunk_size, use_dma).await; | ||||||
|  |             place += chunk_size as u32; | ||||||
|  |             left -= chunk_size; | ||||||
|  |             chunk_start += chunk_size; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn read_register(&mut self, cmd: u8) -> u8 { | ||||||
|  |         let mut buffer = [0; 1]; | ||||||
|  |         let transaction: TransferConfig = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             isize: AddressSize::_8bit, | ||||||
|  |             adwidth: XspiWidth::NONE, | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             instruction: Some(cmd as u32), | ||||||
|  |             address: None, | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.xspi.blocking_read(&mut buffer, transaction).unwrap(); | ||||||
|  |         // info!("Read w25q64 register: 0x{:x}", buffer[0]);
 | ||||||
|  |         buffer[0] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn write_register(&mut self, cmd: u8, value: u8) { | ||||||
|  |         let buffer = [value; 1]; | ||||||
|  |         let transaction: TransferConfig = TransferConfig { | ||||||
|  |             iwidth: XspiWidth::SING, | ||||||
|  |             isize: AddressSize::_8bit, | ||||||
|  |             instruction: Some(cmd as u32), | ||||||
|  |             adsize: AddressSize::_24bit, | ||||||
|  |             adwidth: XspiWidth::NONE, | ||||||
|  |             dwidth: XspiWidth::SING, | ||||||
|  |             address: None, | ||||||
|  |             dummy: DummyCycles::_0, | ||||||
|  |             ..Default::default() | ||||||
|  |         }; | ||||||
|  |         self.xspi.blocking_write(&buffer, transaction).unwrap(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_sr(&mut self) -> u8 { | ||||||
|  |         self.read_register(CMD_READ_SR) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_cr(&mut self) -> u8 { | ||||||
|  |         self.read_register(CMD_READ_CR) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn write_sr(&mut self, value: u8) { | ||||||
|  |         self.write_register(CMD_WRITE_SR, value); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn write_cr(&mut self, value: u8) { | ||||||
|  |         self.write_register(CMD_WRITE_CR, value); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user