add rush 00
This commit is contained in:
@@ -89,4 +89,5 @@ avrdude done. Thank you.
|
||||
|
||||
## screen
|
||||
|
||||
- (optional) `export XTERM=xterm`
|
||||
- `screen /dev/ttyUSB0 115200`
|
||||
|
||||
1
rush00
1
rush00
Submodule rush00 deleted from e4ea057ebf
83
rush_00/Makefile
Normal file
83
rush_00/Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
# frequency of the CPU (in Hz)
|
||||
F_CPU = 16000000UL
|
||||
TARGET = main
|
||||
CC = avr-gcc
|
||||
INCLUDES = -I.
|
||||
|
||||
AVRGCC_MCU_TYPE = atmega328p
|
||||
AVRDUDE_MCU_TYPE = m328p
|
||||
BAUD_RATE = 115200
|
||||
PROGRAMMER_ID = arduino
|
||||
|
||||
# original firmware dump
|
||||
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||
|
||||
# Find all C source files in the current directory
|
||||
SRC = $(wildcard *.c)
|
||||
# Generate object file names from source file names
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS = -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(INCLUDES) -Os
|
||||
|
||||
# Detect OS
|
||||
OS := $(shell uname -s)
|
||||
|
||||
# Set Serial Port based on OS
|
||||
ifeq ($(OS), Darwin) # macOS
|
||||
SERIAL_PORT_1 := /dev/tty.usbserial-310 # $(shell ls /dev/tty.usb* 2>/dev/null | head -n 1) # should be : /dev/tty.usbserial-310
|
||||
SERIAL_PORT_2 := /dev/tty.usbserial-110
|
||||
else ifeq ($(OS), Linux) # Ubuntu/Linux
|
||||
SERIAL_PORT_1 = /dev/ttyUSB0 # $(shell ls /dev/ttyUSB* 2>/dev/null | head -n 1) # should be : /dev/ttyUSB0
|
||||
SERIAL_PORT_2 = /dev/ttyUSB1
|
||||
endif
|
||||
|
||||
##
|
||||
## RULES
|
||||
##
|
||||
|
||||
all: hex flash
|
||||
|
||||
hex: $(TARGET).hex
|
||||
|
||||
# Compile each .c file to corresponding .o file
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Link all object files to create the binary
|
||||
# avr-gcc : compiler for AVR microcontrollers, https://gcc.gnu.org/wiki/avr-gcc#Using_avr-gcc, https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||
# -mmcu : the target microcontrolle (ATmega328P)
|
||||
# -D : defines a preprocessor macro (#define F_CPU <value>)
|
||||
# -o : output filename
|
||||
$(TARGET).bin: $(OBJ)
|
||||
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) $(OBJ) -o $(TARGET).bin
|
||||
|
||||
# Convert binary to hex for flashing
|
||||
# avr-objcopy : man avr-jobcopy, https://linux.die.net/man/1/avr-objcopy
|
||||
# -O : specifies output format, Intel HEX
|
||||
# some formats (list not found in any doc) :
|
||||
# -O ihex : Used for flashing AVR chips
|
||||
# -O binary : Raw binary file
|
||||
# -O elf32-avr : Used for debugging
|
||||
$(TARGET).hex: $(TARGET).bin
|
||||
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||
|
||||
# Flash the hex file to the microcontroller
|
||||
# avr-dude : AVR Downloader/UploaDEr, upload firmware, https://avrdudes.github.io/avrdude, v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf
|
||||
# -p : specifies the microcontroller -> m328p
|
||||
# -c : programmer-id
|
||||
# -b : baud rate for serial communication
|
||||
# -P : the serial port, found with `ls /dev/tty*` -> /dev/ttyUSB0
|
||||
# -U : Uploads (w = write) the HEX firmware file to the flash memory
|
||||
# (-v : verbose info dump)
|
||||
flash:
|
||||
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT_1) -U flash:w:$(TARGET).hex
|
||||
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT_2) -U flash:w:$(TARGET).hex
|
||||
|
||||
restore:
|
||||
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||
|
||||
clean:
|
||||
rm -f main.hex main.bin $(OBJ)
|
||||
|
||||
.PHONY : all clean hex flash restore
|
||||
37
rush_00/README.md
Normal file
37
rush_00/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Parallel Development Plan (chat gpt :p)
|
||||
|
||||
| Task | Developer | Dependencies |
|
||||
| ------------------------------------------- | ------------ | ----------------------------------------------- |
|
||||
| Configure I2C (Master/Slave) | **Person A** | None |
|
||||
| Configure GPIOs (Buttons & LEDs) | **Person B** | None |
|
||||
| Implement button interrupt handling | **Person B** | Needs GPIO setup |
|
||||
| Implement LED countdown sequence | **Person B** | Needs GPIO setup |
|
||||
| Implement I2C send & receive functions | **Person A** | Needs I2C setup |
|
||||
| Implement game state transitions | **Person A** | Needs I2C communication & button press handling |
|
||||
| Implement reaction detection & winner logic | **Person A** | Needs game state management & button interrupts |
|
||||
| Implement LED signals for winner/loser | **Person B** | Needs reaction detection |
|
||||
| Implement game reset logic | **Person A** | Needs winner detection |
|
||||
| Sync both MCUs on game start | **Person A** | Needs I2C and button handling |
|
||||
|
||||
## How Each Person Works in Parallel
|
||||
|
||||
### **Person A: I2C & Game Logic**
|
||||
|
||||
- Starts with I2C initialization and communication functions.
|
||||
- Implements game state management (waiting, countdown, reaction, result).
|
||||
- Manages synchronization between the two MCUs.
|
||||
- Detects the winner and resets the game.
|
||||
|
||||
### **Person B: Buttons & LEDs**
|
||||
|
||||
- Sets up buttons and interrupts.
|
||||
- Implements debounce mechanism to avoid false triggers.
|
||||
- Handles the countdown sequence using LEDs.
|
||||
- Displays winner/loser using LEDs.
|
||||
|
||||
## Collaboration Strategy
|
||||
|
||||
1. **Step 1:** Work independently on separate modules.
|
||||
2. **Step 2:** Integrate button presses with game state transitions.
|
||||
3. **Step 3:** Test button presses and countdown independently.
|
||||
4. **Step 4:** Merge both parts and test full game logic with I2C communication.
|
||||
53
rush_00/bitmanip.h
Normal file
53
rush_00/bitmanip.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef BITMANIP_H
|
||||
#define BITMANIP_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Bit operations on registers
|
||||
#define SET(register, bit) (register |= (1 << (bit)))
|
||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
||||
#define TEST(register, bit) (register & (1 << (bit)))
|
||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
||||
|
||||
// Get arguments from tuple-like definitions
|
||||
#define ARG_1(v1, v2) v1
|
||||
#define ARG_2(v1, v2) v2
|
||||
#define GET_PORT(args) ARG_1 args
|
||||
#define GET_BIT(args) ARG_2 args
|
||||
// // version with "LED1 B, D1" without parenthesis
|
||||
// #define ARG_1(v1, ...) v1
|
||||
// #define ARG_2(v1, v2, ...) v2
|
||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
||||
|
||||
// Actions on elements
|
||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
|
||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
||||
|
||||
// Bit definitions
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
|
||||
// Elements (port, bit)
|
||||
#define LED1 (B, D1)
|
||||
#define LED2 (B, D2)
|
||||
#define LED3 (B, D3)
|
||||
#define LED4 (B, D4)
|
||||
#define BUTTON1 (D, SW1)
|
||||
#define BUTTON2 (D, SW2)
|
||||
|
||||
#endif // BITMANIP_H
|
||||
18
rush_00/game.c
Normal file
18
rush_00/game.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "rush_header.h"
|
||||
|
||||
void timer() {
|
||||
flash_led(D3);
|
||||
_delay_ms(500);
|
||||
flash_led(D3);
|
||||
_delay_ms(500);
|
||||
flash_led(D3);
|
||||
_delay_ms(500);
|
||||
flash_led(D3);
|
||||
_delay_ms(500);
|
||||
turn_on_led(D3);
|
||||
}
|
||||
|
||||
void launch_game() {
|
||||
// timer();
|
||||
write_one_byte_data(0x01);
|
||||
}
|
||||
8
rush_00/interrupt.h
Normal file
8
rush_00/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INTERRUPT_H
|
||||
#define INTERRUPT_H
|
||||
|
||||
// 7.3.1 : SREG – AVR Status Register
|
||||
#define ENABLE_GLOBAL_INTERRUPT (1<<7)
|
||||
#define DISABLE_GLOBAL_INTERRUPT (0<<7)
|
||||
|
||||
#endif // INTERRUPT_H
|
||||
66
rush_00/interrupts.c
Normal file
66
rush_00/interrupts.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "rush_header.h"
|
||||
|
||||
volatile Role role = WAITING;
|
||||
|
||||
void setup_button_interrupt() { // interruption SW1 (PD2)
|
||||
EICRA |= (1 << ISC01); // trigger on falling edge for INT0
|
||||
EIMSK |= (1 << INT0); // Activate INT0
|
||||
|
||||
SREG |= (1 << SREG_I);
|
||||
}
|
||||
|
||||
ISR(INT0_vect) { // interruption SW1 (PD2)
|
||||
if (!TEST_PIN(BUTTON1)) {
|
||||
_delay_ms(30);
|
||||
flash_led(D4);
|
||||
if (role == MASTER) {
|
||||
// write_one_byte_data(0x01);
|
||||
read_one_byte_data();
|
||||
} else if (role == SLAVE) {
|
||||
// PORTD &= ~(1 << PD2); // Pull PD2 low (active LOW signal)
|
||||
// _delay_ms(10); // Give master time to catch the signal
|
||||
// PORTD |= (1 << PD2); // Reset line HIGH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ISR(TWI_vect) { // interruption slave receive data, Table 12-1 : 25, 2-wire Serial Interface
|
||||
uint8_t status = TWSR & MASK_WITHOUT_LAST_3;
|
||||
|
||||
switch (status) {
|
||||
|
||||
// Slave Receiver cases
|
||||
case TW_SR_SLA_ACK: // SLA+W received, ACK sent
|
||||
// flash_led(D4);
|
||||
turn_on_led_2_light();
|
||||
break;
|
||||
case TW_SR_DATA_ACK: // data received, ACK sent
|
||||
if (role == WAITING) {
|
||||
role = SLAVE;
|
||||
}
|
||||
received_data = TWDR; // store received data
|
||||
break;
|
||||
case TW_SR_STOP: // STOP or REPEATED START
|
||||
break;
|
||||
case TW_SR_DATA_NACK: // data received but slave answered NACK (no ACK an means end of communication or error)
|
||||
break;
|
||||
|
||||
// Slave Transmitter cases
|
||||
case TW_ST_SLA_ACK: // SLA+R received, ACK sent - First byte to be transmitted
|
||||
flash_led(D4);
|
||||
TWDR = 0x10; // send first data byte
|
||||
break;
|
||||
case TW_ST_DATA_ACK: // data sent, ACK received - Additional bytes can be sent
|
||||
TWDR = 0x10; // send next data byte
|
||||
break;
|
||||
case TW_ST_DATA_NACK: // data sent, NACK received - No more data requested
|
||||
break; // master doesn't want more data
|
||||
case TW_ST_LAST_DATA: // last data byte sent, ACK received
|
||||
break; // All data sent
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // Clear interrupt flag and enable next transfer
|
||||
}
|
||||
52
rush_00/main.c
Normal file
52
rush_00/main.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "rush_header.h"
|
||||
|
||||
#define BLINK_PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
||||
#define BLINK_DUTY_CYCLE 10
|
||||
|
||||
void flash_led(int bit) {
|
||||
SET(DDRB, bit);
|
||||
SET(PORTB, bit);
|
||||
_delay_ms(100);
|
||||
CLEAR(PORTB, bit);
|
||||
}
|
||||
void turn_on_led(int bit) {
|
||||
SET(DDRB, bit);
|
||||
SET(PORTB, bit);
|
||||
}
|
||||
void turn_on_led_2_light() {
|
||||
uint8_t duty = 10;
|
||||
// Set PB1 (OC1A) as output
|
||||
DDRB |= (1 << PB1);
|
||||
|
||||
// Configure Timer1 for Fast PWM, 8-bit mode
|
||||
TCCR1A = (1 << COM1A1) | (1 << WGM10); // Clear OC1A on compare match, Fast PWM
|
||||
TCCR1B = (1 << WGM12) | (1 << CS11); // Prescaler 8
|
||||
|
||||
// Set duty cycle (0-255, where 255 = fully ON, 0 = fully OFF)
|
||||
OCR1A = duty;
|
||||
}
|
||||
void turn_off_led(int bit) {
|
||||
SET(DDRB, bit);
|
||||
CLEAR(PORTB, bit);
|
||||
}
|
||||
void blink_led_2(int period) {
|
||||
MODE_OUTPUT(LED2);
|
||||
SET(TCCR1A, WGM11); // Table 16-4 : set timer in Fast PWM (Pulse With Modulation) mode with TOP = ICR1 (Mode 14)
|
||||
SET(TCCR1B, WGM12);
|
||||
SET(TCCR1B, WGM13);
|
||||
SET(TCCR1A, COM1A1); // Table 16-2 : non-inverting mode, the LED will be ON for DUTY_CYCLE% of the time (CLEAR OC1A on compare match, SET OC1A at BOTTOM)
|
||||
ICR1 = TIME_MS(period, BLINK_PRESCALE_VALUE); // Table 16-4 : set the period (compare TOP value)
|
||||
OCR1A = TIME_MS(PERCENT(BLINK_DUTY_CYCLE, period), BLINK_PRESCALE_VALUE); // 16.9.3 : set the duty cycle to DUTY_CYCLE% of the time on channel A -> OC1A (alternate function of PORTB1, aka LED2) is cleared when TCNT1 (the counter value) equals OCR1A
|
||||
TCCR1B |= (PRESCALE_SET(BLINK_PRESCALE_VALUE)); // start the timer with the prescaler
|
||||
}
|
||||
|
||||
int main() {
|
||||
MODE_INPUT(BUTTON1); // set as input
|
||||
SET_ELEM(BUTTON1); // pull-up resistor on
|
||||
|
||||
twi_init_slave();
|
||||
get_role();
|
||||
setup_button_interrupt();
|
||||
// launch_game();
|
||||
while (1);
|
||||
}
|
||||
22
rush_00/roles.c
Normal file
22
rush_00/roles.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "rush_header.h"
|
||||
|
||||
void get_role() {
|
||||
int end = FALSE;
|
||||
while(!end) {
|
||||
_delay_ms(50);
|
||||
if (role == SLAVE) {
|
||||
end = TRUE;
|
||||
// MODE_OUTPUT(BUTTON1);
|
||||
continue;
|
||||
}
|
||||
if (!IS_PIN_SET(BUTTON1)) {
|
||||
continue;
|
||||
}
|
||||
end = TRUE;
|
||||
turn_on_led(D1);
|
||||
role = MASTER;
|
||||
twi_stop_slave();
|
||||
twi_init_master();
|
||||
write_one_byte_data(0x01);
|
||||
}
|
||||
}
|
||||
72
rush_00/rush_header.h
Normal file
72
rush_00/rush_header.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef RUSH_HEADER_H
|
||||
#define RUSH_HEADER_H
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "bitmanip.h"
|
||||
#include "timer.h"
|
||||
#include "usart.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
// TWI
|
||||
// table 22-7 : prescale sets
|
||||
#define TWI_PRESCALE_VALUE 1 // can be 1, 4, 16, 64
|
||||
#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)
|
||||
// 100kHz I2C
|
||||
#define TWI_FREQ 100000UL
|
||||
// Slave address
|
||||
#define SLAVE_ADDRESS 42 // 22.3.3 : address 0000000 and 1111xxx are reservedm 42 is 0101010
|
||||
// 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))
|
||||
|
||||
#define MASK_WITHOUT_LAST_3 0xF8 // 11111000
|
||||
|
||||
// FUNCTION PROTOTYPES
|
||||
// main.c
|
||||
void flash_led();
|
||||
void blink_led_2();
|
||||
void turn_on_led(int bit);
|
||||
void turn_on_led_1_light();
|
||||
void turn_on_led_2_light();
|
||||
void turn_off_led(int bit);
|
||||
// twi.c
|
||||
void twi_init_slave(void);
|
||||
void twi_stop_slave(void);
|
||||
void twi_init_master();
|
||||
void twi_start();
|
||||
void twi_send_addr(uint8_t addr_w);
|
||||
void write_one_byte_data(uint8_t data);
|
||||
uint8_t read_one_byte_data();
|
||||
void twi_write(uint8_t data);
|
||||
uint8_t twi_read(uint8_t ack);
|
||||
void twi_stop();
|
||||
// interupts.c
|
||||
void setup_button_interrupt();
|
||||
void setup_button_role();
|
||||
// roles.c
|
||||
void get_role();
|
||||
// game.c
|
||||
void launch_game();
|
||||
|
||||
// GLOBAL VARIABLES
|
||||
typedef enum {
|
||||
WAITING,
|
||||
MASTER,
|
||||
SLAVE
|
||||
} Role;
|
||||
extern volatile Role role;
|
||||
extern volatile uint8_t received_data;
|
||||
|
||||
#endif // RUSH_HEADER_H
|
||||
27
rush_00/timer.h
Normal file
27
rush_00/timer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
// table 16-5 : prescale sets
|
||||
#define PRESCALE_SET(value) \
|
||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
||||
|
||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
||||
|
||||
#endif // TIMER_H
|
||||
105
rush_00/twi.c
Normal file
105
rush_00/twi.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#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
|
||||
SREG |= (1 << SREG_I);
|
||||
}
|
||||
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;
|
||||
}
|
||||
31
rush_00/usart.h
Normal file
31
rush_00/usart.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef USART_H
|
||||
#define USART_H
|
||||
|
||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
||||
#define STOP_ONE_BIT (0<<USBS0)
|
||||
#define STOP_TWO_BIT (1<<USBS0)
|
||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
||||
|
||||
#endif // USART_H
|
||||
23
rush_00/utils.h
Normal file
23
rush_00/utils.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
// stringify
|
||||
#define STRINGIFY_HELPER(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||
|
||||
// concatenate
|
||||
#define CONCAT_HELPER(x, y) x ## y
|
||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
||||
|
||||
// mathematics
|
||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
||||
|
||||
// text
|
||||
#define SWITCH_CASE(ch) (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ? ((ch) ^ (1 << 5)) : (ch))
|
||||
|
||||
// boolean
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#endif // UTILS_H
|
||||
Reference in New Issue
Block a user