--- /dev/null
+/*
+ * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+use core::ptr;
+use screen;
+use gpio;
+use i2c;
+
+pub struct Display {
+ reset_gpio: u32,
+ reset_gpio_pin: u32,
+ i2c_slave_address: u8,
+}
+
+fn delay(u: u32) {
+ let mut r = u;
+
+ unsafe {
+ loop {
+ let x = ptr::read_volatile(&r);
+ ptr::write_volatile(&mut r, x - 1);
+
+ if x == 0 {
+ break
+ }
+
+ let mut a = 0;
+
+ loop {
+ let x = ptr::read_volatile(&a);
+ ptr::write_volatile(&mut a, x + 1);
+
+ if x == 5000 {
+ break
+ }
+ }
+ }
+ }
+}
+
+fn delay2(u: u32) {
+ let mut r = u;
+
+ unsafe {
+ loop {
+ let x = ptr::read_volatile(&r);
+ ptr::write_volatile(&mut r, x - 1);
+
+ if x == 0 {
+ break
+ }
+ }
+ }
+}
+
+impl Display {
+ pub fn new(reset_gpio: u32, reset_gpio_pin: u32, i2c_slave_address: u8) -> Display {
+ Display {
+ reset_gpio: reset_gpio,
+ reset_gpio_pin: reset_gpio_pin,
+ i2c_slave_address: i2c_slave_address,
+ }
+ }
+
+ pub fn init(&mut self) {
+ let init_sequence : [u8; 18] = [
+ 0x3a,
+ 0x88,
+ 0x88,
+ 0x88,
+ 0x88,
+ 0x60,
+ 0xe3,
+ 0x2f,
+ 0x30,
+ 0x96,
+ 0xa4,
+ 0xb1,
+ 0x53,
+ 0xb2,
+ 0x78,
+ 0x01,
+ 0x60,
+ 0x3d,
+ ];
+
+ gpio::clear(self.reset_gpio, self.reset_gpio_pin);
+ delay(100);
+ gpio::set(self.reset_gpio, self.reset_gpio_pin);
+ delay(100);
+
+ for &b in init_sequence.iter() {
+ self.write_command(b);
+ }
+ }
+
+ pub fn clear(&mut self) {
+ self.seek(0, 0);
+
+ for _ in 0..(32 * 128) {
+ self.write_data(0x00);
+ }
+ }
+
+ pub fn draw(&mut self, screen: &screen::Screen) {
+ let mut mask : u8 = 0x80;
+
+ for col in 0..screen::WIDTH_PX {
+ mask = mask.rotate_left(1);
+
+ // Rotate by 90 degrees.
+ //
+ // Also skip special columns 0..8 which we don't consider
+ // to be part of the screen (they hold the icon area).
+ self.seek(screen::WIDTH_PX - 1 - col, 9);
+
+ // We'll draw eight pixels at once.
+ for row in 0..(screen::HEIGHT_PX / 8) {
+ let mut combined = 0;
+
+ for sub in 0..8 {
+ let index = ((row as usize * 8) + sub) * screen::WIDTH_BYTES
+ + (col as usize / 8);
+ let pixel = screen.pixel(index);
+
+ combined <<= 1;
+
+ if (pixel & mask) != 0 {
+ combined |= 1;
+ }
+ }
+
+ self.write_data(combined);
+ }
+ }
+ }
+
+ fn write_command(&self, c: u8) {
+ i2c::tx16(i2c::I2C0, self.i2c_slave_address, 0x80 | ((c as u16) << 8));
+ delay2(50);
+ }
+
+ fn write_data(&self, d: u8) {
+ i2c::tx16(i2c::I2C0, self.i2c_slave_address, 0xc0 | ((d as u16) << 8));
+ delay2(50);
+ }
+
+ fn seek(&self, row: usize, col: usize) {
+ self.write_command(0x00 | ((row >> 0) & 0x0f) as u8);
+ self.write_command(0x10 | ((row >> 4) & 0x07) as u8);
+ self.write_command(0xc0 | ((col >> 0) & 0x1f) as u8);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+pub const HEIGHT_PX: usize = 70;
+pub const WIDTH_PX: usize = 70;
+
+pub const WIDTH_BYTES: usize = (WIDTH_PX as usize + 7) / 8;
+
+pub const SIZE_BYTES: usize = HEIGHT_PX as usize * WIDTH_BYTES;
+
+pub struct Screen {
+ pixels: [u8; SIZE_BYTES],
+}
+
+impl Screen {
+ pub fn new() -> Screen {
+ Screen {
+ pixels: [0u8; SIZE_BYTES],
+ }
+ }
+
+ pub fn pixel(&self, index: usize) -> u8 {
+ self.pixels[index]
+ }
+
+ pub fn blit(&mut self, new_contents: [u8; SIZE_BYTES]) {
+ self.pixels = new_contents;
+ }
+}