Skip to content

Commit f4b083d

Browse files
committed
support FMC u8 data width
1 parent 9516abc commit f4b083d

File tree

4 files changed

+280
-88
lines changed

4 files changed

+280
-88
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111
- remove unneeded trait bound for methods that take in a `serial::Instance` and use the associated `RegisterBlock`
1212
- bump `sdio-host` to 0.9.0, refactor SDIO initialization [#734]
1313
- use RTCCLK for RTC wakeup timer for short durations [#746]
14+
- Support 8-bit FMC data bus
1415

1516
### Fixed
1617

src/fsmc_lcd/display_interface_impl.rs

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{Lcd, SubBank};
22

33
macro_rules! impl_display_interface {
44
($display_interface:ident) => {
5-
impl<S> $display_interface::WriteOnlyDataCommand for Lcd<S>
5+
impl<S> $display_interface::WriteOnlyDataCommand for Lcd<S, u16>
66
where
77
S: SubBank,
88
{
@@ -85,5 +85,128 @@ macro_rules! impl_display_interface {
8585
};
8686
}
8787

88+
macro_rules! impl_display_interface_u8 {
89+
($display_interface:ident) => {
90+
impl<S> $display_interface::WriteOnlyDataCommand for Lcd<S, u8>
91+
where
92+
S: SubBank,
93+
{
94+
fn send_commands(
95+
&mut self,
96+
cmd: $display_interface::DataFormat<'_>,
97+
) -> Result<(), $display_interface::DisplayError> {
98+
use $display_interface::DataFormat;
99+
match cmd {
100+
DataFormat::U8(slice) => {
101+
for value in slice {
102+
self.write_command(*value);
103+
}
104+
}
105+
DataFormat::U16(slice) => {
106+
for value in slice {
107+
let bytes = value.to_ne_bytes();
108+
self.write_command(bytes[0]);
109+
self.write_command(bytes[1]);
110+
}
111+
}
112+
DataFormat::U16BE(slice) => {
113+
for value in slice {
114+
let bytes = value.to_be_bytes();
115+
self.write_command(bytes[0]);
116+
self.write_command(bytes[1]);
117+
}
118+
}
119+
DataFormat::U16LE(slice) => {
120+
for value in slice {
121+
let bytes = value.to_le_bytes();
122+
self.write_command(bytes[0]);
123+
self.write_command(bytes[1]);
124+
}
125+
}
126+
DataFormat::U8Iter(iter) => {
127+
for value in iter {
128+
self.write_command(value);
129+
}
130+
}
131+
DataFormat::U16BEIter(iter) => {
132+
for value in iter {
133+
let bytes = value.to_be_bytes();
134+
self.write_command(bytes[0]);
135+
self.write_command(bytes[1]);
136+
}
137+
}
138+
DataFormat::U16LEIter(iter) => {
139+
for value in iter {
140+
let bytes = value.to_le_bytes();
141+
self.write_command(bytes[0]);
142+
self.write_command(bytes[1]);
143+
}
144+
}
145+
_ => return Err($display_interface::DisplayError::DataFormatNotImplemented),
146+
}
147+
Ok(())
148+
}
149+
150+
fn send_data(
151+
&mut self,
152+
buf: $display_interface::DataFormat<'_>,
153+
) -> Result<(), $display_interface::DisplayError> {
154+
use $display_interface::DataFormat;
155+
match buf {
156+
DataFormat::U8(slice) => {
157+
for value in slice {
158+
self.write_data(*value);
159+
}
160+
}
161+
DataFormat::U8Iter(iter) => {
162+
for value in iter {
163+
self.write_data(value);
164+
}
165+
}
166+
DataFormat::U16(slice) => {
167+
for value in slice {
168+
let bytes = value.to_ne_bytes();
169+
self.write_data(bytes[0]);
170+
self.write_data(bytes[1]);
171+
}
172+
}
173+
DataFormat::U16BE(slice) => {
174+
for value in slice {
175+
let bytes = value.to_be_bytes();
176+
self.write_data(bytes[0]);
177+
self.write_data(bytes[1]);
178+
}
179+
}
180+
DataFormat::U16LE(slice) => {
181+
for value in slice {
182+
let bytes = value.to_le_bytes();
183+
self.write_data(bytes[0]);
184+
self.write_data(bytes[1]);
185+
}
186+
}
187+
DataFormat::U16BEIter(iter) => {
188+
for value in iter {
189+
let bytes = value.to_be_bytes();
190+
self.write_data(bytes[0]);
191+
self.write_data(bytes[1]);
192+
}
193+
}
194+
DataFormat::U16LEIter(iter) => {
195+
for value in iter {
196+
let bytes = value.to_le_bytes();
197+
self.write_data(bytes[0]);
198+
self.write_data(bytes[1]);
199+
}
200+
}
201+
_ => return Err($display_interface::DisplayError::DataFormatNotImplemented),
202+
}
203+
Ok(())
204+
}
205+
}
206+
};
207+
}
208+
88209
impl_display_interface!(display_interface);
89210
impl_display_interface!(display_interface_04);
211+
impl_display_interface_u8!(display_interface);
212+
impl_display_interface_u8!(display_interface_04);

src/fsmc_lcd/mod.rs

Lines changed: 69 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ mod timing;
6565

6666
use core::marker::PhantomData;
6767

68-
pub use self::pins::{AddressPins, ChipSelectPins, DataPins, DataPins16, LcdPins, Pins};
68+
pub use self::pins::{AddressPins, ChipSelectPins, DataPins, DataPins16, DataPins8, LcdPins, Pins};
6969
pub use self::timing::{AccessMode, Timing};
7070

7171
use crate::rcc::{Enable, Reset};
@@ -108,14 +108,26 @@ impl sealed::SealedSubBank for SubBank4 {
108108
impl SubBank for SubBank4 {}
109109

110110
/// An FMC or FSMC configured as an LCD interface
111-
pub struct FsmcLcd<PINS> {
111+
pub struct FsmcLcd<PINS, WORD: Word = u16> {
112112
pins: PINS,
113113
fsmc: FSMC,
114+
_word: PhantomData<WORD>,
114115
}
115116

116-
impl<PINS> FsmcLcd<PINS>
117+
pub trait Word {
118+
const MWID: fsmc::bcr1::MWID_A;
119+
}
120+
121+
impl Word for u8 {
122+
const MWID: fsmc::bcr1::MWID_A = fsmc::bcr1::MWID_A::Bits8;
123+
}
124+
impl Word for u16 {
125+
const MWID: fsmc::bcr1::MWID_A = fsmc::bcr1::MWID_A::Bits8;
126+
}
127+
128+
impl<PINS, WORD: Word> FsmcLcd<PINS, WORD>
117129
where
118-
PINS: Pins,
130+
PINS: Pins<WORD>,
119131
{
120132
/// Configures the FSMC/FMC to interface with an LCD using the provided pins
121133
///
@@ -213,7 +225,7 @@ where
213225
// and sub-banks of bank 1. This driver uses addresses in the different sub-banks of
214226
// bank 1. The configuration registers for "bank x" (like FMC_BCRx) actually refer to
215227
// sub-banks, not banks. We need to configure and enable all four of them.
216-
configure_bcr1(&fsmc.bcr1);
228+
configure_bcr1::<WORD>(&fsmc.bcr1);
217229
configure_bcr(&fsmc.bcr2);
218230
configure_bcr(&fsmc.bcr3);
219231
configure_bcr(&fsmc.bcr4);
@@ -226,7 +238,14 @@ where
226238
configure_bwtr(&fsmc.bwtr3, write_timing);
227239
configure_bwtr(&fsmc.bwtr4, write_timing);
228240

229-
(FsmcLcd { pins, fsmc }, PINS::Lcds::conjure())
241+
(
242+
FsmcLcd {
243+
pins,
244+
fsmc,
245+
_word: PhantomData,
246+
},
247+
PINS::Lcds::conjure(),
248+
)
230249
}
231250

232251
/// Reunites this FsmcLcd and all its associated LCDs, and returns the FSMC and pins for other
@@ -246,54 +265,39 @@ where
246265
}
247266

248267
/// Configures an SRAM/NOR-Flash chip-select control register for LCD interface use
249-
fn configure_bcr1(bcr: &fsmc::BCR1) {
268+
fn configure_bcr1<WORD: Word>(bcr: &fsmc::BCR1) {
250269
bcr.write(|w| {
251-
w
252-
// The write fifo and WFDIS bit are missing from some models.
253-
// Where present, the FIFO is enabled by default.
254-
// ------------
255-
// Disable synchronous writes
256-
.cburstrw()
257-
.disabled()
258-
// Don't split burst transactions (doesn't matter for LCD mode)
259-
.cpsize()
260-
.no_burst_split()
261-
// Ignore wait signal (asynchronous mode)
262-
.asyncwait()
263-
.disabled()
264-
// Enable extended mode, for different read and write timings
265-
.extmod()
266-
.enabled()
267-
// Ignore wait signal (synchronous mode)
268-
.waiten()
269-
.disabled()
270-
// Allow write operations
271-
.wren()
272-
.enabled()
273-
// Default wait timing
274-
.waitcfg()
275-
.before_wait_state()
276-
// Default wait polarity
277-
.waitpol()
278-
.active_low()
279-
// Disable burst reads
280-
.bursten()
281-
.disabled()
282-
// Enable NOR flash operations
283-
.faccen()
284-
.enabled()
285-
// 16-bit bus width
286-
.mwid()
287-
.bits16()
288-
// NOR flash mode (compatible with LCD controllers)
289-
.mtyp()
290-
.flash()
291-
// Address and data not multiplexed
292-
.muxen()
293-
.disabled()
294-
// Enable this memory bank
295-
.mbken()
296-
.enabled()
270+
// The write fifo and WFDIS bit are missing from some models.
271+
// Where present, the FIFO is enabled by default.
272+
// ------------
273+
// Disable synchronous writes
274+
w.cburstrw().disabled();
275+
// Don't split burst transactions (doesn't matter for LCD mode)
276+
w.cpsize().no_burst_split();
277+
// Ignore wait signal (asynchronous mode)
278+
w.asyncwait().disabled();
279+
// Enable extended mode, for different read and write timings
280+
w.extmod().enabled();
281+
// Ignore wait signal (synchronous mode)
282+
w.waiten().disabled();
283+
// Allow write operations
284+
w.wren().enabled();
285+
// Default wait timing
286+
w.waitcfg().before_wait_state();
287+
// Default wait polarity
288+
w.waitpol().active_low();
289+
// Disable burst reads
290+
w.bursten().disabled();
291+
// Enable NOR flash operations
292+
w.faccen().enabled();
293+
// 8/16-bit bus width
294+
w.mwid().variant(WORD::MWID);
295+
// NOR flash mode (compatible with LCD controllers)
296+
w.mtyp().flash();
297+
// Address and data not multiplexed
298+
w.muxen().disabled();
299+
// Enable this memory bank
300+
w.mbken().enabled()
297301
})
298302
}
299303

@@ -384,45 +388,45 @@ fn configure_bwtr(bwtr: &fsmc::BWTR, write_timing: &Timing) {
384388
///
385389
/// This struct provides low-level read and write commands that can be used to implement
386390
/// drivers for LCD controllers. Each function corresponds to exactly one transaction on the bus.
387-
pub struct Lcd<S> {
391+
pub struct Lcd<S, WORD> {
388392
/// Phantom S
389393
///
390394
/// S determines the chip select signal to use, and the addresses used with that signal.
391-
_sub_bank: PhantomData<S>,
395+
_sub_bank: PhantomData<(S, WORD)>,
392396
}
393-
impl<S> Lcd<S> {
397+
impl<S, WORD: Word> Lcd<S, WORD> {
394398
fn new() -> Self {
395399
Self {
396400
_sub_bank: PhantomData,
397401
}
398402
}
399403
}
400404

401-
impl<S> Lcd<S>
405+
impl<S, WORD: Word> Lcd<S, WORD>
402406
where
403407
S: SubBank,
404408
{
405409
/// Writes a value with the data/command (address) signals set high
406-
pub fn write_data(&mut self, value: u16) {
410+
pub fn write_data(&mut self, value: WORD) {
407411
unsafe {
408-
core::ptr::write_volatile(S::DATA_ADDRESS as *mut u16, value);
412+
core::ptr::write_volatile(S::DATA_ADDRESS as *mut WORD, value);
409413
}
410414
}
411415

412416
/// Writes a value with the data/command (address) signals set low
413-
pub fn write_command(&mut self, value: u16) {
417+
pub fn write_command(&mut self, value: WORD) {
414418
unsafe {
415-
core::ptr::write_volatile(S::COMMAND_ADDRESS as *mut u16, value);
419+
core::ptr::write_volatile(S::COMMAND_ADDRESS as *mut WORD, value);
416420
}
417421
}
418422

419423
/// Reads a value with the data/command (address) signals set high
420-
pub fn read_data(&self) -> u16 {
421-
unsafe { core::ptr::read_volatile(S::DATA_ADDRESS as *const u16) }
424+
pub fn read_data(&self) -> WORD {
425+
unsafe { core::ptr::read_volatile(S::DATA_ADDRESS as *const WORD) }
422426
}
423427

424428
/// Reads a value with the data/command (address) signals set low
425-
pub fn read_command(&self) -> u16 {
426-
unsafe { core::ptr::read_volatile(S::COMMAND_ADDRESS as *const u16) }
429+
pub fn read_command(&self) -> WORD {
430+
unsafe { core::ptr::read_volatile(S::COMMAND_ADDRESS as *const WORD) }
427431
}
428432
}

0 commit comments

Comments
 (0)