116 Commits

Author SHA1 Message Date
hugogogo
8532b4ad26 wip better delay m04e02 2025-03-17 17:43:11 +01:00
hugo LAMY
3cd6e72b8d add doc 2025-03-17 09:09:52 +01:00
hugo LAMY
e59346adc6 working with delays 2025-03-17 09:05:13 +01:00
hugo LAMY
a7dd28c31a added newline in output fore readability 2025-03-17 08:23:55 +01:00
hugo LAMY
54d9bea111 i broke everything whaaat 2025-03-16 21:08:33 +01:00
hugo LAMY
6fa2df3b44 printing data but without delay, why 2025-03-16 18:02:43 +01:00
hugo LAMY
e4bbf40bb8 printing complete status infos 2025-03-16 17:36:48 +01:00
hugo LAMY
35582f4286 wip i2c with aht20 2025-03-16 16:56:08 +01:00
hugo LAMY
986efac082 first version of m06e01 2025-03-16 13:33:07 +01:00
hugo LAMY
2b1b609d85 fix headers config 2025-03-16 12:50:36 +01:00
hugo LAMY
4ef36cca4f fix include not recognized by vscode 2025-03-16 12:23:35 +01:00
hugo LAMY
28f0617e48 m06e00 ok 2025-03-16 10:43:33 +01:00
hugogogo
de938b5377 add doc for thermostat 2025-03-15 18:57:40 +01:00
hugogogo
4f18cd2c56 start mod06 ex00 2025-03-15 18:56:04 +01:00
hugogogo
bd23d89706 update math with itoa base 2025-03-15 18:34:10 +01:00
hugogogo
ec928d14b1 updated math functions 2025-03-15 18:15:30 +01:00
hugogogo
16a5bcd313 change rush 00 folder name 2025-03-15 16:41:12 +01:00
hugogogo
70db631c93 add rush 00 2025-03-15 16:39:29 +01:00
hugogogo
1d5e8d4ee7 fix rebase module05 2025-03-15 16:31:30 +01:00
hugogogo
8fef07135a init mod06 2025-03-15 16:16:53 +01:00
hugogogo
92aa850fb4 init module06 2025-03-15 16:16:53 +01:00
hugogogo
8365a79837 m05e02 ok, calibration random 2025-03-15 16:16:53 +01:00
hugogogo
e33261846b update math to add convert int to string 2025-03-15 16:16:53 +01:00
hugogogo
4c25c39e32 init m05e02, in decimal 2025-03-15 16:16:53 +01:00
hugogogo
e9e3cd09dd fix 8 bit precision in ex00 and ex01 2025-03-15 16:16:53 +01:00
hugogogo
5904f7c5e0 m05e01 done 2025-03-15 16:16:53 +01:00
hugo LAMY
2fd1d7d931 m05e00 with automatic trigger should now work 2025-03-15 16:15:32 +01:00
hugo LAMY
4c36e4e775 truc 2025-03-15 16:15:32 +01:00
hugo LAMY
b12eff7ede reorganize files 2025-03-15 16:15:10 +01:00
hugo LAMY
0e87d41c08 convert rush from submodule into normal folder 2025-03-14 14:27:53 +01:00
hugo LAMY
6ef217c05e m05e00 values ok prescaler and 8bits 2025-03-14 14:15:49 +01:00
hugo LAMY
847f969a53 tmp broken 2025-03-14 13:16:12 +01:00
hugogogo
33ca0f68ed m05e00 not so done finally... 2025-03-13 18:57:43 +01:00
hugogogo
7cad1f6776 init m05e01 2025-03-13 18:47:24 +01:00
hugogogo
00bcdb1a79 m05e00 done 2025-03-13 18:42:34 +01:00
hugogogo
7ca02352d9 wip commenting 2025-03-13 16:02:27 +01:00
hugogogo
24158c8f4d first version m05e00 2025-03-13 13:14:07 +01:00
hugogogo
3120668a34 sync rush changes 2025-03-13 11:09:55 +01:00
hugo LAMY
d55f42d6db fix rgb colors 2025-03-12 19:45:42 +01:00
hugo LAMY
f42bd2f869 update makefile to overide includes if necessary 2025-03-12 19:45:35 +01:00
hugo LAMY
33e9df5d37 update mod03 with outside headers 2025-03-12 19:21:20 +01:00
hugo LAMY
3e29e445e6 update mod04 with outside headers 2025-03-12 19:16:31 +01:00
hugo LAMY
3a4aa32434 init mod05 and externalize headers 2025-03-12 15:27:20 +01:00
hugo LAMY
e29965c502 mod04 ex02 done 2025-03-12 15:15:06 +01:00
hugo LAMY
2625dc0946 mod04 ex02 wip 2025-03-12 15:02:28 +01:00
hugo LAMY
08dab7e608 init mod04 ex02 2025-03-12 10:55:55 +01:00
hugo LAMY
fc77fb1749 mod04 ex01 ok but not accurate 2025-03-12 10:01:52 +01:00
hugo LAMY
b487d8f353 mod04 ex01 trigger timer0 set but not working 2025-03-11 22:40:13 +01:00
hugo LAMY
d0427ce83d update rush00 2025-03-11 21:14:48 +01:00
hugogogo
bb785d5209 wip mod04 ex01 2025-03-11 18:41:21 +01:00
hugogogo
692ad7f3ce mod01 ex03 replace pointer function params with global 2025-03-11 16:42:50 +01:00
hugogogo
fdc7e21460 updated subjects fr and en 2025-03-11 11:49:40 +01:00
hugogogo
81e844db7b add rush00 2025-03-11 11:17:58 +01:00
hugo LAMY
2aaaac6c57 wip mod04 ex01 2025-03-10 21:17:39 +01:00
hugo LAMY
e16552b4bc mod04 ex00 ok 2025-03-10 18:38:24 +01:00
hugo LAMY
9bae6d3f49 ex01 mod04 not stable 2025-03-10 17:27:05 +01:00
hugo LAMY
768054d6c2 init module 04 2025-03-10 15:39:50 +01:00
hugo LAMY
5274ba1ee5 mod03 ex03 ok 2025-03-10 15:21:15 +01:00
hugo LAMY
c3357fcfaa works but color is wrong 2025-03-10 15:16:39 +01:00
hugo LAMY
048db02593 convert hex str to color 2025-03-10 14:00:08 +01:00
hugo LAMY
6fcc0462f5 init mod03 ex03 2025-03-10 13:28:01 +01:00
hugo LAMY
2992b00471 mod03 ex02 ok 2025-03-10 13:26:01 +01:00
hugo LAMY
8a7611cdc3 added rush00 as submodule 2025-03-10 10:32:17 +01:00
hugo LAMY
24e74cf105 init mod03 ex02 2025-03-10 10:30:33 +01:00
hugo LAMY
3a1dc78544 mod03 ex01 ok 2025-03-10 10:29:26 +01:00
hugo LAMY
3160435041 updated sreg macro 2025-03-10 10:21:32 +01:00
hugo LAMY
73bb93d96f ex00 ok 2025-03-10 10:19:42 +01:00
hugo LAMY
7459a2155c init module03 2025-03-10 09:41:23 +01:00
hugo LAMY
d83dd6a533 addin rush00 submodule 2025-03-09 22:04:54 +01:00
hugogogo
6cc527b88e new headers 2025-03-09 18:09:34 +01:00
hugogogo
5bf157ce45 adding gitignore .o 2025-03-09 17:09:26 +01:00
hugogogo
df7d962c7e update layout 2025-03-09 13:41:54 +01:00
hugo LAMY
00f1670c14 mod02 bonus works 2025-03-09 11:18:24 +01:00
hugo LAMY
90e77abe08 nimp 2025-03-09 03:00:00 +01:00
hugo LAMY
03e1a7c19d bonus almost working 2025-03-09 02:34:11 +01:00
hugo LAMY
e63951591c headers and comments for module02 2025-03-08 22:41:36 +01:00
hugo LAMY
d91524b14a fix error in timer header in mod01 2025-03-08 22:05:30 +01:00
hugo LAMY
dd13c6582c mod01 update headers and descriptions 2025-03-08 21:53:15 +01:00
hugo LAMY
f992d76fe5 update headers ex04 2025-03-08 21:37:12 +01:00
hugo LAMY
681e0dfa5e mod00 ready for correction 2025-03-08 21:24:17 +01:00
hugogogo
fe0e7fa223 wip adding headers 2025-03-08 16:29:30 +01:00
hugogogo
1be3750300 update macros and headers 2025-03-08 16:13:30 +01:00
hugogogo
18be7948dd added pdfs 2025-03-08 12:11:11 +01:00
hugogogo
91788897b1 backspace works 2025-03-07 17:58:11 +01:00
hugogogo
3140b1a491 init ex04 2025-03-07 17:13:39 +01:00
hugogogo
652a7913de mod02 ex03 2025-03-07 17:03:21 +01:00
hugogogo
b05b9f0298 mod02 ex03 init 2025-03-07 13:00:42 +01:00
hugogogo
c50e5f24aa mod02 ex02 ok 2025-03-07 13:00:13 +01:00
hugogogo
2e47e9dca6 init mod02 x02 2025-03-07 12:31:49 +01:00
hugogogo
426c9884cf exo01 ok with comments 2025-03-07 12:31:19 +01:00
hugogogo
444925be21 added comment bout channel A 2025-03-07 12:07:56 +01:00
hugogogo
f0566e8bde mod02 ex01 works but not clear how 2025-03-07 12:00:18 +01:00
hugogogo
08e1200408 update macro prescale values 2025-03-07 11:34:17 +01:00
hugogogo
1bb2e880c8 add comment 2025-03-07 10:57:59 +01:00
hugo LAMY
10480f63d7 wip ex01 2025-03-07 09:09:16 +01:00
hugo LAMY
936c591be4 updated prescaler values 2025-03-07 09:09:00 +01:00
hugo LAMY
d08cc9fd4c update registers sets 2025-03-07 08:44:53 +01:00
hugo LAMY
c037b5184d update mod01 ex01 main comment 2025-03-07 08:03:17 +01:00
hugo LAMY
928f897992 init mode02 ex01 2025-03-07 07:48:02 +01:00
hugo LAMY
e080531ac6 disable receiver 2025-03-07 07:47:28 +01:00
hugo LAMY
9e9dcae5e3 added unsigned 2025-03-06 22:26:50 +01:00
hugo LAMY
638f1d2a68 update comments 2025-03-06 22:11:15 +01:00
hugo LAMY
fe0249bc05 mod02 ex00 ok 2025-03-06 22:07:56 +01:00
hugo LAMY
136c3b93b0 oneline comment 2025-03-06 16:24:54 +01:00
hugo LAMY
ebb578db5f setup mod02 ex00 and oneline comments 2025-03-06 16:23:18 +01:00
hugo LAMY
6ec379e1ae added subjects for all days 2025-03-06 13:38:02 +01:00
hugo LAMY
e1b76139c5 mod01 ex03 done 2025-03-06 13:11:26 +01:00
hugo LAMY
29687bfdf5 fix percentage error in ex02 2025-03-06 13:11:13 +01:00
hugo LAMY
ea43423716 init mod01 ex03 2025-03-06 12:34:13 +01:00
hugo LAMY
25541d0582 update ex02 comments 2025-03-06 12:33:32 +01:00
hugo LAMY
9398b623af mod01 ex02 works 2025-03-06 12:15:25 +01:00
hugo LAMY
fd2be66727 update ressources 2025-03-06 10:41:05 +01:00
hugo LAMY
4a9fe6cd95 updated mains macros 2025-03-06 10:26:39 +01:00
hugo LAMY
3271fbf96d macros with elements 2025-03-06 09:38:39 +01:00
hugo LAMY
714bf2bd9b init mod01 ex02 2025-03-06 09:16:13 +01:00
hugo LAMY
fc45812dfb updated makefile 2025-03-06 09:09:07 +01:00
170 changed files with 4764 additions and 650 deletions

3
.gitignore vendored
View File

@@ -50,4 +50,5 @@ Thumbs.db
# chips
*.bin
*.hex
*.hex
*.o

View File

@@ -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
View File

@@ -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
View 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

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

@@ -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
View 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

View File

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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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
View 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
View 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
View File

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

47
module01/ex02/bitmanip.h Normal file
View 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
View 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
View 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
View 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
View File

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

47
module01/ex03/bitmanip.h Normal file
View 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
View 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
View 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
View 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
View File

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

53
module02/ex00/bitmanip.h Normal file
View 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
View 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
View 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
View File

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

53
module02/ex01/bitmanip.h Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View File

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

53
module02/ex02/bitmanip.h Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View File

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

53
module02/ex03/bitmanip.h Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View File

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

53
module02/ex04/bitmanip.h Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View File

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

32
module03/ex00/main.c Normal file
View 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
View File

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

44
module03/ex01/main.c Normal file
View 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
View File

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

69
module03/ex02/main.c Normal file
View 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
View File

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

77
module03/ex03/colors.c Normal file
View 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
View 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
View 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
View 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
View File

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

17
module04/ex00/header.h Normal file
View 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
View 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
View File

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

20
module04/ex01/header.h Normal file
View 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
View 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
View File

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

30
module04/ex02/header.h Normal file
View 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
View 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
View File

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

27
module05/ex00/adc.c Normal file
View 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
View 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
View 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