From 72d4e4bfd76b2c83b89787f8b3a8ba779a3e8d81 Mon Sep 17 00:00:00 2001 From: Takeshi ISHII <2170248+mtei@users.noreply.github.com> Date: Tue, 25 Dec 2018 04:14:57 +0900 Subject: [PATCH] Replace serial.c of quantum/split_common/ (#4669) * Add provisional Helix implementation to test the quantum/split_common. * copy keyboards/helix/serial.[ch] to quantum/split_common/ * Make serial.c a pure driver. Remove buffer name and buffer size from serial.c. They should be placed in the caller(matrix.c, split_utils.c). * remove quantum/split_common/serial_backward_compatibility.h * Changed array serial_master_buffer to structure serial_m2s_buffer. * Changed array serial_slave_buffer to structure serial_s2m_buffer. * Change keyboards/miniaxe/matrix.c I also made changes to quantum/split_comon/matrix.c to keyboards/miniaxe/matrix.c. Note: I contacted @ka2hiro, creator of miniaxe, and I got permission to change keyboards/miniaxe/matrix.c. * update history comment in quantum/split_common/serial.c * Revert "Add provisional Helix implementation to test the quantum/split_common." This reverts commit 168c82ef82c88e79979d9796bab9cc819cc2f685. * fix keyboards/miniaxe/matrix.c, quantum/split_common/matrix.c avr-gcc 4.9.[23] report error. avr-gcc 5.4.0, avr-gcc 7.3.0 pass. It is funny. * update comment quantum/split_common/serial.c * Reserve RGBLIGHT_SPLIT macro in quantum/split_common --- common_features.mk | 5 - keyboards/miniaxe/matrix.c | 59 +- quantum/split_common/matrix.c | 61 ++- quantum/split_common/matrix.h | 31 ++ quantum/split_common/serial.c | 509 +++++++++++++----- quantum/split_common/serial.h | 65 ++- .../serial_backward_compatibility.h | 11 - quantum/split_common/split_util.c | 9 +- quantum/split_common/split_util.h | 3 - 9 files changed, 580 insertions(+), 173 deletions(-) create mode 100644 quantum/split_common/matrix.h delete mode 100644 quantum/split_common/serial_backward_compatibility.h diff --git a/common_features.mk b/common_features.mk index 73aab5d845..883681324b 100644 --- a/common_features.mk +++ b/common_features.mk @@ -263,11 +263,6 @@ ifneq ($(strip $(CUSTOM_MATRIX)), yes) endif ifeq ($(strip $(SPLIT_KEYBOARD)), yes) - SERIAL_BACKWARD_COMPAT := $(wildcard $(QUANTUM_DIR)/split_common/serial_backward_compatibility.h) - ifneq ($(SERIAL_BACKWARD_COMPAT),) - CONFIG_H += $(SERIAL_BACKWARD_COMPAT) - # $(info CONFIG_H=$(CONFIG_H)) - endif OPT_DEFS += -DSPLIT_KEYBOARD QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \ $(QUANTUM_DIR)/split_common/split_util.c diff --git a/keyboards/miniaxe/matrix.c b/keyboards/miniaxe/matrix.c index 55c458e1fb..5fec1281df 100644 --- a/keyboards/miniaxe/matrix.c +++ b/keyboards/miniaxe/matrix.c @@ -32,9 +32,6 @@ along with this program. If not, see . #include "timer.h" #include "split_flags.h" -#ifdef RGBLIGHT_ENABLE -# include "rgblight.h" -#endif #ifdef BACKLIGHT_ENABLE # include "backlight.h" extern backlight_config_t backlight_config; @@ -55,6 +52,8 @@ along with this program. If not, see . static bool debouncing = false; #endif +#if defined(USE_I2C) || defined(EH) + #if (MATRIX_COLS <= 8) # define print_matrix_header() print("\nr/c 01234567\n") # define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) @@ -62,6 +61,27 @@ along with this program. If not, see . # define ROW_SHIFTER ((uint8_t)1) #else # error "Currently only supports 8 COLS" +#endif + +#else // USE_SERIAL + +#if (MATRIX_COLS <= 8) +# define print_matrix_header() print("\nr/c 01234567\n") +# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop(matrix[i]) +# define ROW_SHIFTER ((uint8_t)1) +#elif (MATRIX_COLS <= 16) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop16(matrix[i]) +# define ROW_SHIFTER ((uint16_t)1) +#elif (MATRIX_COLS <= 32) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop32(matrix[i]) +# define ROW_SHIFTER ((uint32_t)1) +#endif + #endif static matrix_row_t matrix_debouncing[MATRIX_ROWS]; @@ -315,15 +335,39 @@ i2c_error: // the cable is disconnceted, or something else went wrong #else // USE_SERIAL + +typedef struct _Serial_s2m_buffer_t { + // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack + matrix_row_t smatrix[ROWS_PER_HAND]; +} Serial_s2m_buffer_t; + +volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; +volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; +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 + } +}; + +void serial_master_init(void) +{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } + +void serial_slave_init(void) +{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } + int serial_transaction(void) { int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - if (serial_update_buffers()) { + if (soft_serial_transaction()) { return 1; } + // TODO: if MATRIX_COLS > 8 change to unpack() for (int i = 0; i < ROWS_PER_HAND; ++i) { - matrix[slaveOffset+i] = serial_slave_buffer[i]; + matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i]; } #ifdef RGBLIGHT_ENABLE @@ -332,7 +376,7 @@ int serial_transaction(void) { #ifdef BACKLIGHT_ENABLE // Write backlight level for slave to read - serial_master_buffer[SERIAL_BACKLIT_START] = backlight_config.enable ? backlight_config.level : 0; + serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; #endif return 0; @@ -375,8 +419,9 @@ void matrix_slave_scan(void) { i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i]; } #else // USE_SERIAL + // TODO: if MATRIX_COLS > 8 change to pack() for (int i = 0; i < ROWS_PER_HAND; ++i) { - serial_slave_buffer[i] = matrix[offset+i]; + serial_s2m_buffer.smatrix[i] = matrix[offset+i]; } #endif matrix_slave_scan_user(); diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c index d6359b51fb..2611376386 100644 --- a/quantum/split_common/matrix.c +++ b/quantum/split_common/matrix.c @@ -32,9 +32,6 @@ along with this program. If not, see . #include "timer.h" #include "split_flags.h" -#ifdef RGBLIGHT_ENABLE -# include "rgblight.h" -#endif #ifdef BACKLIGHT_ENABLE # include "backlight.h" extern backlight_config_t backlight_config; @@ -55,6 +52,8 @@ along with this program. If not, see . static bool debouncing = false; #endif +#if defined(USE_I2C) || defined(EH) + #if (MATRIX_COLS <= 8) # define print_matrix_header() print("\nr/c 01234567\n") # define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) @@ -62,6 +61,27 @@ along with this program. If not, see . # define ROW_SHIFTER ((uint8_t)1) #else # error "Currently only supports 8 COLS" +#endif + +#else // USE_SERIAL + +#if (MATRIX_COLS <= 8) +# define print_matrix_header() print("\nr/c 01234567\n") +# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop(matrix[i]) +# define ROW_SHIFTER ((uint8_t)1) +#elif (MATRIX_COLS <= 16) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop16(matrix[i]) +# define ROW_SHIFTER ((uint16_t)1) +#elif (MATRIX_COLS <= 32) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop32(matrix[i]) +# define ROW_SHIFTER ((uint32_t)1) +#endif + #endif static matrix_row_t matrix_debouncing[MATRIX_ROWS]; @@ -286,24 +306,48 @@ i2c_error: // the cable is disconnceted, or something else went wrong #else // USE_SERIAL + +typedef struct _Serial_s2m_buffer_t { + // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack + matrix_row_t smatrix[ROWS_PER_HAND]; +} Serial_s2m_buffer_t; + +volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; +volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; +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 + } +}; + +void serial_master_init(void) +{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } + +void serial_slave_init(void) +{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } + int serial_transaction(void) { int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - if (serial_update_buffers()) { + if (soft_serial_transaction()) { return 1; } + // TODO: if MATRIX_COLS > 8 change to unpack() for (int i = 0; i < ROWS_PER_HAND; ++i) { - matrix[slaveOffset+i] = serial_slave_buffer[i]; + matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i]; } - #ifdef RGBLIGHT_ENABLE + #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_master_buffer[SERIAL_BACKLIT_START] = backlight_config.enable ? backlight_config.level : 0; + serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; #endif return 0; @@ -346,8 +390,9 @@ void matrix_slave_scan(void) { i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i]; } #else // USE_SERIAL + // TODO: if MATRIX_COLS > 8 change to pack() for (int i = 0; i < ROWS_PER_HAND; ++i) { - serial_slave_buffer[i] = matrix[offset+i]; + serial_s2m_buffer.smatrix[i] = matrix[offset+i]; } #endif matrix_slave_scan_user(); diff --git a/quantum/split_common/matrix.h b/quantum/split_common/matrix.h new file mode 100644 index 0000000000..b5cb45baed --- /dev/null +++ b/quantum/split_common/matrix.h @@ -0,0 +1,31 @@ +#ifndef SPLIT_COMMON_MATRIX_H +#define SPLIT_COMMON_MATRIX_H + +#include + +#ifdef RGBLIGHT_ENABLE +# include "rgblight.h" +#endif + +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 +} Serial_m2s_buffer_t; + +extern volatile Serial_m2s_buffer_t serial_m2s_buffer; + +void serial_master_init(void); +void serial_slave_init(void); + +#endif diff --git a/quantum/split_common/serial.c b/quantum/split_common/serial.c index 13e58d8259..4df8d103bd 100644 --- a/quantum/split_common/serial.c +++ b/quantum/split_common/serial.c @@ -1,5 +1,10 @@ /* * WARNING: be careful changing this code, it is very timing dependent + * + * 2018-10-28 checked + * avr-gcc 4.9.2 + * avr-gcc 5.4.0 + * avr-gcc 7.3.0 */ #ifndef F_CPU @@ -9,17 +14,19 @@ #include #include #include +#include #include #include "serial.h" +//#include #ifdef SOFT_SERIAL_PIN #ifdef __AVR_ATmega32U4__ // if using ATmega32U4 I2C, can not use PD0 and PD1 in soft serial. #ifdef USE_AVR_I2C - #if SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1 - #error Using ATmega32U4 I2C, so can not use PD0, PD1 - #endif + #if SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1 + #error Using ATmega32U4 I2C, so can not use PD0, PD1 + #endif #endif #if SOFT_SERIAL_PIN >= D0 && SOFT_SERIAL_PIN <= D3 @@ -63,215 +70,477 @@ #error serial.c now support ATmega32U4 only #endif -// Serial pulse period in microseconds. Its probably a bad idea to lower this -// value. -#define SERIAL_DELAY 24 +#define ALWAYS_INLINE __attribute__((always_inline)) +#define NO_INLINE __attribute__((noinline)) +#define _delay_sub_us(x) __builtin_avr_delay_cycles(x) -uint8_t volatile serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH] = {0}; -uint8_t volatile serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH] = {0}; +// parity check +#define ODD_PARITY 1 +#define EVEN_PARITY 0 +#define PARITY EVEN_PARITY -#define SLAVE_DATA_CORRUPT (1<<0) -volatile uint8_t status = 0; +#ifdef SERIAL_DELAY + // custom setup in config.h + // #define TID_SEND_ADJUST 2 + // #define SERIAL_DELAY 6 // micro sec + // #define READ_WRITE_START_ADJUST 30 // cycles + // #define READ_WRITE_WIDTH_ADJUST 8 // cycles +#else +// ============ Standard setups ============ +#ifndef SELECT_SOFT_SERIAL_SPEED +#define SELECT_SOFT_SERIAL_SPEED 1 +// 0: about 189kbps (Experiment only) +// 1: about 137kbps (default) +// 2: about 75kbps +// 3: about 39kbps +// 4: about 26kbps +// 5: about 20kbps +#endif + +#if __GNUC__ < 6 + #define TID_SEND_ADJUST 14 +#else + #define TID_SEND_ADJUST 2 +#endif + +#if SELECT_SOFT_SERIAL_SPEED == 0 + // Very High speed + #define SERIAL_DELAY 4 // micro sec + #if __GNUC__ < 6 + #define READ_WRITE_START_ADJUST 33 // cycles + #define READ_WRITE_WIDTH_ADJUST 3 // cycles + #else + #define READ_WRITE_START_ADJUST 34 // cycles + #define READ_WRITE_WIDTH_ADJUST 7 // cycles + #endif +#elif SELECT_SOFT_SERIAL_SPEED == 1 + // High speed + #define SERIAL_DELAY 6 // micro sec + #if __GNUC__ < 6 + #define READ_WRITE_START_ADJUST 30 // cycles + #define READ_WRITE_WIDTH_ADJUST 3 // cycles + #else + #define READ_WRITE_START_ADJUST 33 // cycles + #define READ_WRITE_WIDTH_ADJUST 7 // cycles + #endif +#elif SELECT_SOFT_SERIAL_SPEED == 2 + // Middle speed + #define SERIAL_DELAY 12 // micro sec + #define READ_WRITE_START_ADJUST 30 // cycles + #if __GNUC__ < 6 + #define READ_WRITE_WIDTH_ADJUST 3 // cycles + #else + #define READ_WRITE_WIDTH_ADJUST 7 // cycles + #endif +#elif SELECT_SOFT_SERIAL_SPEED == 3 + // Low speed + #define SERIAL_DELAY 24 // micro sec + #define READ_WRITE_START_ADJUST 30 // cycles + #if __GNUC__ < 6 + #define READ_WRITE_WIDTH_ADJUST 3 // cycles + #else + #define READ_WRITE_WIDTH_ADJUST 7 // cycles + #endif +#elif SELECT_SOFT_SERIAL_SPEED == 4 + // Very Low speed + #define SERIAL_DELAY 36 // micro sec + #define READ_WRITE_START_ADJUST 30 // cycles + #if __GNUC__ < 6 + #define READ_WRITE_WIDTH_ADJUST 3 // cycles + #else + #define READ_WRITE_WIDTH_ADJUST 7 // cycles + #endif +#elif SELECT_SOFT_SERIAL_SPEED == 5 + // Ultra Low speed + #define SERIAL_DELAY 48 // micro sec + #define READ_WRITE_START_ADJUST 30 // cycles + #if __GNUC__ < 6 + #define READ_WRITE_WIDTH_ADJUST 3 // cycles + #else + #define READ_WRITE_WIDTH_ADJUST 7 // cycles + #endif +#else +#error invalid SELECT_SOFT_SERIAL_SPEED value +#endif /* SELECT_SOFT_SERIAL_SPEED */ +#endif /* SERIAL_DELAY */ + +#define SERIAL_DELAY_HALF1 (SERIAL_DELAY/2) +#define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY/2) + +#define SLAVE_INT_WIDTH_US 1 +#ifndef SERIAL_USE_MULTI_TRANSACTION + #define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY +#else + #define SLAVE_INT_ACK_WIDTH_UNIT 2 + #define SLAVE_INT_ACK_WIDTH 4 +#endif + +static SSTD_t *Transaction_table = NULL; +static uint8_t Transaction_table_size = 0; + +inline static void serial_delay(void) ALWAYS_INLINE; inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); } +inline static void serial_delay_half1(void) ALWAYS_INLINE; +inline static +void serial_delay_half1(void) { + _delay_us(SERIAL_DELAY_HALF1); +} + +inline static void serial_delay_half2(void) ALWAYS_INLINE; +inline static +void serial_delay_half2(void) { + _delay_us(SERIAL_DELAY_HALF2); +} + +inline static void serial_output(void) ALWAYS_INLINE; inline static void serial_output(void) { SERIAL_PIN_DDR |= SERIAL_PIN_MASK; } // make the serial pin an input with pull-up resistor +inline static void serial_input_with_pullup(void) ALWAYS_INLINE; inline static -void serial_input(void) { +void serial_input_with_pullup(void) { SERIAL_PIN_DDR &= ~SERIAL_PIN_MASK; SERIAL_PIN_PORT |= SERIAL_PIN_MASK; } +inline static uint8_t serial_read_pin(void) ALWAYS_INLINE; inline static uint8_t serial_read_pin(void) { return !!(SERIAL_PIN_INPUT & SERIAL_PIN_MASK); } +inline static void serial_low(void) ALWAYS_INLINE; inline static void serial_low(void) { SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; } +inline static void serial_high(void) ALWAYS_INLINE; inline static void serial_high(void) { SERIAL_PIN_PORT |= SERIAL_PIN_MASK; } -void serial_master_init(void) { - serial_output(); - serial_high(); +void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) +{ + Transaction_table = sstd_table; + Transaction_table_size = (uint8_t)sstd_table_size; + serial_output(); + serial_high(); } -void serial_slave_init(void) { - serial_input(); +void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) +{ + Transaction_table = sstd_table; + Transaction_table_size = (uint8_t)sstd_table_size; + serial_input_with_pullup(); - // Enable INT0 - EIMSK |= _BV(INT0); - // Trigger on falling edge of INT0 - EICRA &= ~(_BV(ISC00) | _BV(ISC01)); + // Enable INT0-INT3,INT6 + EIMSK |= EIMSK_BIT; +#if SERIAL_PIN_MASK == _BV(PE6) + // Trigger on falling edge of INT6 + EICRB &= EICRx_BIT; +#else + // Trigger on falling edge of INT0-INT3 + EICRA &= EICRx_BIT; +#endif } -// Used by the master to synchronize timing with the slave. +// Used by the sender to synchronize timing with the reciver. +static void sync_recv(void) NO_INLINE; static void sync_recv(void) { - serial_input(); - // This shouldn't hang if the slave disconnects because the - // serial line will float to high if the slave does disconnect. + for (uint8_t i = 0; i < SERIAL_DELAY*5 && serial_read_pin(); i++ ) { + } + // This shouldn't hang if the target disconnects because the + // serial line will float to high if the target does disconnect. while (!serial_read_pin()); - serial_delay(); } -// Used by the slave to send a synchronization signal to the master. +// Used by the reciver to send a synchronization signal to the sender. +static void sync_send(void) NO_INLINE; static void sync_send(void) { - serial_output(); - serial_low(); serial_delay(); - serial_high(); } // Reads a byte from the serial line -static -uint8_t serial_read_byte(void) { - uint8_t byte = 0; - serial_input(); - for ( uint8_t i = 0; i < 8; ++i) { - byte = (byte << 1) | serial_read_pin(); - serial_delay(); - _delay_us(1); +static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) NO_INLINE; +static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) { + uint8_t byte, i, p, pb; + + _delay_sub_us(READ_WRITE_START_ADJUST); + for( i = 0, byte = 0, p = PARITY; i < bit; i++ ) { + serial_delay_half1(); // read the middle of pulses + if( serial_read_pin() ) { + byte = (byte << 1) | 1; p ^= 1; + } else { + byte = (byte << 1) | 0; p ^= 0; + } + _delay_sub_us(READ_WRITE_WIDTH_ADJUST); + serial_delay_half2(); } + /* recive parity bit */ + serial_delay_half1(); // read the middle of pulses + pb = serial_read_pin(); + _delay_sub_us(READ_WRITE_WIDTH_ADJUST); + serial_delay_half2(); + + *pterrcount += (p != pb)? 1 : 0; return byte; } // Sends a byte with MSB ordering -static -void serial_write_byte(uint8_t data) { - uint8_t b = 8; - serial_output(); - while( b-- ) { - if(data & (1 << b)) { - serial_high(); - } else { - serial_low(); +void serial_write_chunk(uint8_t data, uint8_t bit) NO_INLINE; +void serial_write_chunk(uint8_t data, uint8_t bit) { + uint8_t b, p; + for( p = PARITY, b = 1<<(bit-1); b ; b >>= 1) { + if(data & b) { + serial_high(); p ^= 1; + } else { + serial_low(); p ^= 0; + } + serial_delay(); } + /* send parity bit */ + if(p & 1) { serial_high(); } + else { serial_low(); } serial_delay(); + + serial_low(); // sync_send() / senc_recv() need raise edge +} + +static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE; +static +void serial_send_packet(uint8_t *buffer, uint8_t size) { + for (uint8_t i = 0; i < size; ++i) { + uint8_t data; + data = buffer[i]; + sync_send(); + serial_write_chunk(data,8); } } -// interrupt handle to be used by the slave device +static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) NO_INLINE; +static +uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) { + uint8_t pecount = 0; + for (uint8_t i = 0; i < size; ++i) { + uint8_t data; + sync_recv(); + data = serial_read_chunk(&pecount, 8); + buffer[i] = data; + } + return pecount == 0; +} + +inline static +void change_sender2reciver(void) { + sync_send(); //0 + serial_delay_half1(); //1 + serial_low(); //2 + serial_input_with_pullup(); //2 + serial_delay_half1(); //3 +} + +inline static +void change_reciver2sender(void) { + sync_recv(); //0 + serial_delay(); //1 + serial_low(); //3 + serial_output(); //3 + serial_delay_half1(); //4 +} + +static inline uint8_t nibble_bits_count(uint8_t bits) +{ + bits = (bits & 0x5) + (bits >> 1 & 0x5); + bits = (bits & 0x3) + (bits >> 2 & 0x3); + return bits; +} + +// interrupt handle to be used by the target device ISR(SERIAL_PIN_INTERRUPT) { - sync_send(); - uint8_t checksum = 0; - for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { - serial_write_byte(serial_slave_buffer[i]); - sync_send(); - checksum += serial_slave_buffer[i]; +#ifndef SERIAL_USE_MULTI_TRANSACTION + serial_low(); + serial_output(); + SSTD_t *trans = Transaction_table; +#else + // recive transaction table index + uint8_t tid, bits; + uint8_t pecount = 0; + sync_recv(); + bits = serial_read_chunk(&pecount,7); + tid = bits>>3; + bits = (bits&7) != nibble_bits_count(tid); + if( bits || pecount> 0 || tid > Transaction_table_size ) { + return; } - serial_write_byte(checksum); - sync_send(); + serial_delay_half1(); - // wait for the sync to finish sending - serial_delay(); + serial_high(); // response step1 low->high + serial_output(); + _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT*SLAVE_INT_ACK_WIDTH); + SSTD_t *trans = &Transaction_table[tid]; + serial_low(); // response step2 ack high->low +#endif - // read the middle of pulses - _delay_us(SERIAL_DELAY/2); + // target send phase + if( trans->target2initiator_buffer_size > 0 ) + serial_send_packet((uint8_t *)trans->target2initiator_buffer, + trans->target2initiator_buffer_size); + // target switch to input + change_sender2reciver(); - uint8_t checksum_computed = 0; - for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) { - serial_master_buffer[i] = serial_read_byte(); - sync_send(); - checksum_computed += serial_master_buffer[i]; - } - uint8_t checksum_received = serial_read_byte(); - sync_send(); - - serial_input(); // end transaction - - if ( checksum_computed != checksum_received ) { - status |= SLAVE_DATA_CORRUPT; + // target recive phase + if( trans->initiator2target_buffer_size > 0 ) { + if (serial_recive_packet((uint8_t *)trans->initiator2target_buffer, + trans->initiator2target_buffer_size) ) { + *trans->status = TRANSACTION_ACCEPTED; + } else { + *trans->status = TRANSACTION_DATA_ERROR; + } } else { - status &= ~SLAVE_DATA_CORRUPT; + *trans->status = TRANSACTION_ACCEPTED; } + + sync_recv(); //weit initiator output to high } -inline -bool serial_slave_DATA_CORRUPT(void) { - return status & SLAVE_DATA_CORRUPT; -} - -// Copies the serial_slave_buffer to the master and sends the -// serial_master_buffer to the slave. +///////// +// start transaction by initiator +// +// int soft_serial_transaction(int sstd_index) // // Returns: -// 0 => no error -// 1 => slave did not respond -int serial_update_buffers(void) { - // this code is very time dependent, so we need to disable interrupts +// TRANSACTION_END +// TRANSACTION_NO_RESPONSE +// TRANSACTION_DATA_ERROR +// this code is very time dependent, so we need to disable interrupts +#ifndef SERIAL_USE_MULTI_TRANSACTION +int soft_serial_transaction(void) { + SSTD_t *trans = Transaction_table; +#else +int soft_serial_transaction(int sstd_index) { + if( sstd_index > Transaction_table_size ) + return TRANSACTION_TYPE_ERROR; + SSTD_t *trans = &Transaction_table[sstd_index]; +#endif cli(); - // signal to the slave that we want to start a transaction + // signal to the target that we want to start a transaction serial_output(); serial_low(); - _delay_us(1); + _delay_us(SLAVE_INT_WIDTH_US); - // wait for the slaves response - serial_input(); - serial_high(); - _delay_us(SERIAL_DELAY); +#ifndef SERIAL_USE_MULTI_TRANSACTION + // wait for the target response + serial_input_with_pullup(); + _delay_us(SLAVE_INT_RESPONSE_TIME); - // check if the slave is present + // check if the target is present if (serial_read_pin()) { - // slave failed to pull the line low, assume not present + // target failed to pull the line low, assume not present + serial_output(); + serial_high(); + *trans->status = TRANSACTION_NO_RESPONSE; sei(); - return 1; + return TRANSACTION_NO_RESPONSE; } - // if the slave is present syncronize with it - sync_recv(); +#else + // send transaction table index + int tid = (sstd_index<<3) | (7 & nibble_bits_count(sstd_index)); + sync_send(); + _delay_sub_us(TID_SEND_ADJUST); + serial_write_chunk(tid, 7); + serial_delay_half1(); - uint8_t checksum_computed = 0; - // receive data from the slave - for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { - serial_slave_buffer[i] = serial_read_byte(); - sync_recv(); - checksum_computed += serial_slave_buffer[i]; - } - uint8_t checksum_received = serial_read_byte(); - sync_recv(); - - if (checksum_computed != checksum_received) { - sei(); - return 1; + // wait for the target response (step1 low->high) + serial_input_with_pullup(); + while( !serial_read_pin() ) { + _delay_sub_us(2); } - uint8_t checksum = 0; - // send data to the slave - for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) { - serial_write_byte(serial_master_buffer[i]); - sync_recv(); - checksum += serial_master_buffer[i]; + // check if the target is present (step2 high->low) + for( int i = 0; serial_read_pin(); i++ ) { + if (i > SLAVE_INT_ACK_WIDTH + 1) { + // slave failed to pull the line low, assume not present + serial_output(); + serial_high(); + *trans->status = TRANSACTION_NO_RESPONSE; + sei(); + return TRANSACTION_NO_RESPONSE; + } + _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT); + } +#endif + + // initiator recive phase + // if the target is present syncronize with it + if( trans->target2initiator_buffer_size > 0 ) { + if (!serial_recive_packet((uint8_t *)trans->target2initiator_buffer, + trans->target2initiator_buffer_size) ) { + serial_output(); + serial_high(); + *trans->status = TRANSACTION_DATA_ERROR; + sei(); + return TRANSACTION_DATA_ERROR; + } + } + + // initiator switch to output + change_reciver2sender(); + + // initiator send phase + if( trans->initiator2target_buffer_size > 0 ) { + serial_send_packet((uint8_t *)trans->initiator2target_buffer, + trans->initiator2target_buffer_size); } - serial_write_byte(checksum); - sync_recv(); // always, release the line when not in use - serial_output(); - serial_high(); + sync_send(); + *trans->status = TRANSACTION_END; sei(); - return 0; + return TRANSACTION_END; } -#endif /* SOFT_SERIAL_PIN */ +#ifdef SERIAL_USE_MULTI_TRANSACTION +int soft_serial_get_and_clean_status(int sstd_index) { + SSTD_t *trans = &Transaction_table[sstd_index]; + cli(); + int retval = *trans->status; + *trans->status = 0;; + sei(); + return retval; +} +#endif + +#endif + +// Helix serial.c history +// 2018-1-29 fork from let's split and add PD2, modify sync_recv() (#2308, bceffdefc) +// 2018-6-28 bug fix master to slave comm and speed up (#3255, 1038bbef4) +// (adjusted with avr-gcc 4.9.2) +// 2018-7-13 remove USE_SERIAL_PD2 macro (#3374, f30d6dd78) +// (adjusted with avr-gcc 4.9.2) +// 2018-8-11 add support multi-type transaction (#3608, feb5e4aae) +// (adjusted with avr-gcc 4.9.2) +// 2018-10-21 fix serial and RGB animation conflict (#4191, 4665e4fff) +// (adjusted with avr-gcc 7.3.0) +// 2018-10-28 re-adjust compiler depend value of delay (#4269, 8517f8a66) +// (adjusted with avr-gcc 5.4.0, 7.3.0) +// 2018-12-17 copy to TOP/quantum/split_common/ and remove backward compatibility code (#4669) diff --git a/quantum/split_common/serial.h b/quantum/split_common/serial.h index 0b99f352d0..b6638b3bde 100644 --- a/quantum/split_common/serial.h +++ b/quantum/split_common/serial.h @@ -1,5 +1,5 @@ -#ifndef MY_SERIAL_H -#define MY_SERIAL_H +#ifndef SOFT_SERIAL_H +#define SOFT_SERIAL_H #include @@ -7,20 +7,59 @@ // Need Soft Serial defines in config.h // ///////////////////////////////////////////////////////////////// // ex. -// /* Configuration of lower interface with the lower layer(hardware) of serial.c */ // #define SOFT_SERIAL_PIN ?? // ?? = D0,D1,D2,D3,E6 +// OPTIONAL: #define SELECT_SOFT_SERIAL_SPEED ? // ? = 1,2,3,4,5 +// // 1: about 137kbps (default) +// // 2: about 75kbps +// // 3: about 39kbps +// // 4: about 26kbps +// // 5: about 20kbps // -// /* Configuration of upper interface with the upper layer of serial.c */ -// #define SERIAL_SLAVE_BUFFER_LENGTH MATRIX_ROWS/2 -// #define SERIAL_MASTER_BUFFER_LENGTH 1 +// //// USE simple API (using signle-type transaction function) +// /* nothing */ +// //// USE flexible API (using multi-type transaction function) +// #define SERIAL_USE_MULTI_TRANSACTION +// +// ///////////////////////////////////////////////////////////////// -// Buffers for master - slave communication -extern volatile uint8_t serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH]; -extern volatile uint8_t serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH]; +// Soft Serial Transaction Descriptor +typedef struct _SSTD_t { + uint8_t *status; + uint8_t initiator2target_buffer_size; + uint8_t *initiator2target_buffer; + uint8_t target2initiator_buffer_size; + uint8_t *target2initiator_buffer; +} SSTD_t; +#define TID_LIMIT( table ) (sizeof(table) / sizeof(SSTD_t)) -void serial_master_init(void); -void serial_slave_init(void); -int serial_update_buffers(void); -bool serial_slave_data_corrupt(void); +// initiator is transaction start side +void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size); +// target is interrupt accept side +void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size); +// initiator resullt +#define TRANSACTION_END 0 +#define TRANSACTION_NO_RESPONSE 0x1 +#define TRANSACTION_DATA_ERROR 0x2 +#define TRANSACTION_TYPE_ERROR 0x4 +#ifndef SERIAL_USE_MULTI_TRANSACTION +int soft_serial_transaction(void); +#else +int soft_serial_transaction(int sstd_index); #endif + +// target status +// *SSTD_t.status has +// initiator: +// TRANSACTION_END +// or TRANSACTION_NO_RESPONSE +// or TRANSACTION_DATA_ERROR +// target: +// TRANSACTION_DATA_ERROR +// or TRANSACTION_ACCEPTED +#define TRANSACTION_ACCEPTED 0x8 +#ifdef SERIAL_USE_MULTI_TRANSACTION +int soft_serial_get_and_clean_status(int sstd_index); +#endif + +#endif /* SOFT_SERIAL_H */ diff --git a/quantum/split_common/serial_backward_compatibility.h b/quantum/split_common/serial_backward_compatibility.h deleted file mode 100644 index 216b6c41ff..0000000000 --- a/quantum/split_common/serial_backward_compatibility.h +++ /dev/null @@ -1,11 +0,0 @@ -/* serial.h backward compatibility */ - -// #ifndef SOFT_SERIAL_PIN -// #define SOFT_SERIAL_PIN D0 -// #endif - -#ifndef SERIAL_SLAVE_BUFFER_LENGTH - #define SERIAL_SLAVE_BUFFER_LENGTH MATRIX_ROWS/2 - #define SERIAL_MASTER_BUFFER_LENGTH 1 -#endif - diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index 56077e4f20..e4475c5356 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -11,9 +11,6 @@ #include "timer.h" #include "split_flags.h" -#ifdef RGBLIGHT_ENABLE -# include "rgblight.h" -#endif #ifdef BACKLIGHT_ENABLE # include "backlight.h" #endif @@ -24,8 +21,6 @@ #if defined(USE_I2C) || defined(EH) # include "i2c.h" -#else -# include "serial.h" #endif volatile bool isLeftHand = true; @@ -112,7 +107,7 @@ void keyboard_slave_loop(void) { BACKLIT_DIRTY = false; } #else // USE_SERIAL - backlight_set(serial_master_buffer[SERIAL_BACKLIT_START]); + backlight_set(serial_m2s_buffer.backlight_level); #endif #endif // Read RGB Info @@ -137,7 +132,9 @@ void keyboard_slave_loop(void) { sei(); } #else // USE_SERIAL + #ifdef RGBLIGHT_SPLIT // Add serial implementation for RGB here + #endif #endif #endif } diff --git a/quantum/split_common/split_util.h b/quantum/split_common/split_util.h index 45e8db0f2f..d6cf3e72a9 100644 --- a/quantum/split_common/split_util.h +++ b/quantum/split_common/split_util.h @@ -7,9 +7,6 @@ #include #include "eeconfig.h" -// backlight level store index in serial_master_buffer[] for slave to read -#define SERIAL_BACKLIT_START 0x00 - #define SLAVE_I2C_ADDRESS 0x32 extern volatile bool isLeftHand;