Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions ui-stm32/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@ defmt = "1.0.1"
defmt-rtt = "1.0.0"

embassy-executor = { version = "0.8.0", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
embassy-futures = { version = "0.1.1", features = ["defmt"] }
embassy-stm32 = { version = "0.3.0", features = ["defmt", "stm32f405rg", "memory-x", "time-driver-tim1", "exti", "chrono"] }
embassy-time = { version = "0.5.0", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
embassy-sync = { version = "0.7.1", features = ["defmt"] }
num_enum = { version = "0.7.4", default-features = false }
hex = { version = "0.4.3", default-features = false }
heapless = { version = "0.9.1", features = ["defmt"] }
embedded-io-async = "0.6.1"
embedded-io = { version = "0.6.1", default-features = false }
ili9341 = "0.6.0"
display-interface = "0.5.0"
embedded-graphics-core = { version = "0.4.0", default-features = false }
bitmap-font = "0.3.0"
embedded-graphics = "0.8.1"
embedded-hal = { version = "1.0.0", default-features = false }
mipidsi = "0.9.0"
embassy-embedded-hal = "0.5.0"
static_cell = "2.1.1"

[profile.release]
debug = 2

[profile.dev]
debug = 2
opt-level = "s"

# Tell `cargo machete` that these packages are needed
[package.metadata.cargo-machete]
ignored = ["cortex-m-rt"]
130 changes: 33 additions & 97 deletions ui-stm32/src/board/ev12.rs
Original file line number Diff line number Diff line change
@@ -1,114 +1,44 @@
use super::{Button, Eeprom, Keyboard, NetTx, StatusLed};
use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
use core::cell::RefCell;
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
use embassy_stm32::{
bind_interrupts,
exti::ExtiInput,
gpio::{Input, Level, Output, Pull, Speed},
i2c::{mode::Master, I2c},
mode::{Async, Blocking},
peripherals,
spi::{Spi, Word},
spi::Spi,
usart::{self, UartRx, UartTx},
};
use embassy_sync::blocking_mutex::{raw::NoopRawMutex, NoopMutex};
use embassy_time::Delay;
use embedded_graphics::{pixelcolor::Rgb565, prelude::*};
use ili9341::{Ili9341, Orientation};
use mipidsi::{
interface::SpiInterface,
models::ILI9341Rgb565,
options::{ColorOrder, Orientation},
Builder, Display,
};
use static_cell::StaticCell;
use ui_app::{Led, Outputs};

struct DisplayData {
// These fields are not used, but we need to keep them alive so that the chip select output is
// held low and the backlight output is held high.
_chip_select: Output<'static>,
_backlight: Output<'static>,

data_command: Output<'static>,
spi: Spi<'static, Blocking>,
}

impl DisplayData {
fn new(
mut backlight: Output<'static>,
mut chip_select: Output<'static>,
data_command: Output<'static>,
spi: Spi<'static, Blocking>,
) -> Self {
backlight.set_high();
chip_select.set_low();

Self {
_backlight: backlight,
_chip_select: chip_select,
data_command,
spi,
}
}

fn write(&mut self, data: DataFormat<'_>) -> Result<(), DisplayError> {
use DataFormat::*;
match data {
U8(slice) => self.write_slice(slice),
U16(slice) => self.write_slice(slice),
U16BE(slice) => self.write_slice(slice),
U16LE(slice) => self.write_slice(slice),
U8Iter(iter) => self.write_iter(iter),
U16BEIter(iter) => self.write_iter(iter),
U16LEIter(iter) => self.write_iter(iter),
_ => unreachable!(),
}
}

fn write_slice<W: Word>(&mut self, data: &[W]) -> Result<(), DisplayError> {
self.spi.blocking_write(data).unwrap();
Ok(())
}

fn write_iter<W: Word>(
&mut self,
iter: &mut dyn Iterator<Item = W>,
) -> Result<(), DisplayError> {
// 1kb of render buffer
const CHUNK_SIZE: usize = 512;

// XXX(RLB) Very C-style iteration, could probably write this in a way that would optimize
// better.
let mut data = [W::default(); CHUNK_SIZE];
let mut n = 0;
for (i, x) in iter.enumerate() {
data[i % CHUNK_SIZE] = x;
n += 1;

if n > 0 && n % CHUNK_SIZE == 0 {
self.spi.blocking_write(&data).unwrap();
n = 0;
}
}

self.spi.blocking_write(&data[..n]).unwrap();
Ok(())
}
}

impl WriteOnlyDataCommand for DisplayData {
fn send_commands(&mut self, cmd: DataFormat<'_>) -> Result<(), DisplayError> {
self.data_command.set_low();
self.write(cmd)
}

fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
self.data_command.set_high();
self.write(buf)
}
}
type DisplaySpiDevice = SpiDevice<'static, NoopRawMutex, Spi<'static, Blocking>, Output<'static>>;
type DisplaySpiInterface = SpiInterface<'static, DisplaySpiDevice, Output<'static>>;

pub struct Board {
status_led: StatusLed,
screen: Ili9341<DisplayData, Output<'static>>,
screen: Display<DisplaySpiInterface, ILI9341Rgb565, Output<'static>>,
net_tx: NetTx<UartTx<'static, Async>>,
i2c: I2c<'static, Blocking, Master>,
pub button_a: Option<Button>,
pub button_b: Option<Button>,
pub keyboard: Option<Keyboard>,
pub net_rx: Option<UartRx<'static, Async>>,

// This field isn't used, but is held to keep the pin low instead of floating
#[allow(dead_code)]
backlight: Output<'static>,
}

bind_interrupts!(struct Irqs {
Expand Down Expand Up @@ -179,6 +109,9 @@ impl Board {
let keyboard = Keyboard::new(cols, rows);

// Screen
static SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<'static, Blocking>>>> = StaticCell::new();
let display_buffer = cortex_m::singleton!(: [u8; 512] = [0; 512]).unwrap();

let chip_select = Output::new(p.PB8, Level::Low, Speed::Low);
let data_command = Output::new(p.PB9, Level::Low, Speed::Low);
let reset = Output::new(p.PC13, Level::Low, Speed::Low);
Expand All @@ -193,15 +126,17 @@ impl Board {
config
};
let spi = Spi::new_blocking_txonly(p.SPI1, p.PA5, p.PA7, config);

let screen = Ili9341::new(
DisplayData::new(backlight, chip_select, data_command, spi),
reset,
&mut Delay,
Orientation::Portrait,
ili9341::DisplaySize240x320,
)
.unwrap();
let spi_bus = NoopMutex::new(RefCell::new(spi));
let spi_bus = SPI_BUS.init(spi_bus);
let spi_dev = SpiDevice::new(spi_bus, chip_select);
let spi_if = SpiInterface::new(spi_dev, data_command, display_buffer);

let screen = Builder::new(ILI9341Rgb565, spi_if)
.reset_pin(reset)
.orientation(Orientation::new().flip_horizontal())
.color_order(ColorOrder::Bgr)
.init(&mut Delay)
.unwrap();

// NET UART
let net_uart = {
Expand Down Expand Up @@ -230,6 +165,7 @@ impl Board {
button_b: Some(button_b),
keyboard: Some(keyboard),
net_rx: Some(net_rx),
backlight,
}
}
}
Expand Down
130 changes: 33 additions & 97 deletions ui-stm32/src/board/ev13.rs
Original file line number Diff line number Diff line change
@@ -1,114 +1,44 @@
use super::{Button, Eeprom, Keyboard, NetTx, StatusLed};
use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
use core::cell::RefCell;
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
use embassy_stm32::{
bind_interrupts,
exti::ExtiInput,
gpio::{Input, Level, Output, Pull, Speed},
i2c::{mode::Master, I2c},
mode::{Async, Blocking},
peripherals,
spi::{Spi, Word},
spi::Spi,
usart::{self, UartRx, UartTx},
};
use embassy_sync::blocking_mutex::{raw::NoopRawMutex, NoopMutex};
use embassy_time::Delay;
use embedded_graphics::{pixelcolor::Rgb565, prelude::*};
use ili9341::{Ili9341, Orientation};
use mipidsi::{
interface::SpiInterface,
models::ILI9341Rgb565,
options::{ColorOrder, Orientation},
Builder, Display,
};
use static_cell::StaticCell;
use ui_app::{Led, Outputs};

struct DisplayData {
// These fields are not used, but we need to keep them alive so that the chip select output is
// held low and the backlight output is held high.
_chip_select: Output<'static>,
_backlight: Output<'static>,

data_command: Output<'static>,
spi: Spi<'static, Blocking>,
}

impl DisplayData {
fn new(
mut backlight: Output<'static>,
mut chip_select: Output<'static>,
data_command: Output<'static>,
spi: Spi<'static, Blocking>,
) -> Self {
backlight.set_high();
chip_select.set_low();

Self {
_backlight: backlight,
_chip_select: chip_select,
data_command,
spi,
}
}

fn write(&mut self, data: DataFormat<'_>) -> Result<(), DisplayError> {
use DataFormat::*;
match data {
U8(slice) => self.write_slice(slice),
U16(slice) => self.write_slice(slice),
U16BE(slice) => self.write_slice(slice),
U16LE(slice) => self.write_slice(slice),
U8Iter(iter) => self.write_iter(iter),
U16BEIter(iter) => self.write_iter(iter),
U16LEIter(iter) => self.write_iter(iter),
_ => unreachable!(),
}
}

fn write_slice<W: Word>(&mut self, data: &[W]) -> Result<(), DisplayError> {
self.spi.blocking_write(data).unwrap();
Ok(())
}

fn write_iter<W: Word>(
&mut self,
iter: &mut dyn Iterator<Item = W>,
) -> Result<(), DisplayError> {
// 1kb of render buffer
const CHUNK_SIZE: usize = 512;

// XXX(RLB) Very C-style iteration, could probably write this in a way that would optimize
// better.
let mut data = [W::default(); CHUNK_SIZE];
let mut n = 0;
for (i, x) in iter.enumerate() {
data[i % CHUNK_SIZE] = x;
n += 1;

if n > 0 && n % CHUNK_SIZE == 0 {
self.spi.blocking_write(&data).unwrap();
n = 0;
}
}

self.spi.blocking_write(&data[..n]).unwrap();
Ok(())
}
}

impl WriteOnlyDataCommand for DisplayData {
fn send_commands(&mut self, cmd: DataFormat<'_>) -> Result<(), DisplayError> {
self.data_command.set_low();
self.write(cmd)
}

fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
self.data_command.set_high();
self.write(buf)
}
}
type DisplaySpiDevice = SpiDevice<'static, NoopRawMutex, Spi<'static, Blocking>, Output<'static>>;
type DisplaySpiInterface = SpiInterface<'static, DisplaySpiDevice, Output<'static>>;

pub struct Board {
status_led: StatusLed,
screen: Ili9341<DisplayData, Output<'static>>,
screen: Display<DisplaySpiInterface, ILI9341Rgb565, Output<'static>>,
net_tx: NetTx<UartTx<'static, Async>>,
i2c: I2c<'static, Blocking, Master>,
pub button_a: Option<Button>,
pub button_b: Option<Button>,
pub keyboard: Option<Keyboard>,
pub net_rx: Option<UartRx<'static, Async>>,

// This field isn't used, but is held to keep the pin low instead of floating
#[allow(dead_code)]
backlight: Output<'static>,
}

bind_interrupts!(struct Irqs {
Expand Down Expand Up @@ -179,6 +109,9 @@ impl Board {
let keyboard = Keyboard::new(cols, rows);

// Screen
static SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<'static, Blocking>>>> = StaticCell::new();
let display_buffer = cortex_m::singleton!(: [u8; 512] = [0; 512]).unwrap();

let chip_select = Output::new(p.PB8, Level::Low, Speed::Low);
let data_command = Output::new(p.PB9, Level::Low, Speed::Low);
let reset = Output::new(p.PC13, Level::Low, Speed::Low);
Expand All @@ -193,15 +126,17 @@ impl Board {
config
};
let spi = Spi::new_blocking_txonly(p.SPI1, p.PA5, p.PA7, config);

let screen = Ili9341::new(
DisplayData::new(backlight, chip_select, data_command, spi),
reset,
&mut Delay,
Orientation::Portrait,
ili9341::DisplaySize240x320,
)
.unwrap();
let spi_bus = NoopMutex::new(RefCell::new(spi));
let spi_bus = SPI_BUS.init(spi_bus);
let spi_dev = SpiDevice::new(spi_bus, chip_select);
let spi_if = SpiInterface::new(spi_dev, data_command, display_buffer);

let screen = Builder::new(ILI9341Rgb565, spi_if)
.reset_pin(reset)
.orientation(Orientation::new().flip_horizontal())
.color_order(ColorOrder::Bgr)
.init(&mut Delay)
.unwrap();

// NET UART
let net_uart = {
Expand Down Expand Up @@ -230,6 +165,7 @@ impl Board {
button_b: Some(button_b),
keyboard: Some(keyboard),
net_rx: Some(net_rx),
backlight,
}
}
}
Expand Down