aboutsummaryrefslogtreecommitdiff
path: root/drivers/avr
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/avr')
-rw-r--r--drivers/avr/i2c_master.c19
-rw-r--r--drivers/avr/i2c_slave.c29
-rw-r--r--drivers/avr/i2c_slave.h13
-rw-r--r--drivers/avr/serial.c82
-rw-r--r--drivers/avr/serial.h62
5 files changed, 81 insertions, 124 deletions
diff --git a/drivers/avr/i2c_master.c b/drivers/avr/i2c_master.c
index b1e488529..2773e0077 100644
--- a/drivers/avr/i2c_master.c
+++ b/drivers/avr/i2c_master.c
@@ -28,8 +28,14 @@
28# define F_SCL 400000UL // SCL frequency 28# define F_SCL 400000UL // SCL frequency
29#endif 29#endif
30 30
31#ifndef I2C_START_RETRY_COUNT
32# define I2C_START_RETRY_COUNT 20
33#endif // I2C_START_RETRY_COUNT
34
31#define TWBR_val (((F_CPU / F_SCL) - 16) / 2) 35#define TWBR_val (((F_CPU / F_SCL) - 16) / 2)
32 36
37#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
38
33void i2c_init(void) { 39void i2c_init(void) {
34 TWSR = 0; /* no prescaler */ 40 TWSR = 0; /* no prescaler */
35 TWBR = (uint8_t)TWBR_val; 41 TWBR = (uint8_t)TWBR_val;
@@ -47,7 +53,7 @@ void i2c_init(void) {
47#endif 53#endif
48} 54}
49 55
50i2c_status_t i2c_start(uint8_t address, uint16_t timeout) { 56static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
51 // reset TWI control register 57 // reset TWI control register
52 TWCR = 0; 58 TWCR = 0;
53 // transmit START condition 59 // transmit START condition
@@ -86,6 +92,17 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
86 return I2C_STATUS_SUCCESS; 92 return I2C_STATUS_SUCCESS;
87} 93}
88 94
95i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
96 // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
97 uint16_t timeout_timer = timer_read();
98 uint16_t time_slice = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
99 i2c_status_t status;
100 do {
101 status = i2c_start_impl(address, time_slice);
102 } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) < timeout)));
103 return status;
104}
105
89i2c_status_t i2c_write(uint8_t data, uint16_t timeout) { 106i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
90 // load data into data register 107 // load data into data register
91 TWDR = data; 108 TWDR = data;
diff --git a/drivers/avr/i2c_slave.c b/drivers/avr/i2c_slave.c
index 62a378165..2907f164c 100644
--- a/drivers/avr/i2c_slave.c
+++ b/drivers/avr/i2c_slave.c
@@ -17,6 +17,7 @@
17 * GitHub repository: https://github.com/g4lvanix/I2C-slave-lib 17 * GitHub repository: https://github.com/g4lvanix/I2C-slave-lib
18 */ 18 */
19 19
20#include <stddef.h>
20#include <avr/io.h> 21#include <avr/io.h>
21#include <util/twi.h> 22#include <util/twi.h>
22#include <avr/interrupt.h> 23#include <avr/interrupt.h>
@@ -24,6 +25,12 @@
24 25
25#include "i2c_slave.h" 26#include "i2c_slave.h"
26 27
28#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
29# include "transactions.h"
30
31static volatile bool is_callback_executor = false;
32#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
33
27volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT]; 34volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
28 35
29static volatile uint8_t buffer_address; 36static volatile uint8_t buffer_address;
@@ -48,11 +55,14 @@ ISR(TWI_vect) {
48 case TW_SR_SLA_ACK: 55 case TW_SR_SLA_ACK:
49 // The device is now a slave receiver 56 // The device is now a slave receiver
50 slave_has_register_set = false; 57 slave_has_register_set = false;
58#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
59 is_callback_executor = false;
60#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
51 break; 61 break;
52 62
53 case TW_SR_DATA_ACK: 63 case TW_SR_DATA_ACK:
54 // This device is a slave receiver and has received data 64 // This device is a slave receiver and has received data
55 // First byte is the location then the bytes will be writen in buffer with auto-incriment 65 // First byte is the location then the bytes will be writen in buffer with auto-increment
56 if (!slave_has_register_set) { 66 if (!slave_has_register_set) {
57 buffer_address = TWDR; 67 buffer_address = TWDR;
58 68
@@ -60,10 +70,25 @@ ISR(TWI_vect) {
60 ack = 0; 70 ack = 0;
61 buffer_address = 0; 71 buffer_address = 0;
62 } 72 }
63 slave_has_register_set = true; // address has been receaved now fill in buffer 73 slave_has_register_set = true; // address has been received now fill in buffer
74
75#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
76 // Work out if we're attempting to execute a callback
77 is_callback_executor = buffer_address == split_transaction_table[I2C_EXECUTE_CALLBACK].initiator2target_offset;
78#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
64 } else { 79 } else {
65 i2c_slave_reg[buffer_address] = TWDR; 80 i2c_slave_reg[buffer_address] = TWDR;
66 buffer_address++; 81 buffer_address++;
82
83#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
84 // If we're intending to execute a transaction callback, do so, as we've just received the transaction ID
85 if (is_callback_executor) {
86 split_transaction_desc_t *trans = &split_transaction_table[split_shmem->transaction_id];
87 if (trans->slave_callback) {
88 trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
89 }
90 }
91#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
67 } 92 }
68 break; 93 break;
69 94
diff --git a/drivers/avr/i2c_slave.h b/drivers/avr/i2c_slave.h
index 1cd0625ef..a8647c9da 100644
--- a/drivers/avr/i2c_slave.h
+++ b/drivers/avr/i2c_slave.h
@@ -22,7 +22,18 @@
22 22
23#pragma once 23#pragma once
24 24
25#define I2C_SLAVE_REG_COUNT 30 25#ifndef I2C_SLAVE_REG_COUNT
26
27# if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
28# include "transport.h"
29# define I2C_SLAVE_REG_COUNT sizeof(split_shared_memory_t)
30# else // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
31# define I2C_SLAVE_REG_COUNT 30
32# endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
33
34#endif // I2C_SLAVE_REG_COUNT
35
36_Static_assert(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte");
26 37
27extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT]; 38extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
28 39
diff --git a/drivers/avr/serial.c b/drivers/avr/serial.c
index 3647bee0d..9a7345a53 100644
--- a/drivers/avr/serial.c
+++ b/drivers/avr/serial.c
@@ -224,15 +224,8 @@
224# define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY / 2) 224# define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY / 2)
225 225
226# define SLAVE_INT_WIDTH_US 1 226# define SLAVE_INT_WIDTH_US 1
227# ifndef SERIAL_USE_MULTI_TRANSACTION 227# define SLAVE_INT_ACK_WIDTH_UNIT 2
228# define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY 228# define SLAVE_INT_ACK_WIDTH 4
229# else
230# define SLAVE_INT_ACK_WIDTH_UNIT 2
231# define SLAVE_INT_ACK_WIDTH 4
232# endif
233
234static SSTD_t *Transaction_table = NULL;
235static uint8_t Transaction_table_size = 0;
236 229
237inline static void serial_delay(void) ALWAYS_INLINE; 230inline static void serial_delay(void) ALWAYS_INLINE;
238inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); } 231inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); }
@@ -259,16 +252,12 @@ inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
259inline static void serial_high(void) ALWAYS_INLINE; 252inline static void serial_high(void) ALWAYS_INLINE;
260inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); } 253inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
261 254
262void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) { 255void soft_serial_initiator_init(void) {
263 Transaction_table = sstd_table;
264 Transaction_table_size = (uint8_t)sstd_table_size;
265 serial_output(); 256 serial_output();
266 serial_high(); 257 serial_high();
267} 258}
268 259
269void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) { 260void soft_serial_target_init(void) {
270 Transaction_table = sstd_table;
271 Transaction_table_size = (uint8_t)sstd_table_size;
272 serial_input_with_pullup(); 261 serial_input_with_pullup();
273 262
274 // Enable INT0-INT7 263 // Enable INT0-INT7
@@ -395,19 +384,14 @@ static inline uint8_t nibble_bits_count(uint8_t bits) {
395 384
396// interrupt handle to be used by the target device 385// interrupt handle to be used by the target device
397ISR(SERIAL_PIN_INTERRUPT) { 386ISR(SERIAL_PIN_INTERRUPT) {
398# ifndef SERIAL_USE_MULTI_TRANSACTION
399 serial_low();
400 serial_output();
401 SSTD_t *trans = Transaction_table;
402# else
403 // recive transaction table index 387 // recive transaction table index
404 uint8_t tid, bits; 388 uint8_t tid, bits;
405 uint8_t pecount = 0; 389 uint8_t pecount = 0;
406 sync_recv(); 390 sync_recv();
407 bits = serial_read_chunk(&pecount, 7); 391 bits = serial_read_chunk(&pecount, 8);
408 tid = bits >> 3; 392 tid = bits >> 3;
409 bits = (bits & 7) != nibble_bits_count(tid); 393 bits = (bits & 7) != (nibble_bits_count(tid) & 7);
410 if (bits || pecount > 0 || tid > Transaction_table_size) { 394 if (bits || pecount > 0 || tid > NUM_TOTAL_TRANSACTIONS) {
411 return; 395 return;
412 } 396 }
413 serial_delay_half1(); 397 serial_delay_half1();
@@ -415,18 +399,22 @@ ISR(SERIAL_PIN_INTERRUPT) {
415 serial_high(); // response step1 low->high 399 serial_high(); // response step1 low->high
416 serial_output(); 400 serial_output();
417 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH); 401 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH);
418 SSTD_t *trans = &Transaction_table[tid]; 402 split_transaction_desc_t *trans = &split_transaction_table[tid];
419 serial_low(); // response step2 ack high->low 403 serial_low(); // response step2 ack high->low
420# endif 404
405 // If the transaction has a callback, we can execute it now
406 if (trans->slave_callback) {
407 trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
408 }
421 409
422 // target send phase 410 // target send phase
423 if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)trans->target2initiator_buffer, trans->target2initiator_buffer_size); 411 if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size);
424 // target switch to input 412 // target switch to input
425 change_sender2reciver(); 413 change_sender2reciver();
426 414
427 // target recive phase 415 // target recive phase
428 if (trans->initiator2target_buffer_size > 0) { 416 if (trans->initiator2target_buffer_size > 0) {
429 if (serial_recive_packet((uint8_t *)trans->initiator2target_buffer, trans->initiator2target_buffer_size)) { 417 if (serial_recive_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) {
430 *trans->status = TRANSACTION_ACCEPTED; 418 *trans->status = TRANSACTION_ACCEPTED;
431 } else { 419 } else {
432 *trans->status = TRANSACTION_DATA_ERROR; 420 *trans->status = TRANSACTION_DATA_ERROR;
@@ -448,14 +436,12 @@ ISR(SERIAL_PIN_INTERRUPT) {
448// TRANSACTION_NO_RESPONSE 436// TRANSACTION_NO_RESPONSE
449// TRANSACTION_DATA_ERROR 437// TRANSACTION_DATA_ERROR
450// this code is very time dependent, so we need to disable interrupts 438// this code is very time dependent, so we need to disable interrupts
451# ifndef SERIAL_USE_MULTI_TRANSACTION
452int soft_serial_transaction(void) {
453 SSTD_t *trans = Transaction_table;
454# else
455int soft_serial_transaction(int sstd_index) { 439int soft_serial_transaction(int sstd_index) {
456 if (sstd_index > Transaction_table_size) return TRANSACTION_TYPE_ERROR; 440 if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
457 SSTD_t *trans = &Transaction_table[sstd_index]; 441 split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
458# endif 442
443 if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
444
459 cli(); 445 cli();
460 446
461 // signal to the target that we want to start a transaction 447 // signal to the target that we want to start a transaction
@@ -463,27 +449,11 @@ int soft_serial_transaction(int sstd_index) {
463 serial_low(); 449 serial_low();
464 _delay_us(SLAVE_INT_WIDTH_US); 450 _delay_us(SLAVE_INT_WIDTH_US);
465 451
466# ifndef SERIAL_USE_MULTI_TRANSACTION
467 // wait for the target response
468 serial_input_with_pullup();
469 _delay_us(SLAVE_INT_RESPONSE_TIME);
470
471 // check if the target is present
472 if (serial_read_pin()) {
473 // target failed to pull the line low, assume not present
474 serial_output();
475 serial_high();
476 *trans->status = TRANSACTION_NO_RESPONSE;
477 sei();
478 return TRANSACTION_NO_RESPONSE;
479 }
480
481# else
482 // send transaction table index 452 // send transaction table index
483 int tid = (sstd_index << 3) | (7 & nibble_bits_count(sstd_index)); 453 int tid = (sstd_index << 3) | (7 & nibble_bits_count(sstd_index));
484 sync_send(); 454 sync_send();
485 _delay_sub_us(TID_SEND_ADJUST); 455 _delay_sub_us(TID_SEND_ADJUST);
486 serial_write_chunk(tid, 7); 456 serial_write_chunk(tid, 8);
487 serial_delay_half1(); 457 serial_delay_half1();
488 458
489 // wait for the target response (step1 low->high) 459 // wait for the target response (step1 low->high)
@@ -504,12 +474,11 @@ int soft_serial_transaction(int sstd_index) {
504 } 474 }
505 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT); 475 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT);
506 } 476 }
507# endif
508 477
509 // initiator recive phase 478 // initiator recive phase
510 // if the target is present syncronize with it 479 // if the target is present syncronize with it
511 if (trans->target2initiator_buffer_size > 0) { 480 if (trans->target2initiator_buffer_size > 0) {
512 if (!serial_recive_packet((uint8_t *)trans->target2initiator_buffer, trans->target2initiator_buffer_size)) { 481 if (!serial_recive_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) {
513 serial_output(); 482 serial_output();
514 serial_high(); 483 serial_high();
515 *trans->status = TRANSACTION_DATA_ERROR; 484 *trans->status = TRANSACTION_DATA_ERROR;
@@ -523,7 +492,7 @@ int soft_serial_transaction(int sstd_index) {
523 492
524 // initiator send phase 493 // initiator send phase
525 if (trans->initiator2target_buffer_size > 0) { 494 if (trans->initiator2target_buffer_size > 0) {
526 serial_send_packet((uint8_t *)trans->initiator2target_buffer, trans->initiator2target_buffer_size); 495 serial_send_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
527 } 496 }
528 497
529 // always, release the line when not in use 498 // always, release the line when not in use
@@ -534,9 +503,8 @@ int soft_serial_transaction(int sstd_index) {
534 return TRANSACTION_END; 503 return TRANSACTION_END;
535} 504}
536 505
537# ifdef SERIAL_USE_MULTI_TRANSACTION
538int soft_serial_get_and_clean_status(int sstd_index) { 506int soft_serial_get_and_clean_status(int sstd_index) {
539 SSTD_t *trans = &Transaction_table[sstd_index]; 507 split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
540 cli(); 508 cli();
541 int retval = *trans->status; 509 int retval = *trans->status;
542 *trans->status = 0; 510 *trans->status = 0;
@@ -544,8 +512,6 @@ int soft_serial_get_and_clean_status(int sstd_index) {
544 sei(); 512 sei();
545 return retval; 513 return retval;
546} 514}
547# endif
548
549#endif 515#endif
550 516
551// Helix serial.c history 517// Helix serial.c history
diff --git a/drivers/avr/serial.h b/drivers/avr/serial.h
deleted file mode 100644
index 53e66cf90..000000000
--- a/drivers/avr/serial.h
+++ /dev/null
@@ -1,62 +0,0 @@
1#pragma once
2
3#include <stdbool.h>
4
5// /////////////////////////////////////////////////////////////////
6// Need Soft Serial defines in config.h
7// /////////////////////////////////////////////////////////////////
8// ex.
9// #define SOFT_SERIAL_PIN ?? // ?? = D0,D1,D2,D3,E6
10// OPTIONAL: #define SELECT_SOFT_SERIAL_SPEED ? // ? = 1,2,3,4,5
11// // 1: about 137kbps (default)
12// // 2: about 75kbps
13// // 3: about 39kbps
14// // 4: about 26kbps
15// // 5: about 20kbps
16//
17// //// USE simple API (using signle-type transaction function)
18// /* nothing */
19// //// USE flexible API (using multi-type transaction function)
20// #define SERIAL_USE_MULTI_TRANSACTION
21//
22// /////////////////////////////////////////////////////////////////
23
24// Soft Serial Transaction Descriptor
25typedef struct _SSTD_t {
26 uint8_t *status;
27 uint8_t initiator2target_buffer_size;
28 uint8_t *initiator2target_buffer;
29 uint8_t target2initiator_buffer_size;
30 uint8_t *target2initiator_buffer;
31} SSTD_t;
32#define TID_LIMIT(table) (sizeof(table) / sizeof(SSTD_t))
33
34// initiator is transaction start side
35void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size);
36// target is interrupt accept side
37void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size);
38
39// initiator resullt
40#define TRANSACTION_END 0
41#define TRANSACTION_NO_RESPONSE 0x1
42#define TRANSACTION_DATA_ERROR 0x2
43#define TRANSACTION_TYPE_ERROR 0x4
44#ifndef SERIAL_USE_MULTI_TRANSACTION
45int soft_serial_transaction(void);
46#else
47int soft_serial_transaction(int sstd_index);
48#endif
49
50// target status
51// *SSTD_t.status has
52// initiator:
53// TRANSACTION_END
54// or TRANSACTION_NO_RESPONSE
55// or TRANSACTION_DATA_ERROR
56// target:
57// TRANSACTION_DATA_ERROR
58// or TRANSACTION_ACCEPTED
59#define TRANSACTION_ACCEPTED 0x8
60#ifdef SERIAL_USE_MULTI_TRANSACTION
61int soft_serial_get_and_clean_status(int sstd_index);
62#endif