i2c.c (4520B)
1 /* 2 MNT Reform 2.0 Keyboard Firmware 3 See keyboard.c for Copyright 4 SPDX-License-Identifier: MIT 5 */ 6 7 #include <util/twi.h> 8 #include <avr/io.h> 9 #include <stdlib.h> 10 #include <avr/interrupt.h> 11 #include <util/twi.h> 12 #include <stdbool.h> 13 #include "i2c.h" 14 15 // Limits the amount of we wait for any one i2c transaction. 16 // Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is 17 // 9 bits, a single transaction will take around 90μs to complete. 18 // 19 // (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit 20 // poll loop takes at least 8 clock cycles to execute 21 #define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8 22 23 #define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE) 24 25 volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; 26 27 static volatile uint8_t slave_buffer_pos; 28 static volatile bool slave_has_register_set = false; 29 30 // Wait for an i2c operation to finish 31 inline static 32 void i2c_delay(void) { 33 uint16_t lim = 0; 34 while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT) 35 lim++; 36 37 // easier way, but will wait slightly longer 38 // _delay_us(100); 39 } 40 41 // Setup twi to run at 100kHz or 400kHz (see ./i2c.h SCL_CLOCK) 42 void i2c_master_init(void) { 43 // no prescaler 44 TWSR = 0; 45 // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10. 46 // Check datasheets for more info. 47 TWBR = ((F_CPU/SCL_CLOCK)-16)/2; 48 } 49 50 // Start a transaction with the given i2c slave address. The direction of the 51 // transfer is set with I2C_READ and I2C_WRITE. 52 // returns: 0 => success 53 // 1 => error 54 uint8_t i2c_master_start(uint8_t address) { 55 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA); 56 57 i2c_delay(); 58 59 // check that we started successfully 60 if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START)) 61 return 1; 62 63 TWDR = address; 64 TWCR = (1<<TWINT) | (1<<TWEN); 65 66 i2c_delay(); 67 68 if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) ) 69 return 1; // slave did not acknowledge 70 else 71 return 0; // success 72 } 73 74 75 // Finish the i2c transaction. 76 void i2c_master_stop(void) { 77 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); 78 79 uint16_t lim = 0; 80 while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT) 81 lim++; 82 } 83 84 // Write one byte to the i2c slave. 85 // returns 0 => slave ACK 86 // 1 => slave NACK 87 uint8_t i2c_master_write(uint8_t data) { 88 TWDR = data; 89 TWCR = (1<<TWINT) | (1<<TWEN); 90 91 i2c_delay(); 92 93 // check if the slave acknowledged us 94 return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1; 95 } 96 97 // Read one byte from the i2c slave. If ack=1 the slave is acknowledged, 98 // if ack=0 the acknowledge bit is not set. 99 // returns: byte read from i2c device 100 uint8_t i2c_master_read(int ack) { 101 TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA); 102 103 i2c_delay(); 104 return TWDR; 105 } 106 107 void i2c_reset_state(void) { 108 TWCR = 0; 109 } 110 111 void i2c_slave_init(uint8_t address) { 112 TWAR = address << 0; // slave i2c address 113 // TWEN - twi enable 114 // TWEA - enable address acknowledgement 115 // TWINT - twi interrupt flag 116 // TWIE - enable the twi interrupt 117 TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN); 118 } 119 120 ISR(TWI_vect); 121 122 ISR(TWI_vect) { 123 uint8_t ack = 1; 124 switch(TW_STATUS) { 125 case TW_SR_SLA_ACK: 126 // this device has been addressed as a slave receiver 127 slave_has_register_set = false; 128 break; 129 130 case TW_SR_DATA_ACK: 131 // this device has received data as a slave receiver 132 // The first byte that we receive in this transaction sets the location 133 // of the read/write location of the slaves memory that it exposes over 134 // i2c. After that, bytes will be written at slave_buffer_pos, incrementing 135 // slave_buffer_pos after each write. 136 if(!slave_has_register_set) { 137 slave_buffer_pos = TWDR; 138 // don't acknowledge the master if this memory loctaion is out of bounds 139 if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) { 140 ack = 0; 141 slave_buffer_pos = 0; 142 } 143 slave_has_register_set = true; 144 } else { 145 i2c_slave_buffer[slave_buffer_pos] = TWDR; 146 BUFFER_POS_INC(); 147 } 148 break; 149 150 case TW_ST_SLA_ACK: 151 case TW_ST_DATA_ACK: 152 // master has addressed this device as a slave transmitter and is 153 // requesting data. 154 TWDR = i2c_slave_buffer[slave_buffer_pos]; 155 BUFFER_POS_INC(); 156 break; 157 158 case TW_BUS_ERROR: // something went wrong, reset twi state 159 TWCR = 0; 160 default: 161 break; 162 } 163 // Reset everything, so we are ready for the next TWI interrupt 164 TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN); 165 }