3 Commits

Author SHA1 Message Date
hugo LAMY
41b5ec5e35 added test macro in readme 2025-03-06 02:01:04 +01:00
hugo LAMY
c650ff1157 trying to fiw devcontainer to works with 42 chips 2025-03-06 02:00:56 +01:00
hugo LAMY
8a28799aac added devcontainer 2025-03-06 00:30:38 +00:00
172 changed files with 715 additions and 4759 deletions

24
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
# Use Ubuntu as the base image
FROM ubuntu:latest
# Update and install necessary dependencies
RUN apt-get update && apt-get install -y \
build-essential \
curl \
git \
vim \
avr-libc gcc-avr binutils-avr \
avrdude \
&& rm -rf /var/lib/apt/lists/*
# Set the working directory to /workspace (VSCode will mount your local folder here)
WORKDIR /workspace
# Set the default user as root for installing packages
USER root
# Expose any necessary ports (if needed)
# EXPOSE 3000
# Run bash as the default command when the container starts
CMD ["/bin/bash"]

View File

@@ -0,0 +1,11 @@
{
"name": "Ubuntu DevContainer",
"dockerFile": "Dockerfile", // Reference to your Dockerfile
"context": ".", // The context is the root of your project
"workspaceFolder": "/workspace", // Where VSCode will mount your current folder inside the container
"mounts": [
"source=${localWorkspaceFolder},target=/workspace,type=bind",
"source=/dev/tty.usbserial-310,target=/dev/ttyUSB0,type=bind"
],
"postCreateCommand": "echo 'Devcontainer setup complete!'"
}

1
.gitignore vendored
View File

@@ -51,4 +51,3 @@ Thumbs.db
# chips # chips
*.bin *.bin
*.hex *.hex
*.o

View File

@@ -1,28 +1,24 @@
// { {
// "configurations": [ "configurations": [
// { {
// "name": "AVR", "name": "linux-avr-gcc",
// "includePath": [ "includePath": ["${workspaceFolder}/**", "/usr/lib/avr/include/**"],
// "${workspaceFolder}/headers", "defines": [],
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/lib/avr-gcc/9/gcc/avr/9.4.0/include", "mergeConfigurations": false,
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/avr/include", "compilerPath": "/usr/bin/avr-gcc",
// "/opt/homebrew/include" "cStandard": "gnu11",
// ], "cppStandard": "gnu++14",
// "defines": ["__AVR_ATmega328P__"], "intelliSenseMode": "linux-gcc-x64",
// "intelliSenseMode": "gcc-x64", "compilerArgs": ["-mmcu=atmega328p", "-DF_CPU=16000000UL", "-Os"]
// "cStandard": "c11", },
// "cppStandard": "c++17", {
// "browse": { "name": "linux-gcc-x64",
// "path": [ "includePath": ["${workspaceFolder}/**"],
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/lib/avr-gcc/9/gcc/avr/9.4.0/include", "compilerPath": "/usr/bin/gcc",
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/avr/include", "intelliSenseMode": "linux-gcc-x64",
// "/opt/homebrew/include" "compilerArgs": [""],
// // "/opt/homebrew/lib/gcc/avr/include", "mergeConfigurations": false
// // "/opt/homebrew/lib/gcc/avr/include-fixed" }
// ], ],
// "limitSymbolsToIncludedHeaders": true "version": 4
// } }
// }
// ],
// "version": 4
// }

14
.vscode/settings.json vendored
View File

@@ -1,14 +1,6 @@
{ {
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"files.associations": { "files.associations": {
"header.h": "c" "io.h": "c",
}, "delay.h": "c"
"C_Cpp.default.includePath": [ }
"${workspaceFolder}/headers",
"/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/lib/avr-gcc/9/gcc/avr/9.4.0/include",
"/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/avr/include",
"/opt/homebrew/include"
],
"C_Cpp.default.defines": ["__AVR_ATmega328P__"]
} }

View File

@@ -1,83 +0,0 @@
# frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
INCLUDES ?= -I../../headers/ # ?= : dont define if already defined
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 := $(shell ls /dev/tty.usb* 2>/dev/null | head -n 1) # should be : /dev/tty.usbserial-310
else ifeq ($(OS), Linux) # Ubuntu/Linux
SERIAL_PORT = $(shell ls /dev/ttyUSB* 2>/dev/null | head -n 1) # should be : /dev/ttyUSB0
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) -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)
dump:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:r:dump.hex
clean:
rm -f main.hex main.bin *.o
.PHONY : all clean hex flash restore

View File

@@ -1,14 +1,11 @@
# RESSOURCES # RESSOURCES
- guide survie piscine embarquee : https://42chips.notion.site/survive
- atmega328p : https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf - atmega328p : https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf
- Getting started with AVR programming : https://github.com/m3y54m/start-avr/tree/master - Getting started with AVR programming : https://github.com/m3y54m/start-avr/tree/master
- avrdude doc : https://avrdudes.github.io/avrdude/ - avrdude doc : https://avrdudes.github.io/avrdude/
- avrdude 6.3 doc : https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf - avrdude 6.3 doc : https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf
- embedded systems : https://en.wikibooks.org/wiki/Embedded_Systems/Atmel_AVR - embedded systems : https://en.wikibooks.org/wiki/Embedded_Systems/Atmel_AVR
- timers for newbies : https://qiriro.com/bme6163/static_files/notes/L3/Newbie%27s%20Guide%20to%20AVR%20Timers.pdf - timers for newbies : https://qiriro.com/bme6163/static_files/notes/L3/Newbie%27s%20Guide%20to%20AVR%20Timers.pdf
- timer and pwm : https://wolles-elektronikkiste.de/en/timer-and-pwm-part-2-16-bit-timer1
- doc AHT20 thermostat : https://asairsensors.com/wp-content/uploads/2021/09/Data-Sheet-AHT20-Humidity-and-Temperature-Sensor-ASAIR-V1.0.03.pdf
## m00ex00 ## m00ex00
@@ -83,12 +80,37 @@ avrdude: safemode: Fuses OK (E:00, H:00, L:00)
avrdude done. Thank you. avrdude done. Thank you.
``` ```
## makefile on mac ## test macros
- `brew tap osx-cross/avr` #include <stdio.h>
- `brew install avr-gcc avrdude` #include <avr/io.h>
## screen // // stringify
#define STRINGIFY_HELPER(x) #x
#define STRINGIFY(x) STRINGIFY_HELPER(x)
- (optional) `export TERM=xterm` #define CONCAT_HELPER(x, y) x ## y
- `screen /dev/ttyUSB0 115200` #define CONCAT(x, y) CONCAT_HELPER(x, y)
// get argument at nth position
#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
// actions on registers
#define SET(register, bit) register |= 1 << bit
// actions on ports
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
// elements
#define LED1 (B, 0)
int main()
{
MODE_OUTPUT(LED1);
return 0;
}

View File

@@ -1,25 +0,0 @@
#ifndef ADC_H
#define ADC_H
// Table 24-5 : prescaler ADC
#define ADC_PRESCALE_SET(value) \
((value) == 2 ? (0<<ADPS2 | 0<<ADPS1 | 1<<ADPS0) : \
(value) == 4 ? (0<<ADPS2 | 1<<ADPS1 | 0<<ADPS0) : \
(value) == 8 ? (0<<ADPS2 | 1<<ADPS1 | 1<<ADPS0) : \
(value) == 16 ? (1<<ADPS2 | 0<<ADPS1 | 0<<ADPS0) : \
(value) == 32 ? (1<<ADPS2 | 0<<ADPS1 | 1<<ADPS0) : \
(value) == 64 ? (1<<ADPS2 | 1<<ADPS1 | 0<<ADPS0) : \
(value) == 128 ? (1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0) : \
(0<<ADPS2 | 0<<ADPS1 | 0<<ADPS0))
// Table 24-6 : ADC Auto Trigger Source Selections
#define ADC_TRIGGER_FREE_RUNNING (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0)
#define ADC_TRIGGER_ANALOG_COMPARE (0 << ADTS2) | (0 << ADTS1) | (1 << ADTS0)
#define ADC_TRIGGER_EXTERNAL_INTERRUPT_0 (0 << ADTS2) | (1 << ADTS1) | (0 << ADTS0)
#define ADC_TRIGGER_TIMER_0_COMPARE_A (0 << ADTS2) | (1 << ADTS1) | (1 << ADTS0)
#define ADC_TRIGGER_TIMER_0_OVERFLOW (1 << ADTS2) | (0 << ADTS1) | (0 << ADTS0)
#define ADC_TRIGGER_TIMER_1_COMPARE_B (1 << ADTS2) | (0 << ADTS1) | (1 << ADTS0)
#define ADC_TRIGGER_TIMER_1_OVERFLOW (1 << ADTS2) | (1 << ADTS1) | (0 << ADTS0)
#define ADC_TRIGGER_TIMER_1_CAPTURE_EVENT (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0)
#endif // ADC_H

View File

@@ -1,61 +0,0 @@
#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)
#define PULLUP_ON(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
#define PULLUP_OFF(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
// Bit definitions (<pin number> // <pin name>)
#define D1 0 // PB0
#define D2 1 // PB1
#define D3 2 // PB2
#define D4 4 // PB4
#define SW1 2 // PD2
#define SW2 4 // PD4
#define D5B 3 // PD3
#define D5R 5 // PD5
#define D5G 6 // PD6
// 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)
#define RGB5_BLUE (D, D5B)
#define RGB5_RED (D, D5R)
#define RGB5_GEEN (D, D5G)
#endif // BITMANIP_H

View File

@@ -1,17 +0,0 @@
#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 TWI_START_CONDITION ((1<<TWINT) | (1<<TWEN)) | (1<<TWSTA)
#define TWI_STOP_CONDITION ((1<<TWINT) | (1<<TWEN)) | (1<<TWSTO)
#define TWI_ACKNOWLEDGE ((1<<TWINT) | (1<<TWEN) | (1<<TWEA))
#define TWI_NACKNOWLEDGE ((1<<TWINT) | (1<<TWEN))
#endif // I2C_H

View File

@@ -1,8 +0,0 @@
#ifndef INTERRUPT_H
#define INTERRUPT_H
// 7.3.1 : SREG AVR Status Register
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
#endif // INTERRUPT_H

View File

@@ -1,37 +0,0 @@
#ifndef TIMER_H
#define TIMER_H
// table 15-9 : timer 0 prescale sets
#define T0_PRESCALE_SET(value) \
((value) == 1 ? (0<<CS02 | 0<<CS01 | 1<<CS00) : \
(value) == 8 ? (0<<CS02 | 1<<CS01 | 0<<CS00) : \
(value) == 64 ? (0<<CS02 | 1<<CS01 | 1<<CS00) : \
(value) == 256 ? (1<<CS02 | 0<<CS01 | 0<<CS00) : \
(value) == 1024? (1<<CS02 | 0<<CS01 | 1<<CS00) : \
(0<<CS02 | 0<<CS01 | 0<<CS00))
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
// table 16-5 : timer 1 prescale sets
#define T1_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

View File

@@ -1,31 +0,0 @@
#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

View File

@@ -1,32 +0,0 @@
#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)))
#define INT_TO_HEX_CHAR(n) ((n) < 10 ? ('0' + (n)) : ('A' + ((n) - 10)))
// text
#define SWITCH_CASE(ch) (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ? ((ch) ^ (1 << 5)) : (ch))
// // boolean
// #define TRUE 1
// #define FALSE 0
//
// ENUM
//
typedef enum {
FALSE,
TRUE
} Boolean;
#endif // UTILS_H

View File

@@ -1 +1,50 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
all: hex flash
hex: $(TARGET).hex
# 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: $(TARGET).c
$(CC) -mmcu=atmega328p -D F_CPU=$(F_CPU) $(TARGET).c -o $(TARGET).bin
# 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
# 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 m328p -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:w:$(TARGET).hex
# avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -v
# avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:w:../../ressources/dump_atmega328p_ori.hex
dump:
avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:r:dump_atmega328p.hex
clean:
rm -f main.hex main.bin
.PHONY : all clean hex flash dump

View File

@@ -1,4 +1,3 @@
// write a makefile that compiles the code and flashes it to the microcontroller
int main() int main()
{ {
} }

View File

@@ -1 +1,43 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
AVRGCC_MCU_TYPE = atmega328p
AVRDUDE_MCU_TYPE = m328p
BAUD_RATE = 115200
SERIAL_PORT = /dev/ttyUSB0
PROGRAMMER_ID = arduino
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
all: hex flash
hex: $(TARGET).hex
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
$(TARGET).bin: $(TARGET).c
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
# https://linux.die.net/man/1/avr-objcopy
$(TARGET).hex: $(TARGET).bin
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
flash:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -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
.PHONY : all clean hex flash restore

View File

@@ -1,4 +1,5 @@
#include <avr/io.h> #include <avr/io.h>
// #include <util/delay.h>
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT #define SET(REGISTER, BIT) REGISTER |= 1 << BIT
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT) #define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
@@ -10,27 +11,75 @@
#define D3 2 #define D3 2
#define D4 4 #define D4 4
// 14.2 : registers :
// DDRx : (Data Direction Register) Controls whether each pin is an input or output
// - 1 = output (pull-up off)
// - 0 = input
// PORTx : (Port Data Register)
// if DDRx = 1 (output mode) : Controls the output state of a pin when it's configured as an output
// - 1 = HIGH (5V?) (VCC)
// - 0 = LOW (0V) (GND)
// if DDRx = 0 (input mode) : Controls the internal pull-up resistor when the pin is an input
// - 1 = pull-up on
// - 0 = pull-up off (pin floats)
// PINx : (Pin Input Register) Reads the current logical state of a pin
// Reflects the actual voltage on the pin
// Special feature: Writing 1 to PINxn toggles the corresponding PORTxn bit (regardless of DDRx)
// turns on led 1 with only AVR registers (DDRX , PORTX, PINX)
int main() int main()
{ {
// registers :
// DDRx : (Data Direction Register) Controls whether each pin is an input or output
// - 1 = output (pull-up off)
// - 0 = input
// PORTx : (Port Data Register)
// if DDRx = 1 (output mode) : Controls the output state of a pin when it's configured as an output
// - 1 = HIGH (5V?) (VCC)
// - 0 = LOW (0V) (GND)
// if DDRx = 0 (input mode) : Controls the internal pull-up resistor when the pin is an input
// - 1 = pull-up on
// - 0 = pull-up off (pin floats)
// PINx : (Pin Input Register) Reads the current logical state of a pin
// Reflects the actual voltage on the pin
// Special feature: Writing 1 to PINxn toggles the corresponding PORTxn bit (regardless of DDRx)
// turns on led 1 // turns on led 1
SET(DDRB, D1); // make PB0 as OUTPUT (pullup is off) SET(DDRB, D1); // make PB0 as OUTPUT (pullup is off)
SET(PORTB, D1); // make PB0 as HIGH (LED turns ON) SET(PORTB, D1); // make PB0 as HIGH (LED turns ON)
// SET(DDRB, D2); // make PB1 as OUTPUT (pullup is off)
// CLEAR(PORTB, D2); // make PB1 as LOW (LED turns OFF)
// CLEAR(DDRB, D3); // make PB2 as INPUT
// SET(PORTB, D3); // make PB2 pullup on
// CLEAR(DDRB, D4); // make PB4 as INPUT
// CLEAR(PORTB, D4); // make PB4 pullup off
////////////////////////////////
// TEST weird behavior of PIN register :
// in initial tests, using PIN register to toggle ON two leds only worked for the second one
// after some tests, this behavior is not anymore
//
// test 1 : only led 3 turns on
// SET(DDRB, D1);
// CLEAR(PORTB, D1);
// SET(PINB, D1);
// SET(DDRB, D3);
// CLEAR(PORTB, D3);
// SET(PINB, D3);
//
// test 2 : only led 3 turns on
// SET(DDRB, D1);
// CLEAR(PORTB, D1);
// SET(DDRB, D3);
// CLEAR(PORTB, D3);
// SET(PINB, D1);
// SET(PINB, D3);
//
// test 3 : both leds turns on
// SET(DDRB, D1);
// CLEAR(PORTB, D1);
// SET(DDRB, D3);
// CLEAR(PORTB, D3);
// PINB = (1 << D1) | (1 << D3);
//
// test 4 : both leds turns on
// SET(DDRB, D1);
// CLEAR(PORTB, D1);
// SET(DDRB, D3);
// CLEAR(PORTB, D3);
// SET(PINB, D1);
// _delay_us(500);
// SET(PINB, D3);
//
////////////////////////////////
return 0; return 0;
} }

View File

@@ -1 +1,43 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
AVRGCC_MCU_TYPE = atmega328p
AVRDUDE_MCU_TYPE = m328p
BAUD_RATE = 115200
SERIAL_PORT = /dev/ttyUSB0
PROGRAMMER_ID = arduino
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
all: hex flash
hex: $(TARGET).hex
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
$(TARGET).bin: $(TARGET).c
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
# https://linux.die.net/man/1/avr-objcopy
$(TARGET).hex: $(TARGET).bin
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
flash:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -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
.PHONY : all clean hex flash restore

View File

@@ -1,67 +1,101 @@
#include <avr/io.h> #include <avr/io.h>
#include <util/delay.h>
// stringify // test with https://www.onlinegdb.com/online_c_compiler
#define STRINGIFY_HELPER(x) #x // // V1
#define STRINGIFY(x) STRINGIFY_HELPER(x) //
// // macro to extract port and bit from a single pin
// #define _PORT(pin) ((pin) >> 3)
// #define _BIT(pin) ((pin) & 0x07) // 0x07 is 00000111
//
// // helper macros for port name concatenation
// #define _CONCAT(a, b) a ## b
// #define PORT_REGISTER(pin) _CONCAT(PORT, _PORT(pin))
// #define DDR_REGISTER(pin) _CONCAT(DDR, _PORT(pin))
// #define PIN_REGISTER(pin) _CONCAT(PIN, _PORT(pin))
//
// // Macros to set/clear/toggle specific bit
// #define SET(REGISTER, PIN) REGISTER |= 1 << _BIT(PIN)
// #define CLEAR(REGISTER, PIN) REGISTER &= ~(1 << _BIT(PIN))
// #define TOGGLE(REGISTER, PIN) REGISTER ^= 1 << _BIT(PIN)
// #define MODE_OUTPUT(PIN) (DDR_REGISTER(PIN) |= 1 << _BIT(PIN))
// #define MODE_INPUT(PIN) (DDR_REGISTER(PIN) &= ~(1 << _BIT(PIN)))
//
// // Test and check macros
// #define TEST_PIN(PIN) (PIN_REGISTER(PIN) & (1 << _BIT(PIN)))
// #define IS_SET(PIN) (TEST(PIN) != 0)
// #define IS_CLEAR(PIN) (TEST(PIN) == 0)
//
// // Pin definitions
// #define D1 (0 + (1 << 3)) // Port B, bit 0
// #define D2 (1 + (1 << 3)) // Port B, bit 1
// #define D3 (2 + (1 << 3)) // Port B, bit 2
// #define D4 (4 + (1 << 3)) // Port B, bit 4
// #define SW1 (2 + (3 << 3)) // Port D, bit 2
// #define SW2 (4 + (3 << 3)) // Port D, bit 4
// concatenate // // V2
#define CONCAT_HELPER(x, y) x ## y //
#define CONCAT(x, y) CONCAT_HELPER(x, y) // // Define the ports
// #define PORT_B 0 // Port A (represented by 0)
// #define PORT_C 1 // Port B (represented by 1)
// #define PORT_D 2 // Port C (represented by 2)
//
// // Macros to extract the port and bit
// #define _PORT_INT(pin) ((pin) >> 3) // Extract the port
// #define _PORT(pin) \
// ((_PORT_INT(pin)) == PORT_B ? 'B' : \
// ((_PORT_INT(pin)) == PORT_C ? 'C' : \
// ((_PORT_INT(pin)) == PORT_D ? 'D' : \
// 'X')))
// #define _BIT(pin) ((pin) & 0x07) // Extract the bit
//
// // Macros to set/clear/toggle specific bit
// #define SET(REGISTER, PIN) REGISTER |= 1 << _BIT(PIN)
// #define CLEAR(REGISTER, PIN) REGISTER &= ~(1 << _BIT(PIN))
// #define TOGGLE(REGISTER, PIN) REGISTER ^= 1 << _BIT(PIN)
// #define MODE_OUTPUT(PIN) (_PORT(PIN) |= 1 << _BIT(PIN))
// #define MODE_INPUT(PIN) (_PORT(PIN) &= ~(1 << _BIT(PIN)))
//
// // Test and check macros
// #define TEST(PIN) (PIN_REGISTER(PIN) & (1 << _BIT(PIN)))
// #define IS_SET(PIN) (TEST(PIN) != 0)
// #define IS_CLEAR(PIN) (TEST(PIN) == 0)
//
// // Define each LED's port and bit using macros
// #define D1 (PORT_B << 3 | 0) // LED1 is on Port B, bit 0
// #define D2 (PORT_B << 3 | 1) // LED2 is on Port A, bit 1
// #define D3 (PORT_B << 3 | 2) // LED3 is on Port C, bit 2
// #define D4 (PORT_B << 3 | 4) // LED4 is on Port C, bit 4
// get argument // V0
#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
// actions on registers #define SET(REGISTER, BIT) REGISTER |= 1 << BIT
#define SET(register, bit) register |= 1 << bit #define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
#define CLEAR(register, bit) register &= ~(1 << bit) #define TEST(REGISTER, BIT) REGISTER & 1 << BIT
#define TEST(register, bit) register & 1 << bit #define TEST_PIN(PORT, BIT) PIN ## PORT & 1 << BIT
#define TOGGLE(register, bit) register ^= 1 << bit #define TOGGLE(REGISTER, BIT) REGISTER ^= 1 << BIT
#define MODE_INPUT(PORT, BIT) CLEAR(DDR ## PORT, BIT)
#define MODE_OUTPUT(PORT, BIT) SET(DDR ## PORT, BIT)
#define IS_PIN_SET(PORT, BIT) (TEST_PIN(PORT, BIT)) == 0
#define IS_PIN_CLEAR(PORT, BIT) (TEST_PIN(PORT, BIT)) == 1
// actions on elements #define D1 0
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem)) #define D2 1
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem)) #define D3 2
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem)) #define D4 4
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem)) #define SW1 2
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem)) #define SW2 4
#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)
// bits
#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)
#define BUTTON(id)
// END MACROS
// turn on LED1 when BUTTON1 is pressed
int main() int main()
{ {
MODE_OUTPUT(LED1); MODE_OUTPUT(B, D1);
MODE_INPUT(BUTTON1); MODE_INPUT(D, SW1);
while(1) { while(1) {
if (IS_PIN_SET(BUTTON1)) { if (IS_PIN_SET(D, SW1)) {
SET_ELEM(LED1); SET(PORTB, D1);
} else { } else {
CLEAR_ELEM(LED1); CLEAR(PORTB, D1);
} }
} }
return 0; return 0;

View File

@@ -1 +1,43 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
AVRGCC_MCU_TYPE = atmega328p
AVRDUDE_MCU_TYPE = m328p
BAUD_RATE = 115200
SERIAL_PORT = /dev/ttyUSB0
PROGRAMMER_ID = arduino
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
all: hex flash
hex: $(TARGET).hex
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
$(TARGET).bin: $(TARGET).c
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
# https://linux.die.net/man/1/avr-objcopy
$(TARGET).hex: $(TARGET).bin
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
flash:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -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
.PHONY : all clean hex flash restore

View File

@@ -1,54 +0,0 @@
#ifndef HEADERS_H
#define HEADERS_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)
// get argument
#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
// actions 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
// actions on elements
#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)
// bits
#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)
#define BUTTON(id)
#endif

View File

@@ -1,17 +1,32 @@
#include <avr/io.h> #include <avr/io.h>
#include <util/delay.h> #include <util/delay.h>
#include "macros.h" #define SET(REGISTER, BIT) REGISTER |= 1 << BIT
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
#define TEST(REGISTER, BIT) REGISTER & 1 << BIT
#define TEST_PIN(PORT, BIT) PIN ## PORT & 1 << BIT
#define TOGGLE(REGISTER, BIT) REGISTER ^= 1 << BIT
#define TOGGLE_PIN(PORT, BIT) PIN ## PORT |= 1 << BIT
#define MODE_INPUT(PORT, BIT) CLEAR(DDR ## PORT, BIT)
#define MODE_OUTPUT(PORT, BIT) SET(DDR ## PORT, BIT)
#define IS_PIN_SET(PORT, BIT) (TEST_PIN(PORT, BIT)) == 0
#define IS_PIN_CLEAR(PORT, BIT) (TEST_PIN(PORT, BIT)) == 1
#define D1 0
#define D2 1
#define D3 2
#define D4 4
#define SW1 2
#define SW2 4
// toggle LED1 when BUTTON1 is pressed
int main() { int main() {
MODE_OUTPUT(LED1); MODE_OUTPUT(B, D1);
MODE_INPUT(BUTTON1); MODE_INPUT(D, SW1);
while(1) { while(1) {
if (IS_PIN_SET(BUTTON1)) { if (IS_PIN_SET(D, SW1)) {
TOGGLE_PIN(LED1); TOGGLE_PIN(B, D1);
_delay_ms(20); _delay_ms(20);
while(IS_PIN_SET(BUTTON1)) { while(IS_PIN_SET(D, SW1)) {
continue; continue;
} }
_delay_ms(20); _delay_ms(20);

View File

@@ -1 +1,43 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
AVRGCC_MCU_TYPE = atmega328p
AVRDUDE_MCU_TYPE = m328p
BAUD_RATE = 115200
SERIAL_PORT = /dev/ttyUSB0
PROGRAMMER_ID = arduino
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
all: hex flash
hex: $(TARGET).hex
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
$(TARGET).bin: $(TARGET).c
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
# https://linux.die.net/man/1/avr-objcopy
$(TARGET).hex: $(TARGET).bin
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
flash:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -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
.PHONY : all clean hex flash restore

View File

@@ -1,47 +0,0 @@
#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
// Actions on elements
#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

View File

@@ -1,8 +1,23 @@
#include <avr/io.h> #include <avr/io.h>
#include <util/delay.h> #include <util/delay.h>
#include "utils.h" #define SET(REGISTER, BIT) REGISTER |= 1 << BIT
#include "bitmanip.h" #define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
#define TEST(REGISTER, BIT) REGISTER & 1 << BIT
#define TEST_PIN(PORT, BIT) PIN ## PORT & 1 << BIT
#define TOGGLE(REGISTER, BIT) REGISTER ^= 1 << BIT
#define TOGGLE_PIN(PORT, BIT) PIN ## PORT |= 1 << BIT
#define MODE_INPUT(PORT, BIT) CLEAR(DDR ## PORT, BIT)
#define MODE_OUTPUT(PORT, BIT) SET(DDR ## PORT, BIT)
#define IS_PIN_SET(PORT, BIT) (TEST_PIN(PORT, BIT)) == 0
#define IS_PIN_CLEAR(PORT, BIT) (TEST_PIN(PORT, BIT)) == 1
#define D1 0
#define D2 1
#define D3 2
#define D4 4
#define SW1 2
#define SW2 4
typedef struct { typedef struct {
int *value; int *value;
@@ -42,24 +57,23 @@ void decrement_led(void *param) {
} }
void on_press(int bit, void (*action)(void*), void *params) { void on_press(int bit, void (*action)(void*), void *params) {
if ((TEST(PIND, bit)) == 0) { if (IS_PIN_SET(D, bit)) {
action(params); action(params);
_delay_ms(20); _delay_ms(20);
while ((TEST(PIND, bit)) == 0) { while (IS_PIN_SET(D, bit)) {
continue; continue;
} }
_delay_ms(20); _delay_ms(20);
} }
} }
// write a program that increments and decrements a binary number using the buttons, and displays the result on the LEDs
int main() { int main() {
MODE_OUTPUT(LED1); MODE_OUTPUT(B, D1);
MODE_OUTPUT(LED2); MODE_OUTPUT(B, D2);
MODE_OUTPUT(LED3); MODE_OUTPUT(B, D3);
MODE_OUTPUT(LED4); MODE_OUTPUT(B, D4);
MODE_INPUT(BUTTON1); MODE_INPUT(D, SW1);
MODE_INPUT(BUTTON2); MODE_INPUT(D, SW2);
int value = 0; int value = 0;
int max = 15; int max = 15;

View File

@@ -1,12 +0,0 @@
#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)
#endif // UTILS_H

View File

@@ -1 +1,43 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
AVRGCC_MCU_TYPE = atmega328p
AVRDUDE_MCU_TYPE = m328p
BAUD_RATE = 115200
SERIAL_PORT = /dev/ttyUSB0
PROGRAMMER_ID = arduino
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
all: hex flash
hex: $(TARGET).hex
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
$(TARGET).bin: $(TARGET).c
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
# https://linux.die.net/man/1/avr-objcopy
$(TARGET).hex: $(TARGET).bin
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
flash:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -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
.PHONY : all clean hex flash restore

View File

@@ -1,47 +0,0 @@
#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
// Actions on elements
#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

View File

@@ -1,33 +1,65 @@
#include <avr/io.h> #include <avr/io.h>
#include "utils.h" // #define FIRST_LETTER_IMPL(x) #x[0]
#include "bitmanip.h" // #define FIRST_LETTER(x) FIRST_LETTER_IMPL(x)
// #define PORT_LETTER(PIN) FIRST_LETTER(PIN)
// TIMER // global registers
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024 #define SET(register, bit) register |= 1 << bit
// table 16-5 : prescale sets #define CLEAR(register, bit) register &= ~(1 << bit)
#define PRESCALE_SET(value) \ #define TEST(register, bit) register & 1 << bit
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \ #define TOGGLE(register, bit) register ^= 1 << bit
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \ // actions on ports
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \ #define TEST_PIN(port, bit) TEST(PIN ## port, bit)
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \ #define TOGGLE_PIN(port, bit) SET(PIN ## port, bit)
(0<<CS12 | 0<<CS11 | 0<<CS10)) #define MODE_INPUT(port, bit) CLEAR(DDR ## port, bit)
#define MODE_OUTPUT(port, bit) SET(DDR ## port, bit)
#define IS_PIN_SET(port, bit) (TEST_PIN(port, bit)) == 0
#define IS_PIN_CLEAR(port, bit) (TEST_PIN(port, bit)) == 1
#define TURN_ON(_PORT, BIT) SET(PORT ## _PORT, BIT)
#define TURN_OFF(_PORT, BIT) CLEAR(PORT ## _PORT, BIT)
// LEDs
#define TURN_ON_LED(bit) SET(PORTB, bit)
#define TURN_OFF_LED(bit) CLEAR(PORTB, bit)
#define TOGGLE_LED(led) TOGGLE_PIN(B, led)
// ELEMENTS
#define D1 0
#define D2 1
#define D3 2
#define D4 4
#define SW1 2
#define SW2 4
// TIME
#define PRESCALE_VALUE 1024
#if (PRESCALE_VALUE == 1)
#define PRESCALE_SET (1 << CS10)
#elif (PRESCALE_VALUE == 8)
#define PRESCALE_SET (1 << CS11)
#elif (PRESCALE_VALUE == 64)
#define PRESCALE_SET (1 << CS10) | (1 << CS11)
#elif (PRESCALE_VALUE == 256)
#define PRESCALE_SET (1 << CS12)
#elif (PRESCALE_VALUE == 1024)
#define PRESCALE_SET (1 << CS10) | (1 << CS12)
#endif
#define TIME_MS(ms) (((F_CPU / PRESCALE_VALUE) * ms) / 1000) #define TIME_MS(ms) (((F_CPU / PRESCALE_VALUE) * ms) / 1000)
// END MACROS
// write a program that blinks an LED every 500ms using a software timer
int main() { int main() {
MODE_OUTPUT(LED2); MODE_OUTPUT(B, D2);
CLEAR_ELEM(LED2); TURN_OFF_LED(D2);
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // 16.4 : set timer according to prescale value, in register TCCR1B, table 16-5 : prescale sets TCCR1B |= (PRESCALE_SET); // set timer with prescale
// -> 16.4 : set timer with bits CS10-12, in register TCCR1B
// -> table 16-5 : prescale values
while(1) { while(1) {
if (TCNT1 >= TIME_MS(500)) { // 16.11.4 : read timer with register TCNT1 (read/write allowed), that combines two 8 bits registers if (TCNT1 >= TIME_MS(500)) { // 16.11.4 : read timer with register TCNT1 (read/write allowed), that combines two 8 bits registers
TOGGLE_PIN(LED2); TOGGLE_LED(D2);
TCNT1 = 0; // reset timer value, also in register TCNT1 TCNT1 = 0; // reset timer value, also in register TCNT1
} }
} }
} }

View File

@@ -1,12 +0,0 @@
#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)
#endif // UTILS_H

View File

@@ -1 +1,43 @@
include ../../Makefile # frequency of the CPU (in Hz)
F_CPU = 16000000UL
TARGET = main
CC = avr-gcc
AVRGCC_MCU_TYPE = atmega328p
AVRDUDE_MCU_TYPE = m328p
BAUD_RATE = 115200
SERIAL_PORT = /dev/ttyUSB0
PROGRAMMER_ID = arduino
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
all: hex flash
hex: $(TARGET).hex
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
$(TARGET).bin: $(TARGET).c
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
# https://linux.die.net/man/1/avr-objcopy
$(TARGET).hex: $(TARGET).bin
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
flash:
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -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
.PHONY : all clean hex flash restore

View File

@@ -1,47 +0,0 @@
#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
// Actions on elements
#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

View File

@@ -1,25 +1,72 @@
#include <avr/io.h> #include <avr/io.h>
#include "utils.h" // #define FIRST_LETTER_IMPL(x) #x[0]
#include "bitmanip.h" // #define FIRST_LETTER(x) FIRST_LETTER_IMPL(x)
#include "timer.h" // #define PORT_LETTER(PIN) FIRST_LETTER(PIN)
#define PERIOD 500 // global registers
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024 #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
// actions on ports
#define TEST_PIN(port, bit) TEST(PIN ## port, bit)
#define TOGGLE_PIN(port, bit) SET(PIN ## port, bit)
#define MODE_INPUT(port, bit) CLEAR(DDR ## port, bit)
#define MODE_OUTPUT(port, bit) SET(DDR ## port, bit)
#define IS_PIN_SET(port, bit) (TEST_PIN(port, bit)) == 0
#define IS_PIN_CLEAR(port, bit) (TEST_PIN(port, bit)) == 1
#define TURN_ON(_PORT, BIT) SET(PORT ## _PORT, BIT)
#define TURN_OFF(_PORT, BIT) CLEAR(PORT ## _PORT, BIT)
// LEDs
#define TURN_ON_LED(bit) SET(PORTB, bit)
#define TURN_OFF_LED(bit) CLEAR(PORTB, bit)
#define TOGGLE_LED(led) TOGGLE_PIN(B, led)
// ELEMENTS
#define D1 0
#define D2 1
#define D3 2
#define D4 4
#define SW1 2
#define SW2 4
// TIME
#define PRESCALE_VALUE 1024
#if (PRESCALE_VALUE == 1)
#define PRESCALE_SET (1 << CS10)
#elif (PRESCALE_VALUE == 8)
#define PRESCALE_SET (1 << CS11)
#elif (PRESCALE_VALUE == 64)
#define PRESCALE_SET (1 << CS10) | (1 << CS11)
#elif (PRESCALE_VALUE == 256)
#define PRESCALE_SET (1 << CS12)
#elif (PRESCALE_VALUE == 1024)
#define PRESCALE_SET (1 << CS10) | (1 << CS12)
#endif
#define TIME_MS(ms) (((F_CPU / PRESCALE_VALUE) * ms) / 1000)
// led turns on and off every PERIOD ms using CTC timer
int main() { int main() {
MODE_OUTPUT(LED2); MODE_OUTPUT(B, D2);
TCCR1B |= (1 << WGM12); // Table 16-4 : set timer in CTC (Clear Time on Compare) mode, use bit WGM12, located in register TCCR1B (16.11.2) TCCR1B |= (1 << WGM12); // set timer in CTC (Clear Time on Compare) mode
// -> Table 16-4 : use bit WGM12 to set mode ctc
// -> 16.11.2 : bit WGM12 is located in register TCCR1B
TCCR1A |= (1 << COM1A0); // 14.3.1 : set Compare Output with COM1A0, it toggles OC1A on compare match (Table 16-1), OC1A is alternate function for PORTB1 (Table 14-3) TCCR1A |= (1 << COM1A0 ) ; // Enable timer 1 Compare Output channel A in toggle mode
// -> Table 14-3 : alternate functions for PORTB1 is OC1A (Timer/Counter1 Output Compare Match A Output)
// -> 14.3.1 : OC1A/PCINT1 Port B, Bit 1
OCR1A = TIME_MS(PERIOD, PRESCALE_VALUE); // Table 16-4 : set CTC compare value on channel A, the counter is cleared to zero when the counter value (TCNT1) matches the OCR1A register OCR1A = TIME_MS(500); // set CTC compare value
// -> Table 16-4 : the value to reset the timer is the Output Compare Registers OCR1A
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); TCCR1B |= (PRESCALE_SET);
while(1); while(1) {
continue;
}
} }

View File

@@ -1,14 +0,0 @@
#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)
#endif // TIMER_H

View File

@@ -1,12 +0,0 @@
#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)
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,47 +0,0 @@
#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
// Actions on elements
#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

View File

@@ -1,28 +0,0 @@
#include <avr/io.h>
#include "utils.h"
#include "bitmanip.h"
#include "timer.h"
#define PERIOD 1000
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
#define DUTY_CYCLE 10
// turns on led2 at 1Hz and duty cycle of 10%, not using PORTx, with empty infinite loop
int main() {
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, PRESCALE_VALUE); // Table 16-4 : set the period (compare TOP value)
OCR1A = TIME_MS(PERCENT(DUTY_CYCLE, PERIOD), 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(PRESCALE_VALUE)); // start the timer with the prescaler
while(1);
}

View File

@@ -1,14 +0,0 @@
#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)
#endif // TIMER_H

View File

@@ -1,15 +0,0 @@
#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)
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,47 +0,0 @@
#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
// Actions on elements
#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

View File

@@ -1,73 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include "utils.h"
#include "bitmanip.h"
#include "timer.h"
#define PERIOD 1000
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
#define DUTY_CYCLE 10
#define MAX 100 // max duty cycle percentage
#define MIN 10 // min duty cycle percentage
// 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)
// END MACROS
volatile int duty_cycle = DUTY_CYCLE;
void increment_duty_cycle() {
if(duty_cycle < MAX) {
duty_cycle += 10;
}
OCR1A = TIME_MS(PERCENT(duty_cycle, PERIOD), PRESCALE_VALUE);
}
void decrement_duty_cycle() {
if(duty_cycle > MIN) {
duty_cycle -= 10;
}
OCR1A = TIME_MS(PERCENT(duty_cycle, PERIOD), PRESCALE_VALUE);
}
void on_press(int bit, void (*action)(void)) {
if ((TEST(PIND, bit)) == 0) {
action();
_delay_ms(20);
while ((TEST(PIND, bit)) == 0) {
continue;
}
_delay_ms(20);
}
}
// led turns on and off every PERIOD ms using Fast PWM timer, with duty cycle controlled by SW1 and SW2
int main() {
MODE_OUTPUT(LED2);
TCCR1A |= FAST_PWM_TOP_ICR1_IN_TCCR1A; // Table 16-4 : set timer in Fast PWM (Pulse With Modulation) mode with TOP = ICR1 (Mode 14)
TCCR1B |= FAST_PWM_TOP_ICR1_IN_TCCR1B;
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, PRESCALE_VALUE); // Table 16-4 : set the period (compare TOP value)
OCR1A = TIME_MS(PERCENT(DUTY_CYCLE, PERIOD), PRESCALE_VALUE); // 16.9.3 : set the duty cycle to DUTY_CYCLE% of the time in channel A -> OC1A (alternate function of PORTB1, aka LED2) is cleared when TCNT1 (the counter value) equals OCR1A
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // start the timer with the prescaler
while(1) {
on_press(SW1, increment_duty_cycle);
on_press(SW2, decrement_duty_cycle);
}
}

View File

@@ -1,14 +0,0 @@
#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)
#endif // TIMER_H

View File

@@ -1,15 +0,0 @@
#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)
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,53 +0,0 @@
#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

View File

@@ -1,60 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
// USART
// Table 20-1 : Baud Rate Calculation
#define USART_BAUDRATE 115200
#define BAUD_PRESCALER (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)
// END MACROS
// 20.4 Frame Formats : 8N1 : 8 data bits, no parity, 1 stop bit
// 20.5 USART Initialization : (1) setting baud rate, (2) setting frame format, (3) enabling the Transmitter or the Receiver
void uart_init() {
UBRR0H = (unsigned char) (BAUD_PRESCALER >> 8); // 20.11.5 : UBRRnL and UBRRnH USART Baud Rate Registers
UBRR0L = (unsigned char) BAUD_PRESCALER;
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B |= RECEIVER_DISABLED | TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver and/or Transmitter
}
void uart_tx(char c) {
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDR emission buffer is empty, if UDREn flag is 1, UCSRnA register is empty
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn USART I/O Data Register (read and write)
}
// write Z on serial port, at a 1Hz frequency
// `screen /dev/ttyUSB0 115200`
int main() {
uart_init();
while (1) {
uart_tx('Z');
_delay_ms(1000);
}
}

View File

@@ -1,16 +0,0 @@
#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)))
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,53 +0,0 @@
#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

View File

@@ -1,8 +0,0 @@
#ifndef INTERRUPT_H
#define INTERRUPT_H
// 7.3.1 : SREG AVR Status Register
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
#endif // INTERRUPT_H

View File

@@ -1,63 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
#include "timer.h"
#include "usart.h"
#include "interrupt.h"
// TIMER
#define PERIOD 2000
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
// USART
#define USART_BAUDRATE 115200 // Table 20-1 : Baud Rate Calculation
// END MACROS
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 |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B |= RECEIVER_DISABLED | TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver and/or Transmitter
}
void uart_tx(char c) {
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDR emission buffer is empty, if UDREn flag is 1, UCSRnA register is 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++;
}
}
// print "Hello World!\n", on serial port, every 2 seconds, with empty infinite loop
// `screen /dev/ttyUSB0 115200`
int main() {
uart_init();
TCCR1A |= CTC_TOP_OCR1A_IN_TCCR1A; // Table 16-4 : set timer in CTC (Clear Time on Compare) mode
TCCR1B |= CTC_TOP_OCR1A_IN_TCCR1B;
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I Global Interrupt Enable
TIMSK1 |= INTERRUPT_ENABLE_CHANNEL_A; // 16.11.8 : enables the Timer1 Compare Match A interrupt, this makes the MCU react when OCR1A == TCNT1 by calling TIMER1_COMPA_vect
OCR1A = TIME_MS(PERIOD, PRESCALE_VALUE); // Table 16-4 : set CTC compare value on channel A, the counter is cleared to zero when the counter value (TCNT1) matches the OCR1A register
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // 16.4 : set timer according to prescale value, in register TCCR1B, table 16-5 : prescale sets
while(1);
}
// ISR interrupt macro : https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
ISR(TIMER1_COMPA_vect) { // Table 12-7 : we select the code for timer 1 on channel A
uart_printstr("Hello World!\r\n"); // \n and \r : https://stackoverflow.com/questions/7812142/how-to-toggle-cr-lf-in-gnu-screen
}

View File

@@ -1,27 +0,0 @@
#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

View File

@@ -1,27 +0,0 @@
#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)
#endif // USART_H

View File

@@ -1,16 +0,0 @@
#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)))
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,53 +0,0 @@
#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

View File

@@ -1,8 +0,0 @@
#ifndef INTERRUPT_H
#define INTERRUPT_H
// 7.3.1 : SREG AVR Status Register
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
#endif // INTERRUPT_H

View File

@@ -1,43 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
#include "usart.h"
// USART
#define USART_BAUDRATE 115200
// END MACROS
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 |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver and/or Transmitter
}
void uart_tx(char c) {
while (TEST(UCSR0A, UDRE0) == 0); // 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)
}
char uart_rx(void) {
while (TEST(UCSR0A, RXC0) == 0); // 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)
}
// send back caracters received on serial port
// `screen /dev/ttyUSB0 115200`
int main() {
uart_init();
char received_char;
while(1) {
received_char = uart_rx();
uart_tx(received_char);
}
}

View File

@@ -1,27 +0,0 @@
#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

View File

@@ -1,27 +0,0 @@
#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)
#endif // USART_H

View File

@@ -1,16 +0,0 @@
#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)))
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,53 +0,0 @@
#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

View File

@@ -1,8 +0,0 @@
#ifndef INTERRUPT_H
#define INTERRUPT_H
// 7.3.1 : SREG AVR Status Register
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
#endif // INTERRUPT_H

View File

@@ -1,53 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> // https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
#include "utils.h"
#include "bitmanip.h"
#include "timer.h"
#include "usart.h"
#include "interrupt.h"
// USART
#define USART_BAUDRATE 115200
// TIMER
#define PERIOD 2000
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
// END MACROS
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 |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver
}
// char uart_rx(void) {
// while (TEST(UCSR0A, RXC0) == 0); // 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) == 0); // 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)
}
// send back caracters received on serial port with case toggling, using interupt and empty infinite loop
// `screen /dev/ttyUSB0 115200`
int main() {
uart_init();
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I Global Interrupt Enable
while(1);
}
ISR(USART_RX_vect) { // Table 12-7 : we select the code for USART Receive
// char received_char = uart_rx();
char received_char = UDR0; // Read received character
uart_tx(SWITCH_CASE(received_char)); // Toggle case and send back
}

View File

@@ -1,27 +0,0 @@
#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

View File

@@ -1,31 +0,0 @@
#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

View File

@@ -1,19 +0,0 @@
#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))
#endif // UTILS_H

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,53 +0,0 @@
#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

View File

@@ -1,8 +0,0 @@
#ifndef INTERRUPT_H
#define INTERRUPT_H
// 7.3.1 : SREG AVR Status Register
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
#endif // INTERRUPT_H

View File

@@ -1,203 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> // https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
#include "utils.h"
#include "bitmanip.h"
#include "timer.h"
#include "usart.h"
#include "interrupt.h"
// USART
#define USART_BAUDRATE 115200
// TIMER
#define PERIOD 2000
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
// END MACROS
// FUNCTION PROTOTYPES
void uart_init();
// char uart_rx(void);
void uart_tx(char c);
void uart_printstr(const char* str);
void remove_last_character();
void fill_str(char input);
int compare_str(volatile char *input_str, volatile char *base_str);
int strlength(volatile char *str);
void reset_message();
void ask_for_username();
void ask_for_password();
void on_error();
void on_success();
// GLOBAL VARIABLES
typedef enum {
USERNAME,
PASSWORD
} State;
volatile char username[] = "admin";
volatile char password[] = "password";
volatile char username_input[100] = {0};
volatile char password_input[100] = {0};
volatile int input_index = 0;
volatile State state = USERNAME;
volatile int username_correct = FALSE;
volatile int password_correct = FALSE;
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 |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver
}
// char uart_rx(void) {
// while (TEST(UCSR0A, RXC0) == 0); // 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) == 0); // 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++;
}
}
ISR(USART_RX_vect) { // Table 12-7 : we select the code for USART Receive
// char received_char = uart_rx();
char received_char = UDR0; // read received character
if (received_char == '\b' || received_char == 127) { // if backspace is received
if (input_index <= 0) 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 (state == USERNAME) {
if (compare_str(username_input, username)) {
username_correct = TRUE;
} else {
username_correct = FALSE;
// uart_printstr("(error1)");
}
state = PASSWORD;
input_index = 0;
uart_tx('\r');
uart_tx('\n');
ask_for_password();
} else if (state == PASSWORD) {
if (!username_correct) {
// uart_printstr("(error2)");
return reset_message();
}
if (!compare_str(password_input, password)) {
// uart_printstr("(error3)");
return reset_message();
}
uart_tx('\r');
uart_tx('\n');
on_success();
}
} else {
fill_str(received_char);
if (state == USERNAME) {
uart_tx(received_char);
}
else if (state == PASSWORD) {
uart_tx('*');
}
input_index++;
}
}
void fill_str(char input) {
if (input_index >= 100) {
// uart_printstr("(error4)");
return;
}
if (state == USERNAME) {
username_input[input_index] = input;
} else if (state == PASSWORD) {
password_input[input_index] = input;
}
}
void remove_last_character() {
if (state == USERNAME) {
username_input[input_index] = 0;
} else if (state == PASSWORD) {
password_input[input_index] = 0;
}
}
int compare_str(volatile char *input_str, volatile char *base_str) {
int base_length = strlength(base_str);
int input_length = strlength(input_str);
if (base_length != input_length) {
// uart_printstr("(error5)");
return FALSE;
}
for(int i = 0; i < base_length; i++) {
if (input_str[i] != base_str[i]) {
// uart_printstr("(error6)");
return FALSE;
}
}
return TRUE;
}
int strlength(volatile char *str) {
int length = 0;
while (*str) {
length++;
str++;
}
return length;
}
void reset_message() {
for(int i = 0; i < 100; i++) {
username_input[i] = 0;
password_input[i] = 0;
}
input_index = 0;
username_correct = FALSE;
password_correct = FALSE;
state = USERNAME;
uart_tx('\r');
uart_tx('\n');
on_error();
ask_for_username();
}
void ask_for_username() {
uart_printstr("Enter your login: \r\n username: ");
}
void ask_for_password() {
uart_printstr(" password: ");
}
void on_error() {
uart_printstr("Bad combinaison username/password\r\n\r\n");
}
void on_success() {
uart_printstr("Hello spectre!\r\nShall we play a game?\r\n");
}
// ask for username and password
// `screen /dev/ttyUSB0 115200`
int main() {
uart_init();
ask_for_username();
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I Global Interrupt Enable
while(1);
}

View File

@@ -1,27 +0,0 @@
#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

View File

@@ -1,31 +0,0 @@
#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

View File

@@ -1,23 +0,0 @@
#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

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,32 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
void rgb_d5_roll_colors() {
MODE_OUTPUT(RGB5_RED);
MODE_OUTPUT(RGB5_GEEN);
MODE_OUTPUT(RGB5_BLUE);
while(1) {
SET_ELEM(RGB5_RED);
_delay_ms(1000);
CLEAR_ELEM(RGB5_RED);
SET_ELEM(RGB5_GEEN);
_delay_ms(1000);
CLEAR_ELEM(RGB5_GEEN);
SET_ELEM(RGB5_BLUE);
_delay_ms(1000);
CLEAR_ELEM(RGB5_BLUE);
}
}
// led RGB D5 must turns on in red then green then blue in a loop
int main() {
while(1) {
rgb_d5_roll_colors();
}
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,44 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
void rgb_d5_roll_colors() {
MODE_OUTPUT(RGB5_RED);
MODE_OUTPUT(RGB5_GEEN);
MODE_OUTPUT(RGB5_BLUE);
while(1) {
// RED
PORTD = (1<<D5R) | (0<<D5G) | (0<<D5B);
_delay_ms(1000);
// GREEN
PORTD = (0<<D5R) | (1<<D5G) | (0<<D5B);
_delay_ms(1000);
// BLUE
PORTD = (0<<D5R) | (0<<D5G) | (1<<D5B);
_delay_ms(1000);
// YELLOW
PORTD = (1<<D5R) | (1<<D5G) | (0<<D5B);
_delay_ms(1000);
// CYAN
PORTD = (0<<D5R) | (1<<D5G) | (1<<D5B);
_delay_ms(1000);
// MAGENTA
PORTD = (1<<D5R) | (0<<D5G) | (1<<D5B);
_delay_ms(1000);
// WHITE
PORTD = (1<<D5R) | (1<<D5G) | (1<<D5B);
_delay_ms(1000);
}
}
// led RGB D5 must turns on in a loop of colors: red, green, blue, yellow, cyan, magenta, white
int main() {
while(1) {
rgb_d5_roll_colors();
}
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,69 +0,0 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
void init_rgb();
void set_rgb(uint8_t r, uint8_t g, uint8_t b);
void wheel(uint8_t pos) {
pos = 255 - pos;
if (pos < 85) {
set_rgb(255 - pos * 3, 0, pos * 3);
} else if (pos < 170) {
pos = pos - 85;
set_rgb(0, pos * 3, 255 - pos * 3);
} else {
pos = pos - 170;
set_rgb(pos * 3, 255 - pos * 3, 0);
}
}
// Table 14-9 : Port D Pins Alternate Functions
// OC2B (PD3) : Red
// OC0B (PD5) : Green
// OC0A (PD6) : Blue
void init_rgb() {
MODE_OUTPUT(RGB5_RED);
MODE_OUTPUT(RGB5_GEEN);
MODE_OUTPUT(RGB5_BLUE);
TCCR0A = 0; // 15.9.1 : Clear Timer0 control register A
TCCR0B = 0; // 15.9.2 : Clear Timer0 control register B
TCCR2A = 0; // Clear Timer2 control register A
TCCR0A |= (1 << WGM00) | (1 << WGM01); // Table 15-8 : Timer0 in Fast PWM mode
TCCR2A |= (1 << WGM20) | (1 << WGM21); // Table 18-8 : Timer2 in Fast PWM mode
TCCR0A |= (1 << COM0A1); // Table 15-3 : BLUE - Timer0 Non-inverting mode for Blue (OC0A -> PD6)
TCCR0A |= (1 << COM0B1); // Table 15-6 : GREEN - Timer0 Non-inverting mode for Green (OC0B -> PD5)
TCCR2A |= (1 << COM2B1); // Table 18-6 : RED - Timer2 Non-inverting mode for Red (OC2B -> PD3)
TCCR0B |= (1 << CS01); // Table 15-9 : Prescaler 8 → ~8kHz PWM frequency
TCCR2B |= (1 << CS21); // Table 18-9 : Prescaler 8 → ~8kHz PWM frequency
OCR0A = 0; // Blue OFF
OCR0B = 0; // Green OFF
OCR2B = 0; // Red OFF
}
void set_rgb(uint8_t r, uint8_t g, uint8_t b) {
OCR2B = r; // Red (PD3, Timer2 OCR2B)
OCR0B = g; // Green (PD5, Timer0 OCR0B)
OCR0A = b; // Blue (PD6, Timer0 OCR0A)
}
// led RGB D5 must turns on in a loop of colors using PWM
int main() {
init_rgb();
uint8_t pos = 0;
while (1) {
wheel(pos); // Set color based on wheel position
_delay_ms(10); // Small delay for smooth transition
pos++; // Increment color position
}
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,77 +0,0 @@
#include "header.h"
// Table 14-9 : Port D Pins Alternate Functions
// OC2B (PD3) : Red
// OC0B (PD5) : Green
// OC0A (PD6) : Blue
void init_rgb() {
MODE_OUTPUT(RGB5_RED);
MODE_OUTPUT(RGB5_GEEN);
MODE_OUTPUT(RGB5_BLUE);
TCCR0A = 0; // 15.9.1 : Clear Timer0 control register A
TCCR0B = 0; // 15.9.2 : Clear Timer0 control register B
TCCR2A = 0; // 18.11.1 : Clear Timer2 control register A
TCCR0A |= (1 << WGM00) | (1 << WGM01); // Table 15-8 : Timer0 in Fast PWM mode
TCCR2A |= (1 << WGM20) | (1 << WGM21); // Table 18-8 : Timer2 in Fast PWM mode
TCCR0A |= (1 << COM0A1); // Table 15-3 : BLUE - Timer0 Non-inverting mode for Blue (OC0A -> PD6)
TCCR0A |= (1 << COM0B1); // Table 15-6 : GREEN - Timer0 Non-inverting mode for Green (OC0B -> PD5)
TCCR2A |= (1 << COM2B1); // Table 18-6 : RED - Timer2 Non-inverting mode for Red (OC2B -> PD3)
TCCR0B |= (1 << CS01); // Table 15-9 : Prescaler 8 → ~8kHz PWM frequency
TCCR2B |= (1 << CS21); // Table 18-9 : Prescaler 8 → ~8kHz PWM frequency
OCR0A = 0; // Blue OFF
OCR0B = 0; // Green OFF
OCR2B = 0; // Red OFF
}
void set_rgb(uint8_t r, uint8_t g, uint8_t b) {
OCR0B = r; // Red (PD3, Timer2)
OCR0A = g; // Green (PD5, Timer0)
OCR2B = b; // Blue (PD6, Timer0)
}
// convert hex to int : https://stackoverflow.com/a/39052987
uint8_t hex_to_int(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
return 0;
}
// "<< 4" is equivalent to "* 16"
uint8_t get_red(char *input) {
if (input[0] != '#') {
return 0;
}
return (hex_to_int(input[1]) << 4) + hex_to_int(input[2]);
}
uint8_t get_green(char *input) {
if (input[0] != '#') {
return 0;
}
return (hex_to_int(input[3]) << 4) + hex_to_int(input[4]);
}
uint8_t get_blue(char *input) {
if (input[0] != '#') {
return 0;
}
return (hex_to_int(input[5]) << 4) + hex_to_int(input[6]);
}
void set_color(char *color_input) {
uint8_t r = get_red(color_input);
uint8_t g = get_green(color_input);
uint8_t b = get_blue(color_input);
set_rgb(r, g, b);
}

View File

@@ -1,38 +0,0 @@
#ifndef HEADER_H
#define HEADER_H
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
#include "usart.h"
#include "interrupt.h"
//
// PROTOTYPES
//
// main.c
// colors.c
void init_rgb();
void set_rgb(uint8_t r, uint8_t g, uint8_t b);
uint8_t get_red(char *input);
uint8_t get_green(char *input);
uint8_t get_blue(char *input);
uint8_t hex_to_int(char c);
void uart_init();
void set_color(char *color_input);
// uart.c
void uart_init();
char uart_rx(void);
void uart_tx(char c);
// void uart_printstr(const char* str);
void remove_last_character();
void fill_str(char input);
int strlength(volatile char *str);
void reset_input();
int is_valid_color_input(char c);
#endif // HEADER_H

View File

@@ -1,11 +0,0 @@
#include "header.h"
// led RGB D5 must turns on in a loop of colors using PWM
int main() {
init_rgb();
uart_init();
while (1);
}

View File

@@ -1,121 +0,0 @@
#include "header.h"
// MACROS
// USART
#define USART_BAUDRATE 115200
#define INPUT_SIZE 7
// GLOBAL VARIABLES
volatile char color_input[INPUT_SIZE + 1] = {0};
volatile int input_index = 0;
//
// 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 |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I Global Interrupt Enable
}
char uart_rx(void) {
while (TEST(UCSR0A, RXC0) == 0); // 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) == 0); // 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++;
// }
// }
ISR(USART_RX_vect) { // Table 12-7 : 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++;
}
}
int is_valid_color_input(char c) {
if (input_index == 0) {
if (c == '#') {
return TRUE;
} else {
return FALSE;
}
}
if (input_index >= INPUT_SIZE) {
return FALSE;
}
if (c >= '0' && c <= '9') {
return TRUE;
} else if (c >= 'A' && c <= 'F') {
return TRUE;
} else if (c >= 'a' && c <= 'f') {
return TRUE;
}
return FALSE;
}
void fill_str(char input) {
if (input_index >= INPUT_SIZE) {
return;
}
color_input[input_index] = input;
}
void remove_last_character() {
color_input[input_index] = 0;
}
int strlength(volatile char *str) {
int length = 0;
while (*str) {
length++;
str++;
}
return length;
}
void reset_input() {
for(int i = 0; i < INPUT_SIZE; i++) {
color_input[i] = 0;
}
uart_tx('\r');
uart_tx('\n');
input_index = 0;
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,17 +0,0 @@
#ifndef HEADER_H
#define HEADER_H
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
#include "interrupt.h"
//
// PROTOTYPES
//
// main.c
#endif // HEADER_H

View File

@@ -1,43 +0,0 @@
#include "header.h"
// 14.3.3 : alternate functions on port D
// PD2 : - INT0 (External Interrupt 0 Input)
// - PCINT18 (Pin Change Interrupt 18)
// 12.4 : Interrupt Vectors in ATmega328 and ATmega328P
// - INT0 : External Interrupt Request 0
typedef enum {
DOWN,
UP
} State;
volatile uint8_t button_state = UP;
// Table 13-2 : interrupt types
#define INT0_LOW ((0 << ISC01) | (0 << ISC00))
#define INT0_LOGICAL ((0 << ISC01) | (1 << ISC00))
#define INT0_FALLING ((1 << ISC01) | (0 << ISC00))
#define INT0_RAISING ((1 << ISC01) | (1 << ISC00))
// use interruption to change led1 state when button1 is pressed
int main() {
MODE_OUTPUT(LED1);
CLEAR_ELEM(LED1);
MODE_INPUT(BUTTON1);
PULLUP_ON(BUTTON1);
SREG |= ENABLE_GLOBAL_INTERRUPT;
EIMSK = (1 << INT0); // 13.2.2 : Enable INT0 interrupt (EIMSK External Interrupt Mask Register)
EICRA = INT0_LOGICAL; // Table 13-2 : trigger type (EICRA External Interrupt Control Register A)
while (1);
}
ISR(INT0_vect) {
button_state = (button_state == UP) ? DOWN : UP;
if (button_state == UP) {
TOGGLE_ELEM(LED1);
}
_delay_ms(50); // for debounce, bad idea to put it here in more complexe codes, it is blocking
EIFR |= (1 << INTF0); // 13.2.3 : clear flag, when the flag is set it triggers the interrupt, and eventhough it should be clear by the trigger, it can be set again by the bouncing
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,20 +0,0 @@
#ifndef HEADER_H
#define HEADER_H
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
#include "interrupt.h"
#include "timer.h"
//
// PROTOTYPES
//
// main.c
void blink_led_1();
void vary_duty();
#endif // HEADER_H

View File

@@ -1,138 +0,0 @@
#include "header.h"
// 14.3.1 : alternate functions for led2 PB1
// - OC1A (Timer/Counter1 Output Compare Match A Output)
// - 16.11.1 controlled by COM1A1:0 in TCCR1A
// - Table 16-2 : Compare Output Mode, Fast PWM
// (1 << COM1A1) | (0 << COM1A0) -> non-inverting mode
// - Table 16-4 : set timer 1 in fast PWM mode, with top as ICR1 or OCR1A
// - ICR1 : Input Capture Register ((1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (0 << WGM10))
// - OCR1A : Output Compare Register ((1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (1 << WGM10))
// -> if OCR1A is top, it's also duty cycle, so changing duty cycle will also change frequency
// -> if ICR1 is top, OCR1A is duty cycle, so it can be changed independantly
// - PCINT1 (Pin Change Interrupt 1) : to interrupt when pin change, in input mode only
// calulations
// - frequency is 16Mhz -> it means that the clock runs 16 000 000 times per seconds
// - and the timer1 can store 16 bits value of cycle -> which is 2^16 = 65536
// - so it will only last 65536/16000000 = 0,004096 second
// - if i want my cycle to be 0.001 second, prescaler 1 is enough
// - if i want my cycle to be 0.01 second, which prescaler ?
// - 8 * 0,004096 = 0.032768 -> it is enough
// - 64 * 0,004096 = 0.262144 -> it is largely enough
// - after how many "ticks" do i need to reset my clock, for a duration of 0.01s, for every prescalers :
// - 1 : (16000000 / 1) * 0.01 = 16000000 * 0.01 = 160000 "ticks"
// - 8 : (16000000 / 8) * 0.01 = 2000000 * 0.01 = 20000 "ticks"
// - 64 : (16000000 / 64) * 0.01 = 250000 * 0.01 = 2500 "ticks"
// - 256 : (16000000 / 256) * 0.01 = 62500 * 0.01 = 625 "ticks"
// - 1024 : (16000000 / 1024) * 0.01 = 15625 * 0.01 = 156.25 "ticks"
// - after how many "ticks" do i need to reset my clock, for a duration of 0.005s (*200/s), for every prescalers :
// - 1 : (16000000 / 1) * 0.005 = 16000000 * 0.005 = 80000 "ticks"
// - 8 : (16000000 / 8) * 0.005 = 2000000 * 0.005 = 10000 "ticks"
// - 64 : (16000000 / 64) * 0.005 = 250000 * 0.005 = 1250 "ticks"
// - 256 : (16000000 / 256) * 0.005 = 62500 * 0.005 = 312.5 "ticks"
// - 1024 : (16000000 / 1024) * 0.005 = 15625 * 0.005 = 78.125 "ticks"
// alternatively, can use the default values :
// - Fast PWM, 8-bit, TOP 0x00FF (255)
// - Fast PWM, 9-bit, TOP 0x01FF (511)
// - Fast PWM, 10-bit, TOP 0x03FF (1023)
// no need to set a second for the "blinking" with PWM and duty cycle :
// only need to use a top value convenient, like a multiple of 100
// if choose top value of 100 :
// - at prescaler 1 : 100 / 16000000 = 0.00000625s (it takes this time to do a cycle)
// - at prescaler 8 : (100 * 8) / 16000000 = 0.00005s
// - at prescaler 64 : (100 * 64) / 16000000 = 0.0004s
// - at prescaler 256 : (100 * 256) / 16000000 = 0.0016s
// - at prescaler 1024 : (100 * 1024) / 16000000 = 0.0064s
// if choose top value of 1000 :
// - at prescaler 1 : 1000 / 16000000 = 0.0000625s (it takes this time to do a cycle)
// - at prescaler 8 : (1000 * 8) / 16000000 = 0.0005s
// - at prescaler 64 : (1000 * 64) / 16000000 = 0.004s
// - at prescaler 256 : (1000 * 256) / 16000000 = 0.016s
// - at prescaler 1024 : (1000 * 1024) / 16000000 = 0.064s
// 16.9.3 : timer1 fast PWM
// TIMER 1
#define T1_PWM_PRESCALER 256 // can be 1, 8, 64, 256, 1024
#define T1_DUTY_CYCLE_PERCENT 9
// #define FREQUENCY_MS 1
#define T1_TOP_VALUE 1000
// TIMER 0
#define T0_PWM_PRESCALER 1024 // can be 1, 8, 64, 256, 1024
#define T0_FREQUENCY_MS 5
typedef enum {
DOWN,
UP
} Slope;
volatile uint8_t duty_cycle = T1_DUTY_CYCLE_PERCENT;
// using TIMER 1
void blink_led_1() {
TCCR1A = (1 << WGM11); // Table 16-4 : set timer1 in fast PWM mode 14, with TOP ICR1, so we can use OCR1A for duty cycle and keep ICR1 for frequency
TCCR1B = (1 << WGM13) | (1 << WGM12); // mode 15 with OCR1A TOP prevent using duty cycle trigger on OC1A (OCR1B is free but triggers OC1B -> PB2)
// other fast PWM modes 5, 6, and 7 uses predefined TOP, preventing to define a multiple of 100 for percent accuracy
TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM (14.3.1 : OC1A is alternate function of PB1)
TCCR1B |= T1_PRESCALE_SET(T1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values for timer 1
// ICR1 = TIME_MS(FREQUENCY_MS, T1_PWM_PRESCALER); // top value for Xms
ICR1 = T1_TOP_VALUE;
OCR1A = PERCENT(duty_cycle, ICR1); // 16.9.3 : duty cycle
}
// using TIMER 0
void vary_duty() {
TCCR0A = (1 << WGM01); // Table 15-8 : set timer0 in CTC mode, with TOP OCRA (15.9.1 : WGM01 in register TCCR0A)
OCR0A = TIME_MS(T0_FREQUENCY_MS, T0_PWM_PRESCALER); // 15.9.4 : compare value to trigger an Output Compare interrupt on register A
TCCR0B |= T0_PRESCALE_SET(T0_PWM_PRESCALER); // 15.9.2 : set the appropriate prescale values for timer 0
TIMSK0 = (1 << OCIE0A); // 15.9.6 : enable interrupt in timer 0
}
// use timers interruptions to varie led1 intensity using duty cycle, from 0% to 100% to 0% in 1 second
// timer1 sets the led duty cycle, timer0 change the duty cycle percentage
int main() {
MODE_OUTPUT(LED1);
CLEAR_ELEM(LED1);
MODE_OUTPUT(LED2);
CLEAR_ELEM(LED2);
MODE_OUTPUT(LED3);
CLEAR_ELEM(LED3);
MODE_OUTPUT(LED4);
CLEAR_ELEM(LED4);
SREG |= ENABLE_GLOBAL_INTERRUPT;
blink_led_1();
vary_duty();
while (1);
}
ISR(TIMER0_COMPA_vect) {
volatile static Slope slope = UP;
if (slope == UP) {
if (duty_cycle >= 100) {
duty_cycle = 100;
slope = DOWN;
} else {
duty_cycle += 1;
}
} else if (slope == DOWN) {
if (duty_cycle <= 0) {
duty_cycle = 0;
slope = UP;
} else {
duty_cycle -= 1;
}
}
OCR1A = PERCENT(duty_cycle, ICR1);
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -1,30 +0,0 @@
#ifndef HEADER_H
#define HEADER_H
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "utils.h"
#include "bitmanip.h"
#include "interrupt.h"
#include "timer.h"
//
// PROTOTYPES
//
// main.c
void print_binary(int value);
void increment_int();
void decrement_int();
void increment_led();
void decrement_led();
void on_press(int bit, void (*action)(void));
//
// MACROS
//
#define MAX 15
#define MIN 0
#endif // HEADER_H

View File

@@ -1,143 +0,0 @@
#include "header.h"
// ALTERNATE FUNCTIONS :
// Table 14-9 : port D alternate functions
// BUTTON1 SW1 PD2 :
// -> INT0 (External Interrupt 0 Input)
// -> PCINT18 (Pin Change Interrupt 18)
// BUTTON2 SW2 PD4 :
// -> XCK (USART External Clock Input/Output)
// -> T0 (Timer/Counter 0 External Counter Input)
// -> PCINT20 (Pin Change Interrupt 20)
// EXTERNAL INTERRUPTS GROUP :
// 13.2.4 : pin change interrupt controle register (PCICR)
// -> bit PCIE2 for PCINT[23:16] (PCI2 Interrupt Vector)
// PCMSK2 to enable each pin
// INTERRUPT VECTORS NAME :
// Table 12-6 : interrupts vectors
// -> PCINT2_vect
// ENABLE PIN CHANGE INTERRUPT :
// 13.2.6 : PCMSK2 Pin Change Mask Register 2
// -> (1 << PCINT20) | (1 << PCINT18)
#define TIMER_TOP_MS 20
volatile uint8_t value = 0;
volatile Boolean pressed = FALSE;
volatile Boolean timer_0_init = FALSE;
volatile Boolean timer_delay_enabled = FALSE;
volatile uint16_t timer_delay = 0;
void print_binary(int value) {
int mask_3 = 0b1000;
int bit_at_3 = value & mask_3;
int bit_at_4 = bit_at_3 << 1;
PORTB = (value & 0b111) + bit_at_4;
}
void increment_int() {
// int *value = params->value;
// int max = params->max;
value = (value >= MAX) ? MAX : ++value;
}
void decrement_int() {
// int *value = params->value;
// int min = params->min;
value = (value <= MIN) ? MIN : --value;
}
void increment_led() {
// IncrementParams *params = (IncrementParams *)param;
increment_int();
print_binary(value);
}
void decrement_led() {
// IncrementParams *params = (IncrementParams *)param;
decrement_int();
print_binary(value);
}
void timer0_init_1_ms() {
TCCR0A |= (1 << WGM01); // CTC mode
OCR0A = 249; // Compare match every 1ms (F_CPU / Prescaler = 16,000,000 / 64 = 250,000 ticks/sec)
TIMSK0 |= (1 << OCIE0A); // Enable Compare Match A interrupt
TCCR0B |= (1 << CS01) | (1 << CS00); // Prescaler 64
sei(); // Enable global interrupts
timer_0_init = TRUE;
}
void launch_delay_ms(void) {
if (!timer_0_init) {
timer0_init_1_ms();
}
CLEAR(PCICR, PCIE2); // disable interupt PCINT2
CLEAR(PCMSK2, PCINT20);
CLEAR(PCMSK2, PCINT18);
timer_delay = 0;
timer_delay_enabled = TRUE;
SET(PCIFR, PCIF2); // reset flag interrupt PCINT2
}
ISR(TIMER0_COMPA_vect) {
if (!timer_delay_enabled) {
return;
}
timer_delay++;
if (timer_delay >= TIMER_TOP_MS) {
// TOGGLE_ELEM(LED1);
timer_delay_enabled = FALSE;
SET(PCICR, PCIE2); // re-enable interupt PCINT2
SET(PCMSK2, PCINT20);
SET(PCMSK2, PCINT18);
}
}
void on_press(int bit, void (*action)(void)) {
// if ((TEST(PIND, bit)) == 0) {
// action();
// _delay_ms(20);
// while ((TEST(PIND, bit)) == 0) {
// continue;
// }
// _delay_ms(20);
// }
launch_delay_ms();
if (!pressed) {
// if ((TEST(PIND, bit)) == 0) {
// }
pressed = TRUE;
action();
} else {
pressed = FALSE;
}
}
// write a program that incr/decr-ements a number with the buttons, using interrupts, empty infinite loop, and displays the result on LEDs in binary
int main() {
MODE_OUTPUT(LED1);
MODE_OUTPUT(LED2);
MODE_OUTPUT(LED3);
MODE_OUTPUT(LED4);
MODE_INPUT(BUTTON1);
MODE_INPUT(BUTTON2);
PULLUP_ON(BUTTON1);
PULLUP_ON(BUTTON2);
SREG |= ENABLE_GLOBAL_INTERRUPT;
PCICR = (1 << PCIE2); // 13.2.4 : enable pin change interrupt, bit PCIE2 for PCINT[23:16], (Table 14-9 : alternates : PD2 - PCINT18, PD4 - PCINT20)
PCMSK2 = (1 << PCINT20) | (1 << PCINT18); // 13.2.6 : enable individual pin chang interrupt
while(1);
}
ISR(PCINT2_vect) {
if (!TEST_PIN(BUTTON1)) {
on_press(SW1, increment_led);
}
if (!TEST_PIN(BUTTON2)) {
on_press(SW2, decrement_led);
}
}

View File

@@ -1 +0,0 @@
include ../../Makefile

View File

@@ -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);
}

Some files were not shown because too many files have changed in this diff Show More