mirror of
https://github.com/laanwj/k210-sdk-stuff.git
synced 2024-11-25 02:46:18 +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)
|
[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
|
ROM re'ing
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ members = [
|
|||||||
"rgbcontrol",
|
"rgbcontrol",
|
||||||
"weather",
|
"weather",
|
||||||
"dvp-ov",
|
"dvp-ov",
|
||||||
|
"glyph-mapping",
|
||||||
]
|
]
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
@ -59,8 +59,6 @@ fn io_init() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = pac::Peripherals::take().unwrap();
|
let p = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
// Configure clocks (TODO)
|
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
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
|
/** Set address for planar R8G8B8 output `Option<(r_addr, g_addr, b_addr)>`.
|
||||||
* `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)>) {
|
pub fn set_ai_addr(&self, addr: Option<(*mut u8, *mut u8, *mut u8)>) {
|
||||||
if let Some((r_addr, g_addr, b_addr)) = addr {
|
if let Some((r_addr, g_addr, b_addr)) = addr {
|
||||||
|
Loading…
Reference in New Issue
Block a user