Refactor satt/comet46 to use core OLED driver (#17856)
12 files changed, 54 insertions(+), 946 deletions(-) D keyboards/satt/comet46/i2c.c D keyboards/satt/comet46/i2c.h D keyboards/satt/comet46/keymaps/default/config.h M keyboards/satt/comet46/keymaps/default/keymap.c M keyboards/satt/comet46/keymaps/default/rules.mk D keyboards/satt/comet46/keymaps/satt/config.h M keyboards/satt/comet46/keymaps/satt/keymap.c M keyboards/satt/comet46/keymaps/satt/rules.mk D keyboards/satt/comet46/lib/glcdfont.c M keyboards/satt/comet46/rules.mk D keyboards/satt/comet46/ssd1306.c D keyboards/satt/comet46/ssd1306.h
D keyboards/satt/comet46/i2c.c => keyboards/satt/comet46/i2c.c +0 -162
@@ 1,162 0,0 @@ #include <util/twi.h> #include <avr/io.h> #include <stdlib.h> #include <avr/interrupt.h> #include <util/twi.h> #include <stdbool.h> #include "i2c.h" #ifdef USE_I2C // Limits the amount of we wait for any one i2c transaction. // Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is // 9 bits, a single transaction will take around 90μs to complete. // // (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit // poll loop takes at least 8 clock cycles to execute #define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8 #define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE) volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; static volatile uint8_t slave_buffer_pos; static volatile bool slave_has_register_set = false; // Wait for an i2c operation to finish inline static void i2c_delay(void) { uint16_t lim = 0; while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT) lim++; // easier way, but will wait slightly longer // _delay_us(100); } // Setup twi to run at 100kHz or 400kHz (see ./i2c.h SCL_CLOCK) void i2c_master_init(void) { // no prescaler TWSR = 0; // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10. // Check datasheets for more info. TWBR = ((F_CPU/SCL_CLOCK)-16)/2; } // Start a transaction with the given i2c slave address. The direction of the // transfer is set with I2C_READ and I2C_WRITE. // returns: 0 => success // 1 => error uint8_t i2c_master_start(uint8_t address) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA); i2c_delay(); // check that we started successfully if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START)) return 1; TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); i2c_delay(); if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) ) return 1; // slave did not acknowledge else return 0; // success } // Finish the i2c transaction. void i2c_master_stop(void) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); uint16_t lim = 0; while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT) lim++; } // Write one byte to the i2c slave. // returns 0 => slave ACK // 1 => slave NACK uint8_t i2c_master_write(uint8_t data) { TWDR = data; TWCR = (1<<TWINT) | (1<<TWEN); i2c_delay(); // check if the slave acknowledged us return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1; } // Read one byte from the i2c slave. If ack=1 the slave is acknowledged, // if ack=0 the acknowledge bit is not set. // returns: byte read from i2c device uint8_t i2c_master_read(int ack) { TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA); i2c_delay(); return TWDR; } void i2c_reset_state(void) { TWCR = 0; } void i2c_slave_init(uint8_t address) { TWAR = address << 0; // slave i2c address // TWEN - twi enable // TWEA - enable address acknowledgement // TWINT - twi interrupt flag // TWIE - enable the twi interrupt TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN); } ISR(TWI_vect); ISR(TWI_vect) { uint8_t ack = 1; switch(TW_STATUS) { case TW_SR_SLA_ACK: // this device has been addressed as a slave receiver slave_has_register_set = false; break; case TW_SR_DATA_ACK: // this device has received data as a slave receiver // The first byte that we receive in this transaction sets the location // of the read/write location of the slaves memory that it exposes over // i2c. After that, bytes will be written at slave_buffer_pos, incrementing // slave_buffer_pos after each write. if(!slave_has_register_set) { slave_buffer_pos = TWDR; // don't acknowledge the master if this memory loctaion is out of bounds if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) { ack = 0; slave_buffer_pos = 0; } slave_has_register_set = true; } else { i2c_slave_buffer[slave_buffer_pos] = TWDR; BUFFER_POS_INC(); } break; case TW_ST_SLA_ACK: case TW_ST_DATA_ACK: // master has addressed this device as a slave transmitter and is // requesting data. TWDR = i2c_slave_buffer[slave_buffer_pos]; BUFFER_POS_INC(); break; case TW_BUS_ERROR: // something went wrong, reset twi state TWCR = 0; default: break; } // Reset everything, so we are ready for the next TWI interrupt TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN); } #endif
D keyboards/satt/comet46/i2c.h => keyboards/satt/comet46/i2c.h +0 -46
@@ 1,46 0,0 @@ #pragma once #include <stdint.h> #ifndef F_CPU #define F_CPU 16000000UL #endif #define I2C_READ 1 #define I2C_WRITE 0 #define I2C_ACK 1 #define I2C_NACK 0 #define SLAVE_BUFFER_SIZE 0x10 // i2c SCL clock frequency 400kHz #define SCL_CLOCK 400000L extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; void i2c_master_init(void); uint8_t i2c_master_start(uint8_t address); void i2c_master_stop(void); uint8_t i2c_master_write(uint8_t data); uint8_t i2c_master_read(int); void i2c_reset_state(void); void i2c_slave_init(uint8_t address); static inline unsigned char i2c_start_read(unsigned char addr) { return i2c_master_start((addr << 1) | I2C_READ); } static inline unsigned char i2c_start_write(unsigned char addr) { return i2c_master_start((addr << 1) | I2C_WRITE); } // from SSD1306 scrips extern unsigned char i2c_rep_start(unsigned char addr); extern void i2c_start_wait(unsigned char addr); extern unsigned char i2c_readAck(void); extern unsigned char i2c_readNak(void); extern unsigned char i2c_read(unsigned char ack); #define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
D keyboards/satt/comet46/keymaps/default/config.h => keyboards/satt/comet46/keymaps/default/config.h +0 -29
@@ 1,29 0,0 @@ /* This is the c configuration file for the keymap Copyright 2012 Jun Wako <wakojun@gmail.com> Copyright 2015 Jack Humbert This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once // place overrides here /* Use I2C or Serial */ #define USE_I2C #define SSD1306OLED
M keyboards/satt/comet46/keymaps/default/keymap.c => keyboards/satt/comet46/keymaps/default/keymap.c +10 -35
@@ 2,9 2,6 @@ // This is the canonical layout file for the Quantum project. If you want to add another keyboard, #include QMK_KEYBOARD_H #ifdef SSD1306OLED #include "ssd1306.h" #endif @@ // Each layer gets a name for readability, which is then used in the keymap matrix below. 148,8 145,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { return update_tri_layer_state(state, _RAISE, _LOWER, _ADJUST); } //SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h #ifdef SSD1306OLED #ifdef OLED_ENABLE // You need to add source files to SRC in rules.mk when using OLED display functions @@ void set_keylog(uint16_t keycode); 157,25 153,10 @@ const char *read_keylog(void); const char *read_modifier_state(void); const char *read_host_led_state(void); void matrix_init_user(void) { iota_gfx_init(false); // turns on the display } void matrix_scan_user(void) { iota_gfx_task(); // this is what updates the display continuously } void matrix_update(struct CharacterMatrix *dest, const struct CharacterMatrix *source) { if (memcmp(dest->display, source->display, sizeof(dest->display))) { memcpy(dest->display, source->display, sizeof(dest->display)); dest->dirty = true; } } void render_status(struct CharacterMatrix *matrix) { bool oled_task_user(void) { // Layer state char layer_str[22]; matrix_write(matrix, "Layer: "); oled_write_P(PSTR("Layer: "), false); uint8_t layer = get_highest_layer(layer_state); uint8_t default_layer = get_highest_layer(eeconfig_read_default_layer()); @@ switch (layer) { 207,27 188,21 @@ void render_status(struct CharacterMatrix *matrix) { default: snprintf(layer_str, sizeof(layer_str), "Undef-%d", layer); } matrix_write_ln(matrix, layer_str); oled_write_ln(layer_str, false); // Last entered keycode matrix_write_ln(matrix, read_keylog()); oled_write_ln(read_keylog(), false); // Modifier state matrix_write_ln(matrix, read_modifier_state()); oled_write_ln(read_modifier_state(), false); // Host Keyboard LED Status matrix_write(matrix, read_host_led_state()); } oled_write(read_host_led_state(), false); void iota_gfx_task_user(void) { struct CharacterMatrix matrix; matrix_clear(&matrix); render_status(&matrix); matrix_update(&display, &matrix); return false; } #endif//SSD1306OLED #endif bool process_record_user(uint16_t keycode, keyrecord_t *record) { #ifdef SSD1306OLED #ifdef OLED_ENABLE if (record->event.pressed) { set_keylog(keycode); }
M keyboards/satt/comet46/keymaps/default/rules.mk => keyboards/satt/comet46/keymaps/default/rules.mk +3 -2
@@ 1,5 1,6 @@ # If you want to change display settings of the OLED, you need to change the following lines SRC += ./lib/glcdfont.c \ ./lib/keylogger.c \ SRC += ./lib/keylogger.c \ ./lib/modifier_state_reader.c \ ./lib/host_led_state_reader.c OLED_ENABLE = yes
D keyboards/satt/comet46/keymaps/satt/config.h => keyboards/satt/comet46/keymaps/satt/config.h +0 -29
@@ 1,29 0,0 @@ /* This is the c configuration file for the keymap Copyright 2012 Jun Wako <wakojun@gmail.com> Copyright 2015 Jack Humbert This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef CONFIG_USER_H #define CONFIG_USER_H /* Use I2C or Serial */ #define USE_I2C #define SSD1306OLED #endif
M keyboards/satt/comet46/keymaps/satt/keymap.c => keyboards/satt/comet46/keymaps/satt/keymap.c +37 -68
@@ 5,9 5,6 @@ #include "keymap_jis2us.h" #include "action_pseudo_lut.h" #include "keymap_japanese.h" #ifdef SSD1306OLED #include "ssd1306.h" #endif // Each layer gets a name for readability, which is then used in the keymap matrix below. @@ // The underscores don't mean anything - you can have a layer called STUFF or any other name. 176,8 173,7 @@ layer_state_t layer_state_set_user(layer_state_t state) { } } //SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h #ifdef SSD1306OLED #ifdef OLED_ENABLE // You need to add source files to SRC in rules.mk when using OLED display functions @@ void set_keylog(uint16_t keycode); 185,86 181,59 @@ const char *read_keylog(void); const char *read_modifier_state(void); const char *read_host_led_state(void); void matrix_init_user(void) { iota_gfx_init(false); // turns on the display } void matrix_scan_user(void) { iota_gfx_task(); // this is what updates the display continuously } void matrix_update(struct CharacterMatrix *dest, const struct CharacterMatrix *source) { if (memcmp(dest->display, source->display, sizeof(dest->display))) { memcpy(dest->display, source->display, sizeof(dest->display)); dest->dirty = true; } } void render_status(struct CharacterMatrix *matrix) { bool oled_task_user(void) { // Layer state char layer_str[22]; matrix_write(matrix, "Layer: "); oled_write_P(PSTR("Layer: "), false); uint8_t layer = get_highest_layer(layer_state); uint8_t default_layer = biton32(eeconfig_read_default_layer()); switch (layer) { case _QWERTY: switch (default_layer) { case _QWERTY: snprintf(layer_str, sizeof(layer_str), "Qwerty"); break; case _PSEUDO_US: snprintf(layer_str, sizeof(layer_str), "Psuedo_US"); break; default: snprintf(layer_str, sizeof(layer_str), "Undef-%d", default_layer); break; } break; case _RAISE: snprintf(layer_str, sizeof(layer_str), "Raise"); break; case _LOWER: snprintf(layer_str, sizeof(layer_str), "Lower"); break; uint8_t default_layer = get_highest_layer(eeconfig_read_default_layer()); switch (layer) { case _QWERTY: switch (default_layer) { case _QWERTY: snprintf(layer_str, sizeof(layer_str), "Qwerty"); break; case _PSEUDO_US: snprintf(layer_str, sizeof(layer_str), "Psuedo_US"); break; default: snprintf(layer_str, sizeof(layer_str), "Undef-%d", default_layer); break; } break; case _RAISE: snprintf(layer_str, sizeof(layer_str), "Raise"); break; case _LOWER: snprintf(layer_str, sizeof(layer_str), "Lower"); break; case _PSEUDO_US_RAISE: snprintf(layer_str, sizeof(layer_str), "P_US_Raise"); break; case _PSEUDO_US_LOWER: snprintf(layer_str, sizeof(layer_str), "P_US_Lower"); break; case _ADJUST: snprintf(layer_str, sizeof(layer_str), "Adjust"); break; default: snprintf(layer_str, sizeof(layer_str), "Undef-%d", layer); } matrix_write_ln(matrix, layer_str); case _ADJUST: snprintf(layer_str, sizeof(layer_str), "Adjust"); break; default: snprintf(layer_str, sizeof(layer_str), "Undef-%d", layer); } oled_write_ln(layer_str, false); // Last entered keycode matrix_write_ln(matrix, read_keylog()); oled_write_ln(read_keylog(), false); // Modifier state matrix_write_ln(matrix, read_modifier_state()); oled_write_ln(read_modifier_state(), false); // Host Keyboard LED Status matrix_write(matrix, read_host_led_state()); } void iota_gfx_task_user(void) { struct CharacterMatrix matrix; #if DEBUG_TO_SCREEN if (debug_enable) { return; } #endif oled_write(read_host_led_state(), false); matrix_clear(&matrix); render_status(&matrix); matrix_update(&display, &matrix); return false; } #endif//SSD1306OLED #endif bool process_record_user(uint16_t keycode, keyrecord_t *record) { #ifdef SSD1306OLED #ifdef OLED_ENABLE if (record->event.pressed) { set_keylog(keycode); }
M keyboards/satt/comet46/keymaps/satt/rules.mk => keyboards/satt/comet46/keymaps/satt/rules.mk +2 -2
@@ 1,8 1,8 @@ SRC += action_pseudo_lut.c # If you want to change display settings of the OLED, you need to change the following lines SRC += ./lib/glcdfont.c \ ./lib/keylogger.c \ SRC += ./lib/keylogger.c \ ./lib/modifier_state_reader.c \ ./lib/host_led_state_reader.c OLED_ENABLE = yes
D keyboards/satt/comet46/lib/glcdfont.c => keyboards/satt/comet46/lib/glcdfont.c +0 -137
@@ 1,137 0,0 @@ // This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. // See gfxfont.h for newer custom bitmap font info. #include "progmem.h" // Standard ASCII 5x7 font const unsigned char font[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00 };
M keyboards/satt/comet46/rules.mk => keyboards/satt/comet46/rules.mk +2 -3
@@ 17,9 17,8 @@ BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow AUDIO_ENABLE = no # Audio output CUSTOM_MATRIX = lite OLED_DRIVER = SSD1306 # project specific files SRC += matrix.c \ i2c.c \ ssd1306.c SRC += matrix.c QUANTUM_LIB_SRC += uart.c
D keyboards/satt/comet46/ssd1306.c => keyboards/satt/comet46/ssd1306.c +0 -343
@@ 1,343 0,0 @@ #ifdef SSD1306OLED #include "ssd1306.h" #include "i2c.h" #include <string.h> #include "print.h" #ifdef PROTOCOL_LUFA #include "lufa.h" #endif #include "sendchar.h" #include "timer.h" struct CharacterMatrix display; extern const unsigned char font[] PROGMEM; // Set this to 1 to help diagnose early startup problems // when testing power-on with ble. Turn it off otherwise, // as the latency of printing most of the debug info messes // with the matrix scan, causing keys to drop. #define DEBUG_TO_SCREEN 0 //static uint16_t last_battery_update; //static uint32_t vbat; //#define BatteryUpdateInterval 10000 /* milliseconds */ // 'last_flush' is declared as uint16_t, // so this must be less than 65535 #define ScreenOffInterval 60000 /* milliseconds */ #if DEBUG_TO_SCREEN static uint8_t displaying; #endif static uint16_t last_flush; static bool force_dirty = true; // Write command sequence. // Returns true on success. static inline bool _send_cmd1(uint8_t cmd) { bool res = false; if (i2c_start_write(SSD1306_ADDRESS)) { xprintf("failed to start write to %d\n", SSD1306_ADDRESS); goto done; } if (i2c_master_write(0x0 /* command byte follows */)) { print("failed to write control byte\n"); goto done; } if (i2c_master_write(cmd)) { xprintf("failed to write command %d\n", cmd); goto done; } res = true; done: i2c_master_stop(); return res; } // Write 2-byte command sequence. // Returns true on success static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) { if (!_send_cmd1(cmd)) { return false; } return _send_cmd1(opr); } // Write 3-byte command sequence. // Returns true on success static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) { if (!_send_cmd1(cmd)) { return false; } if (!_send_cmd1(opr1)) { return false; } return _send_cmd1(opr2); } #define send_cmd1(c) if (!_send_cmd1(c)) {goto done;} #define send_cmd2(c,o) if (!_send_cmd2(c,o)) {goto done;} #define send_cmd3(c,o1,o2) if (!_send_cmd3(c,o1,o2)) {goto done;} static void clear_display(void) { matrix_clear(&display); // Clear all of the display bits (there can be random noise // in the RAM on startup) send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1); send_cmd3(ColumnAddr, 0, DisplayWidth - 1); if (i2c_start_write(SSD1306_ADDRESS)) { goto done; } if (i2c_master_write(0x40)) { // Data mode goto done; } for (uint8_t row = 0; row < MatrixRows; ++row) { for (uint8_t col = 0; col < DisplayWidth; ++col) { i2c_master_write(0); } } display.dirty = false; done: i2c_master_stop(); } #if DEBUG_TO_SCREEN #undef sendchar static int8_t capture_sendchar(uint8_t c) { sendchar(c); iota_gfx_write_char(c); if (!displaying) { iota_gfx_flush(); } return 0; } #endif bool iota_gfx_init(bool rotate) { bool success = false; i2c_master_init(); send_cmd1(DisplayOff); send_cmd2(SetDisplayClockDiv, 0x80); send_cmd2(SetMultiPlex, DisplayHeight - 1); send_cmd2(SetDisplayOffset, 0); send_cmd1(SetStartLine | 0x0); send_cmd2(SetChargePump, 0x14 /* Enable */); send_cmd2(SetMemoryMode, 0 /* horizontal addressing */); if(rotate){ // the following Flip the display orientation 180 degrees send_cmd1(SegRemap); send_cmd1(ComScanInc); }else{ // Flips the display orientation 0 degrees send_cmd1(SegRemap | 0x1); send_cmd1(ComScanDec); } send_cmd2(SetComPins, 0x2); send_cmd2(SetContrast, 0x8f); send_cmd2(SetPreCharge, 0xf1); send_cmd2(SetVComDetect, 0x40); send_cmd1(DisplayAllOnResume); send_cmd1(NormalDisplay); send_cmd1(DeActivateScroll); send_cmd1(DisplayOn); send_cmd2(SetContrast, 0); // Dim clear_display(); success = true; iota_gfx_flush(); #if DEBUG_TO_SCREEN print_set_sendchar(capture_sendchar); #endif done: return success; } bool iota_gfx_off(void) { bool success = false; send_cmd1(DisplayOff); success = true; done: return success; } bool iota_gfx_on(void) { bool success = false; send_cmd1(DisplayOn); success = true; done: return success; } void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) { *matrix->cursor = c; ++matrix->cursor; if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) { // We went off the end; scroll the display upwards by one line memmove(&matrix->display[0], &matrix->display[1], MatrixCols * (MatrixRows - 1)); matrix->cursor = &matrix->display[MatrixRows - 1][0]; memset(matrix->cursor, ' ', MatrixCols); } } void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) { matrix->dirty = true; if (c == '\n') { // Clear to end of line from the cursor and then move to the // start of the next line uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols; while (cursor_col++ < MatrixCols) { matrix_write_char_inner(matrix, ' '); } return; } matrix_write_char_inner(matrix, c); } void iota_gfx_write_char(uint8_t c) { matrix_write_char(&display, c); } void matrix_write(struct CharacterMatrix *matrix, const char *data) { const char *end = data + strlen(data); while (data < end) { matrix_write_char(matrix, *data); ++data; } } void matrix_write_ln(struct CharacterMatrix *matrix, const char *data) { char data_ln[strlen(data)+2]; snprintf(data_ln, sizeof(data_ln), "%s\n", data); matrix_write(matrix, data_ln); } void iota_gfx_write(const char *data) { matrix_write(&display, data); } void matrix_write_P(struct CharacterMatrix *matrix, const char *data) { while (true) { uint8_t c = pgm_read_byte(data); if (c == 0) { return; } matrix_write_char(matrix, c); ++data; } } void iota_gfx_write_P(const char *data) { matrix_write_P(&display, data); } void matrix_clear(struct CharacterMatrix *matrix) { memset(matrix->display, ' ', sizeof(matrix->display)); matrix->cursor = &matrix->display[0][0]; matrix->dirty = true; } void iota_gfx_clear_screen(void) { matrix_clear(&display); } void matrix_render(struct CharacterMatrix *matrix) { last_flush = timer_read(); iota_gfx_on(); #if DEBUG_TO_SCREEN ++displaying; #endif // Move to the home position send_cmd3(PageAddr, 0, MatrixRows - 1); send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1); if (i2c_start_write(SSD1306_ADDRESS)) { goto done; } if (i2c_master_write(0x40)) { // Data mode goto done; } for (uint8_t row = 0; row < MatrixRows; ++row) { for (uint8_t col = 0; col < MatrixCols; ++col) { const uint8_t *glyph = font + (matrix->display[row][col] * FontWidth); for (uint8_t glyphCol = 0; glyphCol < FontWidth; ++glyphCol) { uint8_t colBits = pgm_read_byte(glyph + glyphCol); i2c_master_write(colBits); } // 1 column of space between chars (it's not included in the glyph) //i2c_master_write(0); } } matrix->dirty = false; done: i2c_master_stop(); #if DEBUG_TO_SCREEN --displaying; #endif } void iota_gfx_flush(void) { matrix_render(&display); } __attribute__ ((weak)) void iota_gfx_task_user(void) { } void iota_gfx_task(void) { iota_gfx_task_user(); if (display.dirty|| force_dirty) { iota_gfx_flush(); force_dirty = false; } if (timer_elapsed(last_flush) > ScreenOffInterval) { iota_gfx_off(); } } bool process_record_gfx(uint16_t keycode, keyrecord_t *record) { force_dirty = true; return true; } #endif
D keyboards/satt/comet46/ssd1306.h => keyboards/satt/comet46/ssd1306.h +0 -90
@@ 1,90 0,0 @@ #pragma once #include <stdbool.h> #include <stdio.h> #include "action.h" enum ssd1306_cmds { DisplayOff = 0xAE, DisplayOn = 0xAF, SetContrast = 0x81, DisplayAllOnResume = 0xA4, DisplayAllOn = 0xA5, NormalDisplay = 0xA6, InvertDisplay = 0xA7, SetDisplayOffset = 0xD3, SetComPins = 0xda, SetVComDetect = 0xdb, SetDisplayClockDiv = 0xD5, SetPreCharge = 0xd9, SetMultiPlex = 0xa8, SetLowColumn = 0x00, SetHighColumn = 0x10, SetStartLine = 0x40, SetMemoryMode = 0x20, ColumnAddr = 0x21, PageAddr = 0x22, ComScanInc = 0xc0, ComScanDec = 0xc8, SegRemap = 0xa0, SetChargePump = 0x8d, ExternalVcc = 0x01, SwitchCapVcc = 0x02, ActivateScroll = 0x2f, DeActivateScroll = 0x2e, SetVerticalScrollArea = 0xa3, RightHorizontalScroll = 0x26, LeftHorizontalScroll = 0x27, VerticalAndRightHorizontalScroll = 0x29, VerticalAndLeftHorizontalScroll = 0x2a, }; // Controls the SSD1306 128x32 OLED display via i2c #ifndef SSD1306_ADDRESS #define SSD1306_ADDRESS 0x3C #endif #define DisplayHeight 32 #define DisplayWidth 128 #define FontHeight 8 #define FontWidth 6 #define MatrixRows (DisplayHeight / FontHeight) #define MatrixCols (DisplayWidth / FontWidth) struct CharacterMatrix { uint8_t display[MatrixRows][MatrixCols]; uint8_t *cursor; bool dirty; }; extern struct CharacterMatrix display; bool iota_gfx_init(bool rotate); void iota_gfx_task(void); bool iota_gfx_off(void); bool iota_gfx_on(void); void iota_gfx_flush(void); void iota_gfx_write_char(uint8_t c); void iota_gfx_write(const char *data); void iota_gfx_write_P(const char *data); void iota_gfx_clear_screen(void); void iota_gfx_task_user(void); void matrix_clear(struct CharacterMatrix *matrix); void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c); void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c); void matrix_write(struct CharacterMatrix *matrix, const char *data); void matrix_write_ln(struct CharacterMatrix *matrix, const char *data); void matrix_write_P(struct CharacterMatrix *matrix, const char *data); void matrix_render(struct CharacterMatrix *matrix); bool process_record_gfx(uint16_t keycode, keyrecord_t *record);