#ifndef I2C_H_ #define I2C_H_ #if defined(__FREERTOS__) #include "asf.h" #endif #define TWI_OFFSET_FROM_FLEXCOM (0x600UL) #define I2C_INTERRUPT_PRIO (6) #define DEFAULT_I2C_WAIT_TIME 50 // Clock to the RTT is about 10kHz. This is roughly 5ms typedef void(*I2C_Callback)(void); typedef enum { I2C_SIMPLE_WRITE, I2C_SIMPLE_READ, I2C_INT_ADDR_WRITE, I2C_INT_ADDR_READ } I2C_Transaction_Type; typedef enum { I2C_NOT_INIT, I2C_IDLE, I2C_SUCCESS, I2C_NO_REPLY, I2C_ARB_LOST, I2C_OVERRUN, I2C_UNDERRUN, I2C_TIMED_OUT } I2C_Status_Type; typedef enum { I2C_Shifted, // I2C_Shifted: address is lower 7 bits (valid 0x00 to 0x7F) I2C_Unshifted // I2C_Unshifted: address includes R/W bit (valid 0x00 to 0xFE, no odd numbered addressed) } I2C_Address_Shift_Type; // Notes on "Unshifted" vs "Shifted" // I2C addresses are 7 bits, but when addressing a part the bus controller clocks out 8 bits. The final 8th bit // selects between read (1) or write (0). // We can pretend that the address has 7 bits, but they occupy the most significant bits of a byte, like: // // (Unshifted type) Addr.7_Addr.6_Addr.5_Addr.4_Addr.3_Addr.2_Addr.1_Read/Write // This can count from b0000_000n (where n is ignored for the address) to b1111_111n, or 0 to 254 (0xFE) (only even numbers) // // Or they can be considered the lower 7 bits of a byte: // // (Shifted type) Addr.6_Addr.5_Addr.4_Addr.3_Addr.2_Addr.1_Addr.0_Read/Write // This can count from b000_0000 to b111_1111, or 0 to 127 (0x7F) typedef struct { uint8_t dev_addr; // address of I2C device on bus I2C_Address_Shift_Type shift; // 7-bit or 8-bit address definition, see above I2C_Transaction_Type ttype; uint8_t internal_addr; // Only used in I2C_INT_ADDR_WRITE/READ transaction types. Sets the register address in the target device uint8_t len; uint8_t* data; // for write commands, preload with data. for read commands, it will be loaded by the i2c transaction I2C_Callback cb; // set to non-null for getting a callback after transaction is complete or fails } I2C_Transaction_Request; typedef struct { Flexcom* flexcom; uint8_t SCL_Pin; uint8_t SDA_Pin; volatile I2C_Status_Type status; volatile uint8_t sent_bytes; volatile uint8_t busy; I2C_Transaction_Request* current_txn; #if defined(__FREERTOS__) SemaphoreHandle_t i2c_mutex; // used to share i2c bus between multiple tasks SemaphoreHandle_t i2c_busywait; // used within i2c transaction to wait for the end of transaction #endif } I2C_Handle; void init_i2c(I2C_Handle* hi2c, uint32_t desired_clock_speed); void disable_i2c(I2C_Handle* hi2c); //uint8_t i2c_transact(I2C_Handle* hi2c, I2C_Transaction_Request* hi2c_txn); uint8_t i2c_transact_blocking(I2C_Handle* hi2c, I2C_Transaction_Request* hi2c_txn, uint32_t timeout); uint8_t i2c_wait_to_complete(I2C_Handle* hi2c, uint32_t timeout); uint8_t i2c_busy(I2C_Handle* hi2c); I2C_Status_Type i2c_status(I2C_Handle* hi2c); void i2c_irq_handler(I2C_Handle* hi2c); // Call this from your FLEXCOM#_Handler void i2c_lockup_clear_sequence(I2C_Handle* hi2c); #if defined(__FREERTOS__) uint8_t i2c_lock(I2C_Handle* hi2c); uint8_t i2c_unlock(I2C_Handle* hi2c); #endif #endif /* I2C_H_ */