qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

serial.c (17366B)


      1 /*
      2  * WARNING: be careful changing this code, it is very timing dependent
      3  *
      4  * 2018-10-28 checked
      5  *  avr-gcc 4.9.2
      6  *  avr-gcc 5.4.0
      7  *  avr-gcc 7.3.0
      8  */
      9 
     10 #ifndef F_CPU
     11 #    define F_CPU 16000000
     12 #endif
     13 
     14 #include <avr/io.h>
     15 #include <avr/interrupt.h>
     16 #include <util/delay.h>
     17 #include <stddef.h>
     18 #include <stdbool.h>
     19 #include "gpio.h"
     20 #include "serial.h"
     21 
     22 #ifdef SOFT_SERIAL_PIN
     23 
     24 #    if !(defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
     25 #        error serial.c is not supported for the currently selected MCU
     26 #    endif
     27 // if using ATmega32U4/2, AT90USBxxx I2C, can not use PD0 and PD1 in soft serial.
     28 #    if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
     29 #        if defined(USE_AVR_I2C) && (SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1)
     30 #            error Using I2C, so can not use PD0, PD1
     31 #        endif
     32 #    endif
     33 // PD0..PD3, common config
     34 #    if SOFT_SERIAL_PIN == D0
     35 #        define EIMSK_BIT _BV(INT0)
     36 #        define EICRx_BIT (~(_BV(ISC00) | _BV(ISC01)))
     37 #        define SERIAL_PIN_INTERRUPT INT0_vect
     38 #        define EICRx EICRA
     39 #    elif SOFT_SERIAL_PIN == D1
     40 #        define EIMSK_BIT _BV(INT1)
     41 #        define EICRx_BIT (~(_BV(ISC10) | _BV(ISC11)))
     42 #        define SERIAL_PIN_INTERRUPT INT1_vect
     43 #        define EICRx EICRA
     44 #    elif SOFT_SERIAL_PIN == D2
     45 #        define EIMSK_BIT _BV(INT2)
     46 #        define EICRx_BIT (~(_BV(ISC20) | _BV(ISC21)))
     47 #        define SERIAL_PIN_INTERRUPT INT2_vect
     48 #        define EICRx EICRA
     49 #    elif SOFT_SERIAL_PIN == D3
     50 #        define EIMSK_BIT _BV(INT3)
     51 #        define EICRx_BIT (~(_BV(ISC30) | _BV(ISC31)))
     52 #        define SERIAL_PIN_INTERRUPT INT3_vect
     53 #        define EICRx EICRA
     54 #    endif
     55 
     56 // ATmegaxxU2/AT90USB162 specific config
     57 #    if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB162__)
     58 // PD4(INT5), PD6(INT6), PD7(INT7), PC7(INT4)
     59 #        if SOFT_SERIAL_PIN == D4
     60 #            define EIMSK_BIT _BV(INT5)
     61 #            define EICRx_BIT (~(_BV(ISC50) | _BV(ISC51)))
     62 #            define SERIAL_PIN_INTERRUPT INT5_vect
     63 #            define EICRx EICRB
     64 #        elif SOFT_SERIAL_PIN == D6
     65 #            define EIMSK_BIT _BV(INT6)
     66 #            define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
     67 #            define SERIAL_PIN_INTERRUPT INT6_vect
     68 #            define EICRx EICRB
     69 #        elif SOFT_SERIAL_PIN == D7
     70 #            define EIMSK_BIT _BV(INT7)
     71 #            define EICRx_BIT (~(_BV(ISC70) | _BV(ISC71)))
     72 #            define SERIAL_PIN_INTERRUPT INT7_vect
     73 #            define EICRx EICRB
     74 #        elif SOFT_SERIAL_PIN == C7
     75 #            define EIMSK_BIT _BV(INT4)
     76 #            define EICRx_BIT (~(_BV(ISC40) | _BV(ISC41)))
     77 #            define SERIAL_PIN_INTERRUPT INT4_vect
     78 #            define EICRx EICRB
     79 #        endif
     80 #    endif
     81 
     82 // ATmegaxxU4 specific config
     83 #    if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
     84 // PE6(INT6)
     85 #        if SOFT_SERIAL_PIN == E6
     86 #            define EIMSK_BIT _BV(INT6)
     87 #            define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
     88 #            define SERIAL_PIN_INTERRUPT INT6_vect
     89 #            define EICRx EICRB
     90 #        endif
     91 #    endif
     92 
     93 // AT90USBxxx specific config
     94 #    if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
     95 // PE4..PE7(INT4..INT7)
     96 #        if SOFT_SERIAL_PIN == E4
     97 #            define EIMSK_BIT _BV(INT4)
     98 #            define EICRx_BIT (~(_BV(ISC40) | _BV(ISC41)))
     99 #            define SERIAL_PIN_INTERRUPT INT4_vect
    100 #            define EICRx EICRB
    101 #        elif SOFT_SERIAL_PIN == E5
    102 #            define EIMSK_BIT _BV(INT5)
    103 #            define EICRx_BIT (~(_BV(ISC50) | _BV(ISC51)))
    104 #            define SERIAL_PIN_INTERRUPT INT5_vect
    105 #            define EICRx EICRB
    106 #        elif SOFT_SERIAL_PIN == E6
    107 #            define EIMSK_BIT _BV(INT6)
    108 #            define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
    109 #            define SERIAL_PIN_INTERRUPT INT6_vect
    110 #            define EICRx EICRB
    111 #        elif SOFT_SERIAL_PIN == E7
    112 #            define EIMSK_BIT _BV(INT7)
    113 #            define EICRx_BIT (~(_BV(ISC70) | _BV(ISC71)))
    114 #            define SERIAL_PIN_INTERRUPT INT7_vect
    115 #            define EICRx EICRB
    116 #        endif
    117 #    endif
    118 
    119 #    ifndef SERIAL_PIN_INTERRUPT
    120 #        error invalid SOFT_SERIAL_PIN value
    121 #    endif
    122 
    123 #    define ALWAYS_INLINE __attribute__((always_inline))
    124 #    define NO_INLINE __attribute__((noinline))
    125 #    define _delay_sub_us(x) __builtin_avr_delay_cycles(x)
    126 
    127 // parity check
    128 #    define ODD_PARITY 1
    129 #    define EVEN_PARITY 0
    130 #    define PARITY EVEN_PARITY
    131 
    132 #    ifdef SERIAL_DELAY
    133 // custom setup in config.h
    134 // #define TID_SEND_ADJUST 2
    135 // #define SERIAL_DELAY 6             // micro sec
    136 // #define READ_WRITE_START_ADJUST 30 // cycles
    137 // #define READ_WRITE_WIDTH_ADJUST 8 // cycles
    138 #    else
    139 // ============ Standard setups ============
    140 
    141 #        ifndef SELECT_SOFT_SERIAL_SPEED
    142 #            define SELECT_SOFT_SERIAL_SPEED 1
    143 //  0: about 189kbps (Experimental only)
    144 //  1: about 137kbps (default)
    145 //  2: about 75kbps
    146 //  3: about 39kbps
    147 //  4: about 26kbps
    148 //  5: about 20kbps
    149 #        endif
    150 
    151 #        if __GNUC__ < 6
    152 #            define TID_SEND_ADJUST 14
    153 #        else
    154 #            define TID_SEND_ADJUST 2
    155 #        endif
    156 
    157 #        if SELECT_SOFT_SERIAL_SPEED == 0
    158 // Very High speed
    159 #            define SERIAL_DELAY 4 // micro sec
    160 #            if __GNUC__ < 6
    161 #                define READ_WRITE_START_ADJUST 33 // cycles
    162 #                define READ_WRITE_WIDTH_ADJUST 3  // cycles
    163 #            else
    164 #                define READ_WRITE_START_ADJUST 34 // cycles
    165 #                define READ_WRITE_WIDTH_ADJUST 7  // cycles
    166 #            endif
    167 #        elif SELECT_SOFT_SERIAL_SPEED == 1
    168 // High speed
    169 #            define SERIAL_DELAY 6 // micro sec
    170 #            if __GNUC__ < 6
    171 #                define READ_WRITE_START_ADJUST 30 // cycles
    172 #                define READ_WRITE_WIDTH_ADJUST 3  // cycles
    173 #            else
    174 #                define READ_WRITE_START_ADJUST 33 // cycles
    175 #                define READ_WRITE_WIDTH_ADJUST 7  // cycles
    176 #            endif
    177 #        elif SELECT_SOFT_SERIAL_SPEED == 2
    178 // Middle speed
    179 #            define SERIAL_DELAY 12            // micro sec
    180 #            define READ_WRITE_START_ADJUST 30 // cycles
    181 #            if __GNUC__ < 6
    182 #                define READ_WRITE_WIDTH_ADJUST 3 // cycles
    183 #            else
    184 #                define READ_WRITE_WIDTH_ADJUST 7 // cycles
    185 #            endif
    186 #        elif SELECT_SOFT_SERIAL_SPEED == 3
    187 // Low speed
    188 #            define SERIAL_DELAY 24            // micro sec
    189 #            define READ_WRITE_START_ADJUST 30 // cycles
    190 #            if __GNUC__ < 6
    191 #                define READ_WRITE_WIDTH_ADJUST 3 // cycles
    192 #            else
    193 #                define READ_WRITE_WIDTH_ADJUST 7 // cycles
    194 #            endif
    195 #        elif SELECT_SOFT_SERIAL_SPEED == 4
    196 // Very Low speed
    197 #            define SERIAL_DELAY 36            // micro sec
    198 #            define READ_WRITE_START_ADJUST 30 // cycles
    199 #            if __GNUC__ < 6
    200 #                define READ_WRITE_WIDTH_ADJUST 3 // cycles
    201 #            else
    202 #                define READ_WRITE_WIDTH_ADJUST 7 // cycles
    203 #            endif
    204 #        elif SELECT_SOFT_SERIAL_SPEED == 5
    205 // Ultra Low speed
    206 #            define SERIAL_DELAY 48            // micro sec
    207 #            define READ_WRITE_START_ADJUST 30 // cycles
    208 #            if __GNUC__ < 6
    209 #                define READ_WRITE_WIDTH_ADJUST 3 // cycles
    210 #            else
    211 #                define READ_WRITE_WIDTH_ADJUST 7 // cycles
    212 #            endif
    213 #        else
    214 #            error invalid SELECT_SOFT_SERIAL_SPEED value
    215 #        endif /* SELECT_SOFT_SERIAL_SPEED */
    216 #    endif     /* SERIAL_DELAY */
    217 
    218 #    define SERIAL_DELAY_HALF1 (SERIAL_DELAY / 2)
    219 #    define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY / 2)
    220 
    221 #    define SLAVE_INT_WIDTH_US 1
    222 #    define SLAVE_INT_ACK_WIDTH_UNIT 2
    223 #    define SLAVE_INT_ACK_WIDTH 4
    224 
    225 inline static void serial_delay(void) ALWAYS_INLINE;
    226 inline static void serial_delay(void) {
    227     _delay_us(SERIAL_DELAY);
    228 }
    229 
    230 inline static void serial_delay_half1(void) ALWAYS_INLINE;
    231 inline static void serial_delay_half1(void) {
    232     _delay_us(SERIAL_DELAY_HALF1);
    233 }
    234 
    235 inline static void serial_delay_half2(void) ALWAYS_INLINE;
    236 inline static void serial_delay_half2(void) {
    237     _delay_us(SERIAL_DELAY_HALF2);
    238 }
    239 
    240 inline static void serial_output(void) ALWAYS_INLINE;
    241 inline static void serial_output(void) {
    242     gpio_set_pin_output(SOFT_SERIAL_PIN);
    243 }
    244 
    245 // make the serial pin an input with pull-up resistor
    246 inline static void serial_input_with_pullup(void) ALWAYS_INLINE;
    247 inline static void serial_input_with_pullup(void) {
    248     gpio_set_pin_input_high(SOFT_SERIAL_PIN);
    249 }
    250 
    251 inline static uint8_t serial_read_pin(void) ALWAYS_INLINE;
    252 inline static uint8_t serial_read_pin(void) {
    253     return !!gpio_read_pin(SOFT_SERIAL_PIN);
    254 }
    255 
    256 inline static void serial_low(void) ALWAYS_INLINE;
    257 inline static void serial_low(void) {
    258     gpio_write_pin_low(SOFT_SERIAL_PIN);
    259 }
    260 
    261 inline static void serial_high(void) ALWAYS_INLINE;
    262 inline static void serial_high(void) {
    263     gpio_write_pin_high(SOFT_SERIAL_PIN);
    264 }
    265 
    266 void soft_serial_initiator_init(void) {
    267     serial_output();
    268     serial_high();
    269 }
    270 
    271 void soft_serial_target_init(void) {
    272     serial_input_with_pullup();
    273 
    274     // Enable INT0-INT7
    275     EIMSK |= EIMSK_BIT;
    276     EICRx &= EICRx_BIT;
    277 }
    278 
    279 // Used by the sender to synchronize timing with the reciver.
    280 static void sync_recv(void) NO_INLINE;
    281 static void sync_recv(void) {
    282     for (uint8_t i = 0; i < SERIAL_DELAY * 5 && serial_read_pin(); i++) {
    283     }
    284     // This shouldn't hang if the target disconnects because the
    285     // serial line will float to high if the target does disconnect.
    286     while (!serial_read_pin())
    287         ;
    288 }
    289 
    290 // Used by the reciver to send a synchronization signal to the sender.
    291 static void sync_send(void) NO_INLINE;
    292 static void sync_send(void) {
    293     serial_low();
    294     serial_delay();
    295     serial_high();
    296 }
    297 
    298 // Reads a byte from the serial line
    299 static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) NO_INLINE;
    300 static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) {
    301     uint8_t byte, i, p, pb;
    302 
    303     _delay_sub_us(READ_WRITE_START_ADJUST);
    304     for (i = 0, byte = 0, p = PARITY; i < bit; i++) {
    305         serial_delay_half1(); // read the middle of pulses
    306         if (serial_read_pin()) {
    307             byte = (byte << 1) | 1;
    308             p ^= 1;
    309         } else {
    310             byte = (byte << 1) | 0;
    311             p ^= 0;
    312         }
    313         _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
    314         serial_delay_half2();
    315     }
    316     /* recive parity bit */
    317     serial_delay_half1(); // read the middle of pulses
    318     pb = serial_read_pin();
    319     _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
    320     serial_delay_half2();
    321 
    322     *pterrcount += (p != pb) ? 1 : 0;
    323 
    324     return byte;
    325 }
    326 
    327 // Sends a byte with MSB ordering
    328 void serial_write_chunk(uint8_t data, uint8_t bit) NO_INLINE;
    329 void serial_write_chunk(uint8_t data, uint8_t bit) {
    330     uint8_t b, p;
    331     for (p = PARITY, b = 1 << (bit - 1); b; b >>= 1) {
    332         if (data & b) {
    333             serial_high();
    334             p ^= 1;
    335         } else {
    336             serial_low();
    337             p ^= 0;
    338         }
    339         serial_delay();
    340     }
    341     /* send parity bit */
    342     if (p & 1) {
    343         serial_high();
    344     } else {
    345         serial_low();
    346     }
    347     serial_delay();
    348 
    349     serial_low(); // sync_send() / senc_recv() need raise edge
    350 }
    351 
    352 static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE;
    353 static void serial_send_packet(uint8_t *buffer, uint8_t size) {
    354     for (uint8_t i = 0; i < size; ++i) {
    355         uint8_t data;
    356         data = buffer[i];
    357         sync_send();
    358         serial_write_chunk(data, 8);
    359     }
    360 }
    361 
    362 static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) NO_INLINE;
    363 static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) {
    364     uint8_t pecount = 0;
    365     for (uint8_t i = 0; i < size; ++i) {
    366         uint8_t data;
    367         sync_recv();
    368         data      = serial_read_chunk(&pecount, 8);
    369         buffer[i] = data;
    370     }
    371     return pecount == 0;
    372 }
    373 
    374 inline static void change_sender2reciver(void) {
    375     sync_send();                // 0
    376     serial_delay_half1();       // 1
    377     serial_low();               // 2
    378     serial_input_with_pullup(); // 2
    379     serial_delay_half1();       // 3
    380 }
    381 
    382 inline static void change_reciver2sender(void) {
    383     sync_recv();          // 0
    384     serial_delay();       // 1
    385     serial_low();         // 3
    386     serial_output();      // 3
    387     serial_delay_half1(); // 4
    388 }
    389 
    390 static inline uint8_t nibble_bits_count(uint8_t bits) {
    391     bits = (bits & 0x5) + (bits >> 1 & 0x5);
    392     bits = (bits & 0x3) + (bits >> 2 & 0x3);
    393     return bits;
    394 }
    395 
    396 // interrupt handle to be used by the target device
    397 ISR(SERIAL_PIN_INTERRUPT) {
    398     // recive transaction table index
    399     uint8_t tid, bits;
    400     uint8_t pecount = 0;
    401     sync_recv();
    402     bits = serial_read_chunk(&pecount, 8);
    403     tid  = bits >> 3;
    404     bits = (bits & 7) != (nibble_bits_count(tid) & 7);
    405     if (bits || pecount > 0 || tid > NUM_TOTAL_TRANSACTIONS) {
    406         return;
    407     }
    408     serial_delay_half1();
    409 
    410     serial_high(); // response step1 low->high
    411     serial_output();
    412     _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH);
    413     split_transaction_desc_t *trans = &split_transaction_table[tid];
    414     serial_low(); // response step2 ack high->low
    415 
    416     // If the transaction has a callback, we can execute it now
    417     if (trans->slave_callback) {
    418         trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
    419     }
    420 
    421     // target send phase
    422     if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size);
    423     // target switch to input
    424     change_sender2reciver();
    425 
    426     // target recive phase
    427     if (trans->initiator2target_buffer_size > 0) {
    428         serial_recive_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
    429     }
    430 
    431     sync_recv(); // weit initiator output to high
    432 }
    433 
    434 /////////
    435 //  start transaction by initiator
    436 //
    437 // bool  soft_serial_transaction(int sstd_index)
    438 //
    439 // this code is very time dependent, so we need to disable interrupts
    440 bool soft_serial_transaction(int sstd_index) {
    441     if (sstd_index > NUM_TOTAL_TRANSACTIONS) return false;
    442     split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
    443 
    444     cli();
    445 
    446     // signal to the target that we want to start a transaction
    447     serial_output();
    448     serial_low();
    449     _delay_us(SLAVE_INT_WIDTH_US);
    450 
    451     // send transaction table index
    452     int tid = (sstd_index << 3) | (7 & nibble_bits_count(sstd_index));
    453     sync_send();
    454     _delay_sub_us(TID_SEND_ADJUST);
    455     serial_write_chunk(tid, 8);
    456     serial_delay_half1();
    457 
    458     // wait for the target response (step1 low->high)
    459     serial_input_with_pullup();
    460     while (!serial_read_pin()) {
    461         _delay_sub_us(2);
    462     }
    463 
    464     // check if the target is present (step2 high->low)
    465     for (int i = 0; serial_read_pin(); i++) {
    466         if (i > SLAVE_INT_ACK_WIDTH + 1) {
    467             // slave failed to pull the line low, assume not present
    468             serial_output();
    469             serial_high();
    470             sei();
    471             return false;
    472         }
    473         _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT);
    474     }
    475 
    476     // initiator recive phase
    477     // if the target is present syncronize with it
    478     if (trans->target2initiator_buffer_size > 0) {
    479         if (!serial_recive_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) {
    480             serial_output();
    481             serial_high();
    482             sei();
    483             return false;
    484         }
    485     }
    486 
    487     // initiator switch to output
    488     change_reciver2sender();
    489 
    490     // initiator send phase
    491     if (trans->initiator2target_buffer_size > 0) {
    492         serial_send_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
    493     }
    494 
    495     // always, release the line when not in use
    496     sync_send();
    497 
    498     sei();
    499     return true;
    500 }
    501 #else
    502 #    ifndef USE_I2C
    503 #        error SOFT_SERIAL_PIN or USE_I2C is required but has not been defined.
    504 #    endif
    505 #endif
    506 
    507 // Helix serial.c history
    508 //   2018-1-29 fork from let's split and add PD2, modify sync_recv() (#2308, bceffdefc)
    509 //   2018-6-28 bug fix master to slave comm and speed up (#3255, 1038bbef4)
    510 //             (adjusted with avr-gcc 4.9.2)
    511 //   2018-7-13 remove USE_SERIAL_PD2 macro (#3374, f30d6dd78)
    512 //             (adjusted with avr-gcc 4.9.2)
    513 //   2018-8-11 add support multi-type transaction (#3608, feb5e4aae)
    514 //             (adjusted with avr-gcc 4.9.2)
    515 //   2018-10-21 fix serial and RGB animation conflict (#4191, 4665e4fff)
    516 //             (adjusted with avr-gcc 7.3.0)
    517 //   2018-10-28 re-adjust compiler depend value of delay (#4269, 8517f8a66)
    518 //             (adjusted with avr-gcc 5.4.0, 7.3.0)
    519 //   2018-12-17 copy to TOP/quantum/split_common/ and remove backward compatibility code (#4669)