Skip to content

Commit cee3b0e

Browse files
bors[bot]richardeoinx37vphoracekolback
authored
Merge #230 #256
230: Initial OCTOSPI and QUADSPI memories support r=richardeoin a=richardeoin `write_extended` and `read_extended` methods allow more complicated transactions, such as those needed to read/write from flash memories. Rename the `quadspi` flag to `xspi` Ref #165 256: Implement IoPin r=richardeoin a=olback Implements the IoPin trait from embedded-hal. Co-authored-by: Richard Meadows <962920+richardeoin@users.noreply.github.com> Co-authored-by: Alex Norman <alex@x37v.info> Co-authored-by: Richard Meadows <richardeoin@gmail.com> Co-authored-by: Petr Horacek <hrck@protonmail.com> Co-authored-by: Edwin Svensson <git@olback.net> Co-authored-by: Edwin <git@olback.net>
3 parents 83d09b1 + 7d65096 + c558ebd commit cee3b0e

File tree

15 files changed

+1901
-25
lines changed

15 files changed

+1901
-25
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- stm32h7b0
2424
- stm32h735
2525
env: # Peripheral Feature flags
26-
FLAGS: rt,quadspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc
26+
FLAGS: rt,xspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc
2727

2828
steps:
2929
- uses: actions/checkout@v2

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- log-semihost
2020
- log-rtt
2121
env: # Peripheral Feature flags
22-
FLAGS: rt,quadspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc
22+
FLAGS: rt,xspi,sdmmc,fmc,usb_hs,rtc,ethernet,ltdc,crc
2323

2424
steps:
2525
- uses: actions/checkout@v2

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
* spi: Add more hardware CS features #216
3030
* timers: Better calculations for `set_timeout_ticks` #208
3131

32+
* **Breaking**: Rename the `quadspi` flag to `xspi`
33+
3234
## [v0.9.0] 2021-03-12
3335

3436
* Updates `cortex-m` to v0.7.1. `cortex-m` v0.6.5+ [are forward compatible with

Cargo.toml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ features = ["stm32h743v", "rt", "quadspi", "sdmmc", "fmc", "usb_hs", "rtc", "eth
2525
targets = ["thumbv7em-none-eabihf"]
2626

2727
[dependencies]
28-
embedded-hal = "0.2.4"
28+
embedded-hal = "0.2.6"
2929
embedded-dma = "0.1.2"
3030
cortex-m = "^0.7.1"
3131
stm32h7 = "^0.14.0"
@@ -86,7 +86,7 @@ cm4 = []
8686
cm7 = []
8787
smps = []
8888
ltdc = ["embedded-display-controller"]
89-
quadspi = []
89+
xspi = []
9090
fmc = ["stm32-fmc"]
9191
sdmmc = ["sdio-host"]
9292
sdmmc-fatfs = ["embedded-sdmmc", "sdmmc"]
@@ -145,11 +145,19 @@ required-features = ["fmc", "rm0399"]
145145

146146
[[example]]
147147
name = "qspi"
148-
required-features = ["quadspi", "rm0433"]
148+
required-features = ["xspi", "rm0433"]
149149

150150
[[example]]
151151
name = "qspi_mdma"
152-
required-features = ["quadspi", "rm0433"]
152+
required-features = ["xspi", "rm0433"]
153+
154+
[[example]]
155+
name = "qspi_flash_memory"
156+
required-features = ["xspi", "rm0433"]
157+
158+
[[example]]
159+
name = "octospi"
160+
required-features = ["xspi", "rm0468"]
153161

154162
[[example]]
155163
name = "sdmmc"

examples/octospi.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//! OCTOSPI peripheral example in indirect mode
2+
//!
3+
//! Tested on a STM32H735G-DK with a Macronix MX25LM51245GXDI00
4+
5+
#![deny(warnings)]
6+
#![no_main]
7+
#![no_std]
8+
9+
#[macro_use]
10+
mod utilities;
11+
12+
use cortex_m_rt::entry;
13+
use stm32h7xx_hal::rcc::rec::{OctospiClkSel, OctospiClkSelGetter};
14+
use stm32h7xx_hal::{
15+
pac, prelude::*, xspi::OctospiMode, xspi::OctospiWord as XW,
16+
};
17+
18+
use log::info;
19+
20+
#[entry]
21+
fn main() -> ! {
22+
utilities::logger::init();
23+
let dp = pac::Peripherals::take().unwrap();
24+
25+
// Constrain and Freeze power
26+
let pwr = dp.PWR.constrain();
27+
let pwrcfg = example_power!(pwr).freeze();
28+
29+
// Constrain and Freeze clock
30+
let rcc = dp.RCC.constrain();
31+
let ccdr = rcc.sys_ck(96.mhz()).freeze(pwrcfg, &dp.SYSCFG);
32+
33+
// Octospi from HCLK at 48MHz
34+
assert_eq!(ccdr.clocks.hclk().0, 48_000_000);
35+
assert_eq!(
36+
ccdr.peripheral.OCTOSPI1.get_kernel_clk_mux(),
37+
OctospiClkSel::RCC_HCLK3
38+
);
39+
40+
// Acquire the GPIO peripherals. This also enables the clock for
41+
// the GPIOs in the RCC register.
42+
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
43+
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
44+
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
45+
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
46+
47+
let _ncs = gpiog.pg6.into_alternate_af10();
48+
let _clk = gpiof.pf10.into_alternate_af9();
49+
let _io0 = gpiod.pd11.into_alternate_af9();
50+
let _io1 = gpiod.pd12.into_alternate_af9();
51+
let _io2 = gpioe.pe2.into_alternate_af9();
52+
let _io3 = gpiod.pd13.into_alternate_af9();
53+
let _io4 = gpiod.pd4.into_alternate_af10();
54+
let _io5 = gpiod.pd5.into_alternate_af10();
55+
let _io6 = gpiog.pg9.into_alternate_af9();
56+
let _io7 = gpiod.pd7.into_alternate_af10();
57+
58+
info!("");
59+
info!("stm32h7xx-hal example - OCTOSPI");
60+
info!("");
61+
62+
// Initialise the OCTOSPI peripheral.
63+
let mut octospi = dp.OCTOSPI1.octospi_unchecked(
64+
12.mhz(),
65+
&ccdr.clocks,
66+
ccdr.peripheral.OCTOSPI1,
67+
);
68+
69+
octospi.configure_mode(OctospiMode::OneBit).unwrap();
70+
71+
// RDID Read Identification. Abuses address as instruction phase, but that
72+
// works in SPI mode.
73+
let mut read: [u8; 3] = [0; 3];
74+
octospi.read(0x9F, &mut read).unwrap();
75+
info!("Read with instruction 0x9F : {:x?}", read);
76+
77+
// Switch Macronix MX25LM51245GXDI00 to SDR OPI
78+
// Set WREN bit
79+
octospi
80+
.write_extended(XW::U8(0x06), XW::None, XW::None, &[])
81+
.unwrap();
82+
// Write Configuration Register 2
83+
octospi
84+
.write_extended(XW::U8(0x72), XW::U32(0), XW::None, &[1])
85+
.unwrap();
86+
// Change bus mode
87+
octospi.configure_mode(OctospiMode::EightBit).unwrap();
88+
89+
// RDID Read Identification
90+
let mut read: [u8; 3] = [0; 3];
91+
octospi
92+
.read_extended(XW::U16(0x9F60), XW::U32(0), XW::None, 4, &mut read)
93+
.unwrap();
94+
95+
info!("Read with instruction 0x9F60 : {:x?}", read);
96+
97+
loop {}
98+
}

examples/qspi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
mod utilities;
77

88
use cortex_m_rt::entry;
9-
use stm32h7xx_hal::{pac, prelude::*, qspi::QspiMode};
9+
use stm32h7xx_hal::{pac, prelude::*, xspi::QspiMode};
1010

1111
use log::info;
1212

examples/qspi_flash_memory.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
//! Example of communication with flash memory over QSPI interface. This
2+
//! specific program is made for Daisy Seed board and its IS25LP064A flash
3+
//! memory chip. This demo provides a non-volatile restart counter. When it is
4+
//! odd, LED will light up, when even, it stays off.
5+
6+
#![deny(warnings)]
7+
#![no_main]
8+
#![no_std]
9+
10+
#[macro_use]
11+
mod utilities;
12+
13+
use core::mem::transmute;
14+
15+
use cortex_m_rt::entry;
16+
use stm32h7xx_hal::gpio::Speed;
17+
use stm32h7xx_hal::hal::digital::v2::OutputPin;
18+
use stm32h7xx_hal::{
19+
pac, prelude::*, xspi::Qspi, xspi::QspiMode, xspi::QspiWord,
20+
};
21+
22+
use log::info;
23+
24+
// SPI commands from IS25LP064 datasheet
25+
const WRITE_STATUS_REGISTRY_CMD: u8 = 0x01; // WRSR
26+
const WRITE_CMD: u8 = 0x02; // PP
27+
const NORMAL_READ_CMD: u8 = 0x03; // NORD
28+
const READ_STATUS_REGISTRY_CMD: u8 = 0x05; // RDSR
29+
const WRITE_ENABLE_CMD: u8 = 0x06; // WREN
30+
const SET_READ_PARAMETERS_CMD: u8 = 0xC0; // SRP
31+
const SECTOR_ERASE_CMD: u8 = 0xD8; // SER
32+
33+
// Address in the external memory that will be used for the counter
34+
const COUNTER_ADDRESS: u32 = 0x00;
35+
36+
#[entry]
37+
fn main() -> ! {
38+
utilities::logger::init();
39+
let dp = pac::Peripherals::take().unwrap();
40+
41+
// Constrain and Freeze power
42+
let pwr = dp.PWR.constrain();
43+
let pwrcfg = example_power!(pwr).freeze();
44+
45+
// Constrain and Freeze clock
46+
let rcc = dp.RCC.constrain();
47+
let ccdr = rcc.sys_ck(96.mhz()).freeze(pwrcfg, &dp.SYSCFG);
48+
49+
// Acquire the GPIO peripherals
50+
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
51+
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
52+
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
53+
54+
// Even though it is not directly used, CS pin must be acquired and configured
55+
let _qspi_cs = gpiog.pg6.into_alternate_af10().set_speed(Speed::VeryHigh);
56+
57+
let sck = gpiof.pf10.into_alternate_af9().set_speed(Speed::VeryHigh);
58+
let io0 = gpiof.pf8.into_alternate_af10().set_speed(Speed::VeryHigh);
59+
let io1 = gpiof.pf9.into_alternate_af10().set_speed(Speed::VeryHigh);
60+
let io2 = gpiof.pf7.into_alternate_af9().set_speed(Speed::VeryHigh);
61+
let io3 = gpiof.pf6.into_alternate_af9().set_speed(Speed::VeryHigh);
62+
63+
let mut led = gpioc.pc7.into_push_pull_output();
64+
65+
info!("");
66+
info!("stm32h7xx-hal example - QSPI Flash Memory");
67+
info!("");
68+
69+
// Initialise the QSPI peripheral
70+
let mut qspi = dp.QUADSPI.bank1(
71+
(sck, io0, io1, io2, io3),
72+
3.mhz(),
73+
&ccdr.clocks,
74+
ccdr.peripheral.QSPI,
75+
);
76+
qspi.configure_mode(QspiMode::OneBit).unwrap();
77+
78+
// Reset configuration of the flash memory
79+
reset_status_registry(&mut qspi);
80+
reset_read_registry(&mut qspi);
81+
82+
// Read the current value and increment it
83+
let original = read_u32(&mut qspi, COUNTER_ADDRESS);
84+
write_u32(&mut qspi, COUNTER_ADDRESS, original.overflowing_add(1).0);
85+
86+
// Based on the original value, enable or disable LED on the board
87+
if original % 2 == 0 {
88+
led.set_low().unwrap();
89+
} else {
90+
led.set_high().unwrap();
91+
}
92+
93+
loop {
94+
cortex_m::asm::nop();
95+
}
96+
}
97+
98+
fn read_u32(qspi: &mut Qspi<pac::QUADSPI>, address: u32) -> u32 {
99+
let mut buffer: [u8; 4] = [0xFF; 4];
100+
qspi.read_extended(
101+
QspiWord::U8(NORMAL_READ_CMD),
102+
QspiWord::U24(address),
103+
QspiWord::None,
104+
0,
105+
&mut buffer,
106+
)
107+
.unwrap();
108+
u32::from_be_bytes(buffer)
109+
}
110+
111+
fn write_u32(qspi: &mut Qspi<pac::QUADSPI>, address: u32, value: u32) {
112+
enable_write_operation(qspi);
113+
qspi.write_extended(
114+
QspiWord::U8(SECTOR_ERASE_CMD),
115+
QspiWord::U24(address),
116+
QspiWord::None,
117+
&[],
118+
)
119+
.unwrap();
120+
wait_for_write_completition(qspi);
121+
122+
let bytes: [u8; 4] = unsafe { transmute(value.to_be()) };
123+
enable_write_operation(qspi);
124+
qspi.write_extended(
125+
QspiWord::U8(WRITE_CMD),
126+
QspiWord::U24(address),
127+
QspiWord::None,
128+
&bytes,
129+
)
130+
.unwrap();
131+
wait_for_write_completition(qspi);
132+
}
133+
134+
fn reset_status_registry(qspi: &mut Qspi<pac::QUADSPI>) {
135+
enable_write_operation(qspi);
136+
137+
qspi.write_extended(
138+
QspiWord::U8(WRITE_STATUS_REGISTRY_CMD),
139+
QspiWord::U8(0b00000000),
140+
QspiWord::None,
141+
&[],
142+
)
143+
.unwrap();
144+
145+
wait_for_write_completition(qspi);
146+
}
147+
148+
fn reset_read_registry(qspi: &mut Qspi<pac::QUADSPI>) {
149+
enable_write_operation(qspi);
150+
151+
qspi.write_extended(
152+
QspiWord::U8(SET_READ_PARAMETERS_CMD),
153+
QspiWord::U8(0b11100000),
154+
QspiWord::None,
155+
&[],
156+
)
157+
.unwrap();
158+
159+
wait_for_write_completition(qspi);
160+
}
161+
162+
fn enable_write_operation(qspi: &mut Qspi<pac::QUADSPI>) {
163+
qspi.write_extended(
164+
QspiWord::U8(WRITE_ENABLE_CMD),
165+
QspiWord::None,
166+
QspiWord::None,
167+
&[],
168+
)
169+
.unwrap();
170+
}
171+
172+
fn wait_for_write_completition(qspi: &mut Qspi<pac::QUADSPI>) {
173+
loop {
174+
let mut status: [u8; 1] = [0xFF; 1];
175+
qspi.read_extended(
176+
QspiWord::U8(READ_STATUS_REGISTRY_CMD),
177+
QspiWord::None,
178+
QspiWord::None,
179+
0,
180+
&mut status,
181+
)
182+
.unwrap();
183+
184+
if status[0] & 0x01 == 0 {
185+
break;
186+
}
187+
}
188+
}

examples/qspi_mdma.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod utilities;
1313
use core::mem;
1414

1515
use cortex_m_rt::entry;
16-
use stm32h7xx_hal::{pac, prelude::*, qspi, qspi::QspiMode};
16+
use stm32h7xx_hal::{pac, prelude::*, xspi, xspi::QspiMode};
1717

1818
use stm32h7xx_hal::dma::{
1919
mdma::{
@@ -57,7 +57,7 @@ fn main() -> ! {
5757
info!("stm32h7xx-hal example - QSPI with MDMA");
5858
info!("");
5959

60-
let config: qspi::Config = 1.mhz().into();
60+
let config: xspi::Config = 1.mhz().into();
6161
// Threshold when half full
6262
let config = config.fifo_threshold(16);
6363

0 commit comments

Comments
 (0)