first version of m06e01
This commit is contained in:
101
module06/ex01/i2c.c
Normal file
101
module06/ex01/i2c.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "header.h"
|
||||
|
||||
#define TWI_PRESCALE_VALUE 1 // can be 1, 4, 16, 64
|
||||
#define TWI_FREQ 100000UL // 100kHz I2C
|
||||
|
||||
typedef enum {
|
||||
START,
|
||||
STOP
|
||||
} I2C_status;
|
||||
volatile I2C_status i2c_status = START;
|
||||
|
||||
void i2c_init(void) {
|
||||
TWSR = TWI_PRESCALE_SET(TWI_PRESCALE_VALUE); // 22.9.3 : (Status Register) set prescaler
|
||||
TWBR = ((F_CPU / TWI_FREQ) - 16) / (2 * TWI_PRESCALE_VALUE); // 22.9.1 : (Bit Rate Register) set SCL frequency (formula from datasheet, 22.5.2)
|
||||
}
|
||||
|
||||
void i2c_start(void) {
|
||||
i2c_status = START;
|
||||
TWCR = SEND_START_CONDITION; // 22.9.2 : (Control Register) send Start condition (22.7.1) ! writting 1 to TWINT clears it (set it to 0)
|
||||
while (!(TEST(TWCR, TWINT))); // p225 example code : Wait for TWINT Flag set. This indicates that the START condition has been transmitted
|
||||
|
||||
uint8_t status = TWSR & 0b11111000; // Table 22-2. Status codes for Master Transmitter Mode
|
||||
if (status != TW_START && status != TW_REP_START) {
|
||||
return i2c_stop();
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_send_addr_w(uint8_t slave_address) {
|
||||
if (i2c_status == STOP) {
|
||||
return;
|
||||
}
|
||||
uint8_t addr = (slave_address << 1) | TW_WRITE; // 22.3.3 : address format SLA+R/W
|
||||
TWDR = addr; // 22.9.4 : (Data Register) load data into TWDR register
|
||||
TWCR = SEND_CONTINUE_TRANSMISSION; // 22.7.1 : Master Transmitter Mode
|
||||
while (!(TEST(TWCR, TWINT))); // 22.7.1 : Wait for TWINT Flag set. This indicates that the SLA+R/W has been transmitted, and ACK/NACK has been received
|
||||
|
||||
uint8_t status = TWSR & 0b11111000; // Table 22-2 : check status for Transmitter mode, mask prescaler bits
|
||||
if (status == TW_MT_SLA_ACK) { // status 0x18 : slave address transmitted, slave acknoledged (continue transmission)
|
||||
return;
|
||||
} else if (status == TW_MT_SLA_NACK) { // status 0x20 : slave address transmitted, slave did not acknoledge (retry or send STOP)
|
||||
return i2c_stop();
|
||||
} else if (status == TW_MT_ARB_LOST) { // status 0x38 : Arbitration Lost, Another I2C master took control of the bus (wait for bus to be free and retry)
|
||||
return i2c_stop();
|
||||
} else {
|
||||
return i2c_stop();
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_send_addr_r(uint8_t slave_address) {
|
||||
if (i2c_status == STOP) {
|
||||
return;
|
||||
}
|
||||
uint8_t addr = (slave_address << 1) | TW_READ; // 22.3.3 : address format SLA+R/W
|
||||
TWDR = addr; // 22.9.4 : (Data Register) load data into TWDR register
|
||||
TWCR = SEND_CONTINUE_TRANSMISSION; // 22.7.1 : Master Transmitter Mode
|
||||
while (!(TEST(TWCR, TWINT))); // 22.7.1 : Wait for TWINT Flag set. This indicates that the SLA+R/W has been transmitted, and ACK/NACK has been received
|
||||
|
||||
uint8_t status = TWSR & 0b11111000; // Table 22-3 : check status for Receiver mode, mask prescaler bits
|
||||
if (status == TW_MR_SLA_ACK) { // status 0x40 : slave address transmitted, slave acknoledged (continue transmission)
|
||||
return;
|
||||
} else if (status == TW_MR_SLA_NACK) { // status 0x48 : slave address transmitted, slave did not acknoledge (retry or send STOP)
|
||||
return i2c_stop();
|
||||
} else if (status == TW_MR_ARB_LOST) { // status 0x38 : Arbitration Lost, Another I2C master took control of the bus (wait for bus to be free and retry)
|
||||
return i2c_stop();
|
||||
} else {
|
||||
return i2c_stop();
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_write(unsigned char data) {
|
||||
if (i2c_status == STOP) {
|
||||
return;
|
||||
}
|
||||
TWDR = data; // 22.9.4 : (Data Register) load data into TWDR register
|
||||
TWCR = SEND_CONTINUE_TRANSMISSION; // p225 example code : Load DATA into TWDR Register. Clear TWINT bit in TWCR to start transmission of data
|
||||
while (!(TEST(TWCR, TWINT))); // p225 example code : Wait for TWINT Flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received
|
||||
|
||||
uint8_t status = TWSR & 0b11111000; // p225 example code : Check status for Receiver mode. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR
|
||||
if (status != TW_MT_DATA_ACK) {
|
||||
return i2c_stop();
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_read(void) {
|
||||
if (i2c_status == STOP) {
|
||||
return;
|
||||
}
|
||||
// TWDR = data; // 22.9.4 : (Data Register) load data into TWDR register
|
||||
// TWCR = SEND_CONTINUE_TRANSMISSION; // p225 example code : Load DATA into TWDR Register. Clear TWINT bit in TWCR to start transmission of data
|
||||
// while (!(TEST(TWCR, TWINT))); // p225 example code : Wait for TWINT Flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received
|
||||
|
||||
// uint8_t status = TWSR & 0b11111000; // p225 example code : Check status for Receiver mode. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR
|
||||
// if (status != TW_MT_DATA_ACK) {
|
||||
// return i2c_stop();
|
||||
// }
|
||||
}
|
||||
|
||||
void i2c_stop(void) {
|
||||
TWCR = SEND_STOP_CONDITION; // 22.9.2 : send stop condition
|
||||
i2c_status = STOP;
|
||||
}
|
||||
Reference in New Issue
Block a user