Compare commits
116 Commits
mac_devcon
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8532b4ad26 | ||
|
|
3cd6e72b8d | ||
|
|
e59346adc6 | ||
|
|
a7dd28c31a | ||
|
|
54d9bea111 | ||
|
|
6fa2df3b44 | ||
|
|
e4bbf40bb8 | ||
|
|
35582f4286 | ||
|
|
986efac082 | ||
|
|
2b1b609d85 | ||
|
|
4ef36cca4f | ||
|
|
28f0617e48 | ||
|
|
de938b5377 | ||
|
|
4f18cd2c56 | ||
|
|
bd23d89706 | ||
|
|
ec928d14b1 | ||
|
|
16a5bcd313 | ||
|
|
70db631c93 | ||
|
|
1d5e8d4ee7 | ||
|
|
8fef07135a | ||
|
|
92aa850fb4 | ||
|
|
8365a79837 | ||
|
|
e33261846b | ||
|
|
4c25c39e32 | ||
|
|
e9e3cd09dd | ||
|
|
5904f7c5e0 | ||
|
|
2fd1d7d931 | ||
|
|
4c36e4e775 | ||
|
|
b12eff7ede | ||
|
|
0e87d41c08 | ||
|
|
6ef217c05e | ||
|
|
847f969a53 | ||
|
|
33ca0f68ed | ||
|
|
7cad1f6776 | ||
|
|
00bcdb1a79 | ||
|
|
7ca02352d9 | ||
|
|
24158c8f4d | ||
|
|
3120668a34 | ||
|
|
d55f42d6db | ||
|
|
f42bd2f869 | ||
|
|
33e9df5d37 | ||
|
|
3e29e445e6 | ||
|
|
3a4aa32434 | ||
|
|
e29965c502 | ||
|
|
2625dc0946 | ||
|
|
08dab7e608 | ||
|
|
fc77fb1749 | ||
|
|
b487d8f353 | ||
|
|
d0427ce83d | ||
|
|
bb785d5209 | ||
|
|
692ad7f3ce | ||
|
|
fdc7e21460 | ||
|
|
81e844db7b | ||
|
|
2aaaac6c57 | ||
|
|
e16552b4bc | ||
|
|
9bae6d3f49 | ||
|
|
768054d6c2 | ||
|
|
5274ba1ee5 | ||
|
|
c3357fcfaa | ||
|
|
048db02593 | ||
|
|
6fcc0462f5 | ||
|
|
2992b00471 | ||
|
|
8a7611cdc3 | ||
|
|
24e74cf105 | ||
|
|
3a1dc78544 | ||
|
|
3160435041 | ||
|
|
73bb93d96f | ||
|
|
7459a2155c | ||
|
|
d83dd6a533 | ||
|
|
6cc527b88e | ||
|
|
5bf157ce45 | ||
|
|
df7d962c7e | ||
|
|
00f1670c14 | ||
|
|
90e77abe08 | ||
|
|
03e1a7c19d | ||
|
|
e63951591c | ||
|
|
d91524b14a | ||
|
|
dd13c6582c | ||
|
|
f992d76fe5 | ||
|
|
681e0dfa5e | ||
|
|
fe0e7fa223 | ||
|
|
1be3750300 | ||
|
|
18be7948dd | ||
|
|
91788897b1 | ||
|
|
3140b1a491 | ||
|
|
652a7913de | ||
|
|
b05b9f0298 | ||
|
|
c50e5f24aa | ||
|
|
2e47e9dca6 | ||
|
|
426c9884cf | ||
|
|
444925be21 | ||
|
|
f0566e8bde | ||
|
|
08e1200408 | ||
|
|
1bb2e880c8 | ||
|
|
10480f63d7 | ||
|
|
936c591be4 | ||
|
|
d08cc9fd4c | ||
|
|
c037b5184d | ||
|
|
928f897992 | ||
|
|
e080531ac6 | ||
|
|
9e9dcae5e3 | ||
|
|
638f1d2a68 | ||
|
|
fe0249bc05 | ||
|
|
136c3b93b0 | ||
|
|
ebb578db5f | ||
|
|
6ec379e1ae | ||
|
|
e1b76139c5 | ||
|
|
29687bfdf5 | ||
|
|
ea43423716 | ||
|
|
25541d0582 | ||
|
|
9398b623af | ||
|
|
fd2be66727 | ||
|
|
4a9fe6cd95 | ||
|
|
3271fbf96d | ||
|
|
714bf2bd9b | ||
|
|
fc45812dfb |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -50,4 +50,5 @@ Thumbs.db
|
||||
|
||||
# chips
|
||||
*.bin
|
||||
*.hex
|
||||
*.hex
|
||||
*.o
|
||||
52
.vscode/c_cpp_properties.json
vendored
52
.vscode/c_cpp_properties.json
vendored
@@ -1,24 +1,28 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "linux-avr-gcc",
|
||||
"includePath": ["${workspaceFolder}/**", "/usr/lib/avr/include/**"],
|
||||
"defines": [],
|
||||
"mergeConfigurations": false,
|
||||
"compilerPath": "/usr/bin/avr-gcc",
|
||||
"cStandard": "gnu11",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"compilerArgs": ["-mmcu=atmega328p", "-DF_CPU=16000000UL", "-Os"]
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-x64",
|
||||
"includePath": ["${workspaceFolder}/**"],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"compilerArgs": [""],
|
||||
"mergeConfigurations": false
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
// {
|
||||
// "configurations": [
|
||||
// {
|
||||
// "name": "AVR",
|
||||
// "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"
|
||||
// ],
|
||||
// "defines": ["__AVR_ATmega328P__"],
|
||||
// "intelliSenseMode": "gcc-x64",
|
||||
// "cStandard": "c11",
|
||||
// "cppStandard": "c++17",
|
||||
// "browse": {
|
||||
// "path": [
|
||||
// "/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"
|
||||
// // "/opt/homebrew/lib/gcc/avr/include",
|
||||
// // "/opt/homebrew/lib/gcc/avr/include-fixed"
|
||||
// ],
|
||||
// "limitSymbolsToIncludedHeaders": true
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// "version": 4
|
||||
// }
|
||||
|
||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@@ -1,6 +1,14 @@
|
||||
{
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false,
|
||||
"files.associations": {
|
||||
"io.h": "c",
|
||||
"delay.h": "c"
|
||||
}
|
||||
"header.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__"]
|
||||
}
|
||||
|
||||
83
Makefile
Normal file
83
Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
# 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
|
||||
13
README.md
13
README.md
@@ -1,11 +1,14 @@
|
||||
# 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
|
||||
- Getting started with AVR programming : https://github.com/m3y54m/start-avr/tree/master
|
||||
- avrdude doc : https://avrdudes.github.io/avrdude/
|
||||
- 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
|
||||
- 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
|
||||
|
||||
@@ -79,3 +82,13 @@ avrdude: safemode: Fuses OK (E:00, H:00, L:00)
|
||||
|
||||
avrdude done. Thank you.
|
||||
```
|
||||
|
||||
## makefile on mac
|
||||
|
||||
- `brew tap osx-cross/avr`
|
||||
- `brew install avr-gcc avrdude`
|
||||
|
||||
## screen
|
||||
|
||||
- (optional) `export TERM=xterm`
|
||||
- `screen /dev/ttyUSB0 115200`
|
||||
|
||||
25
headers/adc.h
Normal file
25
headers/adc.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#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
|
||||
61
headers/bitmanip.h
Normal file
61
headers/bitmanip.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#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
|
||||
17
headers/i2c.h
Normal file
17
headers/i2c.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#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
|
||||
8
headers/interrupt.h
Normal file
8
headers/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INTERRUPT_H
|
||||
#define INTERRUPT_H
|
||||
|
||||
// 7.3.1 : SREG – AVR Status Register
|
||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
||||
|
||||
#endif // INTERRUPT_H
|
||||
37
headers/timer.h
Normal file
37
headers/timer.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#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
|
||||
31
headers/usart.h
Normal file
31
headers/usart.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef USART_H
|
||||
#define USART_H
|
||||
|
||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
||||
#define STOP_ONE_BIT (0<<USBS0)
|
||||
#define STOP_TWO_BIT (1<<USBS0)
|
||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
||||
|
||||
#endif // USART_H
|
||||
32
headers/utils.h
Normal file
32
headers/utils.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#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
|
||||
@@ -1,50 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
@@ -1,3 +1,4 @@
|
||||
// write a makefile that compiles the code and flashes it to the microcontroller
|
||||
int main()
|
||||
{
|
||||
}
|
||||
@@ -1,43 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <avr/io.h>
|
||||
// #include <util/delay.h>
|
||||
|
||||
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT
|
||||
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
|
||||
@@ -11,75 +10,27 @@
|
||||
#define D3 2
|
||||
#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()
|
||||
{
|
||||
// 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
|
||||
SET(DDRB, D1); // make PB0 as OUTPUT (pullup is off)
|
||||
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);
|
||||
//
|
||||
////////////////////////////////
|
||||
|
||||
SET(DDRB, D1); // make PB0 as OUTPUT (pullup is off)
|
||||
SET(PORTB, D1); // make PB0 as HIGH (LED turns ON)
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,43 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
@@ -1,101 +1,67 @@
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
// test with https://www.onlinegdb.com/online_c_compiler
|
||||
// // V1
|
||||
//
|
||||
// // 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
|
||||
// stringify
|
||||
#define STRINGIFY_HELPER(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||
|
||||
// // V2
|
||||
//
|
||||
// // 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
|
||||
// concatenate
|
||||
#define CONCAT_HELPER(x, y) x ## y
|
||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
||||
|
||||
// V0
|
||||
// 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
|
||||
|
||||
#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 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 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
|
||||
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
// 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)
|
||||
|
||||
// END MACROS
|
||||
|
||||
// turn on LED1 when BUTTON1 is pressed
|
||||
int main()
|
||||
{
|
||||
MODE_OUTPUT(B, D1);
|
||||
MODE_INPUT(D, SW1);
|
||||
MODE_OUTPUT(LED1);
|
||||
MODE_INPUT(BUTTON1);
|
||||
while(1) {
|
||||
if (IS_PIN_SET(D, SW1)) {
|
||||
SET(PORTB, D1);
|
||||
if (IS_PIN_SET(BUTTON1)) {
|
||||
SET_ELEM(LED1);
|
||||
} else {
|
||||
CLEAR(PORTB, D1);
|
||||
CLEAR_ELEM(LED1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1,43 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
54
module00/ex03/macros.h
Normal file
54
module00/ex03/macros.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#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
|
||||
@@ -1,32 +1,17 @@
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.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
|
||||
#include "macros.h"
|
||||
|
||||
// toggle LED1 when BUTTON1 is pressed
|
||||
int main() {
|
||||
MODE_OUTPUT(B, D1);
|
||||
MODE_INPUT(D, SW1);
|
||||
MODE_OUTPUT(LED1);
|
||||
MODE_INPUT(BUTTON1);
|
||||
while(1) {
|
||||
if (IS_PIN_SET(D, SW1)) {
|
||||
TOGGLE_PIN(B, D1);
|
||||
if (IS_PIN_SET(BUTTON1)) {
|
||||
TOGGLE_PIN(LED1);
|
||||
_delay_ms(20);
|
||||
while(IS_PIN_SET(D, SW1)) {
|
||||
while(IS_PIN_SET(BUTTON1)) {
|
||||
continue;
|
||||
}
|
||||
_delay_ms(20);
|
||||
|
||||
@@ -1,43 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
47
module00/ex04/bitmanip.h
Normal file
47
module00/ex04/bitmanip.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#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
|
||||
@@ -1,23 +1,8 @@
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.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
|
||||
#include "utils.h"
|
||||
#include "bitmanip.h"
|
||||
|
||||
typedef struct {
|
||||
int *value;
|
||||
@@ -57,23 +42,24 @@ void decrement_led(void *param) {
|
||||
}
|
||||
|
||||
void on_press(int bit, void (*action)(void*), void *params) {
|
||||
if (IS_PIN_SET(D, bit)) {
|
||||
if ((TEST(PIND, bit)) == 0) {
|
||||
action(params);
|
||||
_delay_ms(20);
|
||||
while (IS_PIN_SET(D, bit)) {
|
||||
while ((TEST(PIND, bit)) == 0) {
|
||||
continue;
|
||||
}
|
||||
_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() {
|
||||
MODE_OUTPUT(B, D1);
|
||||
MODE_OUTPUT(B, D2);
|
||||
MODE_OUTPUT(B, D3);
|
||||
MODE_OUTPUT(B, D4);
|
||||
MODE_INPUT(D, SW1);
|
||||
MODE_INPUT(D, SW2);
|
||||
MODE_OUTPUT(LED1);
|
||||
MODE_OUTPUT(LED2);
|
||||
MODE_OUTPUT(LED3);
|
||||
MODE_OUTPUT(LED4);
|
||||
MODE_INPUT(BUTTON1);
|
||||
MODE_INPUT(BUTTON2);
|
||||
|
||||
int value = 0;
|
||||
int max = 15;
|
||||
|
||||
12
module00/ex04/utils.h
Normal file
12
module00/ex04/utils.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#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
|
||||
@@ -1,43 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
47
module01/ex00/bitmanip.h
Normal file
47
module01/ex00/bitmanip.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#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
|
||||
@@ -1,65 +1,33 @@
|
||||
#include <avr/io.h>
|
||||
|
||||
// #define FIRST_LETTER_IMPL(x) #x[0]
|
||||
// #define FIRST_LETTER(x) FIRST_LETTER_IMPL(x)
|
||||
// #define PORT_LETTER(PIN) FIRST_LETTER(PIN)
|
||||
#include "utils.h"
|
||||
#include "bitmanip.h"
|
||||
|
||||
// global 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 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
|
||||
// TIMER
|
||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
||||
// 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) (((F_CPU / PRESCALE_VALUE) * ms) / 1000)
|
||||
|
||||
int main() {
|
||||
MODE_OUTPUT(B, D2);
|
||||
TURN_OFF_LED(D2);
|
||||
// END MACROS
|
||||
|
||||
TCCR1B |= (PRESCALE_SET); // set timer with prescale
|
||||
// -> 16.4 : set timer with bits CS10-12, in register TCCR1B
|
||||
// -> table 16-5 : prescale values
|
||||
// write a program that blinks an LED every 500ms using a software timer
|
||||
int main() {
|
||||
MODE_OUTPUT(LED2);
|
||||
CLEAR_ELEM(LED2);
|
||||
|
||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // 16.4 : set timer according to prescale value, in register TCCR1B, table 16-5 : prescale sets
|
||||
|
||||
while(1) {
|
||||
if (TCNT1 >= TIME_MS(500)) { // 16.11.4 : read timer with register TCNT1 (read/write allowed), that combines two 8 bits registers
|
||||
TOGGLE_LED(D2);
|
||||
TCNT1 = 0; // reset timer value, also in register TCNT1
|
||||
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);
|
||||
TCNT1 = 0; // reset timer value, also in register TCNT1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
module01/ex00/utils.h
Normal file
12
module01/ex00/utils.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#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
|
||||
@@ -1,43 +1 @@
|
||||
# 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
|
||||
include ../../Makefile
|
||||
47
module01/ex01/bitmanip.h
Normal file
47
module01/ex01/bitmanip.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#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
|
||||
@@ -1,72 +1,25 @@
|
||||
#include <avr/io.h>
|
||||
|
||||
// #define FIRST_LETTER_IMPL(x) #x[0]
|
||||
// #define FIRST_LETTER(x) FIRST_LETTER_IMPL(x)
|
||||
// #define PORT_LETTER(PIN) FIRST_LETTER(PIN)
|
||||
#include "utils.h"
|
||||
#include "bitmanip.h"
|
||||
#include "timer.h"
|
||||
|
||||
// global 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 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)
|
||||
#define PERIOD 500
|
||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
||||
|
||||
// led turns on and off every PERIOD ms using CTC timer
|
||||
int main() {
|
||||
MODE_OUTPUT(B, D2);
|
||||
MODE_OUTPUT(LED2);
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
OCR1A = TIME_MS(500); // set CTC compare value
|
||||
// -> Table 16-4 : the value to reset the timer is the Output Compare Registers OCR1A
|
||||
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);
|
||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE));
|
||||
|
||||
while(1) {
|
||||
continue;
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
14
module01/ex01/timer.h
Normal file
14
module01/ex01/timer.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
12
module01/ex01/utils.h
Normal file
12
module01/ex01/utils.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#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
|
||||
1
module01/ex02/Makefile
Normal file
1
module01/ex02/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
47
module01/ex02/bitmanip.h
Normal file
47
module01/ex02/bitmanip.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#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
|
||||
28
module01/ex02/main.c
Normal file
28
module01/ex02/main.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#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);
|
||||
}
|
||||
14
module01/ex02/timer.h
Normal file
14
module01/ex02/timer.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
15
module01/ex02/utils.h
Normal file
15
module01/ex02/utils.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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
|
||||
1
module01/ex03/Makefile
Normal file
1
module01/ex03/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
47
module01/ex03/bitmanip.h
Normal file
47
module01/ex03/bitmanip.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#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
|
||||
73
module01/ex03/main.c
Normal file
73
module01/ex03/main.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
14
module01/ex03/timer.h
Normal file
14
module01/ex03/timer.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
15
module01/ex03/utils.h
Normal file
15
module01/ex03/utils.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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
|
||||
1
module02/ex00/Makefile
Normal file
1
module02/ex00/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
53
module02/ex00/bitmanip.h
Normal file
53
module02/ex00/bitmanip.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef BITMANIP_H
|
||||
#define BITMANIP_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Bit operations on registers
|
||||
#define SET(register, bit) (register |= (1 << (bit)))
|
||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
||||
#define TEST(register, bit) (register & (1 << (bit)))
|
||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
||||
|
||||
// Get arguments from tuple-like definitions
|
||||
#define ARG_1(v1, v2) v1
|
||||
#define ARG_2(v1, v2) v2
|
||||
#define GET_PORT(args) ARG_1 args
|
||||
#define GET_BIT(args) ARG_2 args
|
||||
// // version with "LED1 B, D1" without parenthesis
|
||||
// #define ARG_1(v1, ...) v1
|
||||
// #define ARG_2(v1, v2, ...) v2
|
||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
||||
|
||||
// Actions on elements
|
||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
|
||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
||||
|
||||
// Bit definitions
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
|
||||
// Elements (port, bit)
|
||||
#define LED1 (B, D1)
|
||||
#define LED2 (B, D2)
|
||||
#define LED3 (B, D3)
|
||||
#define LED4 (B, D4)
|
||||
#define BUTTON1 (D, SW1)
|
||||
#define BUTTON2 (D, SW2)
|
||||
|
||||
#endif // BITMANIP_H
|
||||
60
module02/ex00/main.c
Normal file
60
module02/ex00/main.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
16
module02/ex00/utils.h
Normal file
16
module02/ex00/utils.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#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
|
||||
1
module02/ex01/Makefile
Normal file
1
module02/ex01/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
53
module02/ex01/bitmanip.h
Normal file
53
module02/ex01/bitmanip.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef BITMANIP_H
|
||||
#define BITMANIP_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Bit operations on registers
|
||||
#define SET(register, bit) (register |= (1 << (bit)))
|
||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
||||
#define TEST(register, bit) (register & (1 << (bit)))
|
||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
||||
|
||||
// Get arguments from tuple-like definitions
|
||||
#define ARG_1(v1, v2) v1
|
||||
#define ARG_2(v1, v2) v2
|
||||
#define GET_PORT(args) ARG_1 args
|
||||
#define GET_BIT(args) ARG_2 args
|
||||
// // version with "LED1 B, D1" without parenthesis
|
||||
// #define ARG_1(v1, ...) v1
|
||||
// #define ARG_2(v1, v2, ...) v2
|
||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
||||
|
||||
// Actions on elements
|
||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
|
||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
||||
|
||||
// Bit definitions
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
|
||||
// Elements (port, bit)
|
||||
#define LED1 (B, D1)
|
||||
#define LED2 (B, D2)
|
||||
#define LED3 (B, D3)
|
||||
#define LED4 (B, D4)
|
||||
#define BUTTON1 (D, SW1)
|
||||
#define BUTTON2 (D, SW2)
|
||||
|
||||
#endif // BITMANIP_H
|
||||
8
module02/ex01/interrupt.h
Normal file
8
module02/ex01/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INTERRUPT_H
|
||||
#define INTERRUPT_H
|
||||
|
||||
// 7.3.1 : SREG – AVR Status Register
|
||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
||||
|
||||
#endif // INTERRUPT_H
|
||||
63
module02/ex01/main.c
Normal file
63
module02/ex01/main.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#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
|
||||
}
|
||||
27
module02/ex01/timer.h
Normal file
27
module02/ex01/timer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
// table 16-5 : prescale sets
|
||||
#define PRESCALE_SET(value) \
|
||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
||||
|
||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
||||
|
||||
#endif // TIMER_H
|
||||
27
module02/ex01/usart.h
Normal file
27
module02/ex01/usart.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#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
|
||||
16
module02/ex01/utils.h
Normal file
16
module02/ex01/utils.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#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
|
||||
1
module02/ex02/Makefile
Normal file
1
module02/ex02/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
53
module02/ex02/bitmanip.h
Normal file
53
module02/ex02/bitmanip.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef BITMANIP_H
|
||||
#define BITMANIP_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Bit operations on registers
|
||||
#define SET(register, bit) (register |= (1 << (bit)))
|
||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
||||
#define TEST(register, bit) (register & (1 << (bit)))
|
||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
||||
|
||||
// Get arguments from tuple-like definitions
|
||||
#define ARG_1(v1, v2) v1
|
||||
#define ARG_2(v1, v2) v2
|
||||
#define GET_PORT(args) ARG_1 args
|
||||
#define GET_BIT(args) ARG_2 args
|
||||
// // version with "LED1 B, D1" without parenthesis
|
||||
// #define ARG_1(v1, ...) v1
|
||||
// #define ARG_2(v1, v2, ...) v2
|
||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
||||
|
||||
// Actions on elements
|
||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
|
||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
||||
|
||||
// Bit definitions
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
|
||||
// Elements (port, bit)
|
||||
#define LED1 (B, D1)
|
||||
#define LED2 (B, D2)
|
||||
#define LED3 (B, D3)
|
||||
#define LED4 (B, D4)
|
||||
#define BUTTON1 (D, SW1)
|
||||
#define BUTTON2 (D, SW2)
|
||||
|
||||
#endif // BITMANIP_H
|
||||
8
module02/ex02/interrupt.h
Normal file
8
module02/ex02/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INTERRUPT_H
|
||||
#define INTERRUPT_H
|
||||
|
||||
// 7.3.1 : SREG – AVR Status Register
|
||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
||||
|
||||
#endif // INTERRUPT_H
|
||||
43
module02/ex02/main.c
Normal file
43
module02/ex02/main.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
27
module02/ex02/timer.h
Normal file
27
module02/ex02/timer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
// table 16-5 : prescale sets
|
||||
#define PRESCALE_SET(value) \
|
||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
||||
|
||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
||||
|
||||
#endif // TIMER_H
|
||||
27
module02/ex02/usart.h
Normal file
27
module02/ex02/usart.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#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
|
||||
16
module02/ex02/utils.h
Normal file
16
module02/ex02/utils.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#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
|
||||
1
module02/ex03/Makefile
Normal file
1
module02/ex03/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
53
module02/ex03/bitmanip.h
Normal file
53
module02/ex03/bitmanip.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef BITMANIP_H
|
||||
#define BITMANIP_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Bit operations on registers
|
||||
#define SET(register, bit) (register |= (1 << (bit)))
|
||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
||||
#define TEST(register, bit) (register & (1 << (bit)))
|
||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
||||
|
||||
// Get arguments from tuple-like definitions
|
||||
#define ARG_1(v1, v2) v1
|
||||
#define ARG_2(v1, v2) v2
|
||||
#define GET_PORT(args) ARG_1 args
|
||||
#define GET_BIT(args) ARG_2 args
|
||||
// // version with "LED1 B, D1" without parenthesis
|
||||
// #define ARG_1(v1, ...) v1
|
||||
// #define ARG_2(v1, v2, ...) v2
|
||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
||||
|
||||
// Actions on elements
|
||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
|
||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
||||
|
||||
// Bit definitions
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
|
||||
// Elements (port, bit)
|
||||
#define LED1 (B, D1)
|
||||
#define LED2 (B, D2)
|
||||
#define LED3 (B, D3)
|
||||
#define LED4 (B, D4)
|
||||
#define BUTTON1 (D, SW1)
|
||||
#define BUTTON2 (D, SW2)
|
||||
|
||||
#endif // BITMANIP_H
|
||||
8
module02/ex03/interrupt.h
Normal file
8
module02/ex03/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INTERRUPT_H
|
||||
#define INTERRUPT_H
|
||||
|
||||
// 7.3.1 : SREG – AVR Status Register
|
||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
||||
|
||||
#endif // INTERRUPT_H
|
||||
53
module02/ex03/main.c
Normal file
53
module02/ex03/main.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#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
|
||||
}
|
||||
27
module02/ex03/timer.h
Normal file
27
module02/ex03/timer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
// table 16-5 : prescale sets
|
||||
#define PRESCALE_SET(value) \
|
||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
||||
|
||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
||||
|
||||
#endif // TIMER_H
|
||||
31
module02/ex03/usart.h
Normal file
31
module02/ex03/usart.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef USART_H
|
||||
#define USART_H
|
||||
|
||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
||||
#define STOP_ONE_BIT (0<<USBS0)
|
||||
#define STOP_TWO_BIT (1<<USBS0)
|
||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
||||
|
||||
#endif // USART_H
|
||||
19
module02/ex03/utils.h
Normal file
19
module02/ex03/utils.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#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
|
||||
1
module02/ex04/Makefile
Normal file
1
module02/ex04/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
53
module02/ex04/bitmanip.h
Normal file
53
module02/ex04/bitmanip.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef BITMANIP_H
|
||||
#define BITMANIP_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Bit operations on registers
|
||||
#define SET(register, bit) (register |= (1 << (bit)))
|
||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
||||
#define TEST(register, bit) (register & (1 << (bit)))
|
||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
||||
|
||||
// Get arguments from tuple-like definitions
|
||||
#define ARG_1(v1, v2) v1
|
||||
#define ARG_2(v1, v2) v2
|
||||
#define GET_PORT(args) ARG_1 args
|
||||
#define GET_BIT(args) ARG_2 args
|
||||
// // version with "LED1 B, D1" without parenthesis
|
||||
// #define ARG_1(v1, ...) v1
|
||||
// #define ARG_2(v1, v2, ...) v2
|
||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
||||
|
||||
// Actions on elements
|
||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
||||
|
||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
||||
|
||||
// Bit definitions
|
||||
#define D1 0
|
||||
#define D2 1
|
||||
#define D3 2
|
||||
#define D4 4
|
||||
#define SW1 2
|
||||
#define SW2 4
|
||||
|
||||
// Elements (port, bit)
|
||||
#define LED1 (B, D1)
|
||||
#define LED2 (B, D2)
|
||||
#define LED3 (B, D3)
|
||||
#define LED4 (B, D4)
|
||||
#define BUTTON1 (D, SW1)
|
||||
#define BUTTON2 (D, SW2)
|
||||
|
||||
#endif // BITMANIP_H
|
||||
8
module02/ex04/interrupt.h
Normal file
8
module02/ex04/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INTERRUPT_H
|
||||
#define INTERRUPT_H
|
||||
|
||||
// 7.3.1 : SREG – AVR Status Register
|
||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
||||
|
||||
#endif // INTERRUPT_H
|
||||
203
module02/ex04/main.c
Normal file
203
module02/ex04/main.c
Normal file
@@ -0,0 +1,203 @@
|
||||
#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);
|
||||
}
|
||||
27
module02/ex04/timer.h
Normal file
27
module02/ex04/timer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
// table 16-5 : prescale sets
|
||||
#define PRESCALE_SET(value) \
|
||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
||||
|
||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
||||
|
||||
#endif // TIMER_H
|
||||
31
module02/ex04/usart.h
Normal file
31
module02/ex04/usart.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef USART_H
|
||||
#define USART_H
|
||||
|
||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
||||
#define STOP_ONE_BIT (0<<USBS0)
|
||||
#define STOP_TWO_BIT (1<<USBS0)
|
||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
||||
|
||||
#endif // USART_H
|
||||
23
module02/ex04/utils.h
Normal file
23
module02/ex04/utils.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
// stringify
|
||||
#define STRINGIFY_HELPER(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||
|
||||
// concatenate
|
||||
#define CONCAT_HELPER(x, y) x ## y
|
||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
||||
|
||||
// mathematics
|
||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
||||
|
||||
// text
|
||||
#define SWITCH_CASE(ch) (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ? ((ch) ^ (1 << 5)) : (ch))
|
||||
|
||||
// boolean
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#endif // UTILS_H
|
||||
1
module03/ex00/Makefile
Normal file
1
module03/ex00/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
32
module03/ex00/main.c
Normal file
32
module03/ex00/main.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#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();
|
||||
}
|
||||
}
|
||||
1
module03/ex01/Makefile
Normal file
1
module03/ex01/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
44
module03/ex01/main.c
Normal file
44
module03/ex01/main.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#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();
|
||||
}
|
||||
}
|
||||
1
module03/ex02/Makefile
Normal file
1
module03/ex02/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
69
module03/ex02/main.c
Normal file
69
module03/ex02/main.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#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
|
||||
}
|
||||
}
|
||||
1
module03/ex03/Makefile
Normal file
1
module03/ex03/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
77
module03/ex03/colors.c
Normal file
77
module03/ex03/colors.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#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);
|
||||
}
|
||||
38
module03/ex03/header.h
Normal file
38
module03/ex03/header.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#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
|
||||
11
module03/ex03/main.c
Normal file
11
module03/ex03/main.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "header.h"
|
||||
|
||||
|
||||
// led RGB D5 must turns on in a loop of colors using PWM
|
||||
int main() {
|
||||
init_rgb();
|
||||
uart_init();
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
121
module03/ex03/uart.c
Normal file
121
module03/ex03/uart.c
Normal file
@@ -0,0 +1,121 @@
|
||||
#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;
|
||||
}
|
||||
1
module04/ex00/Makefile
Normal file
1
module04/ex00/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
17
module04/ex00/header.h
Normal file
17
module04/ex00/header.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#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
|
||||
43
module04/ex00/main.c
Normal file
43
module04/ex00/main.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#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
|
||||
}
|
||||
1
module04/ex01/Makefile
Normal file
1
module04/ex01/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
20
module04/ex01/header.h
Normal file
20
module04/ex01/header.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#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
|
||||
138
module04/ex01/main.c
Normal file
138
module04/ex01/main.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#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);
|
||||
}
|
||||
1
module04/ex02/Makefile
Normal file
1
module04/ex02/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
30
module04/ex02/header.h
Normal file
30
module04/ex02/header.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#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
|
||||
143
module04/ex02/main.c
Normal file
143
module04/ex02/main.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
1
module05/ex00/Makefile
Normal file
1
module05/ex00/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include ../../Makefile
|
||||
27
module05/ex00/adc.c
Normal file
27
module05/ex00/adc.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#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);
|
||||
}
|
||||
41
module05/ex00/header.h
Normal file
41
module05/ex00/header.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#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"
|
||||
#include "usart.h"
|
||||
#include "adc.h"
|
||||
|
||||
//
|
||||
// GLOBAL
|
||||
//
|
||||
extern volatile uint8_t adc_channel;
|
||||
|
||||
//
|
||||
// PROTOTYPES
|
||||
//
|
||||
// main.c
|
||||
// timer.c
|
||||
void timer_1B_init();
|
||||
// math.c
|
||||
void int_to_hex_string(uint64_t value, char *out, uint8_t num_digits);
|
||||
// adc.c
|
||||
void adc_init(uint8_t prescaler_value);
|
||||
uint16_t adc_read(uint8_t channel);
|
||||
// uart.c
|
||||
void uart_init();
|
||||
void uart_tx(char c);
|
||||
void uart_printstr(const char* str);
|
||||
void uart_printstr_endl(const char* str);
|
||||
|
||||
//
|
||||
// MACROS
|
||||
//
|
||||
|
||||
#endif // HEADER_H
|
||||
29
module05/ex00/main.c
Normal file
29
module05/ex00/main.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "header.h"
|
||||
|
||||
// 1.1.7 : AVCC is the supply voltage pin for the A/D Converter, PC3:0, and ADC7:6
|
||||
// 1.1.8 : AREF is the analog reference pin for the A/D Converter
|
||||
// 24.4 : frequency needs to be between 50kHz and 200kHz, for less than 10bits accuracy it can be >200kHz
|
||||
// -> Frequence_ADC = Frequance_CPU / Prescaler (Fadc = Fcpu/P):
|
||||
// - P = 2 -> Fadc = 16,000,000 / 2 = 8,000,000 = 8MHz
|
||||
// - P = 4 -> Fadc = 16,000,000 / 4 = 4,000,000 = 4MHz
|
||||
// - P = 8 -> Fadc = 16,000,000 / 8 = 2,000,000 = 2MHz
|
||||
// - P = 16 -> Fadc = 16,000,000 / 16 = 1,000,000 = 1MHz
|
||||
// - P = 32 -> Fadc = 16,000,000 / 32 = 500,000 = 500KHz
|
||||
// - P = 64 -> Fadc = 16,000,000 / 64 = 250,000 = 250KHz -> OK
|
||||
// - P = 128 -> Fadc = 16,000,000 / 128 = 125,000 = 125KHz -> OK
|
||||
|
||||
#define ADC_PRESCALER 64 // Table 24-5 : can only be 2, 4, 8, 16, 32, 64, or 128
|
||||
|
||||
volatile uint8_t adc_channel = 0;
|
||||
|
||||
// read potentiometer value and print it in uart as hexadecimal 2-number
|
||||
int main() {
|
||||
char buffer[4];
|
||||
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I – Global Interrupt Enable
|
||||
uart_init();
|
||||
adc_init(ADC_PRESCALER);
|
||||
|
||||
timer_1B_init();
|
||||
|
||||
while(1);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user