From 4dac1feb85c5b36c7c1c801ff481e7f4ca91d622 Mon Sep 17 00:00:00 2001 From: Le Roux Bodenstein Date: Sat, 2 Nov 2019 21:28:05 +0000 Subject: [PATCH] initial commit --- .gitignore | 1 + README | 0 cpp/README | 0 cpp/include/README | 39 ++++ cpp/lib/README | 46 +++++ cpp/lib/color_utils/color_utils.cpp | 6 + cpp/lib/color_utils/color_utils.h | 1 + cpp/lib/keyboard/keyboard.cpp | 110 +++++++++++ cpp/lib/keyboard/keyboard.h | 25 +++ cpp/lib/pixel_buffer/font.cpp | 260 ++++++++++++++++++++++++ cpp/lib/pixel_buffer/pixel_buffer.cpp | 42 ++++ cpp/lib/pixel_buffer/pixel_buffer.h | 5 + cpp/lib/st7789vi/st7789vi.cpp | 272 ++++++++++++++++++++++++++ cpp/lib/st7789vi/st7789vi.h | 43 ++++ cpp/platformio.ini | 24 +++ cpp/src/main.cpp | 135 +++++++++++++ cpp/test/README | 11 ++ pcb/README | 0 rust/README | 0 19 files changed, 1020 insertions(+) create mode 100644 .gitignore create mode 100644 README create mode 100644 cpp/README create mode 100644 cpp/include/README create mode 100644 cpp/lib/README create mode 100644 cpp/lib/color_utils/color_utils.cpp create mode 100644 cpp/lib/color_utils/color_utils.h create mode 100644 cpp/lib/keyboard/keyboard.cpp create mode 100644 cpp/lib/keyboard/keyboard.h create mode 100644 cpp/lib/pixel_buffer/font.cpp create mode 100644 cpp/lib/pixel_buffer/pixel_buffer.cpp create mode 100644 cpp/lib/pixel_buffer/pixel_buffer.h create mode 100644 cpp/lib/st7789vi/st7789vi.cpp create mode 100644 cpp/lib/st7789vi/st7789vi.h create mode 100644 cpp/platformio.ini create mode 100644 cpp/src/main.cpp create mode 100644 cpp/test/README create mode 100644 pcb/README create mode 100644 rust/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/cpp/README b/cpp/README new file mode 100644 index 0000000..e69de29 diff --git a/cpp/include/README b/cpp/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/cpp/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/cpp/lib/README b/cpp/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/cpp/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/cpp/lib/color_utils/color_utils.cpp b/cpp/lib/color_utils/color_utils.cpp new file mode 100644 index 0000000..059bc25 --- /dev/null +++ b/cpp/lib/color_utils/color_utils.cpp @@ -0,0 +1,6 @@ +#include + +uint16_t rgb_to_12bit(float r, float g, float b) { + return ((uint16_t)(r*15) << 8) | ((uint16_t)(g*15) << 4) | (uint16_t)(b*15); +} + diff --git a/cpp/lib/color_utils/color_utils.h b/cpp/lib/color_utils/color_utils.h new file mode 100644 index 0000000..40fe0a9 --- /dev/null +++ b/cpp/lib/color_utils/color_utils.h @@ -0,0 +1 @@ +uint16_t rgb_to_12bit(float r, float g, float b); diff --git a/cpp/lib/keyboard/keyboard.cpp b/cpp/lib/keyboard/keyboard.cpp new file mode 100644 index 0000000..b3562ac --- /dev/null +++ b/cpp/lib/keyboard/keyboard.cpp @@ -0,0 +1,110 @@ +#include +#include "keyboard.h" +//#include + +// this is slightly inefficient because not all 5 rows have 13 keys each and we could have fit escape in there +unsigned long keys_down[5 * 13 + 1]; +// this is inefficient because we only need one bit per key +byte keys_pressed[5 * 13 + 1]; + +#define KEY_REPEAT 200 + +/* +void requestEvent() { + Wire.write(keys, 8); + for (int i=0; i<8; ++i) { + keys[i] = 0; + } +} +*/ + +void keyboard_init() { + pinMode(R0, OUTPUT); + pinMode(R1, OUTPUT); + pinMode(R2, OUTPUT); + pinMode(R3, OUTPUT); + pinMode(R4, OUTPUT); + + pinMode(C0, INPUT_PULLDOWN); + pinMode(C1, INPUT_PULLDOWN); + pinMode(C2, INPUT_PULLDOWN); + pinMode(C3, INPUT_PULLDOWN); + pinMode(C4, INPUT_PULLDOWN); + pinMode(C5, INPUT_PULLDOWN); + pinMode(C6, INPUT_PULLDOWN); + pinMode(C7, INPUT_PULLDOWN); + pinMode(C8, INPUT_PULLDOWN); + pinMode(C9, INPUT_PULLDOWN); + pinMode(C10, INPUT_PULLDOWN); + pinMode(C11, INPUT_PULLDOWN); + pinMode(C12, INPUT_PULLDOWN); + + pinMode(ESC, INPUT_PULLDOWN); + + //Wire.begin(); + //Wire.begin(8); + //Wire.onRequest(requestEvent); +} + + +void key_press(uint8_t index, unsigned long time) { + keys_down[index] = time; + keys_pressed[index] = 1; +} + +void key_up(uint8_t index) { + keys_down[index] = 0; +} + +void check_key(uint8_t index, byte value) { + if (value == HIGH) { + unsigned long time = millis(); + + // TODO: we probably don't even need this check if we only have presses and no keydown events as time - 0 will also be >= KEY_REPEAT + if (keys_down[index]) { + // ignore unless it has been long enough to repeat + if (time - keys_down[index] >= KEY_REPEAT) { + key_press(index, time); + } + } + else { + // wasn't down before, is now so it is pressed + // TODO: do we want keydown events too? + key_press(index, time); + } + } + else { + // TODO: we don't technically have to check this until we have keyup events + if (keys_down[index]) { + key_up(index); + } + } +} + +void keyboard_poll() { + for (int r=0; r<5; r++) { + // TODO: this can be optimised a lot + + digitalWrite(R0, (r == 0) ? HIGH : LOW); + digitalWrite(R1, (r == 1) ? HIGH : LOW); + digitalWrite(R2, (r == 2) ? HIGH : LOW); + digitalWrite(R3, (r == 3) ? HIGH : LOW); + digitalWrite(R4, (r == 4) ? HIGH : LOW); + + check_key(r*13 + 0, digitalRead(C0)); + check_key(r*13 + 1, digitalRead(C1)); + check_key(r*13 + 2, digitalRead(C2)); + check_key(r*13 + 3, digitalRead(C3)); + check_key(r*13 + 4, digitalRead(C4)); + check_key(r*13 + 5, digitalRead(C5)); + check_key(r*13 + 6, digitalRead(C6)); + check_key(r*13 + 7, digitalRead(C7)); + check_key(r*13 + 8, digitalRead(C8)); + check_key(r*13 + 9, digitalRead(C9)); + check_key(r*13 + 10, digitalRead(C10)); + check_key(r*13 + 11, digitalRead(C11)); + check_key(r*13 + 12, digitalRead(C12)); + } + + check_key(5*13, digitalRead(ESC)); +} diff --git a/cpp/lib/keyboard/keyboard.h b/cpp/lib/keyboard/keyboard.h new file mode 100644 index 0000000..ab1fc61 --- /dev/null +++ b/cpp/lib/keyboard/keyboard.h @@ -0,0 +1,25 @@ +#define R0 PC11 +#define R1 PC12 +#define R2 PC13 +#define R3 PC14 +#define R4 PC15 +#define C0 PF1 +#define C1 PC0 +#define C2 PC1 +#define C3 PC2 +#define C4 PC3 +#define C5 PA0 +#define C6 PA1 +#define C7 PA2 +#define C8 PA3 +#define C9 PA4 +#define C10 PA5 +#define C11 PA6 +#define C12 PA7 +#define ESC PF0 + +extern unsigned long keys_down[5 * 13 + 1]; +extern byte keys_pressed[5 * 13 + 1]; + +void keyboard_init(); +void keyboard_poll(); diff --git a/cpp/lib/pixel_buffer/font.cpp b/cpp/lib/pixel_buffer/font.cpp new file mode 100644 index 0000000..30f279e --- /dev/null +++ b/cpp/lib/pixel_buffer/font.cpp @@ -0,0 +1,260 @@ +// Standard ASCII 5x7 font + +static const unsigned char font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; diff --git a/cpp/lib/pixel_buffer/pixel_buffer.cpp b/cpp/lib/pixel_buffer/pixel_buffer.cpp new file mode 100644 index 0000000..668c19a --- /dev/null +++ b/cpp/lib/pixel_buffer/pixel_buffer.cpp @@ -0,0 +1,42 @@ +#include +#include "font.cpp" + +byte pixel_buffer[320*8/2*3]; + +inline void pixel_buffer_draw_pixel(uint16_t x, uint16_t y, uint16_t color) { + + // TODO: a version of this function that can draw two pixels at a time, starting at an even x position could make pixel_buffer_draw_char a lot faster + + // color is a 12-bit color + + uint16_t pixel_offset = y*320 + x; + uint16_t byte_offset = (int)((float)pixel_offset * 1.5); + + if (pixel_offset % 2 == 0) { + pixel_buffer[byte_offset] = (color >> 4) & 0xff;// bits 5 to 12 of color + + // bits 1 to 4 of next byte plus bits 1 to 4 of color + pixel_buffer[byte_offset + 1] = (pixel_buffer[byte_offset + 1] & 0xf) | ((color & 0xf) << 4); + } + else { + // bits 9 to 12 of color plus bits 5 to 8 of current byte + pixel_buffer[byte_offset] = ((color >> 8) & 0xf) | (((pixel_buffer[byte_offset] >> 4) & 0xf) << 4); + pixel_buffer[byte_offset + 1] = color & 0xff;// bits 1 to 8 of color + } +} + +void pixel_buffer_draw_char(uint16_t x, uint16_t y, byte c, uint16_t color, uint16_t bg) { + + for (int8_t i=0; i<5; i++ ) { // Char bitmap = 5 columns + uint8_t line = font[c * 5 + i]; + + for (int8_t j=0; j<8; j++, line >>= 1) { + if (line & 1) { + pixel_buffer_draw_pixel(x+i, y+j, color); + } + else if (bg != color) { + pixel_buffer_draw_pixel(x+i, y+j, bg); + } + } + } +} diff --git a/cpp/lib/pixel_buffer/pixel_buffer.h b/cpp/lib/pixel_buffer/pixel_buffer.h new file mode 100644 index 0000000..88618f9 --- /dev/null +++ b/cpp/lib/pixel_buffer/pixel_buffer.h @@ -0,0 +1,5 @@ +extern byte pixel_buffer[320*8/2*3]; + +//void pixel_buffer_draw_pixel(uint16_t x, uint16_t y, uint16_t color); + +void pixel_buffer_draw_char(uint16_t x, uint16_t y, byte c, uint16_t color, uint16_t bg); diff --git a/cpp/lib/st7789vi/st7789vi.cpp b/cpp/lib/st7789vi/st7789vi.cpp new file mode 100644 index 0000000..2160288 --- /dev/null +++ b/cpp/lib/st7789vi/st7789vi.cpp @@ -0,0 +1,272 @@ +#include +#include "st7789vi.h" +#include + +inline void tft_write_command(uint16_t command) { + CLR_DC + SET_RD + CLR_WR + GPIOB->ODR = (command << 8) & 0xffff; + SET_WR + SET_DC +} + +inline void tft_write_data(uint16_t data1) { + CLR_WR + GPIOB->ODR = (data1 << 8) & 0xffff; + SET_WR +} + +inline void tft_write_data3(uint16_t data1, uint16_t data2, uint16_t data3) { + CLR_WR + GPIOB->ODR = (data1 << 8) & 0xffff; + SET_WR + CLR_WR + GPIOB->ODR = (data2 << 8) & 0xffff; + SET_WR + CLR_WR + GPIOB->ODR = (data3 << 8) & 0xffff; + SET_WR +} + + +inline void tft_set_write_area(uint16_t x, uint16_t y, uint16_t xlen, uint16_t ylen) { + tft_write_command(0x002A); + tft_write_data((x>>8)&0xFF); + tft_write_data((x>>0)&0xFF); + tft_write_data(((x+xlen)>>8)&0xFF); + tft_write_data(((x+xlen)>>0)&0xFF); + + tft_write_command(0x2B); + tft_write_data((y>>8)&0xFF); + tft_write_data((y>>0)&0xFF); + tft_write_data(((y+ylen)>>8)&0xFF); + tft_write_data(((y+ylen)>>0)&0xFF); + } + +void tft_fill_area(uint16_t x, uint16_t y, uint16_t xlen, uint16_t ylen, uint32_t back) { + uint32_t i, total; + tft_set_write_area(x, y, xlen, ylen); + tft_write_command(0x2C); + + //FIXME: Why do I need these +1 adjustments. Off-by-one in tft_set_write_area? + total = (xlen+1) * (ylen+1); + + /* + for (i=0; i>16) & 0xFF, (back>>8) & 0xFF, (back>>0) & 0xFF); + //tft_write_data((back>>16) & 0xFF); + //tft_write_data((back>>8) & 0xFF); + //tft_write_data((back>>0) & 0xFF); + } + */ + // do two pixels at a time using three bytes because 12 bits times 2 = 24 bits + for (i=0; i> 4) & 0xFF); + tft_write_data((back & 0xF) << 4 | (back >> 8) & 0xF); + tft_write_data(back & 0xFF); + */ + tft_write_data3( + (back >> 4) & 0xFF, + ((back & 0xF) << 4) | ((back >> 8) & 0xF), + back & 0xFF + ); + } +} + + +void tft_init() { + /* + + IM0: PA8 (0: 16-bit. 1: 8-bit) + DC: PC8 (1: data, 0: command) + nWR: PA15 (low: write) + nRD: PC7 (low: read) + nRES: PC6 (low: reset) + DB0-DB15: PB0-PB15 (high byte for 8-bit!) + + */ + + // 8 bit mode + pinMode(IM0, OUTPUT); + digitalWrite(IM0, HIGH); + + pinMode(nRES, OUTPUT); + + // control pins + pinMode(DC, OUTPUT); + pinMode(nWR, OUTPUT); + pinMode(nRD, OUTPUT); + + // bi-directional data bus + pinMode(DB0, OUTPUT); + pinMode(DB1, OUTPUT); + pinMode(DB2, OUTPUT); + pinMode(DB3, OUTPUT); + pinMode(DB4, OUTPUT); + pinMode(DB5, OUTPUT); + pinMode(DB6, OUTPUT); + pinMode(DB7, OUTPUT); + pinMode(DB8, OUTPUT); + pinMode(DB9, OUTPUT); + pinMode(DB10, OUTPUT); + pinMode(DB11, OUTPUT); + pinMode(DB12, OUTPUT); + pinMode(DB13, OUTPUT); + pinMode(DB14, OUTPUT); + pinMode(DB15, OUTPUT); + + digitalWrite(nRES, LOW); + digitalWrite(nRD, HIGH); + digitalWrite(nWR, HIGH); + digitalWrite(nRES, HIGH); + delay(2); + + tft_write_command(0x0029); //exit SLEEP mode + + delay(2); + + // MADCTL: memory data access control + tft_write_command(0x0036); + tft_write_data(0x70); //0b01110000 + // page address order: top to bottom (0) + // column adddress order: right to left (1) + // page/column order: reverse mode (1) + // line address order: LEFT refresh bottom to top (1) ML + // RGB/BGR order: RGB (0) + // Display data latch data order: LCD refresh left to right (0) MH + + // COLMOD: Interface Pixel format + tft_write_command(0x003A); + /* + tft_write_data(0x0066); // 0b01100110 + // 0 + // 110 262K of RGB interface + // 0 + // 110 18bit/pixel + */ + tft_write_data(0x03); + + // PORCTRL: Porch setting + tft_write_command(0x00B2); + tft_write_data(0x0C); + tft_write_data(0x0C); + tft_write_data(0x00); + tft_write_data(0x33); + tft_write_data(0x33); + + // GCTRL: Gate Control + tft_write_command(0x00B7); + tft_write_data(0x0035); + + // VCOMS: VCOM setting + tft_write_command(0x00BB); + tft_write_data(0x002B); + + // LCMCTRL: LCM Control + tft_write_command(0x00C0); + tft_write_data(0x002C); + + // VDVVRHEN: VDV and VRH Command Enable + tft_write_command(0x00C2); + tft_write_data(0x0001); + tft_write_data(0xFF); + + // VRHS: VRH Set + tft_write_command(0x00C3); + tft_write_data(0x0011); + + // VDVS: VDV Set[10] + tft_write_command(0x00C4); + tft_write_data(0x0020); + + // FRCTRL2: Frame Rate control in normal mode + tft_write_command(0x00C6); + //tft_write_data(0x000F); // 39Hz which is the slowest setting + //tft_write_data(0x00); // 58Hz (fastest) + tft_write_data(0x05); // 50Hz + + // PWCTRL1: Power Control 1 + tft_write_command(0x00D0); + tft_write_data(0x00A4); + tft_write_data(0xA1); + + // PVGAMCTRL: Positive Voltage Gamma control + tft_write_command(0x00E0); + tft_write_data(0x00D0); + tft_write_data(0x0000); + tft_write_data(0x0005); + tft_write_data(0x000E); + tft_write_data(0x0015); + tft_write_data(0x000D); + tft_write_data(0x0037); + tft_write_data(0x0043); + tft_write_data(0x0047); + tft_write_data(0x0009); + tft_write_data(0x0015); + tft_write_data(0x0012); + tft_write_data(0x0016); + tft_write_data(0x0019); + + // NVGAMCTRL: Negative Voltage Gamma control + tft_write_command(0x00E1); + tft_write_data(0x00D0); + tft_write_data(0x0000); + tft_write_data(0x0005); + tft_write_data(0x000D); + tft_write_data(0x000C); + tft_write_data(0x0006); + tft_write_data(0x002D); + tft_write_data(0x0044); + tft_write_data(0x0040); + tft_write_data(0x000E); + tft_write_data(0x001C); + tft_write_data(0x0018); + tft_write_data(0x0016); + tft_write_data(0x0019); + + // X address set + tft_write_command(0x002A); + tft_write_data(0x0000); + tft_write_data(0x0000); + tft_write_data(0x0001); + tft_write_data(0x003F); + + // Y address set + tft_write_command(0x002B); + tft_write_data(0x0000); + tft_write_data(0x0000); + tft_write_data(0x0000); + tft_write_data(0x00EF); + + // Sleep out + tft_write_command(0x11); + + // Idle mode off + tft_write_command(0x38); + + // Normal display mode on + tft_write_command(0x13); + + delay(100); + + tft_fill_area(0, 0, 320, 240, 0); +} + +void tft_copy_pixel_buffer(uint8_t line_offset) { + tft_set_write_area(0, line_offset * 8, 320, 8); + tft_write_command(0x2C); + + uint16_t i, total; + + total = 320*8/2*3; + + for (i=0; iODR &= ~(1 << 8); +#define SET_DC GPIOC->ODR |= (1 << 8); + +#define CLR_RD GPIOC->ODR &= ~(1 << 7); +#define SET_RD GPIOC->ODR |= (1 << 7); + +#define CLR_WR GPIOA->ODR &= ~(1 << 15); +#define SET_WR GPIOA->ODR |= (1 << 15); + +inline void tft_write_command(uint16_t command); +inline void tft_write_data(uint16_t data1); +inline void tft_write_data3(uint16_t data1, uint16_t data2, uint16_t data3); +inline void tft_set_write_area (uint16_t x, uint16_t y, uint16_t xlen, uint16_t ylen); +void tft_fill_area(uint16_t x, uint16_t y, uint16_t xlen, uint16_t ylen, uint32_t back); +void tft_init(); +void tft_copy_pixel_buffer(uint8_t line_offset); + + diff --git a/cpp/platformio.ini b/cpp/platformio.ini new file mode 100644 index 0000000..f82d3ec --- /dev/null +++ b/cpp/platformio.ini @@ -0,0 +1,24 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:nucleo_g071rb] +platform = ststm32 +board = nucleo_g071rb +framework = arduino + +board_build.f_cpu = 64000000L + +upload_protocol = blackmagic +upload_port = /dev/cu.usbmodem7B497BB51 +debug_tool = blackmagic +debug_port = /dev/cu.usbmodem7B497BB51 + +monitor_speed = 115200 +monitor_port = /dev/cu.usbmodem7B497BB53 diff --git a/cpp/src/main.cpp b/cpp/src/main.cpp new file mode 100644 index 0000000..72f06d2 --- /dev/null +++ b/cpp/src/main.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include + +//uint16_t tileColor = 0; +//uint16_t xTile = 0; +//uint16_t yTile = 0; +uint16_t nextChar = 0; + +HardwareSerial Serial1(PC5, PC4); + +void setup() { + tft_init(); + keyboard_init(); + + Serial1.begin(115200); + Serial1.println("begin"); +} + +void loop() { + /* + keyboard_poll(); + + // debug + for (int r=0; r<5; ++r) { + Serial1.print(keys[r]); + } + Serial1.println(""); + Serial1.print("ESC: "); + Serial1.println(esc); + delay(1000); + */ + uint16_t i, x, y, row, col; + + if (nextChar > 255) { + return; + } + + unsigned long time = micros(); + for (row=0; row<30; row++) { + /* + for (i=0; i<320*8/2*3; i++) { + pixel_buffer[i] = 0; + } + */ + + /* + for (x=0; x<320; x++) { + for (y=0; y<8; y++) { + pixel_buffer_draw_pixel(x, y, rgb_to_12bit(x/320.0, x/320.0, 0)); + } + } + */ + for (col=0; col<53; col++) { + pixel_buffer_draw_char(col*6, 0, nextChar, 4095, 0); + nextChar++; + + if (nextChar > 255) { + //nextChar = 0; + + Serial1.println(micros() - time); + return; + } + } + + tft_copy_pixel_buffer(row); + } + +/* + Serial1.print("DC: "); + Serial1.print(digitalRead(DC)); + Serial1.print(' '); + + Serial1.print("nRD: "); + Serial1.print(digitalRead(nRD)); + Serial1.print(' '); + + Serial1.print("nWR: "); + Serial1.print(digitalRead(nWR)); + Serial1.print(' '); + + Serial1.println(); + delay(1000); + */ + /* + uint32_t color = 0; + for (int i=0; i<255; i++) { + color = i; + color |= i << 8; + color |= i << 16; + tft_fill_area(0, 0, 320, 240, color); + } + */ + + /* + tft_fill_area(xTile, yTile, 16, 16, tileColor); + + xTile += 16; + if (xTile >= 320) { + xTile = 0; + yTile += 16; + if (yTile >= 240) { + yTile = 0; + } + } + */ + + /* + tileColor++; + if (tileColor >= 4096) { + tileColor = 0; + } + */ + + /* + unsigned long time; + uint32_t color = 0; + time = micros(); + for (uint32_t i=0; i<16; i++) { + color = i; + color |= i << 4; + color |= i << 8; + tft_fill_area(0, 0, 320, 240, color); + } + Serial1.println(micros() - time); + */ + + /* + uint32_t color = rgbTo12bit(0.0, 0.0, 1.0); + Serial1.println(color); + tft_fill_area(0, 0, 320, 240, color); + */ +} diff --git a/cpp/test/README b/cpp/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/cpp/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/pcb/README b/pcb/README new file mode 100644 index 0000000..e69de29 diff --git a/rust/README b/rust/README new file mode 100644 index 0000000..e69de29