examples: fix betrusted LCD under Renode

This gets the Betrusted LCD demo working within emulation, which means
it ought to work on real hardware.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-08-18 12:07:41 +08:00
parent 8920ab57cf
commit 1da460cd41
2 changed files with 62 additions and 30 deletions

View file

@ -21,8 +21,8 @@ csr_base,spinor,0xf0008000,,
csr_base,audio,0xf000a800,,
csr_base,ctrl,0xf0000000,,
csr_base,uart,0xf0001800,,
csr_base,memlcd,0xf0004800,,
csr_base,com,0xf0005000,,
csr_base,memlcd,0xf0005000,,
csr_base,com,0xf000c000,,
csr_register,i2c_prescale,0xf0005800,1,rw
csr_register,messible_in,0xf0006800,1,rw
csr_register,i2c_command,0xf0005810,1,rw

1 #--------------------------------------------------------------------------------
21 csr_base,audio,0xf000a800,,
22 csr_base,ctrl,0xf0000000,,
23 csr_base,uart,0xf0001800,,
24 csr_base,memlcd,0xf0004800,, csr_base,memlcd,0xf0005000,,
25 csr_base,com,0xf0005000,, csr_base,com,0xf000c000,,
26 csr_register,i2c_prescale,0xf0005800,1,rw
27 csr_register,messible_in,0xf0006800,1,rw
28 csr_register,i2c_command,0xf0005810,1,rw

View file

@ -1,4 +1,5 @@
use embedded_graphics::{drawable::Pixel, geometry::Size, pixelcolor::BinaryColor, DrawTarget};
use xous::MemoryRange;
const FB_WIDTH_WORDS: usize = 11;
const FB_WIDTH_PIXELS: usize = 336;
@ -6,26 +7,37 @@ const FB_LINES: usize = 536;
const FB_SIZE: usize = FB_WIDTH_WORDS * FB_LINES; // 44 bytes by 536 lines
const CONFIG_CLOCK_FREQUENCY: u32 = 100_000_000;
// const MAX_FPS: u64 = 15;
const COMMAND_OFFSET: usize = 0;
const BUSY_OFFSET: usize = 1;
const PRESCALER_OFFSET: usize = 2;
pub struct XousDisplay {
fb: &'static mut [u32; FB_WIDTH_PIXELS * FB_LINES],
control: *mut u32,
fb: MemoryRange,
control: MemoryRange,
}
impl XousDisplay {
pub fn new() -> XousDisplay {
let fb = unsafe { &mut *(0xb000_0000 as *mut [u32; FB_WIDTH_PIXELS * FB_LINES]) };
let mut display = XousDisplay {
fb,
control: 0xf000_a000u32 as _,
};
let fb = xous::syscall::map_memory(
xous::MemoryAddress::new(0xb000_0000),
None,
((FB_WIDTH_WORDS * FB_LINES * 4) + 4096) & !4095,
xous::MemoryFlags::R | xous::MemoryFlags::W,
)
.expect("couldn't map control port");
let control = xous::syscall::map_memory(
xous::MemoryAddress::new(0xf000_5000),
None,
4096,
xous::MemoryFlags::R | xous::MemoryFlags::W,
)
.expect("couldn't map control port");
let mut display = XousDisplay { fb, control };
display.set_clock(CONFIG_CLOCK_FREQUENCY);
display.sync_clear();
display
}
@ -41,28 +53,37 @@ impl XousDisplay {
///
fn set_clock(&mut self, clk_mhz: u32) {
unsafe {
self.control
(self.control.as_ptr() as *mut u32)
.add(PRESCALER_OFFSET)
.write_volatile((clk_mhz / 2_000_000) - 1);
}
}
fn update_all(&mut self) {
unsafe { self.control.add(COMMAND_OFFSET).write_volatile(2) };
unsafe {
(self.control.as_ptr() as *mut u32)
.add(COMMAND_OFFSET)
.write_volatile(2)
};
}
fn update_dirty(&mut self) {
unsafe { self.control.add(COMMAND_OFFSET).write_volatile(1) };
unsafe {
(self.control.as_ptr() as *mut u32)
.add(COMMAND_OFFSET)
.write_volatile(1)
};
}
/// "synchronous clear" -- must be called on init, so that the state of the LCD
/// internal memory is consistent with the state of the frame buffer
fn sync_clear(&mut self) {
let framebuffer = self.fb.as_mut_ptr() as *mut u32;
for words in 0..FB_SIZE {
if words % FB_WIDTH_WORDS != 10 {
self.fb[words] = 0xFFFF_FFFF;
unsafe { framebuffer.add(words).write_volatile(0xFFFF_FFFF) };
} else {
self.fb[words] = 0x0000_FFFF;
unsafe { framebuffer.add(words).write_volatile(0x0000_FFFF) };
}
}
self.update_all(); // because we force an all update here
@ -70,35 +91,46 @@ impl XousDisplay {
}
fn busy(&self) -> bool {
unsafe { self.control.add(BUSY_OFFSET).read_volatile() == 1 }
unsafe {
(self.control.as_ptr() as *mut u32)
.add(BUSY_OFFSET)
.read_volatile()
== 1
}
}
}
impl DrawTarget<BinaryColor> for XousDisplay {
type Error = core::convert::Infallible;
/// Draw a `Pixel` that has a color defined as `Gray8`.
/// Draw a `Pixel` that has a color defined as `BinaryColor`.
fn draw_pixel(&mut self, pixel: Pixel<BinaryColor>) -> Result<(), Self::Error> {
let Pixel(coord, color) = pixel;
let framebuffer = self.fb.as_mut_ptr() as *mut u32;
let offset = (coord.x / 32 + coord.y * FB_WIDTH_WORDS as i32) as usize;
match color {
BinaryColor::Off => {
self.fb[(coord.x / 32 + coord.y * FB_WIDTH_WORDS as i32) as usize] |=
1 << (coord.x % 32)
unsafe {
framebuffer.add(offset).write_volatile(
framebuffer.add(offset).read_volatile() | (1 << (coord.x % 32)),
)
};
}
BinaryColor::On => {
self.fb[(coord.x / 32 + coord.y * FB_WIDTH_WORDS as i32) as usize] &=
!(1 << (coord.x % 32))
unsafe {
framebuffer.add(offset).write_volatile(
framebuffer.add(offset).read_volatile() & !(1 << (coord.x % 32)),
)
};
}
}
// set the dirty bit on the line
self.fb[(coord.y * FB_WIDTH_WORDS as i32 + (FB_WIDTH_WORDS as i32 - 1)) as usize] |=
0x1_0000;
// self.buffer[(point.y * (WIDTH as i32) + point.x) as usize] = if color == BinaryColor::On {
// LIGHT_COLOUR
// } else {
// DARK_COLOUR
// };
// set the dirty bit on the line
unsafe {
framebuffer
.add(offset)
.write_volatile(framebuffer.add(offset).read_volatile() | 0x1_0000)
};
Ok(())
}