| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #include <avr/io.h>
- #include <util/twi.h>
- #include <avr/interrupt.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include "twi.h"
- #ifndef F_SCL
- #define F_SCL 100000UL // SCL frequency
- #endif
- #ifndef PRESCALER
- #define PRESCALER 1
- #endif
- // Limits the amount of we wait for any one i2c transaction.
- // Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
- // 9 bits, a single transaction will take around 90μs to complete.
- //
- // (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit
- // poll loop takes at least 8 clock cycles to execute
- #ifdef TWI_TIMEOUT
- #ifndef TWI_TX_SIZE
- #define TWI_TX_SIZE 9
- #endif
- #endif
- // Wait for an twi operation to finish
- inline static
- void twi_wait(uint8_t status) {
- #ifdef TWI_TIMEOUT
- uint16_t lim = 0;
- while ( !(TWCR & (_BV(status))) && lim < (TWI_TX_SIZE+1)*(F_CPU/F_SCL)/8)
- lim++;
- #else
- while ( !(TWCR & (_BV(status))) );
- #endif
- }
- void twi_master_init(void) {
- TWBR = (uint8_t) ((((F_CPU / F_SCL) / PRESCALER) - 16 ) / 2);
- }
- void twi_slave_init(uint8_t address) {
- TWAR = address << 0; // slave i2c address
- TWCR = _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWEN);
- }
- uint8_t twi_master_start(uint8_t address) {
- // reset TWI control register and transmit start
- TWCR = 0;
- TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA);
- twi_wait(TWINT);
-
- // check if the start condition was successfully transmitted
- if (TW_STATUS != TW_START)
- return 1;
-
- // set slave address and transmit
- TWDR = address;
- TWCR = _BV(TWINT) | _BV(TWEN);
- twi_wait(TWINT);
- // check if the device has acknowledged the READ / WRITE mode
- if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
- return 1;
-
- return 0;
- }
- void twi_master_stop(void) {
- // transmit STOP condition
- TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO);
- twi_wait(TWSTO);
- }
- uint8_t twi_write(uint8_t data) {
- // load data into data register and start transmission of data
- TWDR = data;
- TWCR = _BV(TWINT) | _BV(TWEN);
- twi_wait(TWINT);
-
- if ( TW_STATUS != TW_MT_DATA_ACK )
- return 1;
-
- return 0;
- }
- uint8_t twi_read(bool ack) {
- // start TWI module and acknowledge data after reception
- if (ack)
- TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
- else
- TWCR = _BV(TWINT) | _BV(TWEN);
-
- twi_wait(TWINT);
- return TWDR;
- }
- uint8_t twi_transmit(uint8_t address, uint8_t* data, uint16_t length) {
- if (twi_start(address | TW_WRITE))
- return 1;
-
- for (uint16_t i = 0; i < length; i++) {
- if (twi_write(data[i]))
- return 1;
- }
-
- twi_stop();
-
- return 0;
- }
- uint8_t twi_receive(uint8_t address, uint8_t* data, uint16_t length) {
- if (twi_start(address | TW_READ))
- return 1;
-
- for (uint16_t i = 0; i < (length-1); i++) {
- data[i] = twi_read(true);
- }
- data[(length-1)] = twi_read(false);
-
- twi_stop();
-
- return 0;
- }
- uint8_t twi_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length) {
- if (twi_start(devaddr | TW_WRITE))
- return 1;
- twi_write(regaddr);
- for (uint16_t i = 0; i < length; i++) {
- if (twi_write(data[i]))
- return 1;
- }
- twi_stop();
- return 0;
- }
- uint8_t twi_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
- {
- if (twi_start(devaddr))
- return 1;
- twi_write(regaddr);
- if (twi_start(devaddr | TW_READ))
- return 1;
- for (uint16_t i = 0; i < (length-1); i++) {
- data[i] = twi_read(true);
- }
- data[(length-1)] = twi_read(false);
- twi_stop();
- return 0;
- }
- uint8_t buffer_address = 0;
- ISR(TWI_vect) {
- uint8_t data;
- switch (TW_STATUS) {
- case TW_SR_SLA_ACK:
- buffer_address = 0xff;
- TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
- break;
- case TW_SR_DATA_ACK:
- data = TWDR;
- if (buffer_address == 0xff) {
- // store address to read from later
- buffer_address = data;
- TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
- } else {
- // store data from address and increment
- rxbuffer[buffer_address] = data;
- buffer_address++;
- if (buffer_address < 0xFF) {
- // ack
- TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
- } else {
- // nack
- TWCR &= ~_BV(TWEA);
- TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEN);
- }
- }
- break;
- case TW_ST_SLA_ACK:
- case TW_ST_DATA_ACK:
- data = TWDR;
- if (buffer_address == 0xFF) {
- buffer_address = data;
- }
- TWDR = txbuffer[buffer_address];
- buffer_address++;
- if (buffer_address < 0xFF) {
- // ack
- TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
- } else {
- // nack
- TWCR &= ~_BV(TWEA);
- TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEN);
- }
- break;
- case TW_BUS_ERROR:
- TWCR = 0;
- break;
- default:
- TWCR |= _BV(TWIE) | _BV(TWEA) | _BV(TWEN);
- break;
- }
- }
|