AVR-Playground/i2c.c

100 lines
2.6 KiB
C
Raw Normal View History

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>
#include "uart.h" // DEBUG macro
2024-03-23 21:18:52 +01:00
2024-03-24 04:07:20 +01:00
void I2C_init(uint32_t SCL_CLOCK) {
DEBUG("I2C: Initializing...");
2024-03-23 21:18:52 +01:00
// Set the prescaler to 1
TWSR &= ~(1 << TWPS0);
TWSR &= ~(1 << TWPS1);
2024-03-24 04:07:20 +01:00
2024-03-23 21:18:52 +01:00
// Set the bit rate to 100kHz
2024-03-24 04:07:20 +01:00
TWBR = ((F_CPU / SCL_CLOCK) - 16) / 2;
// Enable the TWI module
TWCR |= (1 << TWEN);
DEBUG("I2C: Initialized!");
2024-03-23 21:18:52 +01:00
}
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 04:07:20 +01:00
DEBUG("Start: 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 04:07:20 +01:00
DEBUG("Start: Start condition sent");
2024-03-24 00:00:32 +01:00
// Load the address of the slave device
TWDR = addr;
2024-03-24 04:07:20 +01:00
DEBUG("Start: 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 04:07:20 +01:00
DEBUG("Start: 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 04:07:20 +01:00
DEBUG("Start: Address sent");
2024-03-24 00:00:32 +01:00
// Get the status of the transmission
uint8_t status = TWSR & 0xF8;
2024-03-24 04:07:20 +01:00
DEBUG("Start: 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
2024-03-24 04:07:20 +01:00
DEBUG("Stop: Sending stop condition");
2024-03-23 21:18:52 +01:00
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
2024-03-24 04:07:20 +01:00
2024-03-23 21:18:52 +01:00
// Wait for the stop condition to be sent
2024-03-24 04:07:20 +01:00
DEBUG("Stop: Waiting for stop condition to be sent");
2024-03-24 00:00:32 +01:00
while (TWCR & (1 << TWSTO))
;
2024-03-24 04:07:20 +01:00
DEBUG("Stop: Stop condition sent");
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;
2024-03-24 04:07:20 +01:00
2024-03-23 21:18:52 +01:00
// Start transmission of data
2024-03-24 04:07:20 +01:00
DEBUG("Write: Sending data");
2024-03-23 21:18:52 +01:00
TWCR = (1 << TWINT) | (1 << TWEN);
2024-03-24 04:07:20 +01:00
2024-03-23 21:18:52 +01:00
// Wait for the data to be sent
2024-03-24 04:07:20 +01:00
DEBUG("Write: Waiting for data to be sent");
2024-03-24 00:00:32 +01:00
while (!(TWCR & (1 << TWINT)))
;
// Return true if the data was sent
2024-03-24 04:07:20 +01:00
DEBUG("Write: Data transmission complete");
2024-03-24 00:00:32 +01:00
return (TWSR & 0xF8) == TW_MT_DATA_ACK;
2024-03-23 21:18:52 +01:00
}
uint8_t I2C_read(uint8_t ack) {
2024-03-24 04:07:20 +01:00
DEBUG("Read: Waiting for data to be received");
2024-03-23 21:18:52 +01:00
// Enable TWI, generate ACK (if ack = 1) and clear TWI interrupt flag
TWCR = (1 << TWINT) | (1 << TWEN) | (ack << TWEA);
2024-03-24 04:07:20 +01:00
2024-03-23 21:18:52 +01:00
// Wait until TWI finish its current job (read operation)
2024-03-24 04:07:20 +01:00
DEBUG("Read: Waiting for TWI to finish current job");
2024-03-24 00:00:32 +01:00
while (!(TWCR & (1 << TWINT)))
;
2024-03-24 04:07:20 +01:00
DEBUG("Read: Data received");
2024-03-23 21:18:52 +01:00
// Return received data
return TWDR;
}