mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 14:44:42 +00:00
Remove pin generics from I8080 (#2171)
* Remove pin generics from I8080 * Doc example * temp * More docs * doc fix --------- Co-authored-by: Dominic Fischer <git@dominicfischer.me>
This commit is contained in:
parent
a787a13441
commit
5ae76d727e
@ -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)
|
- 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)
|
- 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)
|
- 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 `AnyPin` with `InputSignal` and `OutputSignal` and renamed `ErasedPin` to `AnyPin` (#2128)
|
||||||
- Replaced the `ErasedTimer` enum with the `AnyTimer` struct. (#?)
|
- Replaced the `ErasedTimer` enum with the `AnyTimer` struct. (#?)
|
||||||
- Changed the parameters of `Spi::with_pins` to no longer be optional (#2133)
|
- Changed the parameters of `Spi::with_pins` to no longer be optional (#2133)
|
||||||
|
@ -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(Some(sclk), Some(mosi), NO_PIN, NO_PIN);
|
||||||
+ .with_pins(sclk, mosi, Level::Low, NoPin);
|
+ .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<AnyPin, AnyPin, AnyPin, ....>, 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]);
|
||||||
|
```
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
//! )
|
//! )
|
||||||
//! .with_ctrl_pins(io.pins.gpio0, io.pins.gpio47);
|
//! .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.
|
/// 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>,
|
lcd_cam: PeripheralRef<'d, LCD_CAM>,
|
||||||
tx_channel: ChannelTx<'d, CH>,
|
tx_channel: ChannelTx<'d, CH>,
|
||||||
tx_chain: DescriptorChain,
|
tx_chain: DescriptorChain,
|
||||||
_pins: P,
|
|
||||||
_phantom: PhantomData<DM>,
|
_phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH: DmaChannel, P: TxPins, DM: Mode> I8080<'d, CH, P, DM>
|
impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH::P: LcdCamPeripheral,
|
CH::P: LcdCamPeripheral,
|
||||||
P::Word: Into<u16>,
|
|
||||||
{
|
{
|
||||||
/// Creates a new instance of the I8080 LCD interface.
|
/// Creates a new instance of the I8080 LCD interface.
|
||||||
pub fn new(
|
pub fn new<P: TxPins>(
|
||||||
lcd: Lcd<'d, DM>,
|
lcd: Lcd<'d, DM>,
|
||||||
mut channel: ChannelTx<'d, CH>,
|
mut channel: ChannelTx<'d, CH>,
|
||||||
descriptors: &'static mut [DmaDescriptor],
|
descriptors: &'static mut [DmaDescriptor],
|
||||||
@ -113,8 +111,6 @@ where
|
|||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let is_2byte_mode = size_of::<P::Word>() == 2;
|
|
||||||
|
|
||||||
let lcd_cam = lcd.lcd_cam;
|
let lcd_cam = lcd.lcd_cam;
|
||||||
|
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
@ -168,7 +164,7 @@ where
|
|||||||
.lcd_byte_order()
|
.lcd_byte_order()
|
||||||
.bit(false)
|
.bit(false)
|
||||||
.lcd_2byte_en()
|
.lcd_2byte_en()
|
||||||
.bit(is_2byte_mode)
|
.bit(false)
|
||||||
});
|
});
|
||||||
lcd_cam.lcd_misc().write(|w| unsafe {
|
lcd_cam.lcd_misc().write(|w| unsafe {
|
||||||
// Set the threshold for Async Tx FIFO full event. (5 bits)
|
// Set the threshold for Async Tx FIFO full event. (5 bits)
|
||||||
@ -252,13 +248,12 @@ where
|
|||||||
lcd_cam,
|
lcd_cam,
|
||||||
tx_channel: channel,
|
tx_channel: channel,
|
||||||
tx_chain: DescriptorChain::new(descriptors),
|
tx_chain: DescriptorChain::new(descriptors),
|
||||||
_pins: pins,
|
|
||||||
_phantom: PhantomData,
|
_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) {
|
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
|
||||||
let lcd_user = self.lcd_cam.lcd_user();
|
let lcd_user = self.lcd_cam.lcd_user();
|
||||||
// Wait until LCD_START is cleared by hardware.
|
// 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>;
|
type TX = ChannelTx<'d, CH>;
|
||||||
|
|
||||||
fn tx(&mut self) -> &mut Self::TX {
|
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>
|
impl<'d, CH: DmaChannel, DM: Mode> I8080<'d, CH, DM> {
|
||||||
where
|
|
||||||
P::Word: Into<u16>,
|
|
||||||
{
|
|
||||||
/// Configures the byte order for data transmission.
|
/// Configures the byte order for data transmission.
|
||||||
pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self {
|
pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self {
|
||||||
let is_inverted = byte_order != ByteOrder::default();
|
let is_inverted = byte_order != ByteOrder::default();
|
||||||
self.lcd_cam.lcd_user().modify(|_, w| {
|
self.lcd_cam.lcd_user().modify(|_, w| {
|
||||||
if size_of::<P::Word>() == 2 {
|
w.lcd_byte_order()
|
||||||
w.lcd_byte_order().bit(is_inverted)
|
.bit(is_inverted)
|
||||||
} else {
|
.lcd_8bits_order()
|
||||||
w.lcd_8bits_order().bit(is_inverted)
|
.bit(is_inverted)
|
||||||
}
|
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -336,11 +327,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a command and data to the LCD using the I8080 interface.
|
/// Sends a command and data to the LCD using the I8080 interface.
|
||||||
pub fn send(
|
///
|
||||||
|
/// Passing a `Command<u8>` will make this an 8-bit transfer and a
|
||||||
|
/// `Command<u16>` 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<W: Copy + Into<u16>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cmd: impl Into<Command<P::Word>>,
|
cmd: impl Into<Command<W>>,
|
||||||
dummy: u8,
|
dummy: u8,
|
||||||
data: &[P::Word],
|
data: &[W],
|
||||||
) -> Result<(), DmaError> {
|
) -> Result<(), DmaError> {
|
||||||
self.setup_send(cmd.into(), dummy);
|
self.setup_send(cmd.into(), dummy);
|
||||||
self.start_write_bytes_dma(data.as_ptr() as _, core::mem::size_of_val(data))?;
|
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.
|
/// Sends a command and data to the LCD using DMA.
|
||||||
pub fn send_dma<'t, TXBUF>(
|
///
|
||||||
|
/// Passing a `Command<u8>` will make this an 8-bit transfer and a
|
||||||
|
/// `Command<u16>` 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,
|
&'t mut self,
|
||||||
cmd: impl Into<Command<P::Word>>,
|
cmd: impl Into<Command<W>>,
|
||||||
dummy: u8,
|
dummy: u8,
|
||||||
data: &'t TXBUF,
|
data: &'t TXBUF,
|
||||||
) -> Result<DmaTransferTx<'_, Self>, DmaError>
|
) -> Result<DmaTransferTx<'_, Self>, DmaError>
|
||||||
where
|
where
|
||||||
|
W: Copy + Into<u16>,
|
||||||
TXBUF: ReadBuffer,
|
TXBUF: ReadBuffer,
|
||||||
{
|
{
|
||||||
let (ptr, len) = unsafe { data.read_buffer() };
|
let (ptr, len) = unsafe { data.read_buffer() };
|
||||||
@ -375,18 +381,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH: DmaChannel, P: TxPins> I8080<'d, CH, P, crate::Async>
|
impl<'d, CH: DmaChannel> I8080<'d, CH, crate::Async> {
|
||||||
where
|
|
||||||
P::Word: Into<u16>,
|
|
||||||
{
|
|
||||||
/// Asynchronously sends a command and data to the LCD using DMA.
|
/// Asynchronously sends a command and data to the LCD using DMA.
|
||||||
pub async fn send_dma_async<'t, TXBUF>(
|
///
|
||||||
|
/// Passing a `Command<u8>` will make this an 8-bit transfer and a
|
||||||
|
/// `Command<u16>` 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,
|
&'t mut self,
|
||||||
cmd: impl Into<Command<P::Word>>,
|
cmd: impl Into<Command<W>>,
|
||||||
dummy: u8,
|
dummy: u8,
|
||||||
data: &'t TXBUF,
|
data: &'t TXBUF,
|
||||||
) -> Result<(), DmaError>
|
) -> Result<(), DmaError>
|
||||||
where
|
where
|
||||||
|
W: Copy + Into<u16>,
|
||||||
TXBUF: ReadBuffer,
|
TXBUF: ReadBuffer,
|
||||||
{
|
{
|
||||||
let (ptr, len) = unsafe { data.read_buffer() };
|
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<T: Copy + Into<u16>>(&mut self, cmd: Command<T>, dummy: u8) {
|
fn setup_send<T: Copy + Into<u16>>(&mut self, cmd: Command<T>, dummy: u8) {
|
||||||
// Reset LCD control unit and Async Tx FIFO
|
// Reset LCD control unit and Async Tx FIFO
|
||||||
self.lcd_cam
|
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::<T>() == 2;
|
||||||
|
|
||||||
self.lcd_cam.lcd_user().modify(|_, w| unsafe {
|
self.lcd_cam.lcd_user().modify(|_, w| unsafe {
|
||||||
|
// Set dummy length
|
||||||
if dummy > 0 {
|
if dummy > 0 {
|
||||||
// Enable DUMMY phase in LCD sequence when LCD starts.
|
// Enable DUMMY phase in LCD sequence when LCD starts.
|
||||||
w.lcd_dummy()
|
w.lcd_dummy()
|
||||||
@ -451,6 +464,8 @@ impl<'d, CH: DmaChannel, P, DM: Mode> I8080<'d, CH, P, DM> {
|
|||||||
} else {
|
} else {
|
||||||
w.lcd_dummy().clear_bit()
|
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 {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("I8080").finish()
|
f.debug_struct("I8080").finish()
|
||||||
}
|
}
|
||||||
@ -572,8 +587,14 @@ pub enum Command<T> {
|
|||||||
Two(T, T),
|
Two(T, T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<T> for Command<T> {
|
impl From<u8> for Command<u8> {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
|
Command::One(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for Command<u16> {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
Command::One(value)
|
Command::One(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,8 +668,6 @@ where
|
|||||||
P6: PeripheralOutput,
|
P6: PeripheralOutput,
|
||||||
P7: PeripheralOutput,
|
P7: PeripheralOutput,
|
||||||
{
|
{
|
||||||
type Word = u8;
|
|
||||||
|
|
||||||
fn configure(&mut self) {
|
fn configure(&mut self) {
|
||||||
self.pin_0.set_to_push_pull_output(crate::private::Internal);
|
self.pin_0.set_to_push_pull_output(crate::private::Internal);
|
||||||
self.pin_0
|
self.pin_0
|
||||||
@ -796,7 +815,6 @@ where
|
|||||||
P14: PeripheralOutput,
|
P14: PeripheralOutput,
|
||||||
P15: PeripheralOutput,
|
P15: PeripheralOutput,
|
||||||
{
|
{
|
||||||
type Word = u16;
|
|
||||||
fn configure(&mut self) {
|
fn configure(&mut self) {
|
||||||
self.pin_0.set_to_push_pull_output(crate::private::Internal);
|
self.pin_0.set_to_push_pull_output(crate::private::Internal);
|
||||||
self.pin_0
|
self.pin_0
|
||||||
@ -857,7 +875,6 @@ where
|
|||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
pub trait TxPins {
|
pub trait TxPins {
|
||||||
type Word: Copy;
|
|
||||||
fn configure(&mut self);
|
fn configure(&mut self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,19 +222,19 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let mut bytes_left_to_write = total_bytes;
|
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();
|
transfer.wait().unwrap();
|
||||||
|
|
||||||
bytes_left_to_write -= buffer.len();
|
bytes_left_to_write -= buffer.len();
|
||||||
|
|
||||||
while 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();
|
transfer.wait().unwrap();
|
||||||
|
|
||||||
bytes_left_to_write -= buffer.len();
|
bytes_left_to_write -= buffer.len();
|
||||||
}
|
}
|
||||||
if bytes_left_to_write > 0 {
|
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();
|
transfer.wait().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user