first version of m06e01
This commit is contained in:
@@ -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
1
module06/ex01/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
48
module06/ex01/header.h
Normal file
48
module06/ex01/header.h
Normal 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
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;
|
||||
}
|
||||
68
module06/ex01/main.c
Normal file
68
module06/ex01/main.c
Normal 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
41
module06/ex01/math.c
Normal 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
88
module06/ex01/uart.c
Normal 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
|
||||
// }
|
||||
Reference in New Issue
Block a user