Skip to content

Instantly share code, notes, and snippets.

@9names
Last active January 18, 2023 11:30
Show Gist options
  • Save 9names/4d8748d14f3417509858566abbb6663b to your computer and use it in GitHub Desktop.
Save 9names/4d8748d14f3417509858566abbb6663b to your computer and use it in GitHub Desktop.
bl702 LCD test
[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"]
//! 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?
#![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 {}
}
#![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