diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 35d213292..37c8bdbbf 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The (previously undocumented) `ErasedPin` enum has been replaced with the `ErasedPin` struct. (#2094) - Renamed and merged `Rtc::get_time_us` and `Rtc::get_time_ms` into `Rtc::time_since_boot` (#1883) - ESP32: Added support for touch sensing on GPIO32 and 33 (#2109) +- Removed gpio pin generics from I8080 driver type. (#2171) +- I8080 driver now decides bus width at transfer time rather than construction time. (#2171) - Replaced `AnyPin` with `InputSignal` and `OutputSignal` and renamed `ErasedPin` to `AnyPin` (#2128) - Replaced the `ErasedTimer` enum with the `AnyTimer` struct. (#?) - Changed the parameters of `Spi::with_pins` to no longer be optional (#2133) diff --git a/esp-hal/MIGRATING-0.20.md b/esp-hal/MIGRATING-0.20.md index 26ea1364f..77544c0d4 100644 --- a/esp-hal/MIGRATING-0.20.md +++ b/esp-hal/MIGRATING-0.20.md @@ -179,3 +179,22 @@ You can pass `NoPin` or `Level` as inputs, and `NoPin` as output if you don't ne - .with_pins(Some(sclk), Some(mosi), NO_PIN, NO_PIN); + .with_pins(sclk, mosi, Level::Low, NoPin); ``` + +## I8080 type definition + +The I8080 driver no longer holds on to pins in its type definition. + +```diff +- let _: I8080<'a, DmaChannel3, TxEightBits, Blocking>; ++ let _: I8080<'a, DmaChannel3, Blocking>; +``` + +## I8080 start transfer type inference + +The I8080 driver now decides bus width at transfer time, which means you don't get inference. + +```diff +let mut i8080 = I8080::new(....); +- i8080.send(0x12, 0, &[0, 1, 2, 3, 4]); ++ i8080.send(0x12u8, 0, &[0, 1, 2, 3, 4]); +``` diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 37316afad..795d190e4 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -53,7 +53,7 @@ //! ) //! .with_ctrl_pins(io.pins.gpio0, io.pins.gpio47); //! -//! i8080.send(0x3A, 0, &[0x55]).unwrap(); // RGB565 +//! i8080.send(0x3Au8, 0, &[0x55]).unwrap(); // RGB565 //! # } //! ``` @@ -91,21 +91,19 @@ use crate::{ }; /// Represents the I8080 LCD interface. -pub struct I8080<'d, CH: DmaChannel, P, DM: Mode> { +pub struct I8080<'d, CH: DmaChannel, DM: Mode> { lcd_cam: PeripheralRef<'d, LCD_CAM>, tx_channel: ChannelTx<'d, CH>, tx_chain: DescriptorChain, - _pins: P, _phantom: PhantomData, } -impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> I8080<'d, CH, P, DM> +impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> where CH::P: LcdCamPeripheral, - P::Word: Into, { /// Creates a new instance of the I8080 LCD interface. - pub fn new( + pub fn new( lcd: Lcd<'d, DM>, mut channel: ChannelTx<'d, CH>, descriptors: &'static mut [DmaDescriptor], @@ -113,8 +111,6 @@ where frequency: HertzU32, config: Config, ) -> Self { - let is_2byte_mode = size_of::() == 2; - let lcd_cam = lcd.lcd_cam; let clocks = Clocks::get(); @@ -168,7 +164,7 @@ where .lcd_byte_order() .bit(false) .lcd_2byte_en() - .bit(is_2byte_mode) + .bit(false) }); lcd_cam.lcd_misc().write(|w| unsafe { // Set the threshold for Async Tx FIFO full event. (5 bits) @@ -252,13 +248,12 @@ where lcd_cam, tx_channel: channel, tx_chain: DescriptorChain::new(descriptors), - _pins: pins, _phantom: PhantomData, } } } -impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> DmaSupport for I8080<'d, CH, P, DM> { +impl<'d, CH: DmaChannel, DM: Mode> DmaSupport for I8080<'d, CH, DM> { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { let lcd_user = self.lcd_cam.lcd_user(); // Wait until LCD_START is cleared by hardware. @@ -271,7 +266,7 @@ impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> DmaSupport for I8080<'d, CH, P, DM } } -impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> DmaSupportTx for I8080<'d, CH, P, DM> { +impl<'d, CH: DmaChannel, DM: Mode> DmaSupportTx for I8080<'d, CH, DM> { type TX = ChannelTx<'d, CH>; fn tx(&mut self) -> &mut Self::TX { @@ -283,19 +278,15 @@ impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> DmaSupportTx for I8080<'d, CH, P, } } -impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> I8080<'d, CH, P, DM> -where - P::Word: Into, -{ +impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> { /// Configures the byte order for data transmission. pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self { let is_inverted = byte_order != ByteOrder::default(); self.lcd_cam.lcd_user().modify(|_, w| { - if size_of::() == 2 { - w.lcd_byte_order().bit(is_inverted) - } else { - w.lcd_8bits_order().bit(is_inverted) - } + w.lcd_byte_order() + .bit(is_inverted) + .lcd_8bits_order() + .bit(is_inverted) }); self } @@ -336,11 +327,18 @@ where } /// Sends a command and data to the LCD using the I8080 interface. - pub fn send( + /// + /// Passing a `Command` will make this an 8-bit transfer and a + /// `Command` will make this a 16-bit transfer. + /// + /// Note: A 16-bit transfer on an 8-bit bus will silently truncate the 2nd + /// byte and an 8-bit transfer on a 16-bit bus will silently pad each + /// byte to 2 bytes. + pub fn send>( &mut self, - cmd: impl Into>, + cmd: impl Into>, dummy: u8, - data: &[P::Word], + data: &[W], ) -> Result<(), DmaError> { self.setup_send(cmd.into(), dummy); self.start_write_bytes_dma(data.as_ptr() as _, core::mem::size_of_val(data))?; @@ -356,13 +354,21 @@ where } /// Sends a command and data to the LCD using DMA. - pub fn send_dma<'t, TXBUF>( + /// + /// Passing a `Command` will make this an 8-bit transfer and a + /// `Command` will make this a 16-bit transfer. + /// + /// Note: A 16-bit transfer on an 8-bit bus will silently truncate the 2nd + /// byte and an 8-bit transfer on a 16-bit bus will silently pad each + /// byte to 2 bytes. + pub fn send_dma<'t, W, TXBUF>( &'t mut self, - cmd: impl Into>, + cmd: impl Into>, dummy: u8, data: &'t TXBUF, ) -> Result, DmaError> where + W: Copy + Into, TXBUF: ReadBuffer, { let (ptr, len) = unsafe { data.read_buffer() }; @@ -375,18 +381,23 @@ where } } -impl<'d, CH: DmaChannel, P: TxPins> I8080<'d, CH, P, crate::Async> -where - P::Word: Into, -{ +impl<'d, CH: DmaChannel> I8080<'d, CH, crate::Async> { /// Asynchronously sends a command and data to the LCD using DMA. - pub async fn send_dma_async<'t, TXBUF>( + /// + /// Passing a `Command` will make this an 8-bit transfer and a + /// `Command` will make this a 16-bit transfer. + /// + /// Note: A 16-bit transfer on an 8-bit bus will silently truncate the 2nd + /// byte and an 8-bit transfer on a 16-bit bus will silently pad each + /// byte to 2 bytes. + pub async fn send_dma_async<'t, W, TXBUF>( &'t mut self, - cmd: impl Into>, + cmd: impl Into>, dummy: u8, data: &'t TXBUF, ) -> Result<(), DmaError> where + W: Copy + Into, TXBUF: ReadBuffer, { let (ptr, len) = unsafe { data.read_buffer() }; @@ -403,7 +414,7 @@ where } } -impl<'d, CH: DmaChannel, P, DM: Mode> I8080<'d, CH, P, DM> { +impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> { fn setup_send>(&mut self, cmd: Command, dummy: u8) { // Reset LCD control unit and Async Tx FIFO self.lcd_cam @@ -439,8 +450,10 @@ impl<'d, CH: DmaChannel, P, DM: Mode> I8080<'d, CH, P, DM> { } } - // Set dummy length + let is_2byte_mode = size_of::() == 2; + self.lcd_cam.lcd_user().modify(|_, w| unsafe { + // Set dummy length if dummy > 0 { // Enable DUMMY phase in LCD sequence when LCD starts. w.lcd_dummy() @@ -451,6 +464,8 @@ impl<'d, CH: DmaChannel, P, DM: Mode> I8080<'d, CH, P, DM> { } else { w.lcd_dummy().clear_bit() } + .lcd_2byte_en() + .bit(is_2byte_mode) }); } @@ -508,7 +523,7 @@ impl<'d, CH: DmaChannel, P, DM: Mode> I8080<'d, CH, P, DM> { } } -impl<'d, CH: DmaChannel, P, DM: Mode> core::fmt::Debug for I8080<'d, CH, P, DM> { +impl<'d, CH: DmaChannel, DM: Mode> core::fmt::Debug for I8080<'d, CH, DM> { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("I8080").finish() } @@ -572,8 +587,14 @@ pub enum Command { Two(T, T), } -impl From for Command { - fn from(value: T) -> Self { +impl From for Command { + fn from(value: u8) -> Self { + Command::One(value) + } +} + +impl From for Command { + fn from(value: u16) -> Self { Command::One(value) } } @@ -647,8 +668,6 @@ where P6: PeripheralOutput, P7: PeripheralOutput, { - type Word = u8; - fn configure(&mut self) { self.pin_0.set_to_push_pull_output(crate::private::Internal); self.pin_0 @@ -796,7 +815,6 @@ where P14: PeripheralOutput, P15: PeripheralOutput, { - type Word = u16; fn configure(&mut self) { self.pin_0.set_to_push_pull_output(crate::private::Internal); self.pin_0 @@ -857,7 +875,6 @@ where mod private { pub trait TxPins { - type Word: Copy; fn configure(&mut self); } } diff --git a/examples/src/bin/lcd_i8080.rs b/examples/src/bin/lcd_i8080.rs index 978cd8019..4d0ccf0ac 100644 --- a/examples/src/bin/lcd_i8080.rs +++ b/examples/src/bin/lcd_i8080.rs @@ -222,19 +222,19 @@ fn main() -> ! { let mut bytes_left_to_write = total_bytes; - let transfer = i8080.send_dma(0x2C, 0, &buffer).unwrap(); + let transfer = i8080.send_dma(0x2Cu8, 0, &buffer).unwrap(); transfer.wait().unwrap(); bytes_left_to_write -= buffer.len(); while bytes_left_to_write >= buffer.len() { - let transfer = i8080.send_dma(0x3C, 0, &buffer).unwrap(); + let transfer = i8080.send_dma(0x3Cu8, 0, &buffer).unwrap(); transfer.wait().unwrap(); bytes_left_to_write -= buffer.len(); } if bytes_left_to_write > 0 { - let transfer = i8080.send_dma(0x3C, 0, &buffer).unwrap(); + let transfer = i8080.send_dma(0x3Cu8, 0, &buffer).unwrap(); transfer.wait().unwrap(); }