aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerryMathews <terry@terrymathews.net>2020-03-18 21:13:12 -0400
committerGitHub <noreply@github.com>2020-03-19 01:13:12 +0000
commit19d7cbc8584ed5c0ec1f768a27767496eeae66f8 (patch)
tree3a699d143690057c510e8f20d99adb6d26631ef1
parent73f903906ee86e70c301da2f1d70a22f58cdbdf1 (diff)
downloadqmk_firmware-19d7cbc8584ed5c0ec1f768a27767496eeae66f8.tar.gz
qmk_firmware-19d7cbc8584ed5c0ec1f768a27767496eeae66f8.zip
M0lly: refactor OLED support and qmk-dfu bootloader (#8475)
-rw-r--r--keyboards/m0lly/config.h5
-rw-r--r--keyboards/m0lly/i2c.c166
-rw-r--r--keyboards/m0lly/i2c.h49
-rw-r--r--keyboards/m0lly/keymaps/default/config.h24
-rw-r--r--keyboards/m0lly/keymaps/default/keymap.c101
-rw-r--r--keyboards/m0lly/rules.mk8
6 files changed, 31 insertions, 322 deletions
diff --git a/keyboards/m0lly/config.h b/keyboards/m0lly/config.h
index 010833ac8..327b0f08c 100644
--- a/keyboards/m0lly/config.h
+++ b/keyboards/m0lly/config.h
@@ -67,6 +67,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
67/* Locking resynchronize hack */ 67/* Locking resynchronize hack */
68#define LOCKING_RESYNC_ENABLE 68#define LOCKING_RESYNC_ENABLE
69 69
70#define QMK_ESC_OUTPUT A0 // usually COL
71#define QMK_ESC_INPUT F4 // usually ROW
72#define QMK_LED D2 // NumLock on M0lly
73//#define QMK_SPEAKER C6
74
70/* 75/*
71 * Force NKRO 76 * Force NKRO
72 * 77 *
diff --git a/keyboards/m0lly/i2c.c b/keyboards/m0lly/i2c.c
deleted file mode 100644
index cd2b835d5..000000000
--- a/keyboards/m0lly/i2c.c
+++ /dev/null
@@ -1,166 +0,0 @@
1#include <util/twi.h>
2#include <avr/io.h>
3#include <stdlib.h>
4#include <avr/interrupt.h>
5#include <util/twi.h>
6#include <stdbool.h>
7#include "i2c.h"
8
9#ifdef USE_I2C
10
11// Limits the amount of we wait for any one i2c transaction.
12// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
13// 9 bits, a single transaction will take around 90μs to complete.
14//
15// (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit
16// poll loop takes at least 8 clock cycles to execute
17#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8
18
19#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE)
20
21volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23static volatile uint8_t slave_buffer_pos;
24static volatile bool slave_has_register_set = false;
25
26// Wait for an i2c operation to finish
27inline static
28void i2c_delay(void) {
29 uint16_t lim = 0;
30 while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT)
31 lim++;
32
33 // easier way, but will wait slightly longer
34 // _delay_us(100);
35}
36
37// Setup twi to run at 100kHz
38void i2c_master_init(void) {
39 // no prescaler
40 TWSR = 0;
41 // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
42 // Check datasheets for more info.
43 TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
44}
45
46// Start a transaction with the given i2c slave address. The direction of the
47// transfer is set with I2C_READ and I2C_WRITE.
48// returns: 0 => success
49// 1 => error
50uint8_t i2c_master_start(uint8_t address) {
51 TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
52
53 i2c_delay();
54
55 // check that we started successfully
56 if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START))
57 return 1;
58
59 // send device address
60 TWDR = address;
61 TWCR = (1<<TWINT) | (1<<TWEN);
62
63 i2c_delay();
64
65 if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
66 return 1; // slave did not acknowledge
67 else
68 return 0; // success
69}
70
71
72// Finish the i2c transaction.
73void i2c_master_stop(void) {
74 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
75
76 uint16_t lim = 0;
77 while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT)
78 lim++;
79}
80
81// Write one byte to the i2c slave.
82// returns 0 => slave ACK
83// 1 => slave NACK
84uint8_t i2c_master_write(uint8_t data) {
85 TWDR = data;
86 TWCR = (1<<TWINT) | (1<<TWEN);
87
88 i2c_delay();
89
90 // check if the slave acknowledged us
91 return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1;
92}
93
94// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
95// if ack=0 the acknowledge bit is not set.
96// returns: byte read from i2c device
97uint8_t i2c_master_read(int ack) {
98 TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
99
100 i2c_delay();
101 return TWDR;
102}
103
104void i2c_reset_state(void) {
105 TWCR = 0;
106}
107
108void i2c_slave_init(uint8_t address) {
109 TWAR = address << 0; // slave i2c address
110 // TWEN - twi enable
111 // TWEA - enable address acknowledgement
112 // TWINT - twi interrupt flag
113 // TWIE - enable the twi interrupt
114 TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
115}
116
117ISR(TWI_vect);
118
119ISR(TWI_vect) {
120 uint8_t ack = 1;
121 switch(TW_STATUS) {
122 case TW_SR_SLA_ACK:
123 // this device has been addressed as a slave receiver
124 slave_has_register_set = false;
125 break;
126
127 case TW_SR_DATA_ACK:
128 // this device has received data as a slave receiver
129 // The first byte that we receive in this transaction sets the location
130 // of the read/write location of the slaves memory that it exposes over
131 // i2c. After that, bytes will be written at slave_buffer_pos, incrementing
132 // slave_buffer_pos after each write.
133 if(!slave_has_register_set) {
134 slave_buffer_pos = TWDR;
135 // don't acknowledge the master if this memory loctaion is out of bounds
136 if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) {
137 ack = 0;
138 slave_buffer_pos = 0;
139 }
140 slave_has_register_set = true;
141 } else {
142 i2c_slave_buffer[slave_buffer_pos] = TWDR;
143 BUFFER_POS_INC();
144 }
145 break;
146
147 case TW_ST_SLA_ACK:
148 case TW_ST_DATA_ACK:
149 // master has addressed this device as a slave transmitter and is
150 // requesting data.
151 TWDR = i2c_slave_buffer[slave_buffer_pos];
152 BUFFER_POS_INC();
153 break;
154
155 case TW_BUS_ERROR: // something went wrong, reset twi state
156 TWCR = 0;
157 default:
158 break;
159 }
160 // Reset everything, so we are ready for the next TWI interrupt
161 TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN);
162}
163
164
165
166#endif
diff --git a/keyboards/m0lly/i2c.h b/keyboards/m0lly/i2c.h
deleted file mode 100644
index 2bd7f4096..000000000
--- a/keyboards/m0lly/i2c.h
+++ /dev/null
@@ -1,49 +0,0 @@
1#ifndef I2C_H
2#define I2C_H
3
4#include <stdint.h>
5
6#ifndef F_CPU
7#define F_CPU 16000000UL
8#endif
9
10#define I2C_READ 1
11#define I2C_WRITE 0
12
13#define I2C_ACK 1
14#define I2C_NACK 0
15
16#define SLAVE_BUFFER_SIZE 0x10
17
18// i2c SCL clock frequency
19#define SCL_CLOCK 800000L
20
21extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23void i2c_master_init(void);
24uint8_t i2c_master_start(uint8_t address);
25void i2c_master_stop(void);
26uint8_t i2c_master_write(uint8_t data);
27uint8_t i2c_master_read(int);
28void i2c_reset_state(void);
29void i2c_slave_init(uint8_t address);
30
31
32static inline unsigned char i2c_start_read(unsigned char addr) {
33 return i2c_master_start((addr << 1) | I2C_READ);
34}
35
36static inline unsigned char i2c_start_write(unsigned char addr) {
37 return i2c_master_start((addr << 1) | I2C_WRITE);
38}
39
40// from SSD1306 scrips
41extern unsigned char i2c_rep_start(unsigned char addr);
42extern void i2c_start_wait(unsigned char addr);
43extern unsigned char i2c_readAck(void);
44extern unsigned char i2c_readNak(void);
45extern unsigned char i2c_read(unsigned char ack);
46
47#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
48
49#endif
diff --git a/keyboards/m0lly/keymaps/default/config.h b/keyboards/m0lly/keymaps/default/config.h
deleted file mode 100644
index ee142927f..000000000
--- a/keyboards/m0lly/keymaps/default/config.h
+++ /dev/null
@@ -1,24 +0,0 @@
1/* Copyright 2017 Mathias Andersson <wraul@dbox.se>
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#define USE_I2C
20#define SSD1306OLED
21//#define OLED_ROTATE180
22#define SSD1306_ADDRESS 0x3C
23
24// place overrides here
diff --git a/keyboards/m0lly/keymaps/default/keymap.c b/keyboards/m0lly/keymaps/default/keymap.c
index 784deb04a..5f6211f0f 100644
--- a/keyboards/m0lly/keymaps/default/keymap.c
+++ b/keyboards/m0lly/keymaps/default/keymap.c
@@ -13,11 +13,8 @@
13 * You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16
16#include QMK_KEYBOARD_H 17#include QMK_KEYBOARD_H
17#include "LUFA/Drivers/Peripheral/TWI.h"
18#include "i2c.h"
19#include "ssd1306.h"
20
21 18
22//Layers 19//Layers
23 20
@@ -26,13 +23,6 @@ enum {
26 FUNCTION, 23 FUNCTION,
27}; 24};
28 25
29bool screenWorks = 0;
30
31//13 characters max without re-writing the "Layer: " format in iota_gfx_task_user()
32static char layer_lookup[][14] = {"Base","Function"};
33
34
35
36const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 26const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
37 /* Keymap BASE: (Base Layer) Default Layer 27 /* Keymap BASE: (Base Layer) Default Layer
38 * 28 *
@@ -78,72 +68,27 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
78 ), 68 ),
79}; 69};
80 70
81bool process_record_user(uint16_t keycode, keyrecord_t *record) { 71#ifdef OLED_DRIVER_ENABLE
82 return true; 72void oled_task_user(void) {
83} 73 oled_write_P(PSTR("TKC1800\n"),false);
84 74 // Host Keyboard Layer Status
85void led_set_user(uint8_t usb_led) { 75 oled_write_P(PSTR("Layer: "), false);
86 76
87} 77 switch (get_highest_layer(layer_state)) {
88 78 case BASE:
89void matrix_init_user(void) { 79 oled_write_P(PSTR("Base\n"), false);
90 #ifdef USE_I2C 80 break;
91 i2c_master_init(); 81 case FUNCTION:
92 #ifdef SSD1306OLED 82 oled_write_P(PSTR("Function\n"), false);
93 // calls code for the SSD1306 OLED 83 break;
94 _delay_ms(400); 84 default:
95 TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 800000)); 85 // Or use the write_ln shortcut over adding '\n' to the end of your string
96 if ( iota_gfx_init() ) { // turns on the display 86 oled_write_ln_P(PSTR("Undefined"), false);
97 screenWorks = 1;
98 }
99 #endif
100 #endif
101 #ifdef AUDIO_ENABLE
102 startup_user();
103 #endif
104}
105
106void matrix_scan_user(void) {
107 #ifdef SSD1306OLED
108 if ( screenWorks ) {
109 iota_gfx_task(); // this is what updates the display continuously
110 };
111 #endif
112}
113
114void matrix_update(struct CharacterMatrix *dest,
115 const struct CharacterMatrix *source) {
116 if (memcmp(dest->display, source->display, sizeof(dest->display))) {
117 memcpy(dest->display, source->display, sizeof(dest->display));
118 dest->dirty = true;
119 }
120}
121
122void iota_gfx_task_user(void) {
123 #if DEBUG_TO_SCREEN
124 if (debug_enable) {
125 return;
126 } 87 }
127 #endif 88 // Host Keyboard LED Status
128 89 led_t led_state = host_keyboard_led_state();
129 struct CharacterMatrix matrix; 90 oled_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR(" "), false);
130 91 oled_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR(" "), false);
131 matrix_clear(&matrix); 92 oled_write_P(led_state.scroll_lock ? PSTR("SCR ") : PSTR(" "), false);
132 matrix_write_P(&matrix, PSTR("TKC M0LLY"));
133
134 uint8_t layer = biton32(layer_state);
135
136 char buf[40];
137 snprintf(buf,sizeof(buf), "Undef-%d", layer);
138 matrix_write_P(&matrix, PSTR("\nLayer: "));
139 matrix_write(&matrix, layer_lookup[layer]);
140
141 // Host Keyboard LED Status
142 char led[40];
143 snprintf(led, sizeof(led), "\n\n%s %s %s",
144 (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : " ",
145 (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : " ",
146 (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : " ");
147 matrix_write(&matrix, led);
148 matrix_update(&display, &matrix);
149} 93}
94#endif \ No newline at end of file
diff --git a/keyboards/m0lly/rules.mk b/keyboards/m0lly/rules.mk
index 60140160c..05e629075 100644
--- a/keyboards/m0lly/rules.mk
+++ b/keyboards/m0lly/rules.mk
@@ -9,12 +9,12 @@ MCU = at90usb1286
9# QMK DFU qmk-dfu 9# QMK DFU qmk-dfu
10# ATmega32A bootloadHID 10# ATmega32A bootloadHID
11# ATmega328P USBasp 11# ATmega328P USBasp
12BOOTLOADER = atmel-dfu 12BOOTLOADER = qmk-dfu
13 13
14# Build Options 14# Build Options
15# change yes to no to disable 15# change yes to no to disable
16# 16#
17BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration 17BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
18MOUSEKEY_ENABLE = yes # Mouse keys 18MOUSEKEY_ENABLE = yes # Mouse keys
19EXTRAKEY_ENABLE = yes # Audio control and System control 19EXTRAKEY_ENABLE = yes # Audio control and System control
20CONSOLE_ENABLE = yes # Console for debug 20CONSOLE_ENABLE = yes # Console for debug
@@ -29,6 +29,4 @@ MIDI_ENABLE = no # MIDI controls
29UNICODE_ENABLE = no # Unicode 29UNICODE_ENABLE = no # Unicode
30BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID 30BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
31AUDIO_ENABLE = no # Audio output on port C6 31AUDIO_ENABLE = no # Audio output on port C6
32 32OLED_DRIVER_ENABLE = yes \ No newline at end of file
33SRC = i2c.c \
34 ssd1306.c