From ec928d14b138ab695b5c16e8a952b473647df9b9 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Sat, 15 Mar 2025 18:15:30 +0100 Subject: [PATCH] updated math functions --- headers/i2c.h | 18 +++++++ module05/ex02/adc.c | 2 +- module05/ex02/header.h | 2 +- module05/ex02/math.c | 6 +-- module06/ex00/adc.c | 27 ----------- module06/ex00/header.h | 18 +++++-- module06/ex00/i2c.c | 26 +++++++++++ module06/ex00/main.c | 10 +--- module06/ex00/math.c | 25 +++++++++- module06/ex00/timer.c | 22 --------- module06/ex00/twi.c | 104 +++++++++++++++++++++++++++++++++++++++++ module06/ex00/uart.c | 6 +++ 12 files changed, 200 insertions(+), 66 deletions(-) create mode 100644 headers/i2c.h delete mode 100644 module06/ex00/adc.c create mode 100644 module06/ex00/i2c.c delete mode 100644 module06/ex00/timer.c create mode 100644 module06/ex00/twi.c diff --git a/headers/i2c.h b/headers/i2c.h new file mode 100644 index 0000000..374c737 --- /dev/null +++ b/headers/i2c.h @@ -0,0 +1,18 @@ +#ifndef I2C_H +#define I2C_H + +// table 22-7 : prescale sets +#define TWI_PRESCALE_SET(value) \ + ((value) == 1 ? (0< it will start a conversion on the selected channel in ADMUX when the selected source (in ADCSRB) is triggered - ADCSRA |= (1 << ADIE); // 24.9.2 : enable ADC Interrupt - ADCSRA |= ADC_PRESCALE_SET(prescaler_value); // Table 24-5 : prescaler ADC - - ADCSRB = ADC_TRIGGER_TIMER_1_COMPARE_B; // Table 24-6 : ADC Auto Trigger Source - ADMUX = (ADMUX & 0b11110000) | (adc_channel & 0b1111); // Table 24-4 : Select ADC channel 0, (Table 14-6 : alternate function for RV1 on PC0 -> ADC0) -} - - -void adc_print_hex(uint8_t value) { - char buffer[3] = {0}; - int_to_hex_string(value, buffer, 2); - uart_printstr_endl(buffer); -} - -ISR(ADC_vect) { // Table 12-6 : interrupt vector for ADC Conversion Complete - uint8_t value = ADCH; // 24.9.3.2 : read ADCH 8 bits precision - adc_print_hex(value); -} diff --git a/module06/ex00/header.h b/module06/ex00/header.h index 9cd2b9d..fda2646 100644 --- a/module06/ex00/header.h +++ b/module06/ex00/header.h @@ -2,8 +2,7 @@ #define HEADER_H #include -#include -#include +#include #include "utils.h" #include "bitmanip.h" @@ -11,19 +10,32 @@ #include "timer.h" #include "usart.h" #include "adc.h" +#include "i2c.h" // // GLOBAL // -extern volatile uint8_t adc_channel; +typedef enum { + WAITING, + MASTER, + SLAVE +} Role; +extern volatile Role role; +extern volatile uint8_t received_data; // // PROTOTYPES // // main.c +// i2c.c void i2c_init(void); void i2c_start(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); // // MACROS diff --git a/module06/ex00/i2c.c b/module06/ex00/i2c.c new file mode 100644 index 0000000..422c206 --- /dev/null +++ b/module06/ex00/i2c.c @@ -0,0 +1,26 @@ +#include "header.h" + +#define TWI_PRESCALE_VALUE 1 // can be 1, 4, 16, 64 +#define TWI_FREQ 100000UL // 100kHz I2C +#define SLAVE_ADDRESS 42 // 22.3.3 : address 0000000 and 1111xxx are reserved, 42 is 0101010 + +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) { + 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; // p225 example code : Check value of TWI Status Register. Mask prescaler bits. If status different from START go to ERROR + uart_printstr_itoa_base_endl(status); + if (status != TW_START && status != TW_REP_START) { + TWCR = SEND_STOP_CONDITION; + return; + } +} + +void i2c_stop(void) { + TWCR = SEND_STOP_CONDITION; // 22.9.2 : send stop condition +} diff --git a/module06/ex00/main.c b/module06/ex00/main.c index 2299fe4..041d6d0 100644 --- a/module06/ex00/main.c +++ b/module06/ex00/main.c @@ -1,15 +1,9 @@ #include "header.h" -void i2c_init(void) { -} -void i2c_start(void) { -} -void i2c_stop(void) { -} - // description int main() { - + uart_init(); + i2c_init(); while(1); } diff --git a/module06/ex00/math.c b/module06/ex00/math.c index 0177fc0..2a4be39 100644 --- a/module06/ex00/math.c +++ b/module06/ex00/math.c @@ -6,4 +6,27 @@ void int_to_hex_string(uint64_t value, char *out, uint8_t num_digits) { // nu out[i] = INT_TO_HEX_CHAR((value >> shift) & 0x0F); } out[num_digits] = '\0'; -} \ No newline at end of file +} + +void int_to_string(uint64_t value, char *buffer) { + // handle zero case + if (value == 0) { + buffer[0] = '0'; + return; + } + + uint8_t size = -1; + uint64_t copy = value; + + while (copy) { + copy /= 10; + size++; + } + + while (value) { + uint8_t digit = value % 10; + buffer[size] = digit + '0'; + value /= 10; + size--; + } +} diff --git a/module06/ex00/timer.c b/module06/ex00/timer.c deleted file mode 100644 index 02307d4..0000000 --- a/module06/ex00/timer.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "header.h" - -// Set up Timer1 in CTC mode to trigger every 20ms -// With 16MHz clock and prescaler of 64, and OCR1A = 49999: -// 16000000/64/50000 = 20ms period -#define T1B_PRESCALE_VALUE 64 -void timer_1B_init() { - TCCR1A = 0; // 16.11.1 : Normal operation, OC1A/OC1B disconnected - TCCR1B = CTC_TOP_OCR1A_IN_TCCR1B; // 16.11.2 : CTC mode top OCR1A - TCCR1B |= T1_PRESCALE_SET(T1B_PRESCALE_VALUE); // 16.11.2 : prescaler - - OCR1A = TIME_MS(20, T1B_PRESCALE_VALUE); // 16.11.5 : Compare match value for register A - // OCR1B = ; // 16.11.6 : Compare match value for register B, since not defined, should default to 0 - - TIMSK1 = (1 << OCIE1B); // 16.11.8 : Enable Timer1 Compare B Match Interrupt - - // ADCSRA |= (1 << ADSC); // 24.9.2 : start first conversion -} - -ISR(TIMER1_COMPB_vect) { - // Empty ISR to ensure proper flag clearing or something like that (p145 : "OCF1B is automatically cleared when the Output Compare Match B Interrupt Vector is executed") -} \ No newline at end of file diff --git a/module06/ex00/twi.c b/module06/ex00/twi.c new file mode 100644 index 0000000..ef50d62 --- /dev/null +++ b/module06/ex00/twi.c @@ -0,0 +1,104 @@ +#include "rush_header.h" + +volatile uint8_t received_data = 0; + +void twi_init_slave(void) { + TWAR = (SLAVE_ADDRESS << 1); + TWCR = (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // Enable TWI, enable ACK, and enable TWI interrupt +} +void twi_stop_slave(void) { + // TWCR = 0x00; // Disable TWI interrupts and TWI module + // TWAR = 0x00; // Optionally, clear the TWI address register +} + +void twi_init_master() { + 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 twi_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 & MASK_WITHOUT_LAST_3; // p225 example code : Check value of TWI Status Register. Mask prescaler bits. If status different from START go to ERROR + if (status != TW_START && status != TW_REP_START) { + TWCR = SEND_STOP_CONDITION; + return; + } +} + +void twi_send_addr(uint8_t addr_r_w) { + TWDR = addr_r_w; // 22.9.4 : (Data Register) load data into TWDR register + TWCR = SEND_CONTINUE_TRANSMISSION; // p225 example code : Load SLA_W into TWDR Register. Clear TWINT bit in TWCR to start transmission of address + while (!(TEST(TWCR, TWINT))); // p225 example code : Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received + + uint8_t status = TWSR & MASK_WITHOUT_LAST_3; // Check value of TWI Status Register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR + if (status != TW_MT_SLA_ACK) { + TWCR = SEND_STOP_CONDITION; + return; + } +} + +void twi_write(uint8_t data) { + 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 & MASK_WITHOUT_LAST_3; // p225 example code : Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR + if (status != TW_MT_DATA_ACK) { + TWCR = SEND_STOP_CONDITION; + return; + } +} + +uint8_t twi_read(uint8_t ack) { + flash_led(D1); // Before setting TWCR + if (ack) { + TWCR = SEND_ACKNOWLEDGE; // Send ACK to request more data + } else { + TWCR = SEND_NACKNOWLEDGE; // Send NACK to indicate last byte read + } + + // while (!(TEST(TWCR, TWINT))); // Wait for data reception + // Add a timeout to prevent infinite waiting + uint16_t timeout = 1000; + while (!(TEST(TWCR, TWINT)) && timeout > 0) { + timeout--; + _delay_us(10); + } + + flash_led(D2); // After TWINT set or timeout + + if (timeout == 0) { + // Timeout occurred, slave didn't respond + flash_led(D3); // Indicate timeout + TWCR = SEND_STOP_CONDITION; + return 0xFF; // Error code for timeout + } + + uint8_t status = TWSR & MASK_WITHOUT_LAST_3; + if (status != TW_MR_DATA_ACK && status != TW_MR_DATA_NACK) { + TWCR = SEND_STOP_CONDITION; + return 0; + } + flash_led(D4); // Indicate status error + return TWDR; +} + +void twi_stop() { + TWCR = SEND_STOP_CONDITION; +} + +void write_one_byte_data(uint8_t data) { + twi_start(); + twi_send_addr((SLAVE_ADDRESS << 1) | TW_WRITE); // Send Slave address with Write bit + twi_write(data); // write data byte + twi_stop(); +} +uint8_t read_one_byte_data() { + twi_start(); + twi_send_addr((SLAVE_ADDRESS << 1) | TW_READ); // Send Slave address with Write bit + uint8_t data = twi_read(FALSE); // Read data with NACK (only one byte expected) + twi_stop(); + return data; +} \ No newline at end of file diff --git a/module06/ex00/uart.c b/module06/ex00/uart.c index f0231f0..8cb3f2b 100644 --- a/module06/ex00/uart.c +++ b/module06/ex00/uart.c @@ -39,6 +39,12 @@ void uart_printstr_endl(const char* str) { uart_printstr("\r\n"); } +void uart_printstr_itoa_base_endl(uint64_t value) { + ; + uart_printstr(str); + 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