Set up an app for the adafruit TFT
This commit is contained in:
parent
911bc97b69
commit
2b291a3196
File diff suppressed because it is too large
Load Diff
|
@ -32,5 +32,7 @@ members = [
|
|||
"sgf",
|
||||
"timezone-testing",
|
||||
"tree",
|
||||
"visions/server", "gm-dash/server", "halloween-leds"
|
||||
"visions/server",
|
||||
"gm-dash/server",
|
||||
"pico-st7789"
|
||||
]
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[target.thumbv6m-none-eabi]
|
||||
rustflags = [
|
||||
"-C", "link-arg=--nmagic",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "no-vectorize-loops",
|
||||
]
|
||||
|
||||
runner = "elf2uf2-rs -d"
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "pico-st7789"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cortex-m-rt = "0.7.3"
|
||||
embedded-hal = "1.0.0"
|
||||
fugit = "0.3.7"
|
||||
panic-halt = "1.0.0"
|
||||
rp-pico = "0.9.0"
|
|
@ -0,0 +1,225 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiBus};
|
||||
use fugit::RateExtU32;
|
||||
use panic_halt as _;
|
||||
use rp_pico::{
|
||||
entry,
|
||||
hal::{
|
||||
clocks::init_clocks_and_plls,
|
||||
gpio::{FunctionSio, Pin, PinId, PullDown, SioOutput},
|
||||
spi::{Enabled, Spi, SpiDevice, ValidSpiPinout},
|
||||
Clock, Sio, Timer, Watchdog,
|
||||
},
|
||||
pac, Pins,
|
||||
};
|
||||
|
||||
const XOSC_CRYSTAL_FREQ: u32 = 12_000_000; // MHz, https://forums.raspberrypi.com/viewtopic.php?t=356764
|
||||
|
||||
struct Step {
|
||||
param_cnt: usize,
|
||||
command: u8,
|
||||
params: [u8; 4],
|
||||
delay: Option<u32>,
|
||||
}
|
||||
|
||||
impl Step {
|
||||
fn send_command<D, Pinout, P>(
|
||||
&self,
|
||||
spi: &mut Spi<Enabled, D, Pinout, 8>,
|
||||
data_command: &mut Pin<P, FunctionSio<SioOutput>, PullDown>,
|
||||
) where
|
||||
D: SpiDevice,
|
||||
Pinout: ValidSpiPinout<D>,
|
||||
P: PinId,
|
||||
{
|
||||
let _ = data_command.set_low();
|
||||
let _ = spi.write(&[self.command]);
|
||||
let _ = data_command.set_high();
|
||||
let _ = spi.write(&self.params[0..self.param_cnt]);
|
||||
}
|
||||
}
|
||||
|
||||
const NOP: u8 = 0x00;
|
||||
|
||||
const SWRESET: Step = Step {
|
||||
param_cnt: 0,
|
||||
command: 0x01,
|
||||
params: [0, 0, 0, 0],
|
||||
delay: Some(150),
|
||||
};
|
||||
const SLPOUT: Step = Step {
|
||||
param_cnt: 0,
|
||||
command: 0x11,
|
||||
params: [0, 0, 0, 0],
|
||||
delay: Some(10),
|
||||
};
|
||||
const COLMOD: u8 = 0x3a;
|
||||
const MADCTL: Step = Step {
|
||||
param_cnt: 0,
|
||||
command: 0x36,
|
||||
params: [0, 0, 0, 0],
|
||||
delay: None,
|
||||
};
|
||||
const CASET: u8 = 0x2a;
|
||||
const RASET: u8 = 0x2b;
|
||||
const INVON: Step = Step {
|
||||
param_cnt: 0,
|
||||
command: 0x21,
|
||||
params: [0, 0, 0, 0],
|
||||
delay: Some(10),
|
||||
};
|
||||
const NORON: Step = Step {
|
||||
param_cnt: 0,
|
||||
command: 0x13,
|
||||
params: [0, 0, 0, 0],
|
||||
delay: Some(10),
|
||||
};
|
||||
const DISPON: Step = Step {
|
||||
param_cnt: 0,
|
||||
command: 0x29,
|
||||
params: [0, 0, 0, 0],
|
||||
delay: Some(10),
|
||||
};
|
||||
const RAMWR: u8 = 0x2c;
|
||||
|
||||
// Adafruit setup instructions
|
||||
// SWRESET (0x01), 150ms delay
|
||||
// SLPOUT (0x11), 10ms delay
|
||||
// COLMOD (0x3a) 0x55 (65K RGB, 16bit/pixel), 10ms delay
|
||||
// MADCTL (0x36) 0x00,
|
||||
// memory data access control, RGB
|
||||
// CASET 0x00, 0, 0, 170,
|
||||
// column address set, 4 parameters
|
||||
// 0x00, 0x00 indicates xstart is 0
|
||||
// 0x00, 170 indicates xend is 170
|
||||
// RASET 0x00, 0, 320 >> 8, 320 & 0xFF,
|
||||
// row address set, 4 parameters
|
||||
// 0x00, 0x00 indicates ystart is 0
|
||||
// 3230 >> 8, 320 & 0xff indicates that 320 is the last y address
|
||||
// INVON, 10ms delay
|
||||
// invert the display
|
||||
// NORON, 10ms delay
|
||||
// normal display mode
|
||||
// DISPON, 10ms delay
|
||||
// turn the display on
|
||||
|
||||
const SETUP_PROGRAM: [Step; 9] = [
|
||||
SWRESET,
|
||||
SLPOUT,
|
||||
Step {
|
||||
param_cnt: 1,
|
||||
command: COLMOD,
|
||||
params: [0x55, 0, 0, 0],
|
||||
delay: Some(10),
|
||||
},
|
||||
MADCTL,
|
||||
Step {
|
||||
param_cnt: 4,
|
||||
command: CASET,
|
||||
params: [0, 0, 0, 170],
|
||||
delay: None,
|
||||
},
|
||||
Step {
|
||||
param_cnt: 4,
|
||||
command: RASET,
|
||||
params: [0, 0, (340 as u16 >> 8) as u8, (320 as u16 & 0xff) as u8],
|
||||
delay: None,
|
||||
},
|
||||
INVON,
|
||||
NORON,
|
||||
DISPON,
|
||||
];
|
||||
|
||||
#[entry]
|
||||
unsafe fn main() -> ! {
|
||||
// rp_pico::pac::Peripherals is a reference to physical hardware defined on the Pico.
|
||||
let mut peripherals = pac::Peripherals::take().unwrap();
|
||||
|
||||
// SIO inidcates "Single Cycle IO". I don't know what this means, but it could mean that this
|
||||
// is a class of IO operations that can be run in a single clock cycle, such as switching a
|
||||
// GPIO pin on or off.
|
||||
let sio = Sio::new(peripherals.SIO);
|
||||
|
||||
// Many of the following systems require a watchdog. I do not know what this does, either, but
|
||||
// it may be some failsafe software that will reset operations if the watchdog detects a lack
|
||||
// of activity.
|
||||
let mut watchdog = Watchdog::new(peripherals.WATCHDOG);
|
||||
|
||||
// Here we grab the GPIO pins in bank 0.
|
||||
let pins = Pins::new(
|
||||
peripherals.IO_BANK0,
|
||||
peripherals.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut peripherals.RESETS,
|
||||
);
|
||||
|
||||
// Initialize an abstraction of the clock system with a batch of standard hardware clocks.
|
||||
let clocks = init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
peripherals.XOSC,
|
||||
peripherals.CLOCKS,
|
||||
peripherals.PLL_SYS,
|
||||
peripherals.PLL_USB,
|
||||
&mut peripherals.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
// An abstraction for a timer which we can use to delay the code.
|
||||
let mut timer = Timer::new(peripherals.TIMER, &mut peripherals.RESETS, &clocks);
|
||||
|
||||
// Grab the clock and data pins for SPI1. For Clock pins and for Data pins, there are only two
|
||||
// pins each on the Pico which can function for SPI1.
|
||||
let spi_clk = pins.gpio2.into_function();
|
||||
let spi_sdo = pins.gpio3.into_function();
|
||||
// let spi_sdi = pins.gpio4.into_function();
|
||||
// Chip select 1 means the chip is not enabled
|
||||
let mut board_select = pins.gpio13.into_function();
|
||||
let mut data_command = pins.gpio14.into_function();
|
||||
let mut reset = pins.gpio15.into_function();
|
||||
|
||||
let _ = reset.set_low();
|
||||
let _ = board_select.set_high();
|
||||
let _ = data_command.set_high();
|
||||
|
||||
// Now, create the SPI function abstraction for SPI1 with spi_clk and spi_sdo.
|
||||
let mut spi = Spi::<_, _, _, 8>::new(peripherals.SPI0, (spi_sdo, spi_clk)).init(
|
||||
&mut peripherals.RESETS,
|
||||
// The SPI system uses the peripheral clock
|
||||
clocks.peripheral_clock.freq(),
|
||||
// Transmit data at a rate of 1Mbit.
|
||||
1_u32.MHz(),
|
||||
// Run with SPI Mode 1. This means that the clock line should start high and that data will
|
||||
// be sampled starting at the first falling edge.
|
||||
embedded_hal::spi::MODE_1,
|
||||
);
|
||||
|
||||
let _ = reset.set_high();
|
||||
timer.delay_ms(10);
|
||||
let _ = board_select.set_low();
|
||||
timer.delay_ms(10);
|
||||
for step in SETUP_PROGRAM {
|
||||
step.send_command(&mut spi, &mut data_command);
|
||||
if let Some(delay) = step.delay {
|
||||
timer.delay_ms(delay);
|
||||
}
|
||||
}
|
||||
|
||||
let _ = data_command.set_low();
|
||||
let _ = spi.write(&[RAMWR]);
|
||||
let _ = data_command.set_high();
|
||||
let mut bitmap: [u8; 86700] = [0; 86700];
|
||||
for i in 0..28900 {
|
||||
bitmap[i] = 0x55;
|
||||
}
|
||||
let _ = spi.write(&bitmap);
|
||||
let _ = data_command.set_low();
|
||||
let _ = spi.write(&[NOP]);
|
||||
let _ = board_select.set_high();
|
||||
|
||||
|
||||
loop {}
|
||||
}
|
Loading…
Reference in New Issue