common: Add the display module.
authorTilman Sauerbeck <tilman@code-monkey.de>
Wed, 18 Dec 2019 08:01:56 +0000 (09:01 +0100)
committerTilman Sauerbeck <tilman@code-monkey.de>
Sun, 5 Jan 2020 19:38:11 +0000 (20:38 +0100)
It currently can initialize, clear and draw the main area
of the display. Drawing or clearing the icon area is not yet
supported.

SConscript.libcommon
src/common/display.rs [new file with mode: 0644]
src/common/lib.rs
src/common/screen.rs [new file with mode: 0644]

index 71044a6f28c35c9d6b1f334d1a6c03b503bf34cc..d353e613912d6979f9c702ff75de3f44e44f791e 100644 (file)
@@ -14,6 +14,8 @@ source_files_rs = [
     'src/common/crc32.rs',
     'src/common/buffer.rs',
     'src/common/usb_serial.rs',
+    'src/common/display.rs',
+    'src/common/screen.rs',
 ]
 
 source_files_c = [
diff --git a/src/common/display.rs b/src/common/display.rs
new file mode 100644 (file)
index 0000000..4f09ef5
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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);
+    }
+}
index c3b23bf5da5883a8d773c9d1afbc10272bcb2e84..b6a08c71904f78ae5a812fe611ae144e6893e3cd 100644 (file)
@@ -36,6 +36,8 @@ pub mod watchdog;
 pub mod crc32;
 pub mod buffer;
 pub mod usb_serial;
+pub mod screen;
+pub mod display;
 
 use core::panic::PanicInfo;
 
diff --git a/src/common/screen.rs b/src/common/screen.rs
new file mode 100644 (file)
index 0000000..71425c4
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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;
+    }
+}