diff options
author | James Churchill <pelrun@gmail.com> | 2019-03-12 18:23:28 +0100 |
---|---|---|
committer | Drashna Jaelre <drashna@live.com> | 2019-03-12 18:23:28 +0100 |
commit | 37932c293c15011f883a91e91ee02631ead44a2e (patch) | |
tree | f1b4b3b44f816240b06580658b42b3646f121025 /quantum/split_common | |
parent | 25bb059e4e42ed2637202230ff3d8b765e1295cd (diff) | |
download | qmk_firmware-37932c293c15011f883a91e91ee02631ead44a2e.tar.gz qmk_firmware-37932c293c15011f883a91e91ee02631ead44a2e.tar.xz |
Next set of split_common changes (#4974)
* Update split_common to use standard i2c drivers
* Eliminate RGB_DIRTY/BACKLIT_DIRTY
* Fix avr i2c_master error handling
* Fix i2c_slave addressing
* Remove unneeded timeout on i2c_stop()
* Fix RGB I2C transfers
* Remove incorrect comment
Diffstat (limited to 'quantum/split_common')
-rw-r--r-- | quantum/split_common/i2c.c | 184 | ||||
-rw-r--r-- | quantum/split_common/i2c.h | 59 | ||||
-rw-r--r-- | quantum/split_common/matrix.c | 1 | ||||
-rw-r--r-- | quantum/split_common/split_flags.c | 5 | ||||
-rw-r--r-- | quantum/split_common/split_flags.h | 15 | ||||
-rw-r--r-- | quantum/split_common/split_util.c | 5 | ||||
-rw-r--r-- | quantum/split_common/transport.c | 236 |
7 files changed, 85 insertions, 420 deletions
diff --git a/quantum/split_common/i2c.c b/quantum/split_common/i2c.c deleted file mode 100644 index 45e958b39..000000000 --- a/quantum/split_common/i2c.c +++ /dev/null @@ -1,184 +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" -#include "split_flags.h" - -// 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 -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; -} - -uint8_t i2c_master_write_data(void *const TXdata, uint8_t dataLen) { - - uint8_t *data = (uint8_t *)TXdata; - int err = 0; - - for (int i = 0; i < dataLen; i++) { - err = i2c_master_write(data[i]); - - if ( err ) - return err; - } - - return err; - -} - -// 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; - - if ( slave_buffer_pos == I2C_BACKLIT_START) { - BACKLIT_DIRTY = true; - } else if ( slave_buffer_pos == (I2C_RGB_START+3)) { - RGB_DIRTY = true; - } - - 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); -} diff --git a/quantum/split_common/i2c.h b/quantum/split_common/i2c.h deleted file mode 100644 index 91e8e96f4..000000000 --- a/quantum/split_common/i2c.h +++ /dev/null @@ -1,59 +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 - -// Address location defines (Keymap should be last, as it's size is dynamic) -#define I2C_BACKLIT_START 0x00 -// Need 4 bytes for RGB (32 bit) -#define I2C_RGB_START 0x01 -#define I2C_KEYMAP_START 0x06 - -// Slave buffer (8bit per) -// Rows per hand + backlit space + rgb space -// TODO : Make this dynamically sized -#define SLAVE_BUFFER_SIZE 0x20 - -// i2c SCL clock frequency -#ifndef SCL_CLOCK -#define SCL_CLOCK 100000L -#endif - -// Support 8bits right now (8 cols) will need to edit to take higher (code exists in delta split?) -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_write_data(void *const TXdata, uint8_t dataLen); -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(); diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c index f2a277c69..dcb96254f 100644 --- a/quantum/split_common/matrix.c +++ b/quantum/split_common/matrix.c @@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "matrix.h" #include "split_util.h" #include "config.h" -#include "split_flags.h" #include "quantum.h" #include "debounce.h" #include "transport.h" diff --git a/quantum/split_common/split_flags.c b/quantum/split_common/split_flags.c deleted file mode 100644 index 1f5825d65..000000000 --- a/quantum/split_common/split_flags.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "split_flags.h" - -volatile bool RGB_DIRTY = false; - -volatile bool BACKLIT_DIRTY = false;
\ No newline at end of file diff --git a/quantum/split_common/split_flags.h b/quantum/split_common/split_flags.h deleted file mode 100644 index aaac474a7..000000000 --- a/quantum/split_common/split_flags.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include <stdbool.h> -#include <stdint.h> - -/** -* Global Flags -**/ - -//RGB Stuff -extern volatile bool RGB_DIRTY; - - -//Backlight Stuff -extern volatile bool BACKLIT_DIRTY; diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index 5095cb8fd..da870f877 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -3,7 +3,6 @@ #include "keyboard.h" #include "config.h" #include "timer.h" -#include "split_flags.h" #include "transport.h" #include "quantum.h" @@ -60,10 +59,6 @@ static void keyboard_master_setup(void) { #endif #endif transport_master_init(); - - // For master the Backlight info needs to be sent on startup - // Otherwise the salve won't start with the proper info until an update - BACKLIT_DIRTY = true; } static void keyboard_slave_setup(void) diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c index 95738530e..b16852bc1 100644 --- a/quantum/split_common/transport.c +++ b/quantum/split_common/transport.c @@ -3,146 +3,83 @@ #include "matrix.h" #include "quantum.h" -#define ROWS_PER_HAND (MATRIX_ROWS/2) +#define ROWS_PER_HAND (MATRIX_ROWS / 2) #ifdef RGBLIGHT_ENABLE -# include "rgblight.h" +# include "rgblight.h" #endif #ifdef BACKLIGHT_ENABLE -# include "backlight.h" - extern backlight_config_t backlight_config; +# include "backlight.h" +extern backlight_config_t backlight_config; #endif #if defined(USE_I2C) || defined(EH) -#include "i2c.h" +# include "i2c_master.h" +# include "i2c_slave.h" -#ifndef SLAVE_I2C_ADDRESS -# define SLAVE_I2C_ADDRESS 0x32 -#endif +# define I2C_BACKLIT_START 0x00 +// Need 4 bytes for RGB (32 bit) +# define I2C_RGB_START 0x01 +# define I2C_KEYMAP_START 0x05 -#if (MATRIX_COLS > 8) -# error "Currently only supports 8 COLS" -#endif +# define TIMEOUT 100 + +# ifndef SLAVE_I2C_ADDRESS +# define SLAVE_I2C_ADDRESS 0x32 +# endif // Get rows from other half over i2c bool transport_master(matrix_row_t matrix[]) { - int err = 0; + i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_START, (void *)matrix, ROWS_PER_HAND * sizeof(matrix_row_t), TIMEOUT); // write backlight info -#ifdef BACKLIGHT_ENABLE - if (BACKLIT_DIRTY) { - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) { goto i2c_error; } - - // Backlight location - err = i2c_master_write(I2C_BACKLIT_START); - if (err) { goto i2c_error; } - - // Write backlight - i2c_master_write(get_backlight_level()); - - BACKLIT_DIRTY = false; - } -#endif - - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) { goto i2c_error; } - - // start of matrix stored at I2C_KEYMAP_START - err = i2c_master_write(I2C_KEYMAP_START); - if (err) { goto i2c_error; } - - // Start read - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); - if (err) { goto i2c_error; } - - if (!err) { - int i; - for (i = 0; i < ROWS_PER_HAND-1; ++i) { - matrix[i] = i2c_master_read(I2C_ACK); - } - matrix[i] = i2c_master_read(I2C_NACK); - i2c_master_stop(); - } else { -i2c_error: // the cable is disconnceted, or something else went wrong - i2c_reset_state(); - return false; +# ifdef BACKLIGHT_ENABLE + static uint8_t prev_level = ~0; + uint8_t level = get_backlight_level(); + if (level != prev_level) { + i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIT_START, (void *)&level, sizeof(level), TIMEOUT); + prev_level = level; } - -#ifdef RGBLIGHT_ENABLE - if (RGB_DIRTY) { - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) { goto i2c_error; } - - // RGB Location - err = i2c_master_write(I2C_RGB_START); - if (err) { goto i2c_error; } - - uint32_t dword = eeconfig_read_rgblight(); - - // Write RGB - err = i2c_master_write_data(&dword, 4); - if (err) { goto i2c_error; } - - RGB_DIRTY = false; - i2c_master_stop(); +# endif + +# ifdef RGBLIGHT_ENABLE + static uint32_t prev_rgb = ~0; + uint32_t rgb = eeconfig_read_rgblight(); + if (rgb != prev_rgb) { + i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_START, (void *)&rgb, sizeof(rgb), TIMEOUT); + prev_rgb = rgb; } -#endif +# endif return true; } void transport_slave(matrix_row_t matrix[]) { - - for (int i = 0; i < ROWS_PER_HAND; ++i) - { - i2c_slave_buffer[I2C_KEYMAP_START + i] = matrix[i]; - } - // Read Backlight Info - #ifdef BACKLIGHT_ENABLE - if (BACKLIT_DIRTY) - { - backlight_set(i2c_slave_buffer[I2C_BACKLIT_START]); - BACKLIT_DIRTY = false; + for (int i = 0; i < ROWS_PER_HAND * sizeof(matrix_row_t); ++i) { + i2c_slave_reg[I2C_KEYMAP_START + i] = matrix[i]; } - #endif - #ifdef RGBLIGHT_ENABLE - if (RGB_DIRTY) - { - // Disable interupts (RGB data is big) - cli(); - // Create new DWORD for RGB data - uint32_t dword; - - // Fill the new DWORD with the data that was sent over - uint8_t * dword_dat = (uint8_t *)(&dword); - for (int i = 0; i < 4; i++) - { - dword_dat[i] = i2c_slave_buffer[I2C_RGB_START + i]; - } - - // Update the RGB now with the new data and set RGB_DIRTY to false - rgblight_update_dword(dword); - RGB_DIRTY = false; - // Re-enable interupts now that RGB is set - sei(); - } - #endif -} -void transport_master_init(void) { - i2c_master_init(); -} +// Read Backlight Info +# ifdef BACKLIGHT_ENABLE + backlight_set(i2c_slave_reg[I2C_BACKLIT_START]); +# endif -void transport_slave_init(void) { - i2c_slave_init(SLAVE_I2C_ADDRESS); +# ifdef RGBLIGHT_ENABLE + uint32_t rgb = *(uint32_t *)(i2c_slave_reg + I2C_RGB_START); + // Update the RGB with the new data + rgblight_update_dword(rgb); +# endif } -#else // USE_SERIAL +void transport_master_init(void) { i2c_init(); } + +void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); } -#include "serial.h" +#else // USE_SERIAL + +# include "serial.h" typedef struct _Serial_s2m_buffer_t { // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack @@ -150,40 +87,40 @@ typedef struct _Serial_s2m_buffer_t { } Serial_s2m_buffer_t; typedef struct _Serial_m2s_buffer_t { -#ifdef BACKLIGHT_ENABLE - uint8_t backlight_level; -#endif -#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) - rgblight_config_t rgblight_config; //not yet use - // - // When MCUs on both sides drive their respective RGB LED chains, - // it is necessary to synchronize, so it is necessary to communicate RGB information. - // In that case, define the RGBLIGHT_SPLIT macro. - // - // Otherwise, if the master side MCU drives both sides RGB LED chains, - // there is no need to communicate. -#endif +# ifdef BACKLIGHT_ENABLE + uint8_t backlight_level; +# endif +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + rgblight_config_t rgblight_config; // not yet use + // + // When MCUs on both sides drive their respective RGB LED chains, + // it is necessary to synchronize, so it is necessary to communicate RGB + // information. In that case, define the RGBLIGHT_SPLIT macro. + // + // Otherwise, if the master side MCU drives both sides RGB LED chains, + // there is no need to communicate. +# endif } Serial_m2s_buffer_t; volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; -uint8_t volatile status0 = 0; +uint8_t volatile status0 = 0; SSTD_t transactions[] = { - { (uint8_t *)&status0, - sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer, - sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer - } + { + (uint8_t *)&status0, + sizeof(serial_m2s_buffer), + (uint8_t *)&serial_m2s_buffer, + sizeof(serial_s2m_buffer), + (uint8_t *)&serial_s2m_buffer, + }, }; -void transport_master_init(void) -{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } +void transport_master_init(void) { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } -void transport_slave_init(void) -{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } +void transport_slave_init(void) { soft_serial_target_init(transactions, TID_LIMIT(transactions)); } bool transport_master(matrix_row_t matrix[]) { - if (soft_serial_transaction()) { return false; } @@ -193,32 +130,29 @@ bool transport_master(matrix_row_t matrix[]) { matrix[i] = serial_s2m_buffer.smatrix[i]; } - #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) - // Code to send RGB over serial goes here (not implemented yet) - #endif +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + // Code to send RGB over serial goes here (not implemented yet) +# endif - #ifdef BACKLIGHT_ENABLE - // Write backlight level for slave to read - serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; - #endif +# ifdef BACKLIGHT_ENABLE + // Write backlight level for slave to read + serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; +# endif return true; } void transport_slave(matrix_row_t matrix[]) { - // TODO: if MATRIX_COLS > 8 change to pack() - for (int i = 0; i < ROWS_PER_HAND; ++i) - { + for (int i = 0; i < ROWS_PER_HAND; ++i) { serial_s2m_buffer.smatrix[i] = matrix[i]; } - #ifdef BACKLIGHT_ENABLE - backlight_set(serial_m2s_buffer.backlight_level); - #endif - #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) - // Add serial implementation for RGB here - #endif - +# ifdef BACKLIGHT_ENABLE + backlight_set(serial_m2s_buffer.backlight_level); +# endif +# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) +// Add serial implementation for RGB here +# endif } #endif |