mirror of
https://github.com/laanwj/k210-sdk-stuff.git
synced 2024-11-22 01:16:20 +04:00
rust: Generalize SPI peripheral
This commit is contained in:
parent
f69a77eb84
commit
13b91fe993
@ -8,12 +8,13 @@ use k210_hal::pac;
|
||||
use k210_hal::prelude::*;
|
||||
use k210_hal::stdout::Stdout;
|
||||
use k210_shared::board::def::{io,DISP_WIDTH,DISP_HEIGHT,MSA300_SLV_ADDR,MSA300_ADDR_BITS,MSA300_CLK};
|
||||
use k210_shared::board::lcd;
|
||||
use k210_shared::board::lcd::{LCD,self};
|
||||
use k210_shared::board::lcd_colors;
|
||||
use k210_shared::board::msa300;
|
||||
use k210_shared::soc::fpioa;
|
||||
use k210_shared::soc::i2c;
|
||||
use k210_shared::soc::sleep::usleep;
|
||||
use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
use libm::F32Ext;
|
||||
use riscv_rt::entry;
|
||||
@ -75,9 +76,11 @@ fn main() -> ! {
|
||||
io_mux_init();
|
||||
io_set_power();
|
||||
|
||||
lcd::init();
|
||||
lcd::set_direction(lcd::direction::YX_LRUD);
|
||||
lcd::clear(lcd_colors::PURPLE);
|
||||
let spi = p.SPI0.constrain();
|
||||
let lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_LRUD);
|
||||
lcd.clear(lcd_colors::PURPLE);
|
||||
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
|
||||
@ -105,7 +108,7 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
lcd::draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
lcd.draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
// usleep(10000);
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,13 @@ use k210_hal::pac;
|
||||
use k210_hal::prelude::*;
|
||||
use k210_hal::stdout::Stdout;
|
||||
use k210_shared::board::def::{io,DISP_WIDTH,DISP_HEIGHT,NS2009_SLV_ADDR,NS2009_CAL,NS2009_ADDR_BITS,NS2009_CLK};
|
||||
use k210_shared::board::lcd;
|
||||
use k210_shared::board::lcd::{LCD,self};
|
||||
use k210_shared::board::lcd_colors;
|
||||
use k210_shared::board::ns2009::TouchScreen;
|
||||
use k210_shared::soc::fpioa;
|
||||
use k210_shared::soc::i2c;
|
||||
use k210_shared::soc::sleep::usleep;
|
||||
use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
use riscv_rt::entry;
|
||||
|
||||
@ -153,9 +154,11 @@ fn main() -> ! {
|
||||
io_mux_init();
|
||||
io_set_power();
|
||||
|
||||
lcd::init();
|
||||
lcd::set_direction(lcd::direction::YX_LRUD);
|
||||
lcd::clear(lcd_colors::PURPLE);
|
||||
let spi = p.SPI0.constrain();
|
||||
let lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_LRUD);
|
||||
lcd.clear(lcd_colors::PURPLE);
|
||||
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
|
||||
@ -205,7 +208,7 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
}
|
||||
lcd::draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
lcd.draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
|
||||
universe.iterate();
|
||||
}
|
||||
|
@ -14,10 +14,11 @@ use k210_hal::pac;
|
||||
use k210_hal::prelude::*;
|
||||
use k210_hal::stdout::Stdout;
|
||||
use k210_shared::board::def::io;
|
||||
use k210_shared::board::lcd;
|
||||
use k210_shared::board::lcd::{LCD,self};
|
||||
use k210_shared::board::lcd_colors;
|
||||
use k210_shared::soc::fpioa;
|
||||
use k210_shared::soc::sleep::usleep;
|
||||
use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
use riscv_rt::entry;
|
||||
|
||||
@ -114,9 +115,11 @@ fn main() -> ! {
|
||||
.unwrap();
|
||||
|
||||
/* LCD init */
|
||||
lcd::init();
|
||||
lcd::set_direction(lcd::direction::YX_RLDU);
|
||||
lcd::clear(lcd_colors::PURPLE);
|
||||
let spi = p.SPI0.constrain();
|
||||
let lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_RLDU);
|
||||
lcd.clear(lcd_colors::PURPLE);
|
||||
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
let mut console: Console = Console::new();
|
||||
@ -192,7 +195,7 @@ fn main() -> ! {
|
||||
}
|
||||
|
||||
console.render(&mut image);
|
||||
lcd::draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
lcd.draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
|
||||
writeln!(stdout, "test {}", frame).unwrap();
|
||||
usleep(1_000_000);
|
||||
|
@ -6,7 +6,7 @@ use pac::spi0::spi_ctrlr0;
|
||||
use crate::soc::gpio;
|
||||
use crate::soc::gpiohs;
|
||||
use crate::soc::sleep::usleep;
|
||||
use crate::soc::spi;
|
||||
use crate::soc::spi::SPI;
|
||||
|
||||
pub const SPI_SLAVE_SELECT: u32 = 3;
|
||||
pub const DCX_GPIONUM: u8 = 2;
|
||||
@ -111,198 +111,207 @@ pub enum direction {
|
||||
pub const DIR_XY_MASK: u8 = 0x20;
|
||||
pub const DIR_MASK: u8 = 0xE0;
|
||||
|
||||
/* Low-level functions */
|
||||
|
||||
fn init_dcx() {
|
||||
gpiohs::set_direction(DCX_GPIONUM, gpio::direction::OUTPUT);
|
||||
gpiohs::set_pin(DCX_GPIONUM, true);
|
||||
pub struct LCD<SPI> {
|
||||
spi: SPI,
|
||||
}
|
||||
|
||||
fn set_dcx_control() {
|
||||
gpiohs::set_pin(DCX_GPIONUM, false);
|
||||
}
|
||||
|
||||
fn set_dcx_data() {
|
||||
gpiohs::set_pin(DCX_GPIONUM, true);
|
||||
}
|
||||
|
||||
fn init_rst() {
|
||||
gpiohs::set_direction(RST_GPIONUM, gpio::direction::OUTPUT);
|
||||
gpiohs::set_pin(RST_GPIONUM, true);
|
||||
}
|
||||
|
||||
fn set_rst(val: bool) {
|
||||
gpiohs::set_pin(RST_GPIONUM, val);
|
||||
}
|
||||
|
||||
pub fn hard_init() {
|
||||
init_dcx();
|
||||
init_rst();
|
||||
set_rst(false);
|
||||
spi::clk_init();
|
||||
spi::init(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
8,
|
||||
0,
|
||||
8, /*instruction length*/
|
||||
0, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
spi::set_clk_rate(10000000);
|
||||
set_rst(true);
|
||||
}
|
||||
|
||||
pub fn write_command(cmd: command) {
|
||||
set_dcx_control();
|
||||
spi::init(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
8,
|
||||
0,
|
||||
8, /*instruction length*/
|
||||
0, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
spi::send_data(SPI_SLAVE_SELECT, &[cmd as u8]);
|
||||
}
|
||||
|
||||
pub fn write_byte(data_buf: &[u8]) {
|
||||
set_dcx_data();
|
||||
spi::init(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
8,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
8, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
spi::send_data(SPI_SLAVE_SELECT, data_buf);
|
||||
}
|
||||
|
||||
pub fn write_half(data_buf: &[u16]) {
|
||||
set_dcx_data();
|
||||
spi::init(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
16,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
16, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
spi::send_data(SPI_SLAVE_SELECT, data_buf);
|
||||
}
|
||||
|
||||
pub fn write_word(data_buf: &[u32]) {
|
||||
set_dcx_data();
|
||||
spi::init(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
32,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
32, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
spi::send_data(SPI_SLAVE_SELECT, data_buf);
|
||||
}
|
||||
|
||||
pub fn fill_data(data: u32, length: usize) {
|
||||
set_dcx_data();
|
||||
spi::init(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
32,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
32, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
spi::fill_data(SPI_SLAVE_SELECT, data, length);
|
||||
}
|
||||
|
||||
/* High-level functions */
|
||||
|
||||
pub fn init() {
|
||||
hard_init();
|
||||
/*soft reset*/
|
||||
write_command(command::SOFTWARE_RESET);
|
||||
usleep(100000);
|
||||
/*exit sleep*/
|
||||
write_command(command::SLEEP_OFF);
|
||||
usleep(100000);
|
||||
/*pixel format*/
|
||||
write_command(command::PIXEL_FORMAT_SET);
|
||||
write_byte(&[0x55]);
|
||||
set_direction(direction::XY_LRUD);
|
||||
|
||||
/*display on*/
|
||||
write_command(command::DISPLAY_ON);
|
||||
}
|
||||
|
||||
pub fn set_direction(dir: direction) {
|
||||
/* No support for YX orientations right now --
|
||||
lcd_ctl.dir = dir;
|
||||
if (dir & DIR_XY_MASK)
|
||||
{
|
||||
lcd_ctl.width = LCD_Y_MAX - 1;
|
||||
lcd_ctl.height = LCD_X_MAX - 1;
|
||||
impl<X: SPI> LCD<X> {
|
||||
pub fn new(spi: X) -> Self {
|
||||
Self { spi }
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_ctl.width = LCD_X_MAX - 1;
|
||||
lcd_ctl.height = LCD_Y_MAX - 1;
|
||||
|
||||
/* Low-level functions */
|
||||
|
||||
fn init_dcx(&self) {
|
||||
gpiohs::set_direction(DCX_GPIONUM, gpio::direction::OUTPUT);
|
||||
gpiohs::set_pin(DCX_GPIONUM, true);
|
||||
}
|
||||
*/
|
||||
|
||||
write_command(command::MEMORY_ACCESS_CTL);
|
||||
write_byte(&[dir as u8]);
|
||||
}
|
||||
|
||||
pub fn set_area(x1: u16, y1: u16, x2: u16, y2: u16) {
|
||||
write_command(command::HORIZONTAL_ADDRESS_SET);
|
||||
write_byte(&[
|
||||
(x1 >> 8) as u8,
|
||||
(x1 & 0xff) as u8,
|
||||
(x2 >> 8) as u8,
|
||||
(x2 & 0xff) as u8,
|
||||
]);
|
||||
|
||||
write_command(command::VERTICAL_ADDRESS_SET);
|
||||
write_byte(&[
|
||||
(y1 >> 8) as u8,
|
||||
(y1 & 0xff) as u8,
|
||||
(y2 >> 8) as u8,
|
||||
(y2 & 0xff) as u8,
|
||||
]);
|
||||
|
||||
write_command(command::MEMORY_WRITE);
|
||||
}
|
||||
|
||||
pub fn clear(color: u16) {
|
||||
let data = ((color as u32) << 16) | (color as u32);
|
||||
|
||||
//set_area(0, 0, lcd_ctl.width, lcd_ctl.height);
|
||||
set_area(0, 0, LCD_X_MAX - 1, LCD_Y_MAX - 1);
|
||||
fill_data(data, (LCD_X_MAX as usize) * (LCD_Y_MAX as usize) / 2);
|
||||
}
|
||||
|
||||
pub fn draw_picture(x1: u16, y1: u16, width: u16, height: u16, data: &[u32]) {
|
||||
set_area(x1, y1, x1 + width - 1, y1 + height - 1);
|
||||
assert!(data.len() == (width as usize) * (height as usize) / 2);
|
||||
write_word(data);
|
||||
fn set_dcx_control(&self) {
|
||||
gpiohs::set_pin(DCX_GPIONUM, false);
|
||||
}
|
||||
|
||||
fn set_dcx_data(&self) {
|
||||
gpiohs::set_pin(DCX_GPIONUM, true);
|
||||
}
|
||||
|
||||
fn init_rst(&self) {
|
||||
gpiohs::set_direction(RST_GPIONUM, gpio::direction::OUTPUT);
|
||||
gpiohs::set_pin(RST_GPIONUM, true);
|
||||
}
|
||||
|
||||
fn set_rst(&self, val: bool) {
|
||||
gpiohs::set_pin(RST_GPIONUM, val);
|
||||
}
|
||||
|
||||
pub fn hard_init(&self) {
|
||||
self.init_dcx();
|
||||
self.init_rst();
|
||||
self.set_rst(false);
|
||||
self.spi.set_clk_rate(10000000);
|
||||
self.spi.configure(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
8,
|
||||
0,
|
||||
8, /*instruction length*/
|
||||
0, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
self.set_rst(true);
|
||||
}
|
||||
|
||||
pub fn write_command(&self, cmd: command) {
|
||||
self.set_dcx_control();
|
||||
self.spi.configure(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
8,
|
||||
0,
|
||||
8, /*instruction length*/
|
||||
0, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
self.spi.send_data(SPI_SLAVE_SELECT, &[cmd as u8]);
|
||||
}
|
||||
|
||||
pub fn write_byte(&self, data_buf: &[u8]) {
|
||||
self.set_dcx_data();
|
||||
self.spi.configure(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
8,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
8, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
self.spi.send_data(SPI_SLAVE_SELECT, data_buf);
|
||||
}
|
||||
|
||||
pub fn write_half(&self, data_buf: &[u16]) {
|
||||
self.set_dcx_data();
|
||||
self.spi.configure(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
16,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
16, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
self.spi.send_data(SPI_SLAVE_SELECT, data_buf);
|
||||
}
|
||||
|
||||
pub fn write_word(&self, data_buf: &[u32]) {
|
||||
self.set_dcx_data();
|
||||
self.spi.configure(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
32,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
32, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
self.spi.send_data(SPI_SLAVE_SELECT, data_buf);
|
||||
}
|
||||
|
||||
pub fn fill_data(&self, data: u32, length: usize) {
|
||||
self.set_dcx_data();
|
||||
self.spi.configure(
|
||||
ctrlr0::WORK_MODEW::MODE0,
|
||||
ctrlr0::FRAME_FORMATW::OCTAL,
|
||||
32,
|
||||
0,
|
||||
0, /*instruction length*/
|
||||
32, /*address length*/
|
||||
0, /*wait cycles*/
|
||||
spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
|
||||
ctrlr0::TMODW::TRANS,
|
||||
);
|
||||
self.spi.fill_data(SPI_SLAVE_SELECT, data, length);
|
||||
}
|
||||
|
||||
/* High-level functions */
|
||||
|
||||
pub fn init(&self) {
|
||||
self.hard_init();
|
||||
/*soft reset*/
|
||||
self.write_command(command::SOFTWARE_RESET);
|
||||
usleep(100000);
|
||||
/*exit sleep*/
|
||||
self.write_command(command::SLEEP_OFF);
|
||||
usleep(100000);
|
||||
/*pixel format*/
|
||||
self.write_command(command::PIXEL_FORMAT_SET);
|
||||
self.write_byte(&[0x55]);
|
||||
self.set_direction(direction::XY_LRUD);
|
||||
|
||||
/*display on*/
|
||||
self.write_command(command::DISPLAY_ON);
|
||||
}
|
||||
|
||||
pub fn set_direction(&self, dir: direction) {
|
||||
/* No support for YX orientations right now --
|
||||
lcd_ctl.dir = dir;
|
||||
if (dir & DIR_XY_MASK)
|
||||
{
|
||||
lcd_ctl.width = LCD_Y_MAX - 1;
|
||||
lcd_ctl.height = LCD_X_MAX - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_ctl.width = LCD_X_MAX - 1;
|
||||
lcd_ctl.height = LCD_Y_MAX - 1;
|
||||
}
|
||||
*/
|
||||
|
||||
self.write_command(command::MEMORY_ACCESS_CTL);
|
||||
self.write_byte(&[dir as u8]);
|
||||
}
|
||||
|
||||
pub fn set_area(&self, x1: u16, y1: u16, x2: u16, y2: u16) {
|
||||
self.write_command(command::HORIZONTAL_ADDRESS_SET);
|
||||
self.write_byte(&[
|
||||
(x1 >> 8) as u8,
|
||||
(x1 & 0xff) as u8,
|
||||
(x2 >> 8) as u8,
|
||||
(x2 & 0xff) as u8,
|
||||
]);
|
||||
|
||||
self.write_command(command::VERTICAL_ADDRESS_SET);
|
||||
self.write_byte(&[
|
||||
(y1 >> 8) as u8,
|
||||
(y1 & 0xff) as u8,
|
||||
(y2 >> 8) as u8,
|
||||
(y2 & 0xff) as u8,
|
||||
]);
|
||||
|
||||
self.write_command(command::MEMORY_WRITE);
|
||||
}
|
||||
|
||||
pub fn clear(&self, color: u16) {
|
||||
let data = ((color as u32) << 16) | (color as u32);
|
||||
|
||||
//set_area(0, 0, lcd_ctl.width, lcd_ctl.height);
|
||||
self.set_area(0, 0, LCD_X_MAX - 1, LCD_Y_MAX - 1);
|
||||
self.fill_data(data, (LCD_X_MAX as usize) * (LCD_Y_MAX as usize) / 2);
|
||||
}
|
||||
|
||||
pub fn draw_picture(&self, x1: u16, y1: u16, width: u16, height: u16, data: &[u32]) {
|
||||
self.set_area(x1, y1, x1 + width - 1, y1 + height - 1);
|
||||
assert!(data.len() == (width as usize) * (height as usize) / 2);
|
||||
self.write_word(data);
|
||||
}
|
||||
}
|
||||
|
@ -1,133 +1,189 @@
|
||||
use core::cmp;
|
||||
use core::ops::Deref;
|
||||
use k210_hal::pac;
|
||||
use pac::{SPI0,SPI1,spi0};
|
||||
use pac::spi0::ctrlr0;
|
||||
use pac::spi0::spi_ctrlr0;
|
||||
|
||||
use crate::soc::sysctl;
|
||||
|
||||
pub fn clk_init() {
|
||||
sysctl::clock_enable(sysctl::clock::SPI0);
|
||||
sysctl::clock_set_threshold(sysctl::threshold::SPI0, 0);
|
||||
unsafe {
|
||||
(*pac::SPI0::ptr()).baudr.write(|w| w.bits(0x14)); // Set baudrate to some default
|
||||
/// Extension trait that constrains SPI peripherals
|
||||
pub trait SPIExt: Sized {
|
||||
/// Constrains SPI peripheral so it plays nicely with the other abstractions
|
||||
fn constrain(self) -> SPIImpl<Self>;
|
||||
}
|
||||
|
||||
/// Trait for generalizing over SPI0 and SPI1 (SPI2 is slave-only and SPI3 is !!!special!!!)
|
||||
pub trait SPI01: Deref<Target = spi0::RegisterBlock> {
|
||||
#[doc(hidden)]
|
||||
const CLK: sysctl::clock;
|
||||
#[doc(hidden)]
|
||||
const DIV: sysctl::threshold;
|
||||
}
|
||||
|
||||
impl SPI01 for SPI0 {
|
||||
const CLK: sysctl::clock = sysctl::clock::SPI0;
|
||||
const DIV: sysctl::threshold = sysctl::threshold::SPI0;
|
||||
}
|
||||
impl SPI01 for SPI1 {
|
||||
const CLK: sysctl::clock = sysctl::clock::SPI1;
|
||||
const DIV: sysctl::threshold = sysctl::threshold::SPI1;
|
||||
}
|
||||
|
||||
impl<SPI: SPI01> SPIExt for SPI {
|
||||
fn constrain(self) -> SPIImpl<SPI> {
|
||||
SPIImpl::<SPI>::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(
|
||||
work_mode: ctrlr0::WORK_MODEW,
|
||||
frame_format: ctrlr0::FRAME_FORMATW,
|
||||
data_bit_length: u8,
|
||||
endian: u32,
|
||||
instruction_length: u8,
|
||||
address_length: u8,
|
||||
wait_cycles: u8,
|
||||
instruction_address_trans_mode: spi_ctrlr0::AITMW,
|
||||
tmod: ctrlr0::TMODW,
|
||||
) {
|
||||
assert!(data_bit_length >= 4 && data_bit_length <= 32);
|
||||
assert!(wait_cycles < (1 << 5));
|
||||
let inst_l: u8 = match instruction_length {
|
||||
0 => 0,
|
||||
4 => 1,
|
||||
8 => 2,
|
||||
16 => 3,
|
||||
_ => panic!("unhandled intruction length"),
|
||||
};
|
||||
pub struct SPIImpl<IF> {
|
||||
spi: IF,
|
||||
}
|
||||
|
||||
assert!(address_length % 4 == 0 && address_length <= 60);
|
||||
let addr_l: u8 = address_length / 4;
|
||||
pub trait SPI {
|
||||
fn configure(
|
||||
&self,
|
||||
work_mode: ctrlr0::WORK_MODEW,
|
||||
frame_format: ctrlr0::FRAME_FORMATW,
|
||||
data_bit_length: u8,
|
||||
endian: u32,
|
||||
instruction_length: u8,
|
||||
address_length: u8,
|
||||
wait_cycles: u8,
|
||||
instruction_address_trans_mode: spi_ctrlr0::AITMW,
|
||||
tmod: ctrlr0::TMODW,
|
||||
);
|
||||
fn set_clk_rate(&self, spi_clk: u32) -> u32;
|
||||
fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]);
|
||||
fn fill_data(&self, chip_select: u32, value: u32, tx_len: usize);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = pac::SPI0::ptr();
|
||||
(*ptr).imr.write(|w| w.bits(0x00));
|
||||
(*ptr).dmacr.write(|w| w.bits(0x00));
|
||||
(*ptr).dmatdlr.write(|w| w.bits(0x10));
|
||||
(*ptr).dmardlr.write(|w| w.bits(0x00));
|
||||
(*ptr).ser.write(|w| w.bits(0x00));
|
||||
(*ptr).ssienr.write(|w| w.bits(0x00));
|
||||
(*ptr).ctrlr0.write(|w| {
|
||||
w.work_mode()
|
||||
.variant(work_mode)
|
||||
.tmod()
|
||||
.variant(tmod)
|
||||
.frame_format()
|
||||
.variant(frame_format)
|
||||
.data_length()
|
||||
.bits(data_bit_length - 1)
|
||||
});
|
||||
(*ptr).spi_ctrlr0.write(|w| {
|
||||
w.aitm()
|
||||
.variant(instruction_address_trans_mode)
|
||||
.addr_length()
|
||||
.bits(addr_l)
|
||||
.inst_length()
|
||||
.bits(inst_l)
|
||||
.wait_cycles()
|
||||
.bits(wait_cycles)
|
||||
});
|
||||
(*ptr).endian.write(|w| w.bits(endian));
|
||||
impl<IF: SPI01> SPIImpl<IF> {
|
||||
pub fn new(spi: IF) -> Self {
|
||||
Self { spi }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_clk_rate(spi_clk: u32) -> u32 {
|
||||
let clock_freq: u32 = sysctl::clock_get_freq(sysctl::clock::SPI0);
|
||||
let spi_baudr = clock_freq / spi_clk;
|
||||
// Clamp baudrate divider to valid range
|
||||
let spi_baudr = cmp::min(cmp::max(spi_baudr, 2), 65534);
|
||||
unsafe {
|
||||
(*pac::SPI0::ptr()).baudr.write(|w| w.bits(spi_baudr));
|
||||
impl<IF: SPI01> SPI for SPIImpl<IF> {
|
||||
/// Configure SPI transaction
|
||||
fn configure(
|
||||
&self,
|
||||
work_mode: ctrlr0::WORK_MODEW,
|
||||
frame_format: ctrlr0::FRAME_FORMATW,
|
||||
data_bit_length: u8,
|
||||
endian: u32,
|
||||
instruction_length: u8,
|
||||
address_length: u8,
|
||||
wait_cycles: u8,
|
||||
instruction_address_trans_mode: spi_ctrlr0::AITMW,
|
||||
tmod: ctrlr0::TMODW,
|
||||
) {
|
||||
assert!(data_bit_length >= 4 && data_bit_length <= 32);
|
||||
assert!(wait_cycles < (1 << 5));
|
||||
let inst_l: u8 = match instruction_length {
|
||||
0 => 0,
|
||||
4 => 1,
|
||||
8 => 2,
|
||||
16 => 3,
|
||||
_ => panic!("unhandled intruction length"),
|
||||
};
|
||||
|
||||
assert!(address_length % 4 == 0 && address_length <= 60);
|
||||
let addr_l: u8 = address_length / 4;
|
||||
|
||||
unsafe {
|
||||
self.spi.imr.write(|w| w.bits(0x00));
|
||||
self.spi.dmacr.write(|w| w.bits(0x00));
|
||||
self.spi.dmatdlr.write(|w| w.bits(0x10));
|
||||
self.spi.dmardlr.write(|w| w.bits(0x00));
|
||||
self.spi.ser.write(|w| w.bits(0x00));
|
||||
self.spi.ssienr.write(|w| w.bits(0x00));
|
||||
self.spi.ctrlr0.write(|w| {
|
||||
w.work_mode()
|
||||
.variant(work_mode)
|
||||
.tmod()
|
||||
.variant(tmod)
|
||||
.frame_format()
|
||||
.variant(frame_format)
|
||||
.data_length()
|
||||
.bits(data_bit_length - 1)
|
||||
});
|
||||
self.spi.spi_ctrlr0.write(|w| {
|
||||
w.aitm()
|
||||
.variant(instruction_address_trans_mode)
|
||||
.addr_length()
|
||||
.bits(addr_l)
|
||||
.inst_length()
|
||||
.bits(inst_l)
|
||||
.wait_cycles()
|
||||
.bits(wait_cycles)
|
||||
});
|
||||
self.spi.endian.write(|w| w.bits(endian));
|
||||
}
|
||||
}
|
||||
clock_freq / spi_baudr
|
||||
}
|
||||
|
||||
pub fn send_data<X: Into<u32> + Copy>(chip_select: u32, tx: &[X]) {
|
||||
unsafe {
|
||||
let ptr = pac::SPI0::ptr();
|
||||
/// Set SPI clock rate
|
||||
fn set_clk_rate(&self, spi_clk: u32) -> u32 {
|
||||
sysctl::clock_enable(IF::CLK);
|
||||
sysctl::clock_set_threshold(IF::DIV, 0);
|
||||
let clock_freq: u32 = sysctl::clock_get_freq(sysctl::clock::SPI0);
|
||||
let spi_baudr = clock_freq / spi_clk;
|
||||
// Clamp baudrate divider to valid range
|
||||
let spi_baudr = cmp::min(cmp::max(spi_baudr, 2), 65534);
|
||||
unsafe {
|
||||
self.spi.baudr.write(|w| w.bits(spi_baudr));
|
||||
}
|
||||
clock_freq / spi_baudr
|
||||
}
|
||||
|
||||
(*ptr).ser.write(|w| w.bits(1 << chip_select));
|
||||
(*ptr).ssienr.write(|w| w.bits(0x01));
|
||||
/// Send arbitrary data
|
||||
fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]) {
|
||||
unsafe {
|
||||
self.spi.ser.write(|w| w.bits(1 << chip_select));
|
||||
self.spi.ssienr.write(|w| w.bits(0x01));
|
||||
|
||||
// TODO: write this using iterators / slices
|
||||
let mut i = 0;
|
||||
let mut tx_len = tx.len();
|
||||
while tx_len != 0 {
|
||||
let fifo_len = (32 - (*ptr).txflr.read().bits()) as usize;
|
||||
let fifo_len = cmp::min(fifo_len, tx_len);
|
||||
for _ in 0..fifo_len {
|
||||
(*ptr).dr[0].write(|f| f.bits(tx[i].into()));
|
||||
i += 1;
|
||||
// TODO: write this using iterators / slices
|
||||
let mut i = 0;
|
||||
let mut tx_len = tx.len();
|
||||
while tx_len != 0 {
|
||||
let fifo_len = (32 - self.spi.txflr.read().bits()) as usize;
|
||||
let fifo_len = cmp::min(fifo_len, tx_len);
|
||||
for _ in 0..fifo_len {
|
||||
self.spi.dr[0].write(|f| f.bits(tx[i].into()));
|
||||
i += 1;
|
||||
}
|
||||
tx_len -= fifo_len;
|
||||
}
|
||||
tx_len -= fifo_len;
|
||||
}
|
||||
|
||||
while ((*ptr).sr.read().bits() & 0x05) != 0x04 {
|
||||
// IDLE
|
||||
}
|
||||
(*ptr).ser.write(|w| w.bits(0x00));
|
||||
(*ptr).ssienr.write(|w| w.bits(0x00));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fill_data(chip_select: u32, value: u32, mut tx_len: usize) {
|
||||
unsafe {
|
||||
let ptr = pac::SPI0::ptr();
|
||||
|
||||
(*ptr).ser.write(|w| w.bits(1 << chip_select));
|
||||
(*ptr).ssienr.write(|w| w.bits(0x01));
|
||||
|
||||
while tx_len != 0 {
|
||||
let fifo_len = (32 - (*ptr).txflr.read().bits()) as usize;
|
||||
let fifo_len = cmp::min(fifo_len, tx_len);
|
||||
for _ in 0..fifo_len {
|
||||
(*ptr).dr[0].write(|f| f.bits(value));
|
||||
while (self.spi.sr.read().bits() & 0x05) != 0x04 {
|
||||
// IDLE
|
||||
}
|
||||
tx_len -= fifo_len;
|
||||
self.spi.ser.write(|w| w.bits(0x00));
|
||||
self.spi.ssienr.write(|w| w.bits(0x00));
|
||||
}
|
||||
}
|
||||
|
||||
while ((*ptr).sr.read().bits() & 0x05) != 0x04 {
|
||||
// IDLE
|
||||
/// Send repeated data
|
||||
fn fill_data(&self, chip_select: u32, value: u32, mut tx_len: usize) {
|
||||
unsafe {
|
||||
self.spi.ser.write(|w| w.bits(1 << chip_select));
|
||||
self.spi.ssienr.write(|w| w.bits(0x01));
|
||||
|
||||
while tx_len != 0 {
|
||||
let fifo_len = (32 - self.spi.txflr.read().bits()) as usize;
|
||||
let fifo_len = cmp::min(fifo_len, tx_len);
|
||||
for _ in 0..fifo_len {
|
||||
self.spi.dr[0].write(|f| f.bits(value));
|
||||
}
|
||||
tx_len -= fifo_len;
|
||||
}
|
||||
|
||||
while (self.spi.sr.read().bits() & 0x05) != 0x04 {
|
||||
// IDLE
|
||||
}
|
||||
self.spi.ser.write(|w| w.bits(0x00));
|
||||
self.spi.ssienr.write(|w| w.bits(0x00));
|
||||
}
|
||||
(*ptr).ser.write(|w| w.bits(0x00));
|
||||
(*ptr).ssienr.write(|w| w.bits(0x00));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,10 +10,11 @@ use k210_hal::pac;
|
||||
use k210_hal::prelude::*;
|
||||
use k210_hal::stdout::Stdout;
|
||||
use k210_shared::board::def::{io,DISP_WIDTH,DISP_HEIGHT};
|
||||
use k210_shared::board::lcd;
|
||||
use k210_shared::board::lcd::{LCD,self};
|
||||
use k210_shared::board::lcd_colors;
|
||||
use k210_shared::soc::fpioa;
|
||||
use k210_shared::soc::sleep::usleep;
|
||||
use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
use riscv_rt::entry;
|
||||
|
||||
@ -79,9 +80,11 @@ fn main() -> ! {
|
||||
io_mux_init();
|
||||
io_set_power();
|
||||
|
||||
lcd::init();
|
||||
lcd::set_direction(lcd::direction::YX_RLDU);
|
||||
lcd::clear(lcd_colors::PURPLE);
|
||||
let spi = p.SPI0.constrain();
|
||||
let lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_RLDU);
|
||||
lcd.clear(lcd_colors::PURPLE);
|
||||
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
|
||||
@ -96,7 +99,7 @@ fn main() -> ! {
|
||||
ofs += 1;
|
||||
}
|
||||
}
|
||||
lcd::draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
lcd.draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
|
||||
frame += 1;
|
||||
zoom *= 0.98f32;
|
||||
|
Loading…
Reference in New Issue
Block a user