Skip to content

Implement ST7306 display #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 6, 2023
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
52 changes: 12 additions & 40 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions b1display/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ usbd-serial = "0.1.1"
usbd-hid = "0.5.1"
fugit = "0.3.6"

display-interface-spi = "0.4.1"
mipidsi = "0.6.0"
st7306-lcd = { git = "ssh://[email protected]/FrameworkComputer/st7306.git" }
embedded-graphics = "0.7"
tinybmp = "0.4.0"

Expand Down
95 changes: 63 additions & 32 deletions b1display/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ use cortex_m::delay::Delay;
use defmt_rtt as _;
use embedded_hal::digital::v2::{InputPin, OutputPin};

use mipidsi::Orientation;
use rp2040_hal::gpio::bank0::Gpio18;
use rp2040_hal::gpio::{Output, Pin, PushPull};
//#[cfg(debug_assertions)]
//use panic_probe as _;
use rp2040_panic_usb_boot as _;

use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::*;
use embedded_hal::blocking::spi;
use st7306_lcd::ST7306;

// Provide an alias for our BSP so we can switch targets quickly.
// Uncomment the BSP you included in Cargo.toml, the rest of the code does not need to change.
Expand All @@ -27,7 +28,7 @@ use lotus_inputmodules::lotus_lcd_hal as bsp;

use bsp::hal::{
clocks::{init_clocks_and_plls, Clock},
pac,
gpio, pac,
sio::Sio,
usb,
watchdog::Watchdog,
Expand All @@ -42,7 +43,7 @@ use usb_device::{class_prelude::*, prelude::*};
use usbd_serial::{SerialPort, USB_CLASS_CDC};

// Used to demonstrate writing formatted strings
use core::fmt::Write;
use core::fmt::{Debug, Write};
use heapless::String;

use lotus_inputmodules::control::*;
Expand Down Expand Up @@ -126,10 +127,12 @@ fn main() -> ! {
let _spi_sclk = pins.scl.into_mode::<bsp::hal::gpio::FunctionSpi>();
let _spi_mosi = pins.sda.into_mode::<bsp::hal::gpio::FunctionSpi>();
let _spi_miso = pins.miso.into_mode::<bsp::hal::gpio::FunctionSpi>();
let spi = bsp::hal::Spi::<_, _, 8>::new(pac.SPI1);
let spi = bsp::hal::Spi::<_, _, 8>::new(pac.SPI0);
// Display control pins
let dc = pins.dc.into_push_pull_output();
let mut lcd_led = pins.backlight.into_push_pull_output();
//let mut lcd_led = pins.backlight.into_push_pull_output();
let mut cs = pins.cs.into_push_pull_output();
cs.set_low().unwrap();
let rst = pins.rstb.into_push_pull_output();

let spi = spi.init(
Expand All @@ -139,27 +142,51 @@ fn main() -> ! {
&embedded_hal::spi::MODE_0,
);

// Create a DisplayInterface from SPI and DC pin, with no manual CS control
let di = display_interface_spi::SPIInterfaceNoCS::new(spi, dc);
let mut disp = mipidsi::Builder::st7735s(di)
.with_invert_colors(true) // Looks cooler. TODO: Should invert image not entire screen
.with_orientation(Orientation::PortraitInverted(false))
.init(&mut delay, Some(rst))
let mut disp: ST7306<
rp2040_hal::Spi<rp2040_hal::spi::Enabled, pac::SPI0, 8>,
Pin<gpio::bank0::Gpio20, Output<PushPull>>,
Pin<gpio::bank0::Gpio17, Output<PushPull>>,
Pin<gpio::bank0::Gpio21, Output<PushPull>>,
25,
200,
> = ST7306::new(spi, dc, cs, rst, false, 300, 400);
disp.init(&mut delay).unwrap();

// TODO: Seems broken
//disp.clear(Rgb565::WHITE).unwrap();
Rectangle::new(Point::new(0, 0), Size::new(300, 400))
.into_styled(PrimitiveStyle::with_fill(Rgb565::WHITE))
.draw(&mut disp)
.unwrap();
disp.clear(Rgb565::WHITE).unwrap();

let logo_rect = draw_logo(&mut disp).unwrap();
Rectangle::new(Point::new(10, 10), Size::new(10, 10))
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut disp)
.unwrap();
Rectangle::new(Point::new(20, 20), Size::new(10, 10))
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut disp)
.unwrap();
Rectangle::new(Point::new(30, 30), Size::new(10, 10))
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut disp)
.unwrap();
Rectangle::new(Point::new(40, 40), Size::new(10, 10))
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut disp)
.unwrap();
Rectangle::new(Point::new(50, 50), Size::new(10, 10))
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut disp)
.unwrap();
draw_text(
&mut disp,
"Framework",
Point::new(0, LOGO_OFFSET + logo_rect.size.height as i32),
Point::new(LOGO_OFFSET_X, LOGO_OFFSET_Y + logo_rect.size.height as i32),
)
.unwrap();

// Wait until the background and image have been rendered otherwise
// the screen will show random pixels for a brief moment
lcd_led.set_high().unwrap();

let sleep = pins.sleep.into_pull_down_input();

let mut state = State {
Expand All @@ -172,10 +199,9 @@ fn main() -> ! {
let mut prev_timer = timer.get_counter().ticks();

loop {
// TODO: Current hardware revision does not have the sleep pin wired up :(
// Go to sleep if the host is sleeping
let _host_sleeping = sleep.is_low().unwrap();
//handle_sleep(host_sleeping, &mut state, &mut matrix, &mut delay);
let host_sleeping = sleep.is_low().unwrap();
handle_sleep(host_sleeping, &mut state, &mut delay, &mut disp);

// Handle period display updates. Don't do it too often
if timer.get_counter().ticks() > prev_timer + 20_000 {
Expand Down Expand Up @@ -212,11 +238,11 @@ fn main() -> ! {
Ok(count) => {
if let Some(command) = parse_command(count, &buf) {
if let Command::Sleep(go_sleeping) = command {
handle_sleep(go_sleeping, &mut state, &mut delay, &mut lcd_led);
handle_sleep(go_sleeping, &mut state, &mut delay, &mut disp);
} else if let SleepState::Awake = state.sleeping {
// While sleeping no command is handled, except waking up
//handle_command(&command, &mut disp, logo_rect);
if let Some(response) = handle_command(&command, &mut disp, logo_rect) {
if let Some(response) = handle_command(&command, logo_rect, &mut disp) {
let _ = serial.write(&response);
};
}
Expand All @@ -227,20 +253,25 @@ fn main() -> ! {
}
}

fn handle_sleep(
fn handle_sleep<SPI, DC, CS, RST, const COLS: usize, const ROWS: usize>(
go_sleeping: bool,
state: &mut State,
_delay: &mut Delay,
lcd_led: &mut Pin<Gpio18, Output<PushPull>>,
) {
disp: &mut ST7306<SPI, DC, CS, RST, COLS, ROWS>,
) where
SPI: spi::Write<u8>,
DC: OutputPin,
CS: OutputPin,
RST: OutputPin,
<SPI as spi::Write<u8>>::Error: Debug,
{
match (state.sleeping.clone(), go_sleeping) {
(SleepState::Awake, false) => (),
(SleepState::Awake, true) => {
state.sleeping = SleepState::Sleeping;
//state.grid = display_sleep();

// Turn off backlight
lcd_led.set_low().unwrap();
// Turn off display
disp.on_off(false).unwrap();

// TODO: Power Display controller down

Expand All @@ -252,10 +283,10 @@ fn handle_sleep(
// Restore back grid before sleeping
state.sleeping = SleepState::Awake;

// TODO: Power display controller back on
// Turn display back on
disp.on_off(true).unwrap();

// Turn backlight back on
lcd_led.set_high().unwrap();
// TODO: Power display controller back on
}
}
}
31 changes: 31 additions & 0 deletions control.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ def main():
help="Get device version", action="store_true")
parser.add_argument("--serial-dev", help="Change the serial dev. Probably /dev/ttyACM0 on Linux, COM0 on Windows",
default='/dev/ttyACM0')

parser.add_argument(
"--disp-str", help="Display a string on the LCD Display", type=str)
parser.add_argument("--display-on", help="Control display power",
action=argparse.BooleanOptionalAction)
parser.add_argument("--invert-screen", help="Invert display",
action=argparse.BooleanOptionalAction)

args = parser.parse_args()

if args.serial_dev is not None:
Expand Down Expand Up @@ -179,6 +187,12 @@ def main():
show_string(args.string)
elif args.symbols is not None:
show_symbols(args.symbols)
elif args.disp_str is not None:
display_string(args.disp_str)
elif args.display_on is not None:
display_on_cmd(args.display_on)
elif args.invert_screen is not None:
invert_screen_cmd(args.invert_screen)
elif args.version:
version = get_version()
print(f"Device version: {version}")
Expand Down Expand Up @@ -922,6 +936,23 @@ def gui():

window.close()


def display_string(disp_str):
b = [ord(x) for x in disp_str]
command = FWK_MAGIC + [0x09, len(disp_str)] + b
send_command(command)


def display_on_cmd(on):
command = FWK_MAGIC + [0x014, int(on)]
send_command(command)


def invert_screen_cmd(invert):
command = FWK_MAGIC + [0x015, int(invert)]
send_command(command)


# 5x6 symbol font. Leaves 2 pixels on each side empty
# We can leave one row empty below and then the display fits 5 of these digits.

Expand Down
5 changes: 2 additions & 3 deletions lotus-inputmodules/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ fugit = "0.3.6"
is31fl3741 = { git = "https://github.com/JohnAZoidberg/is31fl3741", branch = "all-at-once", optional = true }

# B1 Display
display-interface-spi = { version = "0.4.1", optional = true }
mipidsi = { version = "0.6.0", optional = true }
st7306-lcd = { git = "ssh://[email protected]/FrameworkComputer/st7306.git", optional = true }
embedded-graphics = { version = "0.7", optional = true }
tinybmp = { version = "0.4.0", optional = true }

Expand All @@ -42,5 +41,5 @@ ws2812-pio = { version = "0.5.0", optional = true }
[features]
default = []
ledmatrix = [ "is31fl3741" ]
b1display = [ "display-interface-spi", "mipidsi", "embedded-graphics", "tinybmp" ]
b1display = [ "st7306-lcd", "embedded-graphics", "tinybmp" ]
c1minimal = ["smart-leds", "ws2812-pio" ]
Loading