Get dsi_bsp example to compile again

This commit is contained in:
David Haig 2024-06-28 15:12:17 +01:00
parent 47c7bb2bb5
commit 1123e3fd41
2 changed files with 131 additions and 97 deletions

View File

@ -175,8 +175,31 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
}
impl<'d, T: Instance> Ltdc<'d, T> {
// Create a new LTDC driver without specifying color and control pins. This is typically used if you want to drive a display though a DsiHost
/// Note: Full-Duplex modes are not supported at this time
pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
critical_section::with(|_cs| {
// RM says the pllsaidivr should only be changed when pllsai is off. But this could have other unintended side effects. So let's just give it a try like this.
// According to the debugger, this bit gets set, anyway.
#[cfg(stm32f7)]
stm32_metapac::RCC
.dckcfgr1()
.modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
// It is set to RCC_PLLSAIDIVR_2 in ST's BSP example for the STM32469I-DISCO.
#[cfg(not(any(stm32f7, stm32u5)))]
stm32_metapac::RCC
.dckcfgr()
.modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
});
rcc::enable_and_reset::<T>();
into_ref!(peri);
Self { _peri: peri }
}
/// Create a new LTDC driver. 8 pins per color channel for blue, green and red
pub fn new(
pub fn new_with_pins(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
clk: impl Peripheral<P = impl ClkPin<T>> + 'd,
@ -241,93 +264,7 @@ impl<'d, T: Instance> Ltdc<'d, T> {
Self { _peri: peri }
}
fn clear_interrupt_flags() {
T::regs().icr().write(|w| {
w.set_cfuif(Cfuif::CLEAR);
w.set_clif(Clif::CLEAR);
w.set_crrif(Crrif::CLEAR);
w.set_cterrif(Cterrif::CLEAR);
});
}
fn enable_interrupts(enable: bool) {
T::regs().ier().write(|w| {
w.set_fuie(enable);
w.set_lie(false); // we are not interested in the line interrupt enable event
w.set_rrie(enable);
w.set_terrie(enable)
});
// enable interrupts for LTDC peripheral
T::Interrupt::unpend();
if enable {
unsafe { T::Interrupt::enable() };
} else {
T::Interrupt::disable()
}
}
/// Set the current buffer. The async function will return when buffer has been completely copied to the LCD screen
/// frame_buffer_addr is a pointer to memory that should not move (best to make it static)
pub async fn set_buffer(&mut self, layer: LtdcLayer, frame_buffer_addr: *const ()) -> Result<(), Error> {
let mut bits = T::regs().isr().read();
// if all clear
if !bits.fuif() && !bits.lif() && !bits.rrif() && !bits.terrif() {
// wait for interrupt
poll_fn(|cx| {
// quick check to avoid registration if already done.
let bits = T::regs().isr().read();
if bits.fuif() || bits.lif() || bits.rrif() || bits.terrif() {
return Poll::Ready(());
}
LTDC_WAKER.register(cx.waker());
Self::clear_interrupt_flags(); // don't poison the request with old flags
Self::enable_interrupts(true);
// set the new frame buffer address
let layer = T::regs().layer(layer as usize);
layer.cfbar().modify(|w| w.set_cfbadd(frame_buffer_addr as u32));
// configure a shadow reload for the next blanking period
T::regs().srcr().write(|w| {
w.set_vbr(Vbr::RELOAD);
});
// need to check condition after register to avoid a race
// condition that would result in lost notifications.
let bits = T::regs().isr().read();
if bits.fuif() || bits.lif() || bits.rrif() || bits.terrif() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
// re-read the status register after wait.
bits = T::regs().isr().read();
}
let result = if bits.fuif() {
Err(Error::FifoUnderrun)
} else if bits.terrif() {
Err(Error::TransferError)
} else if bits.lif() {
panic!("line interrupt event is disabled")
} else if bits.rrif() {
// register reload flag is expected
Ok(())
} else {
unreachable!("all interrupt status values checked")
};
Self::clear_interrupt_flags();
result
}
/// Initialize the display
/// Initialise and enable the display
pub fn init(&mut self, config: &LtdcConfiguration) {
use stm32_metapac::ltdc::vals::{Depol, Hspol, Pcpol, Vspol};
let ltdc = T::regs();
@ -393,16 +330,27 @@ impl<'d, T: Instance> Ltdc<'d, T> {
w.set_bcblue(0);
});
// enable LTDC by setting LTDCEN bit
ltdc.gcr().modify(|w| {
w.set_ltdcen(true);
});
self.enable();
}
/// Enable the layer
/// Set the enable bit in the control register and assert that it has been enabled
///
/// clut - color look-up table applies to L8, AL44 and AL88 pixel format and will default to greyscale if None supplied and these pixel formats are used
pub fn enable_layer(&mut self, layer_config: &LtdcLayerConfig, clut: Option<&[RgbColor]>) {
/// This does need to be called if init has already been called
pub fn enable(&mut self) {
T::regs().gcr().modify(|w| w.set_ltdcen(true));
assert!(T::regs().gcr().read().ltdcen())
}
/// Unset the enable bit in the control register and assert that it has been disabled
pub fn disable(&mut self) {
T::regs().gcr().modify(|w| w.set_ltdcen(false));
assert!(!T::regs().gcr().read().ltdcen())
}
/// Initialise and enable the layer
///
/// clut - a 256 length color look-up table applies to L8, AL44 and AL88 pixel format and will default to greyscale if `None` supplied and these pixel formats are used
pub fn init_layer(&mut self, layer_config: &LtdcLayerConfig, clut: Option<&[RgbColor]>) {
let ltdc = T::regs();
let layer = ltdc.layer(layer_config.layer as usize);
@ -475,6 +423,92 @@ impl<'d, T: Instance> Ltdc<'d, T> {
w.set_len(true);
});
}
/// Set the current buffer. The async function will return when buffer has been completely copied to the LCD screen
/// frame_buffer_addr is a pointer to memory that should not move (best to make it static)
pub async fn set_buffer(&mut self, layer: LtdcLayer, frame_buffer_addr: *const ()) -> Result<(), Error> {
let mut bits = T::regs().isr().read();
// if all clear
if !bits.fuif() && !bits.lif() && !bits.rrif() && !bits.terrif() {
// wait for interrupt
poll_fn(|cx| {
// quick check to avoid registration if already done.
let bits = T::regs().isr().read();
if bits.fuif() || bits.lif() || bits.rrif() || bits.terrif() {
return Poll::Ready(());
}
LTDC_WAKER.register(cx.waker());
Self::clear_interrupt_flags(); // don't poison the request with old flags
Self::enable_interrupts(true);
// set the new frame buffer address
let layer = T::regs().layer(layer as usize);
layer.cfbar().modify(|w| w.set_cfbadd(frame_buffer_addr as u32));
// configure a shadow reload for the next blanking period
T::regs().srcr().write(|w| {
w.set_vbr(Vbr::RELOAD);
});
// need to check condition after register to avoid a race
// condition that would result in lost notifications.
let bits = T::regs().isr().read();
if bits.fuif() || bits.lif() || bits.rrif() || bits.terrif() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
// re-read the status register after wait.
bits = T::regs().isr().read();
}
let result = if bits.fuif() {
Err(Error::FifoUnderrun)
} else if bits.terrif() {
Err(Error::TransferError)
} else if bits.lif() {
panic!("line interrupt event is disabled")
} else if bits.rrif() {
// register reload flag is expected
Ok(())
} else {
unreachable!("all interrupt status values checked")
};
Self::clear_interrupt_flags();
result
}
fn clear_interrupt_flags() {
T::regs().icr().write(|w| {
w.set_cfuif(Cfuif::CLEAR);
w.set_clif(Clif::CLEAR);
w.set_crrif(Crrif::CLEAR);
w.set_cterrif(Cterrif::CLEAR);
});
}
fn enable_interrupts(enable: bool) {
T::regs().ier().write(|w| {
w.set_fuie(enable);
w.set_lie(false); // we are not interested in the line interrupt enable event
w.set_rrie(enable);
w.set_terrie(enable)
});
// enable interrupts for LTDC peripheral
T::Interrupt::unpend();
if enable {
unsafe { T::Interrupt::enable() };
} else {
T::Interrupt::disable()
}
}
}
impl<'d, T: Instance> Drop for Ltdc<'d, T> {

View File

@ -87,7 +87,7 @@ async fn main(spawner: Spawner) {
};
info!("init ltdc");
let mut ltdc = Ltdc::new(
let mut ltdc = Ltdc::new_with_pins(
p.LTDC, Irqs, p.PG7, p.PC6, p.PA4, p.PG14, p.PD0, p.PD6, p.PA8, p.PE12, p.PA3, p.PB8, p.PB9, p.PB1, p.PB0,
p.PA6, p.PE11, p.PH15, p.PH4, p.PC7, p.PD3, p.PE0, p.PH3, p.PH8, p.PH9, p.PH10, p.PH11, p.PE1, p.PE15,
);
@ -109,7 +109,7 @@ async fn main(spawner: Spawner) {
let clut = build_clut(&color_map);
// enable the bottom layer with a 256 color lookup table
ltdc.enable_layer(&layer_config, Some(&clut));
ltdc.init_layer(&layer_config, Some(&clut));
// Safety: the DoubleBuffer controls access to the statically allocated frame buffers
// and it is the only thing that mutates their content