updated math functions
This commit is contained in:
18
headers/i2c.h
Normal file
18
headers/i2c.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
// table 22-7 : prescale sets
|
||||
#define TWI_PRESCALE_SET(value) \
|
||||
((value) == 1 ? (0<<TWPS1 | 0<<TWPS0) : \
|
||||
(value) == 4 ? (0<<TWPS1 | 1<<TWPS0) : \
|
||||
(value) == 16 ? (1<<TWPS1 | 0<<TWPS0) : \
|
||||
(value) == 64 ? (1<<TWPS1 | 1<<TWPS0) : 0x00)
|
||||
|
||||
// 22.7.1 : TWCR, Master Transmitter Mode
|
||||
#define SEND_START_CONDITION ((1<<TWINT) | (1<<TWEN)) | (1<<TWSTA)
|
||||
#define SEND_CONTINUE_TRANSMISSION ((1<<TWINT) | (1<<TWEN))
|
||||
#define SEND_STOP_CONDITION ((1<<TWINT) | (1<<TWEN)) | (1<<TWSTO)
|
||||
#define SEND_ACKNOWLEDGE ((1<<TWINT) | (1<<TWEN) | (1<<TWEA))
|
||||
#define SEND_NACKNOWLEDGE ((1<<TWINT) | (1<<TWEN))
|
||||
|
||||
#endif // I2C_H
|
||||
@@ -25,7 +25,7 @@ void adc_print_dec(uint16_t value) {
|
||||
// value = calibrate_temperature(value, 5);
|
||||
// }
|
||||
char buffer[17] = {0};
|
||||
uint16_to_string(value, buffer);
|
||||
int_to_string((uint16_t)value, buffer);
|
||||
uart_printstr(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ extern volatile uint8_t adc_channel;
|
||||
void timer_1B_init();
|
||||
// math.c
|
||||
void int_to_hex_string(uint64_t value, char *out, uint8_t num_digits);
|
||||
void uint16_to_string(uint16_t value, char *out);
|
||||
void int_to_string(uint64_t value, char *out);
|
||||
// adc.c
|
||||
void adc_init(uint8_t prescaler_value);
|
||||
uint16_t calibrate_temperature(uint16_t value, uint8_t speed);
|
||||
|
||||
@@ -8,7 +8,7 @@ void int_to_hex_string(uint64_t value, char *out, uint8_t num_digits) { // nu
|
||||
out[num_digits] = '\0';
|
||||
}
|
||||
|
||||
void uint16_to_string(uint16_t value, char buffer[17]) {
|
||||
void int_to_string(uint64_t value, char *buffer) {
|
||||
// handle zero case
|
||||
if (value == 0) {
|
||||
buffer[0] = '0';
|
||||
@@ -16,7 +16,7 @@ void uint16_to_string(uint16_t value, char buffer[17]) {
|
||||
}
|
||||
|
||||
uint8_t size = -1;
|
||||
uint16_t copy = value;
|
||||
uint64_t copy = value;
|
||||
|
||||
while (copy) {
|
||||
copy /= 10;
|
||||
@@ -29,4 +29,4 @@ void uint16_to_string(uint16_t value, char buffer[17]) {
|
||||
value /= 10;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#include "header.h"
|
||||
|
||||
// 24.2 : The ADC generates a 10-bit result which is presented in the ADC Data Registers, ADCH and ADCL
|
||||
|
||||
void adc_init(uint8_t prescaler_value) {
|
||||
ADMUX = (1 << REFS0); // Table 24-3 : set voltage reference, AVCC with external capacitor at AREF pin
|
||||
ADMUX |= (1 << ADLAR); // 24.9.1 : result is left adjusted, meaning the first 8 bits values are readable in ADCH, (24.9.3.2 : ADC data register is not updated util ADCH is read)
|
||||
ADCSRA = (1 << ADEN); // 24.9.2 : enable ADC
|
||||
ADCSRA |= (1 << ADATE); // 24.9.2 : enable Auto Trigger -> 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);
|
||||
}
|
||||
@@ -2,8 +2,7 @@
|
||||
#define HEADER_H
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#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
|
||||
|
||||
26
module06/ex00/i2c.c
Normal file
26
module06/ex00/i2c.c
Normal file
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
104
module06/ex00/twi.c
Normal file
104
module06/ex00/twi.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user