mirror of
https://github.com/laanwj/k210-sdk-stuff.git
synced 2024-11-22 01:16:20 +04:00
rust: Add rust version of glyph mapping demo
This commit is contained in:
parent
1531cc8fe0
commit
ec7ce47dff
@ -195,6 +195,13 @@ SDK: read frames from the OV2640 image sensor and display them on the LCD.
|
||||
|
||||
[README](rust/dvp-ov/README.md)
|
||||
|
||||
rust/glyph-mapping
|
||||
------------------
|
||||
|
||||
Rust port of the glyph mapping demo.
|
||||
|
||||
[README](rust/glyph-mapping/README.md)
|
||||
|
||||
ROM re'ing
|
||||
===========
|
||||
|
||||
|
@ -8,6 +8,7 @@ members = [
|
||||
"rgbcontrol",
|
||||
"weather",
|
||||
"dvp-ov",
|
||||
"glyph-mapping",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
@ -59,8 +59,6 @@ fn io_init() {
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let p = pac::Peripherals::take().unwrap();
|
||||
|
||||
// Configure clocks (TODO)
|
||||
let clocks = k210_hal::clock::Clocks::new();
|
||||
|
||||
usleep(200000);
|
||||
|
2
rust/glyph-mapping/.gitignore
vendored
Normal file
2
rust/glyph-mapping/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
**/*.rs.bk
|
12
rust/glyph-mapping/Cargo.toml
Normal file
12
rust/glyph-mapping/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "glyph-mapping"
|
||||
version = "0.1.0"
|
||||
authors = ["W.J. van der Laan <laanwj@protonmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
riscv-rt = "0.5.0"
|
||||
k210-hal = "0.1.0"
|
||||
riscv = "0.5"
|
||||
k210-shared = { path = "../k210-shared" }
|
||||
k210-console = { path = "../k210-console" }
|
5
rust/glyph-mapping/README.md
Normal file
5
rust/glyph-mapping/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# `glyph-mapping`
|
||||
|
||||
Display the real-time image from ov5640 passed through a glyph-mapping algorithm.
|
||||
|
||||
This samples the camera in planar R8G8B8 format.
|
146
rust/glyph-mapping/src/main.rs
Normal file
146
rust/glyph-mapping/src/main.rs
Normal file
@ -0,0 +1,146 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use k210_console::console::{Console, ScreenImage};
|
||||
use k210_console::cp437_8x8::GLYPH_BY_FILL;
|
||||
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::{LCD,LCDHL,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;
|
||||
use k210_shared::soc::dvp::{DVPExt,sccb_addr_len,image_format};
|
||||
use k210_shared::board::ov2640;
|
||||
|
||||
/** 64-byte aligned planar RAM */
|
||||
#[repr(align(64))]
|
||||
struct PlanarScreenRAM {
|
||||
pub r: [u8; DISP_WIDTH * DISP_HEIGHT],
|
||||
pub g: [u8; DISP_WIDTH * DISP_HEIGHT],
|
||||
pub b: [u8; DISP_WIDTH * DISP_HEIGHT],
|
||||
}
|
||||
impl PlanarScreenRAM {
|
||||
fn as_mut_ptrs(&mut self) -> (*mut u8, *mut u8, *mut u8) {
|
||||
(self.r.as_mut_ptr(),self.g.as_mut_ptr(),self.b.as_mut_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
static mut FRAME_AI: PlanarScreenRAM = PlanarScreenRAM {
|
||||
r: [0; DISP_WIDTH * DISP_HEIGHT],
|
||||
g: [0; DISP_WIDTH * DISP_HEIGHT],
|
||||
b: [0; DISP_WIDTH * DISP_HEIGHT],
|
||||
};
|
||||
|
||||
/** Connect pins to internal functions */
|
||||
fn io_init() {
|
||||
/* Init DVP IO map and function settings */
|
||||
fpioa::set_function(io::DVP_RST, fpioa::function::CMOS_RST);
|
||||
fpioa::set_function(io::DVP_PWDN, fpioa::function::CMOS_PWDN);
|
||||
fpioa::set_function(io::DVP_XCLK, fpioa::function::CMOS_XCLK);
|
||||
fpioa::set_function(io::DVP_VSYNC, fpioa::function::CMOS_VSYNC);
|
||||
fpioa::set_function(io::DVP_HSYNC, fpioa::function::CMOS_HREF);
|
||||
fpioa::set_function(io::DVP_PCLK, fpioa::function::CMOS_PCLK);
|
||||
fpioa::set_function(io::DVP_SCL, fpioa::function::SCCB_SCLK);
|
||||
fpioa::set_function(io::DVP_SDA, fpioa::function::SCCB_SDA);
|
||||
|
||||
/* Init SPI IO map and function settings */
|
||||
fpioa::set_function(io::LCD_RST, fpioa::function::gpiohs(lcd::RST_GPIONUM));
|
||||
fpioa::set_io_pull(io::LCD_RST, fpioa::pull::DOWN); // outputs must be pull-down
|
||||
fpioa::set_function(io::LCD_DC, fpioa::function::gpiohs(lcd::DCX_GPIONUM));
|
||||
fpioa::set_io_pull(io::LCD_DC, fpioa::pull::DOWN);
|
||||
fpioa::set_function(io::LCD_CS, fpioa::function::SPI0_SS3);
|
||||
fpioa::set_function(io::LCD_WR, fpioa::function::SPI0_SCLK);
|
||||
|
||||
sysctl::set_spi0_dvp_data(true);
|
||||
|
||||
/* Set DVP and SPI pin to 1.8V */
|
||||
sysctl::set_power_mode(sysctl::power_bank::BANK6, sysctl::io_power_mode::V18);
|
||||
sysctl::set_power_mode(sysctl::power_bank::BANK7, sysctl::io_power_mode::V18);
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let p = pac::Peripherals::take().unwrap();
|
||||
let clocks = k210_hal::clock::Clocks::new();
|
||||
|
||||
usleep(200000);
|
||||
|
||||
// Configure UART
|
||||
let serial = p.UARTHS.constrain(115_200.bps(), &clocks);
|
||||
let (mut tx, _) = serial.split();
|
||||
|
||||
let mut stdout = Stdout(&mut tx);
|
||||
|
||||
io_init();
|
||||
|
||||
let spi = p.SPI0.constrain();
|
||||
let mut lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_LRUD);
|
||||
lcd.clear(lcd_colors::PURPLE);
|
||||
|
||||
let mut dvp = p.DVP.constrain();
|
||||
writeln!(stdout, "OV2640: init").unwrap();
|
||||
dvp.init(sccb_addr_len::W8);
|
||||
dvp.set_xclk_rate(24000000);
|
||||
dvp.set_image_format(image_format::RGB);
|
||||
dvp.set_image_size(true, 320, 240);
|
||||
ov2640::init(&dvp);
|
||||
writeln!(stdout, "OV2640: init done").unwrap();
|
||||
|
||||
// use planar output for convenient sampling
|
||||
dvp.set_ai_addr(Some(unsafe { FRAME_AI.as_mut_ptrs() }));
|
||||
dvp.set_display_addr(None);
|
||||
dvp.set_auto(false);
|
||||
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
let mut console: Console = Console::new();
|
||||
writeln!(stdout, "Starting frame loop").unwrap();
|
||||
loop {
|
||||
dvp.get_image();
|
||||
|
||||
for y in 0..console.height() {
|
||||
for x in 0..console.width() {
|
||||
// compute average over cell: could use some kernel that emphasizes the center
|
||||
// but this works fairly okay and is nice and fast
|
||||
// /
|
||||
// need to mirror x and y here so that characters are right side up
|
||||
// compared to camera image
|
||||
let mut r = 0;
|
||||
let mut g = 0;
|
||||
let mut b = 0;
|
||||
for iy in 0..8 {
|
||||
for ix in 0..8 {
|
||||
let cx = 319 - (x * 8 + ix) as usize;
|
||||
let cy = 239 - (y * 8 + iy) as usize;
|
||||
let addr = (cy as usize)*320+(cx as usize);
|
||||
r += unsafe { FRAME_AI.r[addr] } as u32;
|
||||
g += unsafe { FRAME_AI.g[addr] } as u32;
|
||||
b += unsafe { FRAME_AI.b[addr] } as u32;
|
||||
}
|
||||
}
|
||||
r /= 8*8;
|
||||
g /= 8*8;
|
||||
b /= 8*8;
|
||||
let i = (77*r + 150*g + 29*b) / 256;
|
||||
console.put_raw(
|
||||
x, y,
|
||||
lcd_colors::rgb565(r as u8, g as u8, b as u8),
|
||||
0,
|
||||
GLYPH_BY_FILL[i as usize].into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.render(&mut image);
|
||||
lcd.draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
}
|
||||
}
|
@ -200,8 +200,10 @@ impl DVP {
|
||||
}
|
||||
}
|
||||
|
||||
/** Set address for planar RGB output for KPU
|
||||
* `Option<(r_addr, g_addr, b_addr)>`
|
||||
/** Set address for planar R8G8B8 output `Option<(r_addr, g_addr, b_addr)>`.
|
||||
* This format is meant for the KPU as input but it's also usable from normal memory,
|
||||
* it's simply an alternative output format. Both `display_addr` and `ai_addr` can be active at
|
||||
* the same time.
|
||||
*/
|
||||
pub fn set_ai_addr(&self, addr: Option<(*mut u8, *mut u8, *mut u8)>) {
|
||||
if let Some((r_addr, g_addr, b_addr)) = addr {
|
||||
|
Loading…
Reference in New Issue
Block a user