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