Merge pull request #16 from therealprof/display-interface

Rough first conversion to display-interface
This commit is contained in:
Yuri Iozzelli 2020-06-06 09:55:03 +02:00 committed by GitHub
commit 332aa05bc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 234 deletions

View file

@ -11,6 +11,7 @@ edition = "2018"
[dependencies] [dependencies]
display-interface = "0.4"
embedded-hal = "0.2.3" embedded-hal = "0.2.3"
[dependencies.embedded-graphics] [dependencies.embedded-graphics]

View file

@ -1,122 +0,0 @@
use crate::{Error, Interface};
use embedded_hal::digital::v2::OutputPin;
/// `Interface` implementation for GPIO interfaces
pub struct Gpio8Interface<'a, DATA, CSX, WRX, RDX, DCX> {
data_pins: &'a mut [DATA; 8],
csx: CSX,
wrx: WRX,
rdx: RDX,
dcx: DCX,
}
impl<'a, CSX, WRX, RDX, DCX, PinE>
Gpio8Interface<'_, &'a mut dyn OutputPin<Error = PinE>, CSX, WRX, RDX, DCX>
where
CSX: OutputPin<Error = PinE>,
WRX: OutputPin<Error = PinE>,
RDX: OutputPin<Error = PinE>,
DCX: OutputPin<Error = PinE>,
{
/// Create a new Gpio8Interface
///
/// Example useage:
///
/// let csx = gpioc.pc2.into_push_pull_output();
/// let wrx = gpiod.pd13.into_push_pull_output();
/// let rdx = gpiod.pd12.into_push_pull_output();
/// let dcx = gpiof.pf7.into_push_pull_output();
///
/// let mut data_pins: [&mut dyn OutputPin<Error = _>; 8] = [
/// &mut gpiod.pd6.into_push_pull_output(),
/// &mut gpiog.pg11.into_push_pull_output(),
/// ...
/// ];
///
/// let if_gpio = ili9341::gpio::Gpio8Interface::new(&mut data_pins, csx, wrx, rdx, dcx);
pub fn new(
data_pins: &'a mut [&'a mut dyn OutputPin<Error = PinE>; 8],
csx: CSX,
wrx: WRX,
rdx: RDX,
dcx: DCX,
) -> Self {
Self {
data_pins,
csx,
wrx,
rdx,
dcx,
}
}
/// Sets the gpio data pins used in the parallel interface
fn set_data_bus(&mut self, data: u8) -> Result<(), Error<PinE, PinE>> {
for (i, d) in self.data_pins.iter_mut().enumerate() {
if ((data >> i) & 0b1) == 0b1 {
d.set_high().map_err(Error::OutputPin)?;
} else {
d.set_low().map_err(Error::OutputPin)?;
}
}
Ok(())
}
}
impl<'a, CSX, WRX, RDX, DCX, PinE> Interface
for Gpio8Interface<'_, &mut dyn OutputPin<Error = PinE>, CSX, WRX, RDX, DCX>
where
CSX: OutputPin<Error = PinE>,
WRX: OutputPin<Error = PinE>,
RDX: OutputPin<Error = PinE>,
DCX: OutputPin<Error = PinE>,
{
type Error = Error<PinE, PinE>;
fn write(&mut self, command: u8, data: &[u8]) -> Result<(), Self::Error> {
self.csx.set_low().map_err(Error::OutputPin)?;
self.rdx.set_high().map_err(Error::OutputPin)?;
self.dcx.set_low().map_err(Error::OutputPin)?;
self.wrx.set_low().map_err(Error::OutputPin)?;
self.set_data_bus(command)?;
self.wrx.set_high().map_err(Error::OutputPin)?;
self.dcx.set_high().map_err(Error::OutputPin)?;
for val in data.iter() {
self.wrx.set_low().map_err(Error::OutputPin)?;
self.set_data_bus(*val)?;
self.wrx.set_high().map_err(Error::OutputPin)?;
}
self.csx.set_high().map_err(Error::OutputPin)?;
Ok(())
}
fn write_iter(
&mut self,
command: u8,
data: impl IntoIterator<Item = u16>,
) -> Result<(), Self::Error> {
self.csx.set_low().map_err(Error::OutputPin)?;
self.rdx.set_high().map_err(Error::OutputPin)?;
self.dcx.set_low().map_err(Error::OutputPin)?;
self.wrx.set_low().map_err(Error::OutputPin)?;
self.set_data_bus(command)?;
self.wrx.set_high().map_err(Error::OutputPin)?;
self.dcx.set_high().map_err(Error::OutputPin)?;
for val in data.into_iter() {
for b in &val.to_be_bytes() {
self.wrx.set_low().map_err(Error::OutputPin)?;
self.set_data_bus(*b)?;
self.wrx.set_high().map_err(Error::OutputPin)?;
}
}
self.csx.set_high().map_err(Error::OutputPin)?;
Ok(())
}
}

View file

@ -1,4 +1,4 @@
use crate::{Ili9341, Interface, OutputPin}; use crate::{Ili9341, OutputPin};
use core::{fmt::Debug, iter}; use core::{fmt::Debug, iter};
@ -14,14 +14,13 @@ use embedded_graphics::{
DrawTarget, DrawTarget,
}; };
impl<IfaceE, PinE, IFACE, RESET> DrawTarget<Rgb565> for Ili9341<IFACE, RESET> impl<PinE, IFACE, RESET> DrawTarget<Rgb565> for Ili9341<IFACE, RESET>
where where
IFACE: Interface<Error = IfaceE>, IFACE: display_interface::WriteOnlyDataCommand,
RESET: OutputPin<Error = PinE>, RESET: OutputPin<Error = PinE>,
IfaceE: Debug,
PinE: Debug, PinE: Debug,
{ {
type Error = IFACE::Error; type Error = crate::Error<PinE>;
fn size(&self) -> Size { fn size(&self) -> Size {
Size::new(self.width as u32, self.height as u32) Size::new(self.width as u32, self.height as u32)

View file

@ -4,13 +4,13 @@
extern crate embedded_graphics; extern crate embedded_graphics;
use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
pub mod spi; use core::iter::once;
use spi::SpiInterface; use display_interface::DataFormat::{U16BEIter, U8Iter};
use display_interface::WriteOnlyDataCommand;
pub mod gpio; pub mod spi;
/// Trait representing the interface to the hardware. /// Trait representing the interface to the hardware.
/// ///
@ -38,17 +38,11 @@ const WIDTH: usize = 240;
const HEIGHT: usize = 320; const HEIGHT: usize = 320;
#[derive(Debug)] #[derive(Debug)]
pub enum Error<IfaceE, PinE> { pub enum Error<PinE> {
Interface(IfaceE), Interface,
OutputPin(PinE), OutputPin(PinE),
} }
impl<IfaceE, PinE> From<IfaceE> for Error<IfaceE, PinE> {
fn from(e: IfaceE) -> Self {
Error::Interface(e)
}
}
/// The default orientation is Portrait /// The default orientation is Portrait
pub enum Orientation { pub enum Orientation {
Portrait, Portrait,
@ -80,38 +74,16 @@ pub struct Ili9341<IFACE, RESET> {
height: usize, height: usize,
} }
impl<SpiE, PinE, SPI, CS, DC, RESET> Ili9341<SpiInterface<SPI, CS, DC>, RESET> impl<PinE, IFACE, RESET> Ili9341<IFACE, RESET>
where where
SPI: Transfer<u8, Error = SpiE> + Write<u8, Error = SpiE>, IFACE: WriteOnlyDataCommand,
CS: OutputPin<Error = PinE>,
DC: OutputPin<Error = PinE>,
RESET: OutputPin<Error = PinE>,
{
pub fn new_spi<DELAY: DelayMs<u16>>(
spi: SPI,
cs: CS,
dc: DC,
reset: RESET,
delay: &mut DELAY,
) -> Result<Self, Error<SpiE, PinE>> {
let interface = SpiInterface::new(spi, cs, dc);
Self::new(interface, reset, delay).map_err(|e| match e {
Error::Interface(inner) => inner,
Error::OutputPin(inner) => Error::OutputPin(inner),
})
}
}
impl<IfaceE, PinE, IFACE, RESET> Ili9341<IFACE, RESET>
where
IFACE: Interface<Error = IfaceE>,
RESET: OutputPin<Error = PinE>, RESET: OutputPin<Error = PinE>,
{ {
pub fn new<DELAY: DelayMs<u16>>( pub fn new<DELAY: DelayMs<u16>>(
interface: IFACE, interface: IFACE,
reset: RESET, reset: RESET,
delay: &mut DELAY, delay: &mut DELAY,
) -> Result<Self, Error<IfaceE, PinE>> { ) -> Result<Self, Error<PinE>> {
let mut ili9341 = Ili9341 { let mut ili9341 = Ili9341 {
interface, interface,
reset, reset,
@ -173,15 +145,23 @@ where
Ok(()) Ok(())
} }
fn command(&mut self, cmd: Command, args: &[u8]) -> Result<(), IFACE::Error> { fn command(&mut self, cmd: Command, args: &[u8]) -> Result<(), Error<PinE>> {
self.interface.write(cmd as u8, args) self.interface
.send_commands(U8Iter(&mut once(cmd as u8)))
.map_err(|_| Error::Interface)?;
self.interface
.send_data(U8Iter(&mut args.iter().cloned()))
.map_err(|_| Error::Interface)
} }
fn write_iter<I: IntoIterator<Item = u16>>(&mut self, data: I) -> Result<(), IFACE::Error> { fn write_iter<I: IntoIterator<Item = u16>>(&mut self, data: I) -> Result<(), Error<PinE>> {
self.interface.write_iter(Command::MemoryWrite as u8, data) self.command(Command::MemoryWrite, &[])?;
self.interface
.send_data(U16BEIter(&mut data.into_iter()))
.map_err(|_| Error::Interface)
} }
fn set_window(&mut self, x0: u16, y0: u16, x1: u16, y1: u16) -> Result<(), IFACE::Error> { fn set_window(&mut self, x0: u16, y0: u16, x1: u16, y1: u16) -> Result<(), Error<PinE>> {
self.command( self.command(
Command::ColumnAddressSet, Command::ColumnAddressSet,
&[ &[
@ -219,7 +199,7 @@ where
x1: u16, x1: u16,
y1: u16, y1: u16,
data: I, data: I,
) -> Result<(), IFACE::Error> { ) -> Result<(), Error<PinE>> {
self.set_window(x0, y0, x1, y1)?; self.set_window(x0, y0, x1, y1)?;
self.write_iter(data) self.write_iter(data)
} }
@ -240,13 +220,13 @@ where
x1: u16, x1: u16,
y1: u16, y1: u16,
data: &[u16], data: &[u16],
) -> Result<(), IFACE::Error> { ) -> Result<(), Error<PinE>> {
self.set_window(x0, y0, x1, y1)?; self.set_window(x0, y0, x1, y1)?;
self.write_iter(data.iter().cloned()) self.write_iter(data.iter().cloned())
} }
/// Change the orientation of the screen /// Change the orientation of the screen
pub fn set_orientation(&mut self, mode: Orientation) -> Result<(), IFACE::Error> { pub fn set_orientation(&mut self, mode: Orientation) -> Result<(), Error<PinE>> {
match mode { match mode {
Orientation::Portrait => { Orientation::Portrait => {
self.width = WIDTH; self.width = WIDTH;

View file

@ -1,6 +1,3 @@
use crate::{Error, Interface};
use embedded_hal::blocking::spi;
use embedded_hal::digital::v2::OutputPin;
use embedded_hal::spi::{Mode, Phase, Polarity}; use embedded_hal::spi::{Mode, Phase, Polarity};
/// SPI mode /// SPI mode
@ -8,62 +5,3 @@ pub const MODE: Mode = Mode {
polarity: Polarity::IdleLow, polarity: Polarity::IdleLow,
phase: Phase::CaptureOnFirstTransition, phase: Phase::CaptureOnFirstTransition,
}; };
/// `Interface` implementation for SPI interfaces
pub struct SpiInterface<SPI, CS, DC> {
spi: SPI,
cs: CS,
dc: DC,
}
impl<SPI, CS, DC, SpiE, PinE> SpiInterface<SPI, CS, DC>
where
SPI: spi::Transfer<u8, Error = SpiE> + spi::Write<u8, Error = SpiE>,
CS: OutputPin<Error = PinE>,
DC: OutputPin<Error = PinE>,
{
pub fn new(spi: SPI, cs: CS, dc: DC) -> Self {
Self { spi, cs, dc }
}
}
impl<SPI, CS, DC, SpiE, PinE> Interface for SpiInterface<SPI, CS, DC>
where
SPI: spi::Transfer<u8, Error = SpiE> + spi::Write<u8, Error = SpiE>,
CS: OutputPin<Error = PinE>,
DC: OutputPin<Error = PinE>,
{
type Error = Error<SpiE, PinE>;
fn write(&mut self, command: u8, data: &[u8]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(Error::OutputPin)?;
self.dc.set_low().map_err(Error::OutputPin)?;
self.spi.write(&[command]).map_err(Error::Interface)?;
self.dc.set_high().map_err(Error::OutputPin)?;
self.spi.write(data).map_err(Error::Interface)?;
self.cs.set_high().map_err(Error::OutputPin)?;
Ok(())
}
fn write_iter(
&mut self,
command: u8,
data: impl IntoIterator<Item = u16>,
) -> Result<(), Self::Error> {
self.cs.set_low().map_err(Error::OutputPin)?;
self.dc.set_low().map_err(Error::OutputPin)?;
self.spi.write(&[command]).map_err(Error::Interface)?;
self.dc.set_high().map_err(Error::OutputPin)?;
for w in data.into_iter() {
self.spi.write(&w.to_be_bytes()).map_err(Error::Interface)?;
}
self.cs.set_high().map_err(Error::OutputPin)?;
Ok(())
}
}