first version of m06e01

This commit is contained in:
hugo LAMY
2025-03-16 13:33:07 +01:00
parent 2b1b609d85
commit 986efac082
7 changed files with 347 additions and 7 deletions

View File

@@ -15,13 +15,6 @@
//
// GLOBAL
//
typedef enum {
WAITING,
MASTER,
SLAVE
} Role;
extern volatile Role role;
extern volatile uint8_t received_data;
//
// PROTOTYPES

1
module06/ex01/Makefile Normal file
View File

@@ -0,0 +1 @@
include ../../Makefile

48
module06/ex01/header.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef HEADER_H
#define HEADER_H
#include <avr/io.h>
#include <util/twi.h>
#include <util/delay.h>
#include "utils.h"
#include "bitmanip.h"
#include "interrupt.h"
#include "timer.h"
#include "usart.h"
#include "adc.h"
#include "i2c.h"
//
// GLOBAL
//
//
// PROTOTYPES
//
// main.c
void print_hex_value(char c);
// i2c.c
void i2c_init(void);
void i2c_start(void);
void i2c_send_addr_w(uint8_t slave_address);
void i2c_send_addr_r(uint8_t slave_address);
void i2c_write(unsigned char data);
void i2c_read(void);
void i2c_stop(void);
// uart.c
void uart_init();
void uart_tx(char c);
void uart_printstr(const char* str);
void uart_printstr_endl(const char* str);
void uart_printstr_itoa_base(uint64_t value, uint8_t base);
void uart_printstr_itoa_base_endl(uint64_t value, uint8_t base);
// math.c
void int_to_hex_string(uint64_t value, char *out, uint8_t num_digits);
void int_to_string_base(uint64_t value, char *buffer, uint8_t base);
//
// MACROS
//
#endif // HEADER_H

101
module06/ex01/i2c.c Normal file
View 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;
}

68
module06/ex01/main.c Normal file
View File

@@ -0,0 +1,68 @@
#include "header.h"
// sqtatus codes :
// -- Master --
// TW_BUS_ERROR 0x00 = 0b0 = 0 -> illegal start or stop condition
// TW_START 0x08 = 0b1000 = 8 -> start condition transmitted
// TW_REP_START 0x10 = 0b10000 = 16 -> repeated start condition transmitted
// -- Master Transmitter --
// TW_MT_SLA_ACK 0x18 = 0b11000 = 24 -> SLA+W transmitted, ACK received
// TW_MT_SLA_NACK 0x20 = 0b100000 = 32 -> SLA+W transmitted, NACK received
// TW_MT_DATA_ACK 0x28 = 0b101000 = 40 -> data transmitted, ACK received
// TW_MT_DATA_NACK 0x30 = 0b110000 = 48 -> data transmitted, NACK received
// TW_MT_ARB_LOST 0x38 = 0b111000 = 56 -> arbitration lost in SLA+W or data
// -- Master Receiver --
// TW_MR_ARB_LOST 0x38 = 0b111000 = 56 -> arbitration lost in SLA+R or NACK
// TW_MR_SLA_ACK 0x40 = 0b1000000 = 64 -> SLA+R transmitted, ACK received
// TW_MR_SLA_NACK 0x48 = 0b1001000 = 72 -> SLA+R transmitted, NACK received
// TW_MR_DATA_ACK 0x50 = 0b1010000 = 80 -> data received, ACK returned
// TW_MR_DATA_NACK 0x58 = 0b1011000 = 88 -> data received, NACK returned
// TW_ST_SLA_ACK 0xA8 = 0b10101000 = 168 -> SLA+R received, ACK returned
// TW_NO_INFO 0xF8 = 0b11111000 = 248 -> no state information available
#define SLAVE_ADDRESS 0x38 // doc AHT20, 7.3 : address of thermistor
void print_hex_value(char c) {}
void print_status(char *str) {
uint8_t status;
status = TWSR & 0b11111000; // Table 22-2. Status codes for Master Transmitter Mode
uart_printstr(str);
uart_printstr(" : ");
uart_printstr_itoa_base_endl(status, 2);
}
// description
int main() {
uart_init();
print_status("before init");
i2c_init();
print_status("after init");
i2c_start();
print_status("after start");
i2c_send_addr_w(SLAVE_ADDRESS);
print_status("after SLA+W");
i2c_write('t');
print_status("after write t");
i2c_write('e');
print_status("after write e");
i2c_write('e');
print_status("after write e");
i2c_write('a');
print_status("after write a");
i2c_write('t');
print_status("after write t");
i2c_stop();
print_status("after stop");
while(1);
}

41
module06/ex01/math.c Normal file
View File

@@ -0,0 +1,41 @@
#include "header.h"
void int_to_hex_string(uint64_t value, char *out, uint8_t num_digits) { // num_digits : number of digit of the output, ex 2 for 3FF (1023) -> FF
for (uint8_t i = 0; i < num_digits; ++i) {
uint8_t shift = (num_digits - 1 - i) * 4;
out[i] = INT_TO_HEX_CHAR((value >> shift) & 0x0F);
}
out[num_digits] = '\0';
}
void int_to_string_base(uint64_t value, char *buffer, uint8_t base) { // buffer must have the right size
if (base < 2 || base > 36) {
buffer[0] = '\0'; // unsupported base
return;
}
// handle zero case
if (value == 0) {
buffer[0] = '0';
buffer[1] = '\0';
return;
}
uint8_t size = 0;
uint64_t copy = value;
while (copy) {
copy /= base;
size++;
}
buffer[size] = '\0'; // null-terminate the string
size--; // adjust index for last digit
while (value) {
uint8_t digit = value % base;
buffer[size] = digit < 10 ? ('0' + digit) : ('A' + digit - 10);
value /= base;
size--;
}
}

88
module06/ex01/uart.c Normal file
View File

@@ -0,0 +1,88 @@
#include "header.h"
// MACROS
// USART
#define USART_BAUDRATE 115200
#define INPUT_SIZE 7
// GLOBAL VARIABLES
//
// FUNCTIONS
//
void uart_init() {
UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH USART Baud Rate Registers
UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE);
UCSR0C = DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B = TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver, Transmitter, and interrupts
}
// char uart_rx(void) {
// while (!TEST(UCSR0A, RXC0)); // 20.11.2 : do nothing until there are unread data in the receive buffer (UDRn), (RXCn flag in UCSRnA register set to 1 when buffer has data)
// return UDR0; // 20.11.1 : get data in buffer, UDRn USART I/O Data Register (read and write)
// }
void uart_tx(char c) {
while (!TEST(UCSR0A, UDRE0)); // 20.11.2 : do nothing until UDRn buffer is empty, (UDREn flag in UCSRnA register set to 1 when buffer empty)
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn USART I/O Data Register (read and write)
}
void uart_printstr(const char* str) {
while (*str) {
uart_tx(*str);
str++;
}
}
void uart_printstr_endl(const char* str) {
uart_printstr(str);
uart_printstr("\r\n");
}
void uart_printstr_itoa_base(uint64_t value, uint8_t base) {
char buffer[100] = {0};
int_to_string_base((uint16_t)value, buffer, base);
uart_printstr(buffer);
}
void uart_printstr_itoa_base_endl(uint64_t value, uint8_t base) {
uart_printstr_itoa_base(value, base);
uart_printstr("\r\n");
}
// ISR(USART_RX_vect) { // Table 12-6 : we select the code for USART Receive
// char received_char = UDR0; // read received character
// if (received_char == '\b' || received_char == 127) { // if backspace is received
// if (input_index <= 0) {
// return;
// }
// if (input_index >= INPUT_SIZE) {
// return;
// }
// remove_last_character();
// input_index--;
// uart_tx('\b'); // Move cursor back
// uart_tx(' '); // Erase the character on screen
// uart_tx('\b'); // Move cursor back again
// } else if (received_char == '\n' || received_char == '\r') { // if enter is received
// if (input_index != INPUT_SIZE) {
// return;
// }
// set_color((char *)color_input);
// reset_input();
// } else { // any other character
// if (input_index >= INPUT_SIZE) {
// return;
// }
// if (!is_valid_color_input(received_char)) {
// return;
// }
// fill_str(received_char);
// uart_tx(received_char);
// input_index++;
// }
// }
// ISR(USART_TX_vect) { // Table 12-6 : we select the code for USART Transmit
// char received_char = UDR0; // read received character
// }