2024-03-24 00:00:32 +01:00
|
|
|
#include "i2c.h"
|
|
|
|
|
2024-03-23 21:18:52 +01:00
|
|
|
#include <avr/io.h>
|
|
|
|
#include <util/delay.h>
|
2024-03-24 00:00:32 +01:00
|
|
|
#include <util/twi.h>
|
|
|
|
#include <stdint.h>
|
2024-03-24 02:35:21 +01:00
|
|
|
#include "uart.h" // DEBUG macro
|
2024-03-23 21:18:52 +01:00
|
|
|
|
2024-03-24 00:00:32 +01:00
|
|
|
void I2C_init() {
|
2024-03-23 21:18:52 +01:00
|
|
|
// Set the prescaler to 1
|
|
|
|
TWSR &= ~(1 << TWPS0);
|
|
|
|
TWSR &= ~(1 << TWPS1);
|
|
|
|
// Set the bit rate to 100kHz
|
|
|
|
TWBR = ((F_CPU / 100000) - 16) / 2;
|
|
|
|
}
|
|
|
|
|
2024-03-24 00:00:32 +01:00
|
|
|
uint8_t I2C_start(uint8_t addr) {
|
2024-03-23 21:18:52 +01:00
|
|
|
// Send the start condition
|
|
|
|
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
|
2024-03-24 00:00:32 +01:00
|
|
|
|
2024-03-24 02:35:21 +01:00
|
|
|
DEBUG("Waiting for start condition to be sent");
|
2024-03-23 21:18:52 +01:00
|
|
|
// Wait for the start condition to be sent
|
|
|
|
while (!(TWCR & (1 << TWINT)))
|
|
|
|
;
|
2024-03-24 00:00:32 +01:00
|
|
|
|
2024-03-24 02:35:21 +01:00
|
|
|
DEBUG("Start condition sent");
|
2024-03-24 00:00:32 +01:00
|
|
|
// Load the address of the slave device
|
|
|
|
TWDR = addr;
|
|
|
|
|
2024-03-24 02:35:21 +01:00
|
|
|
DEBUG("Sending address");
|
2024-03-24 00:00:32 +01:00
|
|
|
// Clear the TWINT bit to start the transmission
|
|
|
|
TWCR = (1 << TWINT) | (1 << TWEN);
|
|
|
|
|
2024-03-24 02:35:21 +01:00
|
|
|
DEBUG("Waiting for address to be sent");
|
2024-03-24 00:00:32 +01:00
|
|
|
// Wait for the address to be sent
|
|
|
|
while (!(TWCR & (1 << TWINT)))
|
|
|
|
;
|
|
|
|
|
2024-03-24 02:35:21 +01:00
|
|
|
DEBUG("Address sent");
|
2024-03-24 00:00:32 +01:00
|
|
|
// Get the status of the transmission
|
|
|
|
uint8_t status = TWSR & 0xF8;
|
|
|
|
|
2024-03-24 02:35:21 +01:00
|
|
|
DEBUG("Checking status");
|
2024-03-24 00:00:32 +01:00
|
|
|
// Return true if the slave acknowledged the address
|
|
|
|
return (status == TW_MT_SLA_ACK || status == TW_MR_SLA_ACK);
|
2024-03-23 21:18:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void I2C_stop() {
|
|
|
|
// Send the stop condition
|
|
|
|
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
|
|
|
|
// Wait for the stop condition to be sent
|
2024-03-24 00:00:32 +01:00
|
|
|
while (TWCR & (1 << TWSTO))
|
|
|
|
;
|
2024-03-23 21:18:52 +01:00
|
|
|
}
|
|
|
|
|
2024-03-24 00:00:32 +01:00
|
|
|
uint8_t I2C_write(uint8_t data) {
|
2024-03-23 21:18:52 +01:00
|
|
|
// Load the data into the data register
|
|
|
|
TWDR = data;
|
|
|
|
// Start transmission of data
|
|
|
|
TWCR = (1 << TWINT) | (1 << TWEN);
|
|
|
|
// Wait for the data to be sent
|
2024-03-24 00:00:32 +01:00
|
|
|
while (!(TWCR & (1 << TWINT)))
|
|
|
|
;
|
|
|
|
|
|
|
|
// Return true if the data was sent
|
|
|
|
return (TWSR & 0xF8) == TW_MT_DATA_ACK;
|
2024-03-23 21:18:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t I2C_read(uint8_t ack) {
|
|
|
|
// Enable TWI, generate ACK (if ack = 1) and clear TWI interrupt flag
|
|
|
|
TWCR = (1 << TWINT) | (1 << TWEN) | (ack << TWEA);
|
|
|
|
// Wait until TWI finish its current job (read operation)
|
2024-03-24 00:00:32 +01:00
|
|
|
while (!(TWCR & (1 << TWINT)))
|
|
|
|
;
|
2024-03-23 21:18:52 +01:00
|
|
|
// Return received data
|
|
|
|
return TWDR;
|
|
|
|
}
|