add rush 00
This commit is contained in:
@@ -89,4 +89,5 @@ avrdude done. Thank you.
|
|||||||
|
|
||||||
## screen
|
## screen
|
||||||
|
|
||||||
|
- (optional) `export XTERM=xterm`
|
||||||
- `screen /dev/ttyUSB0 115200`
|
- `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