diff options
Diffstat (limited to 'quantum/split_common')
| -rw-r--r-- | quantum/split_common/matrix.c | 61 | ||||
| -rw-r--r-- | quantum/split_common/matrix.h | 31 | ||||
| -rw-r--r-- | quantum/split_common/serial.c | 505 | ||||
| -rw-r--r-- | quantum/split_common/serial.h | 65 | ||||
| -rw-r--r-- | quantum/split_common/serial_backward_compatibility.h | 11 | ||||
| -rw-r--r-- | quantum/split_common/split_util.c | 9 | ||||
| -rw-r--r-- | quantum/split_common/split_util.h | 3 | 
7 files changed, 526 insertions, 159 deletions
| 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 <http://www.gnu.org/licenses/>.  #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 <http://www.gnu.org/licenses/>.      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)) @@ -63,6 +62,27 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  #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];  #define ERROR_DISCONNECT_COUNT 5 @@ -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 <common/matrix.h> + +#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 <avr/io.h>  #include <avr/interrupt.h>  #include <util/delay.h> +#include <stddef.h>  #include <stdbool.h>  #include "serial.h" +//#include <pro_micro.h>  #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) + +// parity check +#define ODD_PARITY 1 +#define EVEN_PARITY 0 +#define PARITY EVEN_PARITY + +#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 -uint8_t volatile serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH] = {0}; -uint8_t volatile serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH] = {0}; +#if __GNUC__ < 6 +  #define TID_SEND_ADJUST 14 +#else +  #define TID_SEND_ADJUST 2 +#endif -#define SLAVE_DATA_CORRUPT (1<<0) -volatile uint8_t status = 0; +#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(); - -  // Enable INT0 -  EIMSK |= _BV(INT0); -  // Trigger on falling edge of INT0 -  EICRA &= ~(_BV(ISC00) | _BV(ISC01)); +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-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(); -  } -} -// interrupt handle to be used by the slave device -ISR(SERIAL_PIN_INTERRUPT) { -  sync_send(); +    serial_low(); // sync_send() / senc_recv() need raise edge +} -  uint8_t checksum = 0; -  for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { -    serial_write_byte(serial_slave_buffer[i]); +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(); -    checksum += serial_slave_buffer[i]; +    serial_write_chunk(data,8);    } -  serial_write_byte(checksum); -  sync_send(); +} -  // wait for the sync to finish sending -  serial_delay(); +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; +} -  // read the middle of pulses -  _delay_us(SERIAL_DELAY/2); +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 +} -  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]; +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) { + +#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;    } -  uint8_t checksum_received = serial_read_byte(); -  sync_send(); +  serial_delay_half1(); -  serial_input(); // end transaction +  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 -  if ( checksum_computed != checksum_received ) { -    status |= SLAVE_DATA_CORRUPT; +  // 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(); + +  // 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;    } -} -inline -bool serial_slave_DATA_CORRUPT(void) { -  return status & SLAVE_DATA_CORRUPT; +  sync_recv(); //weit initiator output to high  } -// 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(); - -  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]; +#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(); + +  // wait for the target response (step1 low->high) +  serial_input_with_pullup(); +  while( !serial_read_pin() ) { +      _delay_sub_us(2);    } -  uint8_t checksum_received = serial_read_byte(); -  sync_recv(); -  if (checksum_computed != checksum_received) { -    sei(); -    return 1; +  // 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 -  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]; +  // 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 <stdbool.h> @@ -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 <stdlib.h>  #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; | 
