Reworked display code
This commit is contained in:
parent
639ee2af7f
commit
bc3c25a5d3
2 changed files with 214 additions and 117 deletions
|
|
@ -5,10 +5,7 @@ use core::panic::PanicInfo;
|
|||
|
||||
use cardputer_bsc_nostd::display::{DISPLAY_SIZE_HEIGHT, DISPLAY_SIZE_WIDTH};
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use esp_hal::{
|
||||
ledc::{LowSpeed, channel::ChannelIFace, timer::TimerIFace},
|
||||
main,
|
||||
};
|
||||
use esp_hal::main;
|
||||
use esp_println::println;
|
||||
|
||||
#[panic_handler]
|
||||
|
|
@ -28,39 +25,24 @@ fn entrypoint() -> ! {
|
|||
|
||||
fn _main() {
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
let mut display = cardputer_bsc_nostd::display::build(
|
||||
|
||||
cardputer_bsc_nostd::setup_backlight! {
|
||||
let (mut ledc, mut timer) = setup_backlight(peripherals.LEDC);
|
||||
}
|
||||
|
||||
let mut display = cardputer_bsc_nostd::display::Display::new(
|
||||
peripherals.SPI2,
|
||||
peripherals.GPIO36,
|
||||
peripherals.GPIO35,
|
||||
peripherals.GPIO37,
|
||||
peripherals.GPIO34,
|
||||
peripherals.GPIO33,
|
||||
&ledc,
|
||||
&timer,
|
||||
peripherals.GPIO38,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut ledc = esp_hal::ledc::Ledc::new(peripherals.LEDC);
|
||||
ledc.set_global_slow_clock(esp_hal::ledc::LSGlobalClkSource::APBClk);
|
||||
|
||||
let mut timer = ledc.timer::<LowSpeed>(esp_hal::ledc::timer::Number::Timer3);
|
||||
timer.configure(esp_hal::ledc::timer::config::Config {
|
||||
duty: esp_hal::ledc::timer::config::Duty::Duty8Bit,
|
||||
clock_source: esp_hal::ledc::timer::LSClockSource::APBClk,
|
||||
frequency: esp_hal::time::Rate::from_hz(256),
|
||||
}).unwrap();
|
||||
|
||||
let mut backlight: esp_hal::ledc::channel::Channel<'_, _> =
|
||||
ledc.channel(esp_hal::ledc::channel::Number::Channel7, peripherals.GPIO38);
|
||||
|
||||
backlight
|
||||
.configure(esp_hal::ledc::channel::config::Config {
|
||||
timer: &timer,
|
||||
duty_pct: 100,
|
||||
pin_config: esp_hal::ledc::channel::config::PinConfig::PushPull,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
||||
|
||||
display
|
||||
.set_pixels(
|
||||
0,
|
||||
|
|
@ -86,4 +68,6 @@ fn _main() {
|
|||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
display.set_backlight_brightness(100).unwrap();
|
||||
}
|
||||
|
|
|
|||
217
src/display.rs
217
src/display.rs
|
|
@ -1,7 +1,10 @@
|
|||
//! Create and initialize ST7789 display driver
|
||||
// use display_interface_spi::SPIInterface;
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use esp_hal::ledc::{LowSpeed, channel::ChannelIFace};
|
||||
use mipidsi::{
|
||||
Builder, Display as MipiDisplay,
|
||||
interface::SpiInterface,
|
||||
|
|
@ -10,65 +13,119 @@ use mipidsi::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct Display {}
|
||||
|
||||
type Drawable<'a> = MipiDisplay<
|
||||
SpiInterface<
|
||||
'a,
|
||||
ExclusiveDevice<
|
||||
esp_hal::spi::master::Spi<'a, esp_hal::Blocking>,
|
||||
esp_hal::gpio::Output<'a>,
|
||||
esp_hal::delay::Delay,
|
||||
>,
|
||||
esp_hal::gpio::Output<'a>,
|
||||
>,
|
||||
ST7789,
|
||||
esp_hal::gpio::Output<'a>,
|
||||
>;
|
||||
|
||||
/// Display width
|
||||
pub const DISPLAY_SIZE_WIDTH: u16 = 240;
|
||||
/// Display height
|
||||
pub const DISPLAY_SIZE_HEIGHT: u16 = 135;
|
||||
|
||||
pub const DISPLAY_BUFFER_SIZE: usize =
|
||||
DISPLAY_SIZE_WIDTH as usize * DISPLAY_SIZE_HEIGHT as usize * 2;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BuildError {
|
||||
#[error("SPI config error: {0}")]
|
||||
SpiConfigError(#[from] esp_hal::spi::master::ConfigError),
|
||||
#[error("Some error occurred when initialising the MIPI DSI display")]
|
||||
MipidsiInitError,
|
||||
#[error("SPI error: {0:?}")]
|
||||
SpiError(esp_hal::spi::Error),
|
||||
/// The type for controlling the cardputer's display
|
||||
///
|
||||
/// Example usage:
|
||||
/// ```rust
|
||||
/// cardputer_bsc_nostd::setup_backlight! {
|
||||
/// let (mut ledc, mut timer) = setup_backlight(peripherals.LEDC);
|
||||
/// }
|
||||
///
|
||||
/// let mut display = cardputer_bsc_nostd::display::Display::build(
|
||||
/// peripherals.SPI2,
|
||||
/// peripherals.GPIO36,
|
||||
/// peripherals.GPIO35,
|
||||
/// peripherals.GPIO37,
|
||||
/// peripherals.GPIO34,
|
||||
/// peripherals.GPIO33,
|
||||
/// &ledc,
|
||||
/// &timer,
|
||||
/// peripherals.GPIO38,
|
||||
/// )
|
||||
/// .unwrap();
|
||||
///
|
||||
/// display.set_backlight_brightness(100).unwrap();
|
||||
/// ```
|
||||
pub struct Display<'a> {
|
||||
mipi_display: Drawable<'a>,
|
||||
backlight: esp_hal::ledc::channel::Channel<'a, LowSpeed>,
|
||||
}
|
||||
|
||||
pub fn build<'a>(
|
||||
impl<'a> Deref for Display<'a> {
|
||||
type Target = Drawable<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.mipi_display
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for Display<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.mipi_display
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenience macro which simplifies setting up the LED controller and timer for the display's backlight.
|
||||
///
|
||||
/// Example usage:
|
||||
/// ```rust
|
||||
/// cardputer_bsc_nostd::setup_backlight! {
|
||||
/// let (mut ledc, mut timer) = setup_backlight(peripherals.LEDC);
|
||||
/// }
|
||||
///
|
||||
/// let mut display = cardputer_bsc_nostd::display::Display::build(
|
||||
/// peripherals.SPI2,
|
||||
/// peripherals.GPIO36,
|
||||
/// peripherals.GPIO35,
|
||||
/// peripherals.GPIO37,
|
||||
/// peripherals.GPIO34,
|
||||
/// peripherals.GPIO33,
|
||||
/// &ledc,
|
||||
/// &timer,
|
||||
/// peripherals.GPIO38,
|
||||
/// )
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// You can rename the `ledc` and `timer` bindings, and choose a different expression in place of `peripherals.LEDC`,
|
||||
/// but otherwise you must leave the rest unchanged.
|
||||
///
|
||||
/// Unfortunately the fictional `setup_backlight` function that the accepted syntax looks like it is invoking can't
|
||||
/// be written as `timer` borrows from `ledc`.
|
||||
#[macro_export]
|
||||
macro_rules! setup_backlight {
|
||||
(let (mut $ledc_ident:ident, mut $timer_ident:ident) = setup_backlight($ledc:expr)$(;)?) => {
|
||||
let mut $ledc_ident = esp_hal::ledc::Ledc::new($ledc);
|
||||
$ledc_ident.set_global_slow_clock(esp_hal::ledc::LSGlobalClkSource::APBClk);
|
||||
|
||||
let mut $timer_ident =
|
||||
$ledc_ident.timer::<esp_hal::ledc::LowSpeed>(esp_hal::ledc::timer::Number::Timer3);
|
||||
|
||||
esp_hal::ledc::timer::TimerIFace::configure(
|
||||
&mut $timer_ident,
|
||||
esp_hal::ledc::timer::config::Config {
|
||||
duty: esp_hal::ledc::timer::config::Duty::Duty8Bit,
|
||||
clock_source: esp_hal::ledc::timer::LSClockSource::APBClk,
|
||||
frequency: esp_hal::time::Rate::from_hz(256),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a> Display<'a> {
|
||||
/// Initialises the cardputer's display.
|
||||
///
|
||||
/// The backlight is left powered off as this function doesn't clear the LCD controller's display
|
||||
/// buffer and it usually boots up with random noise. You can call [Display::set_backlight_brightness]
|
||||
/// to switch the backlight on.
|
||||
pub fn new(
|
||||
spi: esp_hal::peripherals::SPI2<'a>,
|
||||
sck: esp_hal::peripherals::GPIO36<'a>,
|
||||
dc: esp_hal::peripherals::GPIO35<'a>,
|
||||
cs: esp_hal::peripherals::GPIO37<'a>,
|
||||
rs: esp_hal::peripherals::GPIO34<'a>,
|
||||
rst: esp_hal::peripherals::GPIO33<'a>,
|
||||
) -> Result<Drawable<'a>, BuildError> {
|
||||
static mut DISPLAY_BUFFER: [u8; 1000] = [0; 1000];
|
||||
|
||||
// let spi_config = SpiConfig::new().baudrate(80.MHz().into());
|
||||
// let device_config = DriverConfig::new();
|
||||
// let spi = SpiDeviceDriver::new_single(
|
||||
// spi,
|
||||
// sck,
|
||||
// dc,
|
||||
// Option::<AnyIOPin>::None,
|
||||
// Some(cs),
|
||||
// &device_config,
|
||||
// &spi_config,
|
||||
// )?;
|
||||
ledc: &'a esp_hal::ledc::Ledc<'a>,
|
||||
timer: &'a esp_hal::ledc::timer::Timer<'a, LowSpeed>,
|
||||
backlight: esp_hal::peripherals::GPIO38<'a>,
|
||||
) -> Result<Self, DisplayInitError> {
|
||||
static mut DISPLAY_BUFFER: [u8; DISPLAY_BUFFER_SIZE] = [0; DISPLAY_BUFFER_SIZE];
|
||||
|
||||
let spi = esp_hal::spi::master::Spi::new(
|
||||
spi,
|
||||
esp_hal::spi::master::Config::default().with_frequency(esp_hal::time::Rate::from_mhz(80)),
|
||||
esp_hal::spi::master::Config::default()
|
||||
.with_frequency(esp_hal::time::Rate::from_mhz(80)),
|
||||
)?
|
||||
.with_sck(sck)
|
||||
.with_mosi(dc);
|
||||
|
|
@ -103,7 +160,7 @@ pub fn build<'a>(
|
|||
.display_offset(40, 53)
|
||||
.reset_pin(rst)
|
||||
.init(&mut esp_hal::delay::Delay::new())
|
||||
.map_err(|_| BuildError::MipidsiInitError)?;
|
||||
.map_err(|_| DisplayInitError::MipidsiInitError)?;
|
||||
// Can't capture the error since it's a public type
|
||||
// in a private module and not re-exported. The master
|
||||
// branch of the mipidsi repo does have a fix but it's
|
||||
|
|
@ -113,7 +170,7 @@ pub fn build<'a>(
|
|||
.set_orientation(Orientation::new().rotate(mipidsi::options::Rotation::Deg90))
|
||||
.map_err(|e| match e {
|
||||
mipidsi::interface::SpiError::Spi(e) => match e {
|
||||
embedded_hal_bus::spi::DeviceError::Spi(e) => BuildError::SpiError(e),
|
||||
embedded_hal_bus::spi::DeviceError::Spi(e) => DisplayInitError::SpiError(e),
|
||||
embedded_hal_bus::spi::DeviceError::Cs(e) => match e {},
|
||||
},
|
||||
mipidsi::interface::SpiError::Dc(e) => match e {},
|
||||
|
|
@ -122,11 +179,67 @@ pub fn build<'a>(
|
|||
.set_vertical_scroll_offset(0)
|
||||
.map_err(|e| match e {
|
||||
mipidsi::interface::SpiError::Spi(e) => match e {
|
||||
embedded_hal_bus::spi::DeviceError::Spi(e) => BuildError::SpiError(e),
|
||||
embedded_hal_bus::spi::DeviceError::Spi(e) => DisplayInitError::SpiError(e),
|
||||
embedded_hal_bus::spi::DeviceError::Cs(e) => match e {},
|
||||
},
|
||||
mipidsi::interface::SpiError::Dc(e) => match e {},
|
||||
})?;
|
||||
|
||||
Ok(drawable)
|
||||
let mut backlight: esp_hal::ledc::channel::Channel<'_, _> =
|
||||
ledc.channel(esp_hal::ledc::channel::Number::Channel7, backlight);
|
||||
|
||||
backlight
|
||||
.configure(esp_hal::ledc::channel::config::Config {
|
||||
timer,
|
||||
duty_pct: 0,
|
||||
pin_config: esp_hal::ledc::channel::config::PinConfig::PushPull,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Ok(Self {
|
||||
mipi_display: drawable,
|
||||
backlight,
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the brightness of the display's backlight. `brightness_percentage` should be in the closed range \[0,100];
|
||||
/// this function will return [esp_hal::ledc::channel::Error::Duty] if not.
|
||||
pub fn set_backlight_brightness(
|
||||
&self,
|
||||
brightness_percentage: u8,
|
||||
) -> Result<(), esp_hal::ledc::channel::Error> {
|
||||
self.backlight.set_duty(brightness_percentage)
|
||||
}
|
||||
}
|
||||
|
||||
type Drawable<'a> = MipiDisplay<
|
||||
SpiInterface<
|
||||
'a,
|
||||
ExclusiveDevice<
|
||||
esp_hal::spi::master::Spi<'a, esp_hal::Blocking>,
|
||||
esp_hal::gpio::Output<'a>,
|
||||
esp_hal::delay::Delay,
|
||||
>,
|
||||
esp_hal::gpio::Output<'a>,
|
||||
>,
|
||||
ST7789,
|
||||
esp_hal::gpio::Output<'a>,
|
||||
>;
|
||||
|
||||
/// Display width
|
||||
pub const DISPLAY_SIZE_WIDTH: u16 = 240;
|
||||
/// Display height
|
||||
pub const DISPLAY_SIZE_HEIGHT: u16 = 135;
|
||||
|
||||
pub const DISPLAY_BUFFER_SIZE: usize =
|
||||
DISPLAY_SIZE_WIDTH as usize * DISPLAY_SIZE_HEIGHT as usize * 2;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DisplayInitError {
|
||||
#[error("SPI config error: {0}")]
|
||||
SpiConfigError(#[from] esp_hal::spi::master::ConfigError),
|
||||
#[error("Some error occurred when initialising the MIPI DSI display")]
|
||||
MipidsiInitError,
|
||||
#[error("SPI error: {0:?}")]
|
||||
SpiError(esp_hal::spi::Error),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue