Last active
January 18, 2023 11:30
-
-
Save 9names/4d8748d14f3417509858566abbb6663b to your computer and use it in GitHub Desktop.
bl702 LCD test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "bl702-hal" | |
version = "0.0.3" | |
edition = "2021" | |
license = "MIT OR MulanPSL-2.0" | |
keywords = ["hal", "bl702", "riscv"] | |
categories = ["embedded", "no-std", "hardware-support"] | |
repository = "https://github.com/9names/bl702-hal" | |
description = "HAL for the Bouffalo Lab BL702 microcontroller family" | |
[dependencies] | |
bl702-pac = "0.0.2" | |
embedded-time = "0.12.0" | |
riscv = "0.10.0" | |
nb = "1.0" | |
paste = "1.0" | |
embedded-hal = { version = "0.2.7", features = ["unproven"] } | |
embedded-hal-alpha = { version = "=1.0.0-alpha.5", package = "embedded-hal" } | |
ufmt = { version = "0.2", optional = true } | |
ufmt-write = { version = "0.1", optional = true } | |
[dev-dependencies] | |
st7735-lcd = "0.8.1" | |
embedded-graphics = "0.7.1" | |
display-interface-spi = "0.4.1" | |
riscv-rt = "0.10.0" | |
panic-halt = "0.2.0" | |
mipidsi = "0.6.0" | |
[build-dependencies] | |
riscv-target = "0.1.2" | |
[features] | |
default = ["panic_serial", "print_serial"] | |
ramexec = [] | |
panic_serial = [] | |
print_serial = ["ufmt", "ufmt-write"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Delays | |
use core::convert::Infallible; | |
use embedded_hal_alpha::delay::blocking::{DelayMs, DelayUs}; | |
use embedded_hal::blocking::delay::DelayMs as DelayMsZero; | |
use embedded_hal::blocking::delay::DelayUs as DelayUsZero; | |
/// Use RISCV machine-mode cycle counter (`mcycle`) as a delay provider. | |
/// | |
/// This can be used for high resolution delays for device initialization, | |
/// bit-banging protocols, etc | |
#[derive(Copy, Clone)] | |
pub struct McycleDelay { | |
core_frequency: u32, | |
} | |
impl McycleDelay { | |
/// Constructs the delay provider based on core clock frequency `freq` | |
pub fn new(freq: u32) -> Self { | |
Self { | |
/// System clock frequency, used to convert clock cycles | |
/// into real-world time values | |
core_frequency: freq, | |
} | |
} | |
/// Retrieves the cycle count for the current HART | |
#[inline] | |
pub fn get_cycle_count() -> u64 { | |
riscv::register::mcycle::read64() | |
} | |
/// Returns the number of elapsed cycles since `previous_cycle_count` | |
#[inline] | |
pub fn cycles_since(previous_cycle_count: u64) -> u64 { | |
riscv::register::mcycle::read64().wrapping_sub(previous_cycle_count) | |
} | |
/// Performs a busy-wait loop until the number of cycles `cycle_count` has elapsed | |
#[inline] | |
pub fn delay_cycles(cycle_count: u64) { | |
let start_cycle_count = McycleDelay::get_cycle_count(); | |
while McycleDelay::cycles_since(start_cycle_count) <= cycle_count {} | |
} | |
} | |
impl DelayUs<u64> for McycleDelay { | |
type Error = Infallible; | |
/// Performs a busy-wait loop until the number of microseconds `us` has elapsed | |
#[inline] | |
fn delay_us(&mut self, us: u64) -> Result<(), Infallible> { | |
McycleDelay::delay_cycles((us * (self.core_frequency as u64)) / 1_000_000); | |
Ok(()) | |
} | |
} | |
impl DelayMs<u64> for McycleDelay { | |
type Error = Infallible; | |
/// Performs a busy-wait loop until the number of milliseconds `ms` has elapsed | |
#[inline] | |
fn delay_ms(&mut self, ms: u64) -> Result<(), Infallible> { | |
McycleDelay::delay_cycles((ms * (self.core_frequency as u64)) / 1000); | |
Ok(()) | |
} | |
} | |
impl DelayMsZero<u64> for McycleDelay { | |
/// Performs a busy-wait loop until the number of milliseconds `ms` has elapsed | |
#[inline] | |
fn delay_ms(&mut self, ms: u64) { | |
McycleDelay::delay_cycles((ms * (self.core_frequency as u64)) / 1000); | |
} | |
} | |
impl DelayUsZero<u64> for McycleDelay { | |
/// Performs a busy-wait loop until the number of microseconds `us` has elapsed | |
#[inline] | |
fn delay_us(&mut self, ms: u64) { | |
McycleDelay::delay_cycles((ms * (self.core_frequency as u64)) / 1_000_000); | |
} | |
} | |
// Different drivers require different integer types, implement in terms of smaller uints | |
impl DelayMsZero<u32> for McycleDelay { | |
/// Performs a busy-wait loop until the number of milliseconds `ms` has elapsed | |
#[inline] | |
fn delay_ms(&mut self, ms: u32) { | |
McycleDelay::delay_cycles((ms as u64 * (self.core_frequency as u64)) / 1000); | |
} | |
} | |
impl DelayMsZero<u16> for McycleDelay { | |
/// Performs a busy-wait loop until the number of milliseconds `ms` has elapsed | |
#[inline] | |
fn delay_ms(&mut self, ms: u16) { | |
McycleDelay::delay_cycles((ms as u64 * (self.core_frequency as u64)) / 1000); | |
} | |
} | |
impl DelayMsZero<u8> for McycleDelay { | |
/// Performs a busy-wait loop until the number of milliseconds `ms` has elapsed | |
#[inline] | |
fn delay_ms(&mut self, ms: u8) { | |
McycleDelay::delay_cycles((ms as u64 * (self.core_frequency as u64)) / 1000); | |
} | |
} | |
impl DelayUsZero<u32> for McycleDelay { | |
/// Performs a busy-wait loop until the number of microseconds `us` has elapsed | |
#[inline] | |
fn delay_us(&mut self, ms: u32) { | |
McycleDelay::delay_cycles((ms as u64 * (self.core_frequency as u64)) / 1_000_000); | |
} | |
} | |
impl DelayUsZero<u16> for McycleDelay { | |
/// Performs a busy-wait loop until the number of microseconds `us` has elapsed | |
#[inline] | |
fn delay_us(&mut self, ms: u16) { | |
McycleDelay::delay_cycles((ms as u64 * (self.core_frequency as u64)) / 1_000_000); | |
} | |
} | |
impl DelayUsZero<u8> for McycleDelay { | |
/// Performs a busy-wait loop until the number of microseconds `us` has elapsed | |
#[inline] | |
fn delay_us(&mut self, ms: u8) { | |
McycleDelay::delay_cycles((ms as u64 * (self.core_frequency as u64)) / 1_000_000); | |
} | |
} | |
// TODO: impls for 1.0 E-H versions. maybe wait until 1.0 is released? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_std] | |
#![no_main] | |
use bl702_hal as hal; | |
use embedded_hal_alpha::digital::blocking::OutputPin; | |
use hal::{ | |
clock::{board_clock_init, system_init, ClockConfig}, | |
delay::McycleDelay, | |
pac, | |
prelude::*, | |
}; | |
#[cfg(not(feature = "panic_serial"))] | |
use panic_halt as _; | |
use embedded_graphics::image::{Image, ImageRaw}; | |
use embedded_graphics::pixelcolor::Rgb565; | |
use embedded_graphics::prelude::*; | |
use st7735_lcd; | |
use st7735_lcd::Orientation; | |
#[riscv_rt::entry] | |
fn main() -> ! { | |
// This *MUST* be called first | |
system_init(); | |
// Set up default board clock config | |
board_clock_init(); | |
let dp = pac::Peripherals::take().unwrap(); | |
let mut parts = dp.GLB.split(); | |
let clocks = ClockConfig::new().freeze(&mut parts.clk_cfg); | |
let sclk = parts.pin23.into_spi_sclk(); | |
let mosi = parts.pin24.into_spi_mosi(); | |
let miso = parts.pin29.into_spi_miso(); // unbonded on bl702 | |
let dc = parts.pin25.into_floating_output(); | |
let mut cs = parts.pin1.into_floating_output(); | |
let rst = parts.pin10.into_floating_output(); // unbonded on bl702 | |
cs.set_high().unwrap(); | |
let spi = hal::spi::Spi::new( | |
dp.SPI, | |
(miso, mosi, sclk), | |
embedded_hal_alpha::spi::MODE_0, | |
1_000_000u32.Hz(), // fastest that obeys st7735 minimum high/low time with 36mhz bclk | |
clocks, | |
); | |
let mut d = McycleDelay::new(clocks.sysclk().0); | |
cs.set_low().unwrap(); | |
let mut disp = st7735_lcd::ST7735::new(spi, dc, rst, false, true, 160, 80); | |
disp.init(&mut d).unwrap(); | |
disp.set_orientation(&Orientation::Landscape).unwrap(); | |
disp.set_offset(0, 25); | |
disp.clear(Rgb565::BLACK).unwrap(); | |
let image_raw: ImageRaw<Rgb565> = ImageRaw::new(include_bytes!("../assets/ferris.raw"), 86); | |
let image = Image::new(&image_raw, Point::new(34, 8)); | |
image.draw(&mut disp).unwrap(); | |
loop {} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_std] | |
#![no_main] | |
use bl702_hal as hal; | |
use display_interface_spi::SPIInterface; | |
use embedded_hal::blocking::delay::DelayMs; | |
use embedded_hal::blocking::delay::DelayUs; | |
use embedded_hal_alpha::digital::blocking::OutputPin; | |
use hal::{ | |
clock::{board_clock_init, system_init, ClockConfig}, | |
delay::McycleDelay, | |
pac, | |
prelude::*, | |
}; | |
use mipidsi::ColorOrder; | |
use mipidsi::Orientation; | |
#[cfg(not(feature = "panic_serial"))] | |
use panic_halt as _; | |
use embedded_graphics::image::{Image, ImageRaw, ImageRawLE}; | |
use embedded_graphics::pixelcolor::Rgb565; | |
use embedded_graphics::prelude::*; | |
use mipidsi; | |
// st7735s m0sense variant with variable offset | |
pub(crate) fn m0sense_offset(options: &ModelOptions) -> (u16, u16) { | |
match options.orientation() { | |
Orientation::Portrait(false) => (25, 0), | |
Orientation::Portrait(true) => (25, 0), | |
Orientation::Landscape(false) => (0, 25), | |
Orientation::Landscape(true) => (0, 25), | |
Orientation::PortraitInverted(false) => (25, 0), | |
Orientation::PortraitInverted(true) => (25, 0), | |
Orientation::LandscapeInverted(false) => (0, 25), | |
Orientation::LandscapeInverted(true) => (0, 25), | |
} | |
} | |
#[riscv_rt::entry] | |
fn main() -> ! { | |
// This *MUST* be called first | |
system_init(); | |
// Set up default board clock config | |
board_clock_init(); | |
let dp = pac::Peripherals::take().unwrap(); | |
let mut parts = dp.GLB.split(); | |
let clocks = ClockConfig::new().freeze(&mut parts.clk_cfg); | |
let sclk = parts.pin23.into_spi_sclk(); | |
let mosi = parts.pin24.into_spi_mosi(); | |
let miso = parts.pin29.into_spi_miso(); // unbonded on bl702 | |
let dc = parts.pin25.into_floating_output(); | |
let mut cs = parts.pin1.into_floating_output(); | |
let rst = parts.pin10.into_floating_output(); // unbonded on bl702 | |
cs.set_high().unwrap(); | |
let spi = hal::spi::Spi::new( | |
dp.SPI, | |
(miso, mosi, sclk), | |
embedded_hal_alpha::spi::MODE_0, | |
16_000_000u32.Hz(), // fastest that obeys st7735 minimum high/low time with 36mhz bclk | |
clocks, | |
); | |
let mut d = McycleDelay::new(clocks.sysclk().0); | |
let di = SPIInterface::new(spi, dc, cs); | |
let mut disp = mipidsi::Builder::st7735s(di) | |
.with_orientation(Orientation::Landscape(true)) | |
.with_color_order(ColorOrder::Bgr) | |
.with_invert_colors(true) | |
.with_window_offset_handler(m0sense_offset) | |
.init(&mut d, Some(rst)) | |
.unwrap(); | |
disp.clear(Rgb565::BLACK).unwrap(); | |
let image_raw: ImageRawLE<Rgb565> = ImageRaw::new(include_bytes!("../assets/ferris.raw"), 86); | |
let image = Image::new(&image_raw, Point::new(34, 8)); | |
image.draw(&mut disp).unwrap(); | |
loop {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment