rust: Generalize SPI peripheral

This commit is contained in:
Wladimir J. van der Laan 2019-05-18 18:14:26 +00:00
parent f69a77eb84
commit 13b91fe993
6 changed files with 393 additions and 316 deletions

View File

@ -8,12 +8,13 @@ use k210_hal::pac;
use k210_hal::prelude::*; use k210_hal::prelude::*;
use k210_hal::stdout::Stdout; 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::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::lcd_colors;
use k210_shared::board::msa300; use k210_shared::board::msa300;
use k210_shared::soc::fpioa; use k210_shared::soc::fpioa;
use k210_shared::soc::i2c; use k210_shared::soc::i2c;
use k210_shared::soc::sleep::usleep; use k210_shared::soc::sleep::usleep;
use k210_shared::soc::spi::SPIExt;
use k210_shared::soc::sysctl; use k210_shared::soc::sysctl;
use libm::F32Ext; use libm::F32Ext;
use riscv_rt::entry; use riscv_rt::entry;
@ -75,9 +76,11 @@ fn main() -> ! {
io_mux_init(); io_mux_init();
io_set_power(); io_set_power();
lcd::init(); let spi = p.SPI0.constrain();
lcd::set_direction(lcd::direction::YX_LRUD); let lcd = LCD::new(spi);
lcd::clear(lcd_colors::PURPLE); lcd.init();
lcd.set_direction(lcd::direction::YX_LRUD);
lcd.clear(lcd_colors::PURPLE);
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2]; 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); // usleep(10000);
} }
} }

View File

@ -8,12 +8,13 @@ use k210_hal::pac;
use k210_hal::prelude::*; use k210_hal::prelude::*;
use k210_hal::stdout::Stdout; 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::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::lcd_colors;
use k210_shared::board::ns2009::TouchScreen; use k210_shared::board::ns2009::TouchScreen;
use k210_shared::soc::fpioa; use k210_shared::soc::fpioa;
use k210_shared::soc::i2c; use k210_shared::soc::i2c;
use k210_shared::soc::sleep::usleep; use k210_shared::soc::sleep::usleep;
use k210_shared::soc::spi::SPIExt;
use k210_shared::soc::sysctl; use k210_shared::soc::sysctl;
use riscv_rt::entry; use riscv_rt::entry;
@ -153,9 +154,11 @@ fn main() -> ! {
io_mux_init(); io_mux_init();
io_set_power(); io_set_power();
lcd::init(); let spi = p.SPI0.constrain();
lcd::set_direction(lcd::direction::YX_LRUD); let lcd = LCD::new(spi);
lcd::clear(lcd_colors::PURPLE); lcd.init();
lcd.set_direction(lcd::direction::YX_LRUD);
lcd.clear(lcd_colors::PURPLE);
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2]; 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(); universe.iterate();
} }

View File

@ -14,10 +14,11 @@ use k210_hal::pac;
use k210_hal::prelude::*; use k210_hal::prelude::*;
use k210_hal::stdout::Stdout; use k210_hal::stdout::Stdout;
use k210_shared::board::def::io; 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::board::lcd_colors;
use k210_shared::soc::fpioa; use k210_shared::soc::fpioa;
use k210_shared::soc::sleep::usleep; use k210_shared::soc::sleep::usleep;
use k210_shared::soc::spi::SPIExt;
use k210_shared::soc::sysctl; use k210_shared::soc::sysctl;
use riscv_rt::entry; use riscv_rt::entry;
@ -114,9 +115,11 @@ fn main() -> ! {
.unwrap(); .unwrap();
/* LCD init */ /* LCD init */
lcd::init(); let spi = p.SPI0.constrain();
lcd::set_direction(lcd::direction::YX_RLDU); let lcd = LCD::new(spi);
lcd::clear(lcd_colors::PURPLE); 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 image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
let mut console: Console = Console::new(); let mut console: Console = Console::new();
@ -192,7 +195,7 @@ fn main() -> ! {
} }
console.render(&mut image); 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(); writeln!(stdout, "test {}", frame).unwrap();
usleep(1_000_000); usleep(1_000_000);

View File

@ -6,7 +6,7 @@ use pac::spi0::spi_ctrlr0;
use crate::soc::gpio; use crate::soc::gpio;
use crate::soc::gpiohs; use crate::soc::gpiohs;
use crate::soc::sleep::usleep; use crate::soc::sleep::usleep;
use crate::soc::spi; use crate::soc::spi::SPI;
pub const SPI_SLAVE_SELECT: u32 = 3; pub const SPI_SLAVE_SELECT: u32 = 3;
pub const DCX_GPIONUM: u8 = 2; pub const DCX_GPIONUM: u8 = 2;
@ -111,198 +111,207 @@ pub enum direction {
pub const DIR_XY_MASK: u8 = 0x20; pub const DIR_XY_MASK: u8 = 0x20;
pub const DIR_MASK: u8 = 0xE0; pub const DIR_MASK: u8 = 0xE0;
/* Low-level functions */ pub struct LCD<SPI> {
spi: SPI,
fn init_dcx() {
gpiohs::set_direction(DCX_GPIONUM, gpio::direction::OUTPUT);
gpiohs::set_pin(DCX_GPIONUM, true);
} }
fn set_dcx_control() { impl<X: SPI> LCD<X> {
gpiohs::set_pin(DCX_GPIONUM, false); pub fn new(spi: X) -> Self {
} Self { spi }
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;
} }
else
{ /* Low-level functions */
lcd_ctl.width = LCD_X_MAX - 1;
lcd_ctl.height = LCD_Y_MAX - 1; fn init_dcx(&self) {
gpiohs::set_direction(DCX_GPIONUM, gpio::direction::OUTPUT);
gpiohs::set_pin(DCX_GPIONUM, true);
} }
*/
write_command(command::MEMORY_ACCESS_CTL); fn set_dcx_control(&self) {
write_byte(&[dir as u8]); gpiohs::set_pin(DCX_GPIONUM, false);
} }
pub fn set_area(x1: u16, y1: u16, x2: u16, y2: u16) { fn set_dcx_data(&self) {
write_command(command::HORIZONTAL_ADDRESS_SET); gpiohs::set_pin(DCX_GPIONUM, true);
write_byte(&[ }
(x1 >> 8) as u8,
(x1 & 0xff) as u8, fn init_rst(&self) {
(x2 >> 8) as u8, gpiohs::set_direction(RST_GPIONUM, gpio::direction::OUTPUT);
(x2 & 0xff) as u8, gpiohs::set_pin(RST_GPIONUM, true);
]); }
write_command(command::VERTICAL_ADDRESS_SET); fn set_rst(&self, val: bool) {
write_byte(&[ gpiohs::set_pin(RST_GPIONUM, val);
(y1 >> 8) as u8, }
(y1 & 0xff) as u8,
(y2 >> 8) as u8, pub fn hard_init(&self) {
(y2 & 0xff) as u8, self.init_dcx();
]); self.init_rst();
self.set_rst(false);
write_command(command::MEMORY_WRITE); self.spi.set_clk_rate(10000000);
} self.spi.configure(
ctrlr0::WORK_MODEW::MODE0,
pub fn clear(color: u16) { ctrlr0::FRAME_FORMATW::OCTAL,
let data = ((color as u32) << 16) | (color as u32); 8,
0,
//set_area(0, 0, lcd_ctl.width, lcd_ctl.height); 8, /*instruction length*/
set_area(0, 0, LCD_X_MAX - 1, LCD_Y_MAX - 1); 0, /*address length*/
fill_data(data, (LCD_X_MAX as usize) * (LCD_Y_MAX as usize) / 2); 0, /*wait cycles*/
} spi_ctrlr0::AITMW::AS_FRAME_FORMAT,
ctrlr0::TMODW::TRANS,
pub fn draw_picture(x1: u16, y1: u16, width: u16, height: u16, data: &[u32]) { );
set_area(x1, y1, x1 + width - 1, y1 + height - 1); self.set_rst(true);
assert!(data.len() == (width as usize) * (height as usize) / 2); }
write_word(data);
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);
}
} }

View File

@ -1,133 +1,189 @@
use core::cmp; use core::cmp;
use core::ops::Deref;
use k210_hal::pac; use k210_hal::pac;
use pac::{SPI0,SPI1,spi0};
use pac::spi0::ctrlr0; use pac::spi0::ctrlr0;
use pac::spi0::spi_ctrlr0; use pac::spi0::spi_ctrlr0;
use crate::soc::sysctl; use crate::soc::sysctl;
pub fn clk_init() { /// Extension trait that constrains SPI peripherals
sysctl::clock_enable(sysctl::clock::SPI0); pub trait SPIExt: Sized {
sysctl::clock_set_threshold(sysctl::threshold::SPI0, 0); /// Constrains SPI peripheral so it plays nicely with the other abstractions
unsafe { fn constrain(self) -> SPIImpl<Self>;
(*pac::SPI0::ptr()).baudr.write(|w| w.bits(0x14)); // Set baudrate to some default }
/// 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( pub struct SPIImpl<IF> {
work_mode: ctrlr0::WORK_MODEW, spi: IF,
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); pub trait SPI {
let addr_l: u8 = address_length / 4; 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 { impl<IF: SPI01> SPIImpl<IF> {
let ptr = pac::SPI0::ptr(); pub fn new(spi: IF) -> Self {
(*ptr).imr.write(|w| w.bits(0x00)); Self { spi }
(*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));
} }
} }
pub fn set_clk_rate(spi_clk: u32) -> u32 { impl<IF: SPI01> SPI for SPIImpl<IF> {
let clock_freq: u32 = sysctl::clock_get_freq(sysctl::clock::SPI0); /// Configure SPI transaction
let spi_baudr = clock_freq / spi_clk; fn configure(
// Clamp baudrate divider to valid range &self,
let spi_baudr = cmp::min(cmp::max(spi_baudr, 2), 65534); work_mode: ctrlr0::WORK_MODEW,
unsafe { frame_format: ctrlr0::FRAME_FORMATW,
(*pac::SPI0::ptr()).baudr.write(|w| w.bits(spi_baudr)); 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]) { /// Set SPI clock rate
unsafe { fn set_clk_rate(&self, spi_clk: u32) -> u32 {
let ptr = pac::SPI0::ptr(); 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)); /// Send arbitrary data
(*ptr).ssienr.write(|w| w.bits(0x01)); 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 // TODO: write this using iterators / slices
let mut i = 0; let mut i = 0;
let mut tx_len = tx.len(); let mut tx_len = tx.len();
while tx_len != 0 { while tx_len != 0 {
let fifo_len = (32 - (*ptr).txflr.read().bits()) as usize; let fifo_len = (32 - self.spi.txflr.read().bits()) as usize;
let fifo_len = cmp::min(fifo_len, tx_len); let fifo_len = cmp::min(fifo_len, tx_len);
for _ in 0..fifo_len { for _ in 0..fifo_len {
(*ptr).dr[0].write(|f| f.bits(tx[i].into())); self.spi.dr[0].write(|f| f.bits(tx[i].into()));
i += 1; i += 1;
}
tx_len -= fifo_len;
} }
tx_len -= fifo_len;
}
while ((*ptr).sr.read().bits() & 0x05) != 0x04 { while (self.spi.sr.read().bits() & 0x05) != 0x04 {
// IDLE // 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));
} }
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 { /// Send repeated data
// IDLE 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));
} }
} }

View File

@ -10,10 +10,11 @@ use k210_hal::pac;
use k210_hal::prelude::*; use k210_hal::prelude::*;
use k210_hal::stdout::Stdout; use k210_hal::stdout::Stdout;
use k210_shared::board::def::{io,DISP_WIDTH,DISP_HEIGHT}; 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::board::lcd_colors;
use k210_shared::soc::fpioa; use k210_shared::soc::fpioa;
use k210_shared::soc::sleep::usleep; use k210_shared::soc::sleep::usleep;
use k210_shared::soc::spi::SPIExt;
use k210_shared::soc::sysctl; use k210_shared::soc::sysctl;
use riscv_rt::entry; use riscv_rt::entry;
@ -79,9 +80,11 @@ fn main() -> ! {
io_mux_init(); io_mux_init();
io_set_power(); io_set_power();
lcd::init(); let spi = p.SPI0.constrain();
lcd::set_direction(lcd::direction::YX_RLDU); let lcd = LCD::new(spi);
lcd::clear(lcd_colors::PURPLE); 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 image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
@ -96,7 +99,7 @@ fn main() -> ! {
ofs += 1; 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; frame += 1;
zoom *= 0.98f32; zoom *= 0.98f32;