Compare commits
3 Commits
master
...
mac_devcon
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41b5ec5e35 | ||
|
|
c650ff1157 | ||
|
|
8a28799aac |
24
.devcontainer/Dockerfile
Normal file
24
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Use Ubuntu as the base image
|
||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
|
# Update and install necessary dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
vim \
|
||||||
|
avr-libc gcc-avr binutils-avr \
|
||||||
|
avrdude \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Set the working directory to /workspace (VSCode will mount your local folder here)
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
# Set the default user as root for installing packages
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# Expose any necessary ports (if needed)
|
||||||
|
# EXPOSE 3000
|
||||||
|
|
||||||
|
# Run bash as the default command when the container starts
|
||||||
|
CMD ["/bin/bash"]
|
||||||
11
.devcontainer/devcontainer.json
Normal file
11
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "Ubuntu DevContainer",
|
||||||
|
"dockerFile": "Dockerfile", // Reference to your Dockerfile
|
||||||
|
"context": ".", // The context is the root of your project
|
||||||
|
"workspaceFolder": "/workspace", // Where VSCode will mount your current folder inside the container
|
||||||
|
"mounts": [
|
||||||
|
"source=${localWorkspaceFolder},target=/workspace,type=bind",
|
||||||
|
"source=/dev/tty.usbserial-310,target=/dev/ttyUSB0,type=bind"
|
||||||
|
],
|
||||||
|
"postCreateCommand": "echo 'Devcontainer setup complete!'"
|
||||||
|
}
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -50,5 +50,4 @@ Thumbs.db
|
|||||||
|
|
||||||
# chips
|
# chips
|
||||||
*.bin
|
*.bin
|
||||||
*.hex
|
*.hex
|
||||||
*.o
|
|
||||||
52
.vscode/c_cpp_properties.json
vendored
52
.vscode/c_cpp_properties.json
vendored
@@ -1,28 +1,24 @@
|
|||||||
// {
|
{
|
||||||
// "configurations": [
|
"configurations": [
|
||||||
// {
|
{
|
||||||
// "name": "AVR",
|
"name": "linux-avr-gcc",
|
||||||
// "includePath": [
|
"includePath": ["${workspaceFolder}/**", "/usr/lib/avr/include/**"],
|
||||||
// "${workspaceFolder}/headers",
|
"defines": [],
|
||||||
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/lib/avr-gcc/9/gcc/avr/9.4.0/include",
|
"mergeConfigurations": false,
|
||||||
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/avr/include",
|
"compilerPath": "/usr/bin/avr-gcc",
|
||||||
// "/opt/homebrew/include"
|
"cStandard": "gnu11",
|
||||||
// ],
|
"cppStandard": "gnu++14",
|
||||||
// "defines": ["__AVR_ATmega328P__"],
|
"intelliSenseMode": "linux-gcc-x64",
|
||||||
// "intelliSenseMode": "gcc-x64",
|
"compilerArgs": ["-mmcu=atmega328p", "-DF_CPU=16000000UL", "-Os"]
|
||||||
// "cStandard": "c11",
|
},
|
||||||
// "cppStandard": "c++17",
|
{
|
||||||
// "browse": {
|
"name": "linux-gcc-x64",
|
||||||
// "path": [
|
"includePath": ["${workspaceFolder}/**"],
|
||||||
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/lib/avr-gcc/9/gcc/avr/9.4.0/include",
|
"compilerPath": "/usr/bin/gcc",
|
||||||
// "/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/avr/include",
|
"intelliSenseMode": "linux-gcc-x64",
|
||||||
// "/opt/homebrew/include"
|
"compilerArgs": [""],
|
||||||
// // "/opt/homebrew/lib/gcc/avr/include",
|
"mergeConfigurations": false
|
||||||
// // "/opt/homebrew/lib/gcc/avr/include-fixed"
|
}
|
||||||
// ],
|
],
|
||||||
// "limitSymbolsToIncludedHeaders": true
|
"version": 4
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// "version": 4
|
|
||||||
// }
|
|
||||||
|
|||||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@@ -1,14 +1,6 @@
|
|||||||
{
|
{
|
||||||
"editor.insertSpaces": false,
|
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"header.h": "c"
|
"io.h": "c",
|
||||||
},
|
"delay.h": "c"
|
||||||
"C_Cpp.default.includePath": [
|
}
|
||||||
"${workspaceFolder}/headers",
|
|
||||||
"/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/lib/avr-gcc/9/gcc/avr/9.4.0/include",
|
|
||||||
"/opt/homebrew/Cellar/avr-gcc@9/9.4.0_1/avr/include",
|
|
||||||
"/opt/homebrew/include"
|
|
||||||
],
|
|
||||||
"C_Cpp.default.defines": ["__AVR_ATmega328P__"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
83
Makefile
83
Makefile
@@ -1,83 +0,0 @@
|
|||||||
# frequency of the CPU (in Hz)
|
|
||||||
F_CPU = 16000000UL
|
|
||||||
TARGET = main
|
|
||||||
CC = avr-gcc
|
|
||||||
INCLUDES ?= -I../../headers/ # ?= : dont define if already defined
|
|
||||||
|
|
||||||
AVRGCC_MCU_TYPE = atmega328p
|
|
||||||
AVRDUDE_MCU_TYPE = m328p
|
|
||||||
BAUD_RATE = 115200
|
|
||||||
PROGRAMMER_ID = arduino
|
|
||||||
|
|
||||||
# original firmware dump
|
|
||||||
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
|
||||||
|
|
||||||
# Find all C source files in the current directory
|
|
||||||
SRC = $(wildcard *.c)
|
|
||||||
# Generate object file names from source file names
|
|
||||||
OBJ = $(SRC:.c=.o)
|
|
||||||
|
|
||||||
# Compiler flags
|
|
||||||
CFLAGS = -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(INCLUDES) -Os
|
|
||||||
|
|
||||||
# Detect OS
|
|
||||||
OS := $(shell uname -s)
|
|
||||||
|
|
||||||
# Set Serial Port based on OS
|
|
||||||
ifeq ($(OS), Darwin) # macOS
|
|
||||||
SERIAL_PORT := $(shell ls /dev/tty.usb* 2>/dev/null | head -n 1) # should be : /dev/tty.usbserial-310
|
|
||||||
else ifeq ($(OS), Linux) # Ubuntu/Linux
|
|
||||||
SERIAL_PORT = $(shell ls /dev/ttyUSB* 2>/dev/null | head -n 1) # should be : /dev/ttyUSB0
|
|
||||||
endif
|
|
||||||
|
|
||||||
##
|
|
||||||
## RULES
|
|
||||||
##
|
|
||||||
|
|
||||||
all: hex flash
|
|
||||||
|
|
||||||
hex: $(TARGET).hex
|
|
||||||
|
|
||||||
# Compile each .c file to corresponding .o file
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
# Link all object files to create the binary
|
|
||||||
# avr-gcc : compiler for AVR microcontrollers, https://gcc.gnu.org/wiki/avr-gcc#Using_avr-gcc, https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
|
||||||
# -mmcu : the target microcontrolle (ATmega328P)
|
|
||||||
# -D : defines a preprocessor macro (#define F_CPU <value>)
|
|
||||||
# -o : output filename
|
|
||||||
$(TARGET).bin: $(OBJ)
|
|
||||||
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) $(OBJ) -o $(TARGET).bin
|
|
||||||
|
|
||||||
# Convert binary to hex for flashing
|
|
||||||
# avr-objcopy : man avr-jobcopy, https://linux.die.net/man/1/avr-objcopy
|
|
||||||
# -O : specifies output format, Intel HEX
|
|
||||||
# some formats (list not found in any doc) :
|
|
||||||
# -O ihex : Used for flashing AVR chips
|
|
||||||
# -O binary : Raw binary file
|
|
||||||
# -O elf32-avr : Used for debugging
|
|
||||||
$(TARGET).hex: $(TARGET).bin
|
|
||||||
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
|
||||||
|
|
||||||
# Flash the hex file to the microcontroller
|
|
||||||
# avr-dude : AVR Downloader/UploaDEr, upload firmware, https://avrdudes.github.io/avrdude, v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf
|
|
||||||
# -p : specifies the microcontroller -> m328p
|
|
||||||
# -c : programmer-id
|
|
||||||
# -b : baud rate for serial communication
|
|
||||||
# -P : the serial port, found with `ls /dev/tty*` -> /dev/ttyUSB0
|
|
||||||
# -U : Uploads (w = write) the HEX firmware file to the flash memory
|
|
||||||
# (-v : verbose info dump)
|
|
||||||
flash:
|
|
||||||
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
|
||||||
|
|
||||||
restore:
|
|
||||||
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
|
||||||
|
|
||||||
dump:
|
|
||||||
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:r:dump.hex
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f main.hex main.bin *.o
|
|
||||||
|
|
||||||
.PHONY : all clean hex flash restore
|
|
||||||
40
README.md
40
README.md
@@ -1,14 +1,11 @@
|
|||||||
# RESSOURCES
|
# RESSOURCES
|
||||||
|
|
||||||
- guide survie piscine embarquee : https://42chips.notion.site/survive
|
|
||||||
- atmega328p : https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf
|
- atmega328p : https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf
|
||||||
- Getting started with AVR programming : https://github.com/m3y54m/start-avr/tree/master
|
- Getting started with AVR programming : https://github.com/m3y54m/start-avr/tree/master
|
||||||
- avrdude doc : https://avrdudes.github.io/avrdude/
|
- avrdude doc : https://avrdudes.github.io/avrdude/
|
||||||
- avrdude 6.3 doc : https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf
|
- avrdude 6.3 doc : https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf
|
||||||
- embedded systems : https://en.wikibooks.org/wiki/Embedded_Systems/Atmel_AVR
|
- embedded systems : https://en.wikibooks.org/wiki/Embedded_Systems/Atmel_AVR
|
||||||
- timers for newbies : https://qiriro.com/bme6163/static_files/notes/L3/Newbie%27s%20Guide%20to%20AVR%20Timers.pdf
|
- timers for newbies : https://qiriro.com/bme6163/static_files/notes/L3/Newbie%27s%20Guide%20to%20AVR%20Timers.pdf
|
||||||
- timer and pwm : https://wolles-elektronikkiste.de/en/timer-and-pwm-part-2-16-bit-timer1
|
|
||||||
- doc AHT20 thermostat : https://asairsensors.com/wp-content/uploads/2021/09/Data-Sheet-AHT20-Humidity-and-Temperature-Sensor-ASAIR-V1.0.03.pdf
|
|
||||||
|
|
||||||
## m00ex00
|
## m00ex00
|
||||||
|
|
||||||
@@ -83,12 +80,37 @@ avrdude: safemode: Fuses OK (E:00, H:00, L:00)
|
|||||||
avrdude done. Thank you.
|
avrdude done. Thank you.
|
||||||
```
|
```
|
||||||
|
|
||||||
## makefile on mac
|
## test macros
|
||||||
|
|
||||||
- `brew tap osx-cross/avr`
|
#include <stdio.h>
|
||||||
- `brew install avr-gcc avrdude`
|
#include <avr/io.h>
|
||||||
|
|
||||||
## screen
|
// // stringify
|
||||||
|
#define STRINGIFY_HELPER(x) #x
|
||||||
|
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||||
|
|
||||||
- (optional) `export TERM=xterm`
|
#define CONCAT_HELPER(x, y) x ## y
|
||||||
- `screen /dev/ttyUSB0 115200`
|
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
||||||
|
|
||||||
|
// get argument at nth position
|
||||||
|
#define ARG_1(v1, v2) v1
|
||||||
|
#define ARG_2(v1, v2) v2
|
||||||
|
#define GET_PORT(args) ARG_1 args
|
||||||
|
#define GET_BIT(args) ARG_2 args
|
||||||
|
|
||||||
|
// actions on registers
|
||||||
|
#define SET(register, bit) register |= 1 << bit
|
||||||
|
|
||||||
|
// actions on ports
|
||||||
|
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
||||||
|
|
||||||
|
// elements
|
||||||
|
#define LED1 (B, 0)
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
MODE_OUTPUT(LED1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef ADC_H
|
|
||||||
#define ADC_H
|
|
||||||
|
|
||||||
// Table 24-5 : prescaler ADC
|
|
||||||
#define ADC_PRESCALE_SET(value) \
|
|
||||||
((value) == 2 ? (0<<ADPS2 | 0<<ADPS1 | 1<<ADPS0) : \
|
|
||||||
(value) == 4 ? (0<<ADPS2 | 1<<ADPS1 | 0<<ADPS0) : \
|
|
||||||
(value) == 8 ? (0<<ADPS2 | 1<<ADPS1 | 1<<ADPS0) : \
|
|
||||||
(value) == 16 ? (1<<ADPS2 | 0<<ADPS1 | 0<<ADPS0) : \
|
|
||||||
(value) == 32 ? (1<<ADPS2 | 0<<ADPS1 | 1<<ADPS0) : \
|
|
||||||
(value) == 64 ? (1<<ADPS2 | 1<<ADPS1 | 0<<ADPS0) : \
|
|
||||||
(value) == 128 ? (1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0) : \
|
|
||||||
(0<<ADPS2 | 0<<ADPS1 | 0<<ADPS0))
|
|
||||||
|
|
||||||
// Table 24-6 : ADC Auto Trigger Source Selections
|
|
||||||
#define ADC_TRIGGER_FREE_RUNNING (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_ANALOG_COMPARE (0 << ADTS2) | (0 << ADTS1) | (1 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_EXTERNAL_INTERRUPT_0 (0 << ADTS2) | (1 << ADTS1) | (0 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_TIMER_0_COMPARE_A (0 << ADTS2) | (1 << ADTS1) | (1 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_TIMER_0_OVERFLOW (1 << ADTS2) | (0 << ADTS1) | (0 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_TIMER_1_COMPARE_B (1 << ADTS2) | (0 << ADTS1) | (1 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_TIMER_1_OVERFLOW (1 << ADTS2) | (1 << ADTS1) | (0 << ADTS0)
|
|
||||||
#define ADC_TRIGGER_TIMER_1_CAPTURE_EVENT (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0)
|
|
||||||
|
|
||||||
#endif // ADC_H
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
// // version with "LED1 B, D1" without parenthesis
|
|
||||||
// #define ARG_1(v1, ...) v1
|
|
||||||
// #define ARG_2(v1, v2, ...) v2
|
|
||||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
|
||||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
#define PULLUP_ON(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define PULLUP_OFF(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
// Bit definitions (<pin number> // <pin name>)
|
|
||||||
#define D1 0 // PB0
|
|
||||||
#define D2 1 // PB1
|
|
||||||
#define D3 2 // PB2
|
|
||||||
#define D4 4 // PB4
|
|
||||||
#define SW1 2 // PD2
|
|
||||||
#define SW2 4 // PD4
|
|
||||||
#define D5B 3 // PD3
|
|
||||||
#define D5R 5 // PD5
|
|
||||||
#define D5G 6 // PD6
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
#define RGB5_BLUE (D, D5B)
|
|
||||||
#define RGB5_RED (D, D5R)
|
|
||||||
#define RGB5_GEEN (D, D5G)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#ifndef I2C_H
|
|
||||||
#define I2C_H
|
|
||||||
|
|
||||||
// table 22-7 : prescale sets
|
|
||||||
#define TWI_PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<TWPS1 | 0<<TWPS0) : \
|
|
||||||
(value) == 4 ? (0<<TWPS1 | 1<<TWPS0) : \
|
|
||||||
(value) == 16 ? (1<<TWPS1 | 0<<TWPS0) : \
|
|
||||||
(value) == 64 ? (1<<TWPS1 | 1<<TWPS0) : 0x00)
|
|
||||||
|
|
||||||
// 22.7.1 : TWCR, Master Transmitter Mode
|
|
||||||
#define TWI_START_CONDITION ((1<<TWINT) | (1<<TWEN)) | (1<<TWSTA)
|
|
||||||
#define TWI_STOP_CONDITION ((1<<TWINT) | (1<<TWEN)) | (1<<TWSTO)
|
|
||||||
#define TWI_ACKNOWLEDGE ((1<<TWINT) | (1<<TWEN) | (1<<TWEA))
|
|
||||||
#define TWI_NACKNOWLEDGE ((1<<TWINT) | (1<<TWEN))
|
|
||||||
|
|
||||||
#endif // I2C_H
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef INTERRUPT_H
|
|
||||||
#define INTERRUPT_H
|
|
||||||
|
|
||||||
// 7.3.1 : SREG – AVR Status Register
|
|
||||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
|
||||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
|
||||||
|
|
||||||
#endif // INTERRUPT_H
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 15-9 : timer 0 prescale sets
|
|
||||||
#define T0_PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS02 | 0<<CS01 | 1<<CS00) : \
|
|
||||||
(value) == 8 ? (0<<CS02 | 1<<CS01 | 0<<CS00) : \
|
|
||||||
(value) == 64 ? (0<<CS02 | 1<<CS01 | 1<<CS00) : \
|
|
||||||
(value) == 256 ? (1<<CS02 | 0<<CS01 | 0<<CS00) : \
|
|
||||||
(value) == 1024? (1<<CS02 | 0<<CS01 | 1<<CS00) : \
|
|
||||||
(0<<CS02 | 0<<CS01 | 0<<CS00))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
// table 16-5 : timer 1 prescale sets
|
|
||||||
#define T1_PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
|
||||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
|
||||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
|
||||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#ifndef USART_H
|
|
||||||
#define USART_H
|
|
||||||
|
|
||||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
|
||||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
|
||||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
|
||||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
|
||||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
|
||||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
|
||||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
|
||||||
#define STOP_ONE_BIT (0<<USBS0)
|
|
||||||
#define STOP_TWO_BIT (1<<USBS0)
|
|
||||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
|
||||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
|
||||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
|
||||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
|
||||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
|
||||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
|
||||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
|
||||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
|
||||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
|
||||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
|
||||||
|
|
||||||
#endif // USART_H
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
||||||
#define INT_TO_HEX_CHAR(n) ((n) < 10 ? ('0' + (n)) : ('A' + ((n) - 10)))
|
|
||||||
|
|
||||||
// text
|
|
||||||
#define SWITCH_CASE(ch) (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ? ((ch) ^ (1 << 5)) : (ch))
|
|
||||||
|
|
||||||
// // boolean
|
|
||||||
// #define TRUE 1
|
|
||||||
// #define FALSE 0
|
|
||||||
|
|
||||||
//
|
|
||||||
// ENUM
|
|
||||||
//
|
|
||||||
typedef enum {
|
|
||||||
FALSE,
|
|
||||||
TRUE
|
|
||||||
} Boolean;
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +1,50 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
# avr-gcc : compiler for AVR microcontrollers, https://gcc.gnu.org/wiki/avr-gcc#Using_avr-gcc, https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
# -mmcu : the target microcontrolle (ATmega328P)
|
||||||
|
# -D : defines a preprocessor macro (#define F_CPU <value>)
|
||||||
|
# -o : output filename
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=atmega328p -D F_CPU=$(F_CPU) $(TARGET).c -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# avr-objcopy : man avr-jobcopy, https://linux.die.net/man/1/avr-objcopy
|
||||||
|
# -O : specifies output format, Intel HEX
|
||||||
|
# some formats (list not found in any doc) :
|
||||||
|
# -O ihex : Used for flashing AVR chips
|
||||||
|
# -O binary : Raw binary file
|
||||||
|
# -O elf32-avr : Used for debugging
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# avr-dude : AVR Downloader/UploaDEr, upload firmware, https://avrdudes.github.io/avrdude, v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf
|
||||||
|
# -p : specifies the microcontroller -> m328p
|
||||||
|
# -c : programmer-id
|
||||||
|
# -b : baud rate for serial communication
|
||||||
|
# -P : the serial port, found with `ls /dev/tty*` -> /dev/ttyUSB0
|
||||||
|
# -U : Uploads (w = write) the HEX firmware file to the flash memory
|
||||||
|
# (-v : verbose info dump)
|
||||||
|
flash:
|
||||||
|
avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:w:$(TARGET).hex
|
||||||
|
# avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -v
|
||||||
|
# avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:w:../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
dump:
|
||||||
|
avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:r:dump_atmega328p.hex
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash dump
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// write a makefile that compiles the code and flashes it to the microcontroller
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -1 +1,43 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
AVRGCC_MCU_TYPE = atmega328p
|
||||||
|
AVRDUDE_MCU_TYPE = m328p
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
SERIAL_PORT = /dev/ttyUSB0
|
||||||
|
PROGRAMMER_ID = arduino
|
||||||
|
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# https://linux.die.net/man/1/avr-objcopy
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
|
||||||
|
flash:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
restore:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash restore
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
// #include <util/delay.h>
|
||||||
|
|
||||||
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT
|
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT
|
||||||
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
|
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
|
||||||
@@ -10,27 +11,75 @@
|
|||||||
#define D3 2
|
#define D3 2
|
||||||
#define D4 4
|
#define D4 4
|
||||||
|
|
||||||
// 14.2 : registers :
|
|
||||||
// DDRx : (Data Direction Register) Controls whether each pin is an input or output
|
|
||||||
// - 1 = output (pull-up off)
|
|
||||||
// - 0 = input
|
|
||||||
// PORTx : (Port Data Register)
|
|
||||||
// if DDRx = 1 (output mode) : Controls the output state of a pin when it's configured as an output
|
|
||||||
// - 1 = HIGH (5V?) (VCC)
|
|
||||||
// - 0 = LOW (0V) (GND)
|
|
||||||
// if DDRx = 0 (input mode) : Controls the internal pull-up resistor when the pin is an input
|
|
||||||
// - 1 = pull-up on
|
|
||||||
// - 0 = pull-up off (pin floats)
|
|
||||||
// PINx : (Pin Input Register) Reads the current logical state of a pin
|
|
||||||
// Reflects the actual voltage on the pin
|
|
||||||
// Special feature: Writing 1 to PINxn toggles the corresponding PORTxn bit (regardless of DDRx)
|
|
||||||
|
|
||||||
// turns on led 1 with only AVR registers (DDRX , PORTX, PINX)
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
// registers :
|
||||||
|
// DDRx : (Data Direction Register) Controls whether each pin is an input or output
|
||||||
|
// - 1 = output (pull-up off)
|
||||||
|
// - 0 = input
|
||||||
|
// PORTx : (Port Data Register)
|
||||||
|
// if DDRx = 1 (output mode) : Controls the output state of a pin when it's configured as an output
|
||||||
|
// - 1 = HIGH (5V?) (VCC)
|
||||||
|
// - 0 = LOW (0V) (GND)
|
||||||
|
// if DDRx = 0 (input mode) : Controls the internal pull-up resistor when the pin is an input
|
||||||
|
// - 1 = pull-up on
|
||||||
|
// - 0 = pull-up off (pin floats)
|
||||||
|
// PINx : (Pin Input Register) Reads the current logical state of a pin
|
||||||
|
// Reflects the actual voltage on the pin
|
||||||
|
// Special feature: Writing 1 to PINxn toggles the corresponding PORTxn bit (regardless of DDRx)
|
||||||
|
|
||||||
// turns on led 1
|
// turns on led 1
|
||||||
SET(DDRB, D1); // make PB0 as OUTPUT (pullup is off)
|
SET(DDRB, D1); // make PB0 as OUTPUT (pullup is off)
|
||||||
SET(PORTB, D1); // make PB0 as HIGH (LED turns ON)
|
SET(PORTB, D1); // make PB0 as HIGH (LED turns ON)
|
||||||
|
|
||||||
|
// SET(DDRB, D2); // make PB1 as OUTPUT (pullup is off)
|
||||||
|
// CLEAR(PORTB, D2); // make PB1 as LOW (LED turns OFF)
|
||||||
|
|
||||||
|
// CLEAR(DDRB, D3); // make PB2 as INPUT
|
||||||
|
// SET(PORTB, D3); // make PB2 pullup on
|
||||||
|
|
||||||
|
// CLEAR(DDRB, D4); // make PB4 as INPUT
|
||||||
|
// CLEAR(PORTB, D4); // make PB4 pullup off
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// TEST weird behavior of PIN register :
|
||||||
|
// in initial tests, using PIN register to toggle ON two leds only worked for the second one
|
||||||
|
// after some tests, this behavior is not anymore
|
||||||
|
//
|
||||||
|
// test 1 : only led 3 turns on
|
||||||
|
// SET(DDRB, D1);
|
||||||
|
// CLEAR(PORTB, D1);
|
||||||
|
// SET(PINB, D1);
|
||||||
|
// SET(DDRB, D3);
|
||||||
|
// CLEAR(PORTB, D3);
|
||||||
|
// SET(PINB, D3);
|
||||||
|
//
|
||||||
|
// test 2 : only led 3 turns on
|
||||||
|
// SET(DDRB, D1);
|
||||||
|
// CLEAR(PORTB, D1);
|
||||||
|
// SET(DDRB, D3);
|
||||||
|
// CLEAR(PORTB, D3);
|
||||||
|
// SET(PINB, D1);
|
||||||
|
// SET(PINB, D3);
|
||||||
|
//
|
||||||
|
// test 3 : both leds turns on
|
||||||
|
// SET(DDRB, D1);
|
||||||
|
// CLEAR(PORTB, D1);
|
||||||
|
// SET(DDRB, D3);
|
||||||
|
// CLEAR(PORTB, D3);
|
||||||
|
// PINB = (1 << D1) | (1 << D3);
|
||||||
|
//
|
||||||
|
// test 4 : both leds turns on
|
||||||
|
// SET(DDRB, D1);
|
||||||
|
// CLEAR(PORTB, D1);
|
||||||
|
// SET(DDRB, D3);
|
||||||
|
// CLEAR(PORTB, D3);
|
||||||
|
// SET(PINB, D1);
|
||||||
|
// _delay_us(500);
|
||||||
|
// SET(PINB, D3);
|
||||||
|
//
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1 +1,43 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
AVRGCC_MCU_TYPE = atmega328p
|
||||||
|
AVRDUDE_MCU_TYPE = m328p
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
SERIAL_PORT = /dev/ttyUSB0
|
||||||
|
PROGRAMMER_ID = arduino
|
||||||
|
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# https://linux.die.net/man/1/avr-objcopy
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
|
||||||
|
flash:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
restore:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash restore
|
||||||
@@ -1,67 +1,101 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
// stringify
|
// test with https://www.onlinegdb.com/online_c_compiler
|
||||||
#define STRINGIFY_HELPER(x) #x
|
// // V1
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
//
|
||||||
|
// // macro to extract port and bit from a single pin
|
||||||
|
// #define _PORT(pin) ((pin) >> 3)
|
||||||
|
// #define _BIT(pin) ((pin) & 0x07) // 0x07 is 00000111
|
||||||
|
//
|
||||||
|
// // helper macros for port name concatenation
|
||||||
|
// #define _CONCAT(a, b) a ## b
|
||||||
|
// #define PORT_REGISTER(pin) _CONCAT(PORT, _PORT(pin))
|
||||||
|
// #define DDR_REGISTER(pin) _CONCAT(DDR, _PORT(pin))
|
||||||
|
// #define PIN_REGISTER(pin) _CONCAT(PIN, _PORT(pin))
|
||||||
|
//
|
||||||
|
// // Macros to set/clear/toggle specific bit
|
||||||
|
// #define SET(REGISTER, PIN) REGISTER |= 1 << _BIT(PIN)
|
||||||
|
// #define CLEAR(REGISTER, PIN) REGISTER &= ~(1 << _BIT(PIN))
|
||||||
|
// #define TOGGLE(REGISTER, PIN) REGISTER ^= 1 << _BIT(PIN)
|
||||||
|
// #define MODE_OUTPUT(PIN) (DDR_REGISTER(PIN) |= 1 << _BIT(PIN))
|
||||||
|
// #define MODE_INPUT(PIN) (DDR_REGISTER(PIN) &= ~(1 << _BIT(PIN)))
|
||||||
|
//
|
||||||
|
// // Test and check macros
|
||||||
|
// #define TEST_PIN(PIN) (PIN_REGISTER(PIN) & (1 << _BIT(PIN)))
|
||||||
|
// #define IS_SET(PIN) (TEST(PIN) != 0)
|
||||||
|
// #define IS_CLEAR(PIN) (TEST(PIN) == 0)
|
||||||
|
//
|
||||||
|
// // Pin definitions
|
||||||
|
// #define D1 (0 + (1 << 3)) // Port B, bit 0
|
||||||
|
// #define D2 (1 + (1 << 3)) // Port B, bit 1
|
||||||
|
// #define D3 (2 + (1 << 3)) // Port B, bit 2
|
||||||
|
// #define D4 (4 + (1 << 3)) // Port B, bit 4
|
||||||
|
// #define SW1 (2 + (3 << 3)) // Port D, bit 2
|
||||||
|
// #define SW2 (4 + (3 << 3)) // Port D, bit 4
|
||||||
|
|
||||||
// concatenate
|
// // V2
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
//
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
// // Define the ports
|
||||||
|
// #define PORT_B 0 // Port A (represented by 0)
|
||||||
|
// #define PORT_C 1 // Port B (represented by 1)
|
||||||
|
// #define PORT_D 2 // Port C (represented by 2)
|
||||||
|
//
|
||||||
|
// // Macros to extract the port and bit
|
||||||
|
// #define _PORT_INT(pin) ((pin) >> 3) // Extract the port
|
||||||
|
// #define _PORT(pin) \
|
||||||
|
// ((_PORT_INT(pin)) == PORT_B ? 'B' : \
|
||||||
|
// ((_PORT_INT(pin)) == PORT_C ? 'C' : \
|
||||||
|
// ((_PORT_INT(pin)) == PORT_D ? 'D' : \
|
||||||
|
// 'X')))
|
||||||
|
// #define _BIT(pin) ((pin) & 0x07) // Extract the bit
|
||||||
|
//
|
||||||
|
// // Macros to set/clear/toggle specific bit
|
||||||
|
// #define SET(REGISTER, PIN) REGISTER |= 1 << _BIT(PIN)
|
||||||
|
// #define CLEAR(REGISTER, PIN) REGISTER &= ~(1 << _BIT(PIN))
|
||||||
|
// #define TOGGLE(REGISTER, PIN) REGISTER ^= 1 << _BIT(PIN)
|
||||||
|
// #define MODE_OUTPUT(PIN) (_PORT(PIN) |= 1 << _BIT(PIN))
|
||||||
|
// #define MODE_INPUT(PIN) (_PORT(PIN) &= ~(1 << _BIT(PIN)))
|
||||||
|
//
|
||||||
|
// // Test and check macros
|
||||||
|
// #define TEST(PIN) (PIN_REGISTER(PIN) & (1 << _BIT(PIN)))
|
||||||
|
// #define IS_SET(PIN) (TEST(PIN) != 0)
|
||||||
|
// #define IS_CLEAR(PIN) (TEST(PIN) == 0)
|
||||||
|
//
|
||||||
|
// // Define each LED's port and bit using macros
|
||||||
|
// #define D1 (PORT_B << 3 | 0) // LED1 is on Port B, bit 0
|
||||||
|
// #define D2 (PORT_B << 3 | 1) // LED2 is on Port A, bit 1
|
||||||
|
// #define D3 (PORT_B << 3 | 2) // LED3 is on Port C, bit 2
|
||||||
|
// #define D4 (PORT_B << 3 | 4) // LED4 is on Port C, bit 4
|
||||||
|
|
||||||
// get argument
|
// V0
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// actions on registers
|
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT
|
||||||
#define SET(register, bit) register |= 1 << bit
|
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
|
||||||
#define CLEAR(register, bit) register &= ~(1 << bit)
|
#define TEST(REGISTER, BIT) REGISTER & 1 << BIT
|
||||||
#define TEST(register, bit) register & 1 << bit
|
#define TEST_PIN(PORT, BIT) PIN ## PORT & 1 << BIT
|
||||||
#define TOGGLE(register, bit) register ^= 1 << bit
|
#define TOGGLE(REGISTER, BIT) REGISTER ^= 1 << BIT
|
||||||
|
#define MODE_INPUT(PORT, BIT) CLEAR(DDR ## PORT, BIT)
|
||||||
|
#define MODE_OUTPUT(PORT, BIT) SET(DDR ## PORT, BIT)
|
||||||
|
#define IS_PIN_SET(PORT, BIT) (TEST_PIN(PORT, BIT)) == 0
|
||||||
|
#define IS_PIN_CLEAR(PORT, BIT) (TEST_PIN(PORT, BIT)) == 1
|
||||||
|
|
||||||
// actions on elements
|
#define D1 0
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
#define D2 1
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
#define D3 2
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
#define D4 4
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
#define SW1 2
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
#define SW2 4
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// bits
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#define BUTTON(id)
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
// turn on LED1 when BUTTON1 is pressed
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
MODE_OUTPUT(LED1);
|
MODE_OUTPUT(B, D1);
|
||||||
MODE_INPUT(BUTTON1);
|
MODE_INPUT(D, SW1);
|
||||||
while(1) {
|
while(1) {
|
||||||
if (IS_PIN_SET(BUTTON1)) {
|
if (IS_PIN_SET(D, SW1)) {
|
||||||
SET_ELEM(LED1);
|
SET(PORTB, D1);
|
||||||
} else {
|
} else {
|
||||||
CLEAR_ELEM(LED1);
|
CLEAR(PORTB, D1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1 +1,43 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
AVRGCC_MCU_TYPE = atmega328p
|
||||||
|
AVRDUDE_MCU_TYPE = m328p
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
SERIAL_PORT = /dev/ttyUSB0
|
||||||
|
PROGRAMMER_ID = arduino
|
||||||
|
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# https://linux.die.net/man/1/avr-objcopy
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
|
||||||
|
flash:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
restore:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash restore
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#ifndef HEADERS_H
|
|
||||||
#define HEADERS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// get argument
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// actions on registers
|
|
||||||
#define SET(register, bit) register |= 1 << bit
|
|
||||||
#define CLEAR(register, bit) register &= ~(1 << bit)
|
|
||||||
#define TEST(register, bit) register & 1 << bit
|
|
||||||
#define TOGGLE(register, bit) register ^= 1 << bit
|
|
||||||
|
|
||||||
// actions on elements
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// bits
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#define BUTTON(id)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,17 +1,32 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
|
||||||
#include "macros.h"
|
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT
|
||||||
|
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
|
||||||
|
#define TEST(REGISTER, BIT) REGISTER & 1 << BIT
|
||||||
|
#define TEST_PIN(PORT, BIT) PIN ## PORT & 1 << BIT
|
||||||
|
#define TOGGLE(REGISTER, BIT) REGISTER ^= 1 << BIT
|
||||||
|
#define TOGGLE_PIN(PORT, BIT) PIN ## PORT |= 1 << BIT
|
||||||
|
#define MODE_INPUT(PORT, BIT) CLEAR(DDR ## PORT, BIT)
|
||||||
|
#define MODE_OUTPUT(PORT, BIT) SET(DDR ## PORT, BIT)
|
||||||
|
#define IS_PIN_SET(PORT, BIT) (TEST_PIN(PORT, BIT)) == 0
|
||||||
|
#define IS_PIN_CLEAR(PORT, BIT) (TEST_PIN(PORT, BIT)) == 1
|
||||||
|
|
||||||
|
#define D1 0
|
||||||
|
#define D2 1
|
||||||
|
#define D3 2
|
||||||
|
#define D4 4
|
||||||
|
#define SW1 2
|
||||||
|
#define SW2 4
|
||||||
|
|
||||||
// toggle LED1 when BUTTON1 is pressed
|
|
||||||
int main() {
|
int main() {
|
||||||
MODE_OUTPUT(LED1);
|
MODE_OUTPUT(B, D1);
|
||||||
MODE_INPUT(BUTTON1);
|
MODE_INPUT(D, SW1);
|
||||||
while(1) {
|
while(1) {
|
||||||
if (IS_PIN_SET(BUTTON1)) {
|
if (IS_PIN_SET(D, SW1)) {
|
||||||
TOGGLE_PIN(LED1);
|
TOGGLE_PIN(B, D1);
|
||||||
_delay_ms(20);
|
_delay_ms(20);
|
||||||
while(IS_PIN_SET(BUTTON1)) {
|
while(IS_PIN_SET(D, SW1)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_delay_ms(20);
|
_delay_ms(20);
|
||||||
|
|||||||
@@ -1 +1,43 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
AVRGCC_MCU_TYPE = atmega328p
|
||||||
|
AVRDUDE_MCU_TYPE = m328p
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
SERIAL_PORT = /dev/ttyUSB0
|
||||||
|
PROGRAMMER_ID = arduino
|
||||||
|
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# https://linux.die.net/man/1/avr-objcopy
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
|
||||||
|
flash:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
restore:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash restore
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,8 +1,23 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#define SET(REGISTER, BIT) REGISTER |= 1 << BIT
|
||||||
#include "bitmanip.h"
|
#define CLEAR(REGISTER, BIT) REGISTER &= ~(1 << BIT)
|
||||||
|
#define TEST(REGISTER, BIT) REGISTER & 1 << BIT
|
||||||
|
#define TEST_PIN(PORT, BIT) PIN ## PORT & 1 << BIT
|
||||||
|
#define TOGGLE(REGISTER, BIT) REGISTER ^= 1 << BIT
|
||||||
|
#define TOGGLE_PIN(PORT, BIT) PIN ## PORT |= 1 << BIT
|
||||||
|
#define MODE_INPUT(PORT, BIT) CLEAR(DDR ## PORT, BIT)
|
||||||
|
#define MODE_OUTPUT(PORT, BIT) SET(DDR ## PORT, BIT)
|
||||||
|
#define IS_PIN_SET(PORT, BIT) (TEST_PIN(PORT, BIT)) == 0
|
||||||
|
#define IS_PIN_CLEAR(PORT, BIT) (TEST_PIN(PORT, BIT)) == 1
|
||||||
|
|
||||||
|
#define D1 0
|
||||||
|
#define D2 1
|
||||||
|
#define D3 2
|
||||||
|
#define D4 4
|
||||||
|
#define SW1 2
|
||||||
|
#define SW2 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int *value;
|
int *value;
|
||||||
@@ -42,24 +57,23 @@ void decrement_led(void *param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_press(int bit, void (*action)(void*), void *params) {
|
void on_press(int bit, void (*action)(void*), void *params) {
|
||||||
if ((TEST(PIND, bit)) == 0) {
|
if (IS_PIN_SET(D, bit)) {
|
||||||
action(params);
|
action(params);
|
||||||
_delay_ms(20);
|
_delay_ms(20);
|
||||||
while ((TEST(PIND, bit)) == 0) {
|
while (IS_PIN_SET(D, bit)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_delay_ms(20);
|
_delay_ms(20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write a program that increments and decrements a binary number using the buttons, and displays the result on the LEDs
|
|
||||||
int main() {
|
int main() {
|
||||||
MODE_OUTPUT(LED1);
|
MODE_OUTPUT(B, D1);
|
||||||
MODE_OUTPUT(LED2);
|
MODE_OUTPUT(B, D2);
|
||||||
MODE_OUTPUT(LED3);
|
MODE_OUTPUT(B, D3);
|
||||||
MODE_OUTPUT(LED4);
|
MODE_OUTPUT(B, D4);
|
||||||
MODE_INPUT(BUTTON1);
|
MODE_INPUT(D, SW1);
|
||||||
MODE_INPUT(BUTTON2);
|
MODE_INPUT(D, SW2);
|
||||||
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
int max = 15;
|
int max = 15;
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +1,43 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
AVRGCC_MCU_TYPE = atmega328p
|
||||||
|
AVRDUDE_MCU_TYPE = m328p
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
SERIAL_PORT = /dev/ttyUSB0
|
||||||
|
PROGRAMMER_ID = arduino
|
||||||
|
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# https://linux.die.net/man/1/avr-objcopy
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
|
||||||
|
flash:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
restore:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash restore
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,33 +1,65 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|
||||||
#include "utils.h"
|
// #define FIRST_LETTER_IMPL(x) #x[0]
|
||||||
#include "bitmanip.h"
|
// #define FIRST_LETTER(x) FIRST_LETTER_IMPL(x)
|
||||||
|
// #define PORT_LETTER(PIN) FIRST_LETTER(PIN)
|
||||||
|
|
||||||
// TIMER
|
// global registers
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
#define SET(register, bit) register |= 1 << bit
|
||||||
// table 16-5 : prescale sets
|
#define CLEAR(register, bit) register &= ~(1 << bit)
|
||||||
#define PRESCALE_SET(value) \
|
#define TEST(register, bit) register & 1 << bit
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
#define TOGGLE(register, bit) register ^= 1 << bit
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
// actions on ports
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
#define TEST_PIN(port, bit) TEST(PIN ## port, bit)
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
#define TOGGLE_PIN(port, bit) SET(PIN ## port, bit)
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
#define MODE_INPUT(port, bit) CLEAR(DDR ## port, bit)
|
||||||
|
#define MODE_OUTPUT(port, bit) SET(DDR ## port, bit)
|
||||||
|
#define IS_PIN_SET(port, bit) (TEST_PIN(port, bit)) == 0
|
||||||
|
#define IS_PIN_CLEAR(port, bit) (TEST_PIN(port, bit)) == 1
|
||||||
|
#define TURN_ON(_PORT, BIT) SET(PORT ## _PORT, BIT)
|
||||||
|
#define TURN_OFF(_PORT, BIT) CLEAR(PORT ## _PORT, BIT)
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
#define TURN_ON_LED(bit) SET(PORTB, bit)
|
||||||
|
#define TURN_OFF_LED(bit) CLEAR(PORTB, bit)
|
||||||
|
#define TOGGLE_LED(led) TOGGLE_PIN(B, led)
|
||||||
|
|
||||||
|
// ELEMENTS
|
||||||
|
#define D1 0
|
||||||
|
#define D2 1
|
||||||
|
#define D3 2
|
||||||
|
#define D4 4
|
||||||
|
#define SW1 2
|
||||||
|
#define SW2 4
|
||||||
|
|
||||||
|
// TIME
|
||||||
|
#define PRESCALE_VALUE 1024
|
||||||
|
#if (PRESCALE_VALUE == 1)
|
||||||
|
#define PRESCALE_SET (1 << CS10)
|
||||||
|
#elif (PRESCALE_VALUE == 8)
|
||||||
|
#define PRESCALE_SET (1 << CS11)
|
||||||
|
#elif (PRESCALE_VALUE == 64)
|
||||||
|
#define PRESCALE_SET (1 << CS10) | (1 << CS11)
|
||||||
|
#elif (PRESCALE_VALUE == 256)
|
||||||
|
#define PRESCALE_SET (1 << CS12)
|
||||||
|
#elif (PRESCALE_VALUE == 1024)
|
||||||
|
#define PRESCALE_SET (1 << CS10) | (1 << CS12)
|
||||||
|
#endif
|
||||||
#define TIME_MS(ms) (((F_CPU / PRESCALE_VALUE) * ms) / 1000)
|
#define TIME_MS(ms) (((F_CPU / PRESCALE_VALUE) * ms) / 1000)
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
// write a program that blinks an LED every 500ms using a software timer
|
|
||||||
int main() {
|
int main() {
|
||||||
MODE_OUTPUT(LED2);
|
MODE_OUTPUT(B, D2);
|
||||||
CLEAR_ELEM(LED2);
|
TURN_OFF_LED(D2);
|
||||||
|
|
||||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // 16.4 : set timer according to prescale value, in register TCCR1B, table 16-5 : prescale sets
|
TCCR1B |= (PRESCALE_SET); // set timer with prescale
|
||||||
|
// -> 16.4 : set timer with bits CS10-12, in register TCCR1B
|
||||||
|
// -> table 16-5 : prescale values
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if (TCNT1 >= TIME_MS(500)) { // 16.11.4 : read timer with register TCNT1 (read/write allowed), that combines two 8 bits registers
|
if (TCNT1 >= TIME_MS(500)) { // 16.11.4 : read timer with register TCNT1 (read/write allowed), that combines two 8 bits registers
|
||||||
TOGGLE_PIN(LED2);
|
TOGGLE_LED(D2);
|
||||||
TCNT1 = 0; // reset timer value, also in register TCNT1
|
TCNT1 = 0; // reset timer value, also in register TCNT1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +1,43 @@
|
|||||||
include ../../Makefile
|
# frequency of the CPU (in Hz)
|
||||||
|
F_CPU = 16000000UL
|
||||||
|
TARGET = main
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
AVRGCC_MCU_TYPE = atmega328p
|
||||||
|
AVRDUDE_MCU_TYPE = m328p
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
SERIAL_PORT = /dev/ttyUSB0
|
||||||
|
PROGRAMMER_ID = arduino
|
||||||
|
DUMP_ORI = ../../ressources/dump_atmega328p_ori.hex
|
||||||
|
|
||||||
|
|
||||||
|
all: hex flash
|
||||||
|
|
||||||
|
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
|
||||||
|
$(TARGET).bin: $(TARGET).c
|
||||||
|
$(CC) -mmcu=$(AVRGCC_MCU_TYPE) -D F_CPU=$(F_CPU) $(TARGET).c -Os -o $(TARGET).bin
|
||||||
|
|
||||||
|
|
||||||
|
# https://linux.die.net/man/1/avr-objcopy
|
||||||
|
$(TARGET).hex: $(TARGET).bin
|
||||||
|
avr-objcopy -O ihex $(TARGET).bin $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
# AVR Downloader/UploaDEr https://avrdudes.github.io/avrdude (v6.3 https://download-mirror.savannah.gnu.org/releases/avrdude/avrdude-doc-6.3.pdf)
|
||||||
|
flash:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
restore:
|
||||||
|
avrdude -p $(AVRDUDE_MCU_TYPE) -c $(PROGRAMMER_ID) -b $(BAUD_RATE) -P $(SERIAL_PORT) -U flash:w:$(DUMP_ORI)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.bin
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY : all clean hex flash restore
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,25 +1,72 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|
||||||
#include "utils.h"
|
// #define FIRST_LETTER_IMPL(x) #x[0]
|
||||||
#include "bitmanip.h"
|
// #define FIRST_LETTER(x) FIRST_LETTER_IMPL(x)
|
||||||
#include "timer.h"
|
// #define PORT_LETTER(PIN) FIRST_LETTER(PIN)
|
||||||
|
|
||||||
#define PERIOD 500
|
// global registers
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
#define SET(register, bit) register |= 1 << bit
|
||||||
|
#define CLEAR(register, bit) register &= ~(1 << bit)
|
||||||
|
#define TEST(register, bit) register & 1 << bit
|
||||||
|
#define TOGGLE(register, bit) register ^= 1 << bit
|
||||||
|
|
||||||
|
// actions on ports
|
||||||
|
#define TEST_PIN(port, bit) TEST(PIN ## port, bit)
|
||||||
|
#define TOGGLE_PIN(port, bit) SET(PIN ## port, bit)
|
||||||
|
#define MODE_INPUT(port, bit) CLEAR(DDR ## port, bit)
|
||||||
|
#define MODE_OUTPUT(port, bit) SET(DDR ## port, bit)
|
||||||
|
#define IS_PIN_SET(port, bit) (TEST_PIN(port, bit)) == 0
|
||||||
|
#define IS_PIN_CLEAR(port, bit) (TEST_PIN(port, bit)) == 1
|
||||||
|
#define TURN_ON(_PORT, BIT) SET(PORT ## _PORT, BIT)
|
||||||
|
#define TURN_OFF(_PORT, BIT) CLEAR(PORT ## _PORT, BIT)
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
#define TURN_ON_LED(bit) SET(PORTB, bit)
|
||||||
|
#define TURN_OFF_LED(bit) CLEAR(PORTB, bit)
|
||||||
|
#define TOGGLE_LED(led) TOGGLE_PIN(B, led)
|
||||||
|
|
||||||
|
// ELEMENTS
|
||||||
|
#define D1 0
|
||||||
|
#define D2 1
|
||||||
|
#define D3 2
|
||||||
|
#define D4 4
|
||||||
|
#define SW1 2
|
||||||
|
#define SW2 4
|
||||||
|
|
||||||
|
// TIME
|
||||||
|
#define PRESCALE_VALUE 1024
|
||||||
|
#if (PRESCALE_VALUE == 1)
|
||||||
|
#define PRESCALE_SET (1 << CS10)
|
||||||
|
#elif (PRESCALE_VALUE == 8)
|
||||||
|
#define PRESCALE_SET (1 << CS11)
|
||||||
|
#elif (PRESCALE_VALUE == 64)
|
||||||
|
#define PRESCALE_SET (1 << CS10) | (1 << CS11)
|
||||||
|
#elif (PRESCALE_VALUE == 256)
|
||||||
|
#define PRESCALE_SET (1 << CS12)
|
||||||
|
#elif (PRESCALE_VALUE == 1024)
|
||||||
|
#define PRESCALE_SET (1 << CS10) | (1 << CS12)
|
||||||
|
#endif
|
||||||
|
#define TIME_MS(ms) (((F_CPU / PRESCALE_VALUE) * ms) / 1000)
|
||||||
|
|
||||||
// led turns on and off every PERIOD ms using CTC timer
|
|
||||||
int main() {
|
int main() {
|
||||||
MODE_OUTPUT(LED2);
|
MODE_OUTPUT(B, D2);
|
||||||
|
|
||||||
TCCR1B |= (1 << WGM12); // Table 16-4 : set timer in CTC (Clear Time on Compare) mode, use bit WGM12, located in register TCCR1B (16.11.2)
|
TCCR1B |= (1 << WGM12); // set timer in CTC (Clear Time on Compare) mode
|
||||||
|
// -> Table 16-4 : use bit WGM12 to set mode ctc
|
||||||
|
// -> 16.11.2 : bit WGM12 is located in register TCCR1B
|
||||||
|
|
||||||
TCCR1A |= (1 << COM1A0); // 14.3.1 : set Compare Output with COM1A0, it toggles OC1A on compare match (Table 16-1), OC1A is alternate function for PORTB1 (Table 14-3)
|
TCCR1A |= (1 << COM1A0 ) ; // Enable timer 1 Compare Output channel A in toggle mode
|
||||||
|
// -> Table 14-3 : alternate functions for PORTB1 is OC1A (Timer/Counter1 Output Compare Match A Output)
|
||||||
|
// -> 14.3.1 : OC1A/PCINT1 – Port B, Bit 1
|
||||||
|
|
||||||
OCR1A = TIME_MS(PERIOD, PRESCALE_VALUE); // Table 16-4 : set CTC compare value on channel A, the counter is cleared to zero when the counter value (TCNT1) matches the OCR1A register
|
OCR1A = TIME_MS(500); // set CTC compare value
|
||||||
|
// -> Table 16-4 : the value to reset the timer is the Output Compare Registers OCR1A
|
||||||
|
|
||||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE));
|
TCCR1B |= (PRESCALE_SET);
|
||||||
|
|
||||||
while(1);
|
while(1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
#define PERIOD 1000
|
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
|
||||||
#define DUTY_CYCLE 10
|
|
||||||
|
|
||||||
// turns on led2 at 1Hz and duty cycle of 10%, not using PORTx, with empty infinite loop
|
|
||||||
int main() {
|
|
||||||
MODE_OUTPUT(LED2);
|
|
||||||
|
|
||||||
SET(TCCR1A, WGM11); // Table 16-4 : set timer in Fast PWM (Pulse With Modulation) mode with TOP = ICR1 (Mode 14)
|
|
||||||
SET(TCCR1B, WGM12);
|
|
||||||
SET(TCCR1B, WGM13);
|
|
||||||
|
|
||||||
SET(TCCR1A, COM1A1); // Table 16-2 : non-inverting mode, the LED will be ON for DUTY_CYCLE% of the time (CLEAR OC1A on compare match, SET OC1A at BOTTOM)
|
|
||||||
|
|
||||||
ICR1 = TIME_MS(PERIOD, PRESCALE_VALUE); // Table 16-4 : set the period (compare TOP value)
|
|
||||||
|
|
||||||
OCR1A = TIME_MS(PERCENT(DUTY_CYCLE, PERIOD), PRESCALE_VALUE); // 16.9.3 : set the duty cycle to DUTY_CYCLE% of the time on channel A -> OC1A (alternate function of PORTB1, aka LED2) is cleared when TCNT1 (the counter value) equals OCR1A
|
|
||||||
|
|
||||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // start the timer with the prescaler
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
#define PERIOD 1000
|
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
|
||||||
#define DUTY_CYCLE 10
|
|
||||||
|
|
||||||
#define MAX 100 // max duty cycle percentage
|
|
||||||
#define MIN 10 // min duty cycle percentage
|
|
||||||
|
|
||||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
volatile int duty_cycle = DUTY_CYCLE;
|
|
||||||
|
|
||||||
void increment_duty_cycle() {
|
|
||||||
if(duty_cycle < MAX) {
|
|
||||||
duty_cycle += 10;
|
|
||||||
}
|
|
||||||
OCR1A = TIME_MS(PERCENT(duty_cycle, PERIOD), PRESCALE_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void decrement_duty_cycle() {
|
|
||||||
if(duty_cycle > MIN) {
|
|
||||||
duty_cycle -= 10;
|
|
||||||
}
|
|
||||||
OCR1A = TIME_MS(PERCENT(duty_cycle, PERIOD), PRESCALE_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_press(int bit, void (*action)(void)) {
|
|
||||||
if ((TEST(PIND, bit)) == 0) {
|
|
||||||
action();
|
|
||||||
_delay_ms(20);
|
|
||||||
while ((TEST(PIND, bit)) == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_delay_ms(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// led turns on and off every PERIOD ms using Fast PWM timer, with duty cycle controlled by SW1 and SW2
|
|
||||||
int main() {
|
|
||||||
MODE_OUTPUT(LED2);
|
|
||||||
|
|
||||||
TCCR1A |= FAST_PWM_TOP_ICR1_IN_TCCR1A; // Table 16-4 : set timer in Fast PWM (Pulse With Modulation) mode with TOP = ICR1 (Mode 14)
|
|
||||||
TCCR1B |= FAST_PWM_TOP_ICR1_IN_TCCR1B;
|
|
||||||
|
|
||||||
SET(TCCR1A, COM1A1); // Table 16-2 : non-inverting mode, the LED will be ON for DUTY_CYCLE% of the time (CLEAR OC1A on compare match, SET OC1A at BOTTOM)
|
|
||||||
|
|
||||||
ICR1 = TIME_MS(PERIOD, PRESCALE_VALUE); // Table 16-4 : set the period (compare TOP value)
|
|
||||||
|
|
||||||
OCR1A = TIME_MS(PERCENT(DUTY_CYCLE, PERIOD), PRESCALE_VALUE); // 16.9.3 : set the duty cycle to DUTY_CYCLE% of the time in channel A -> OC1A (alternate function of PORTB1, aka LED2) is cleared when TCNT1 (the counter value) equals OCR1A
|
|
||||||
|
|
||||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // start the timer with the prescaler
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
on_press(SW1, increment_duty_cycle);
|
|
||||||
on_press(SW2, decrement_duty_cycle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
// // version with "LED1 B, D1" without parenthesis
|
|
||||||
// #define ARG_1(v1, ...) v1
|
|
||||||
// #define ARG_2(v1, v2, ...) v2
|
|
||||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
|
||||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
|
|
||||||
// USART
|
|
||||||
// Table 20-1 : Baud Rate Calculation
|
|
||||||
#define USART_BAUDRATE 115200
|
|
||||||
#define BAUD_PRESCALER (DIV_ROUND_CLOSEST(F_CPU, (16 * USART_BAUDRATE)) - 1)
|
|
||||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
|
||||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
|
||||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
|
||||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
|
||||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
|
||||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
|
||||||
#define STOP_ONE_BIT (0<<USBS0)
|
|
||||||
#define STOP_TWO_BIT (1<<USBS0)
|
|
||||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
|
||||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
|
||||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
|
||||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
|
||||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
|
||||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
// 20.4 Frame Formats : 8N1 : 8 data bits, no parity, 1 stop bit
|
|
||||||
// 20.5 USART Initialization : (1) setting baud rate, (2) setting frame format, (3) enabling the Transmitter or the Receiver
|
|
||||||
void uart_init() {
|
|
||||||
UBRR0H = (unsigned char) (BAUD_PRESCALER >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers
|
|
||||||
UBRR0L = (unsigned char) BAUD_PRESCALER;
|
|
||||||
|
|
||||||
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
|
|
||||||
|
|
||||||
UCSR0B |= RECEIVER_DISABLED | TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver and/or Transmitter
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_tx(char c) {
|
|
||||||
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDR emission buffer is empty, if UDREn flag is 1, UCSRnA register is empty
|
|
||||||
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
// write Z on serial port, at a 1Hz frequency
|
|
||||||
// `screen /dev/ttyUSB0 115200`
|
|
||||||
int main() {
|
|
||||||
uart_init();
|
|
||||||
while (1) {
|
|
||||||
uart_tx('Z');
|
|
||||||
_delay_ms(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
// // version with "LED1 B, D1" without parenthesis
|
|
||||||
// #define ARG_1(v1, ...) v1
|
|
||||||
// #define ARG_2(v1, v2, ...) v2
|
|
||||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
|
||||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef INTERRUPT_H
|
|
||||||
#define INTERRUPT_H
|
|
||||||
|
|
||||||
// 7.3.1 : SREG – AVR Status Register
|
|
||||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
|
||||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
|
||||||
|
|
||||||
#endif // INTERRUPT_H
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
|
|
||||||
// TIMER
|
|
||||||
#define PERIOD 2000
|
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
|
||||||
// USART
|
|
||||||
#define USART_BAUDRATE 115200 // Table 20-1 : Baud Rate Calculation
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
void uart_init() {
|
|
||||||
UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers
|
|
||||||
UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE);
|
|
||||||
|
|
||||||
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
|
|
||||||
|
|
||||||
UCSR0B |= RECEIVER_DISABLED | TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver and/or Transmitter
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_tx(char c) {
|
|
||||||
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDR emission buffer is empty, if UDREn flag is 1, UCSRnA register is empty
|
|
||||||
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_printstr(const char* str) {
|
|
||||||
while (*str) {
|
|
||||||
uart_tx(*str);
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// print "Hello World!\n", on serial port, every 2 seconds, with empty infinite loop
|
|
||||||
// `screen /dev/ttyUSB0 115200`
|
|
||||||
int main() {
|
|
||||||
uart_init();
|
|
||||||
|
|
||||||
TCCR1A |= CTC_TOP_OCR1A_IN_TCCR1A; // Table 16-4 : set timer in CTC (Clear Time on Compare) mode
|
|
||||||
TCCR1B |= CTC_TOP_OCR1A_IN_TCCR1B;
|
|
||||||
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I – Global Interrupt Enable
|
|
||||||
|
|
||||||
TIMSK1 |= INTERRUPT_ENABLE_CHANNEL_A; // 16.11.8 : enables the Timer1 Compare Match A interrupt, this makes the MCU react when OCR1A == TCNT1 by calling TIMER1_COMPA_vect
|
|
||||||
|
|
||||||
OCR1A = TIME_MS(PERIOD, PRESCALE_VALUE); // Table 16-4 : set CTC compare value on channel A, the counter is cleared to zero when the counter value (TCNT1) matches the OCR1A register
|
|
||||||
|
|
||||||
TCCR1B |= (PRESCALE_SET(PRESCALE_VALUE)); // 16.4 : set timer according to prescale value, in register TCCR1B, table 16-5 : prescale sets
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISR interrupt macro : https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
|
|
||||||
ISR(TIMER1_COMPA_vect) { // Table 12-7 : we select the code for timer 1 on channel A
|
|
||||||
uart_printstr("Hello World!\r\n"); // \n and \r : https://stackoverflow.com/questions/7812142/how-to-toggle-cr-lf-in-gnu-screen
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
|
||||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
|
||||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
|
||||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef USART_H
|
|
||||||
#define USART_H
|
|
||||||
|
|
||||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
|
||||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
|
||||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
|
||||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
|
||||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
|
||||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
|
||||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
|
||||||
#define STOP_ONE_BIT (0<<USBS0)
|
|
||||||
#define STOP_TWO_BIT (1<<USBS0)
|
|
||||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
|
||||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
|
||||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
|
||||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
|
||||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
|
||||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
|
||||||
|
|
||||||
#endif // USART_H
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
// // version with "LED1 B, D1" without parenthesis
|
|
||||||
// #define ARG_1(v1, ...) v1
|
|
||||||
// #define ARG_2(v1, v2, ...) v2
|
|
||||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
|
||||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef INTERRUPT_H
|
|
||||||
#define INTERRUPT_H
|
|
||||||
|
|
||||||
// 7.3.1 : SREG – AVR Status Register
|
|
||||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
|
||||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
|
||||||
|
|
||||||
#endif // INTERRUPT_H
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "usart.h"
|
|
||||||
|
|
||||||
// USART
|
|
||||||
#define USART_BAUDRATE 115200
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
void uart_init() {
|
|
||||||
UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers
|
|
||||||
UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE);
|
|
||||||
|
|
||||||
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
|
|
||||||
|
|
||||||
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED; // 20.11.3 : enable Receiver and/or Transmitter
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_tx(char c) {
|
|
||||||
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDRn buffer is empty, (UDREn flag in UCSRnA register set to 1 when buffer empty)
|
|
||||||
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
char uart_rx(void) {
|
|
||||||
while (TEST(UCSR0A, RXC0) == 0); // 20.11.2 : do nothing until there are unread data in the receive buffer (UDRn), (RXCn flag in UCSRnA register set to 1 when buffer has data)
|
|
||||||
return UDR0; // 20.11.1 : get data in buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
// send back caracters received on serial port
|
|
||||||
// `screen /dev/ttyUSB0 115200`
|
|
||||||
int main() {
|
|
||||||
uart_init();
|
|
||||||
|
|
||||||
char received_char;
|
|
||||||
while(1) {
|
|
||||||
received_char = uart_rx();
|
|
||||||
uart_tx(received_char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
|
||||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
|
||||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
|
||||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef USART_H
|
|
||||||
#define USART_H
|
|
||||||
|
|
||||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
|
||||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
|
||||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
|
||||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
|
||||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
|
||||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
|
||||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
|
||||||
#define STOP_ONE_BIT (0<<USBS0)
|
|
||||||
#define STOP_TWO_BIT (1<<USBS0)
|
|
||||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
|
||||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
|
||||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
|
||||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
|
||||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
|
||||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
|
||||||
|
|
||||||
#endif // USART_H
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
// // version with "LED1 B, D1" without parenthesis
|
|
||||||
// #define ARG_1(v1, ...) v1
|
|
||||||
// #define ARG_2(v1, v2, ...) v2
|
|
||||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
|
||||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef INTERRUPT_H
|
|
||||||
#define INTERRUPT_H
|
|
||||||
|
|
||||||
// 7.3.1 : SREG – AVR Status Register
|
|
||||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
|
||||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
|
||||||
|
|
||||||
#endif // INTERRUPT_H
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h> // https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
|
|
||||||
// USART
|
|
||||||
#define USART_BAUDRATE 115200
|
|
||||||
|
|
||||||
// TIMER
|
|
||||||
#define PERIOD 2000
|
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
void uart_init() {
|
|
||||||
UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers
|
|
||||||
UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE);
|
|
||||||
|
|
||||||
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
|
|
||||||
|
|
||||||
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
// char uart_rx(void) {
|
|
||||||
// while (TEST(UCSR0A, RXC0) == 0); // 20.11.2 : do nothing until there are unread data in the receive buffer (UDRn), (RXCn flag in UCSRnA register set to 1 when buffer has data)
|
|
||||||
// return UDR0; // 20.11.1 : get data in buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
// }
|
|
||||||
|
|
||||||
void uart_tx(char c) {
|
|
||||||
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDRn buffer is empty, (UDREn flag in UCSRnA register set to 1 when buffer empty)
|
|
||||||
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
// send back caracters received on serial port with case toggling, using interupt and empty infinite loop
|
|
||||||
// `screen /dev/ttyUSB0 115200`
|
|
||||||
int main() {
|
|
||||||
uart_init();
|
|
||||||
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I – Global Interrupt Enable
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(USART_RX_vect) { // Table 12-7 : we select the code for USART Receive
|
|
||||||
// char received_char = uart_rx();
|
|
||||||
char received_char = UDR0; // Read received character
|
|
||||||
uart_tx(SWITCH_CASE(received_char)); // Toggle case and send back
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
|
||||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
|
||||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
|
||||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#ifndef USART_H
|
|
||||||
#define USART_H
|
|
||||||
|
|
||||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
|
||||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
|
||||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
|
||||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
|
||||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
|
||||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
|
||||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
|
||||||
#define STOP_ONE_BIT (0<<USBS0)
|
|
||||||
#define STOP_TWO_BIT (1<<USBS0)
|
|
||||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
|
||||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
|
||||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
|
||||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
|
||||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
|
||||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
|
||||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
|
||||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
|
||||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
|
||||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
|
||||||
|
|
||||||
#endif // USART_H
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
||||||
|
|
||||||
// text
|
|
||||||
#define SWITCH_CASE(ch) (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ? ((ch) ^ (1 << 5)) : (ch))
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef BITMANIP_H
|
|
||||||
#define BITMANIP_H
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// Bit operations on registers
|
|
||||||
#define SET(register, bit) (register |= (1 << (bit)))
|
|
||||||
#define CLEAR(register, bit) (register &= ~(1 << (bit)))
|
|
||||||
#define TEST(register, bit) (register & (1 << (bit)))
|
|
||||||
#define TOGGLE(register, bit) (register ^= (1 << (bit)))
|
|
||||||
|
|
||||||
// Get arguments from tuple-like definitions
|
|
||||||
#define ARG_1(v1, v2) v1
|
|
||||||
#define ARG_2(v1, v2) v2
|
|
||||||
#define GET_PORT(args) ARG_1 args
|
|
||||||
#define GET_BIT(args) ARG_2 args
|
|
||||||
// // version with "LED1 B, D1" without parenthesis
|
|
||||||
// #define ARG_1(v1, ...) v1
|
|
||||||
// #define ARG_2(v1, v2, ...) v2
|
|
||||||
// #define GET_PORT(...) ARG_1(__VA_ARGS__)
|
|
||||||
// #define GET_BIT(...) ARG_2(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Actions on elements
|
|
||||||
// #define SET_ELEM(...) SET(CONCAT(PORT, GET_PORT(__VA_ARGS__)), GET_BIT(__VA_ARGS__)) // version for "LED1 B, D1" without parenthesis
|
|
||||||
#define SET_ELEM(elem) SET(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define CLEAR_ELEM(elem) CLEAR(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_ELEM(elem) TEST(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_ELEM(elem) TOGGLE(CONCAT(PORT, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
|
|
||||||
#define MODE_OUTPUT(elem) SET(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define MODE_INPUT(elem) CLEAR(CONCAT(DDR, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TOGGLE_PIN(elem) SET(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem))
|
|
||||||
#define TEST_PIN(elem) (TEST(CONCAT(PIN, GET_PORT(elem)), GET_BIT(elem)))
|
|
||||||
#define IS_PIN_SET(elem) (TEST_PIN(elem) == 0)
|
|
||||||
#define IS_PIN_CLEAR(elem) (TEST_PIN(elem) == 1)
|
|
||||||
|
|
||||||
// Bit definitions
|
|
||||||
#define D1 0
|
|
||||||
#define D2 1
|
|
||||||
#define D3 2
|
|
||||||
#define D4 4
|
|
||||||
#define SW1 2
|
|
||||||
#define SW2 4
|
|
||||||
|
|
||||||
// Elements (port, bit)
|
|
||||||
#define LED1 (B, D1)
|
|
||||||
#define LED2 (B, D2)
|
|
||||||
#define LED3 (B, D3)
|
|
||||||
#define LED4 (B, D4)
|
|
||||||
#define BUTTON1 (D, SW1)
|
|
||||||
#define BUTTON2 (D, SW2)
|
|
||||||
|
|
||||||
#endif // BITMANIP_H
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef INTERRUPT_H
|
|
||||||
#define INTERRUPT_H
|
|
||||||
|
|
||||||
// 7.3.1 : SREG – AVR Status Register
|
|
||||||
#define ENABLE_GLOBAL_INTERRUPT (1<<SREG_I)
|
|
||||||
#define DISABLE_GLOBAL_INTERRUPT (0<<SREG_I)
|
|
||||||
|
|
||||||
#endif // INTERRUPT_H
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h> // https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
|
|
||||||
// USART
|
|
||||||
#define USART_BAUDRATE 115200
|
|
||||||
// TIMER
|
|
||||||
#define PERIOD 2000
|
|
||||||
#define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024
|
|
||||||
|
|
||||||
// END MACROS
|
|
||||||
|
|
||||||
// FUNCTION PROTOTYPES
|
|
||||||
void uart_init();
|
|
||||||
// char uart_rx(void);
|
|
||||||
void uart_tx(char c);
|
|
||||||
void uart_printstr(const char* str);
|
|
||||||
void remove_last_character();
|
|
||||||
void fill_str(char input);
|
|
||||||
int compare_str(volatile char *input_str, volatile char *base_str);
|
|
||||||
int strlength(volatile char *str);
|
|
||||||
void reset_message();
|
|
||||||
void ask_for_username();
|
|
||||||
void ask_for_password();
|
|
||||||
void on_error();
|
|
||||||
void on_success();
|
|
||||||
|
|
||||||
// GLOBAL VARIABLES
|
|
||||||
typedef enum {
|
|
||||||
USERNAME,
|
|
||||||
PASSWORD
|
|
||||||
} State;
|
|
||||||
volatile char username[] = "admin";
|
|
||||||
volatile char password[] = "password";
|
|
||||||
volatile char username_input[100] = {0};
|
|
||||||
volatile char password_input[100] = {0};
|
|
||||||
volatile int input_index = 0;
|
|
||||||
volatile State state = USERNAME;
|
|
||||||
volatile int username_correct = FALSE;
|
|
||||||
volatile int password_correct = FALSE;
|
|
||||||
|
|
||||||
void uart_init() {
|
|
||||||
UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers
|
|
||||||
UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE);
|
|
||||||
|
|
||||||
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
|
|
||||||
|
|
||||||
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
// char uart_rx(void) {
|
|
||||||
// while (TEST(UCSR0A, RXC0) == 0); // 20.11.2 : do nothing until there are unread data in the receive buffer (UDRn), (RXCn flag in UCSRnA register set to 1 when buffer has data)
|
|
||||||
// return UDR0; // 20.11.1 : get data in buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
// }
|
|
||||||
|
|
||||||
void uart_tx(char c) {
|
|
||||||
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDRn buffer is empty, (UDREn flag in UCSRnA register set to 1 when buffer empty)
|
|
||||||
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_printstr(const char* str) {
|
|
||||||
while (*str) {
|
|
||||||
uart_tx(*str);
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(USART_RX_vect) { // Table 12-7 : we select the code for USART Receive
|
|
||||||
// char received_char = uart_rx();
|
|
||||||
char received_char = UDR0; // read received character
|
|
||||||
if (received_char == '\b' || received_char == 127) { // if backspace is received
|
|
||||||
if (input_index <= 0) return;
|
|
||||||
remove_last_character();
|
|
||||||
input_index--;
|
|
||||||
uart_tx('\b'); // Move cursor back
|
|
||||||
uart_tx(' '); // Erase the character on screen
|
|
||||||
uart_tx('\b'); // Move cursor back again
|
|
||||||
} else if (received_char == '\n' || received_char == '\r') { // if enter is received
|
|
||||||
if (state == USERNAME) {
|
|
||||||
if (compare_str(username_input, username)) {
|
|
||||||
username_correct = TRUE;
|
|
||||||
} else {
|
|
||||||
username_correct = FALSE;
|
|
||||||
// uart_printstr("(error1)");
|
|
||||||
}
|
|
||||||
state = PASSWORD;
|
|
||||||
input_index = 0;
|
|
||||||
uart_tx('\r');
|
|
||||||
uart_tx('\n');
|
|
||||||
ask_for_password();
|
|
||||||
} else if (state == PASSWORD) {
|
|
||||||
if (!username_correct) {
|
|
||||||
// uart_printstr("(error2)");
|
|
||||||
return reset_message();
|
|
||||||
}
|
|
||||||
if (!compare_str(password_input, password)) {
|
|
||||||
// uart_printstr("(error3)");
|
|
||||||
return reset_message();
|
|
||||||
}
|
|
||||||
uart_tx('\r');
|
|
||||||
uart_tx('\n');
|
|
||||||
on_success();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fill_str(received_char);
|
|
||||||
if (state == USERNAME) {
|
|
||||||
uart_tx(received_char);
|
|
||||||
}
|
|
||||||
else if (state == PASSWORD) {
|
|
||||||
uart_tx('*');
|
|
||||||
}
|
|
||||||
input_index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill_str(char input) {
|
|
||||||
if (input_index >= 100) {
|
|
||||||
// uart_printstr("(error4)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (state == USERNAME) {
|
|
||||||
username_input[input_index] = input;
|
|
||||||
} else if (state == PASSWORD) {
|
|
||||||
password_input[input_index] = input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_last_character() {
|
|
||||||
if (state == USERNAME) {
|
|
||||||
username_input[input_index] = 0;
|
|
||||||
} else if (state == PASSWORD) {
|
|
||||||
password_input[input_index] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare_str(volatile char *input_str, volatile char *base_str) {
|
|
||||||
int base_length = strlength(base_str);
|
|
||||||
int input_length = strlength(input_str);
|
|
||||||
if (base_length != input_length) {
|
|
||||||
// uart_printstr("(error5)");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
for(int i = 0; i < base_length; i++) {
|
|
||||||
if (input_str[i] != base_str[i]) {
|
|
||||||
// uart_printstr("(error6)");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strlength(volatile char *str) {
|
|
||||||
int length = 0;
|
|
||||||
while (*str) {
|
|
||||||
length++;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_message() {
|
|
||||||
for(int i = 0; i < 100; i++) {
|
|
||||||
username_input[i] = 0;
|
|
||||||
password_input[i] = 0;
|
|
||||||
}
|
|
||||||
input_index = 0;
|
|
||||||
username_correct = FALSE;
|
|
||||||
password_correct = FALSE;
|
|
||||||
state = USERNAME;
|
|
||||||
uart_tx('\r');
|
|
||||||
uart_tx('\n');
|
|
||||||
on_error();
|
|
||||||
ask_for_username();
|
|
||||||
}
|
|
||||||
void ask_for_username() {
|
|
||||||
uart_printstr("Enter your login: \r\n username: ");
|
|
||||||
}
|
|
||||||
void ask_for_password() {
|
|
||||||
uart_printstr(" password: ");
|
|
||||||
}
|
|
||||||
void on_error() {
|
|
||||||
uart_printstr("Bad combinaison username/password\r\n\r\n");
|
|
||||||
}
|
|
||||||
void on_success() {
|
|
||||||
uart_printstr("Hello spectre!\r\nShall we play a game?\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ask for username and password
|
|
||||||
// `screen /dev/ttyUSB0 115200`
|
|
||||||
int main() {
|
|
||||||
uart_init();
|
|
||||||
ask_for_username();
|
|
||||||
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I – Global Interrupt Enable
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef TIMER_H
|
|
||||||
#define TIMER_H
|
|
||||||
|
|
||||||
// table 16-5 : prescale sets
|
|
||||||
#define PRESCALE_SET(value) \
|
|
||||||
((value) == 1 ? (0<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 8 ? (0<<CS12 | 1<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 64 ? (0<<CS12 | 1<<CS11 | 1<<CS10) : \
|
|
||||||
(value) == 256 ? (1<<CS12 | 0<<CS11 | 0<<CS10) : \
|
|
||||||
(value) == 1024? (1<<CS12 | 0<<CS11 | 1<<CS10) : \
|
|
||||||
(0<<CS12 | 0<<CS11 | 0<<CS10))
|
|
||||||
#define TIME_MS(ms, prescale_value) (((F_CPU / prescale_value) * ms) / 1000)
|
|
||||||
|
|
||||||
// Table 16-4 : Waveform Generation Mode Bit Description
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1B (0<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_OCR1A_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define CTC_TOP_ICR1_IN_TCCR1A (0<<WGM11 | 0<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_OCR1A_IN_TCCR1A (1<<WGM11 | 1<<WGM10)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1B (1<<WGM13 | 1<<WGM12)
|
|
||||||
#define FAST_PWM_TOP_ICR1_IN_TCCR1A (1<<WGM11 | 0<<WGM10)
|
|
||||||
// 16.11.8 : Timer/Counter1 Interrupt Mask Register
|
|
||||||
#define INTERRUPT_ENABLE_CHANNEL_A (1 << OCIE1A)
|
|
||||||
#define INTERRUPT_DISABLE_CHANNEL_A (0 << OCIE1A)
|
|
||||||
|
|
||||||
#endif // TIMER_H
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#ifndef USART_H
|
|
||||||
#define USART_H
|
|
||||||
|
|
||||||
#define BAUD_PRESCALER(usart_baudrate) (DIV_ROUND_CLOSEST(F_CPU, (16 * usart_baudrate)) - 1)
|
|
||||||
// Table 20-8 : Mode Selection (USART Mode SELect)
|
|
||||||
#define ASYNCHRONOUS (0<<UMSEL01 | 0<<UMSEL00)
|
|
||||||
#define SYNCHRONOUS (0<<UMSEL01 | 1<<UMSEL00)
|
|
||||||
// Table 20-9 : Parity Bit Selection (USART Parity Mode)
|
|
||||||
#define PARITY_DISABLED (0<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_EVEN (1<<UPM01 | 0<<UPM00)
|
|
||||||
#define PARITY_ODD (1<<UPM01 | 1<<UPM00)
|
|
||||||
// Table 20-10 : Stop Bit Selection (USART Stop Bit Select)
|
|
||||||
#define STOP_ONE_BIT (0<<USBS0)
|
|
||||||
#define STOP_TWO_BIT (1<<USBS0)
|
|
||||||
// Table 20-11 : Data Bit Selection (USART Character SiZe)
|
|
||||||
#define DATA_FIVE_BIT (0<<UCSZ02 | 0<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_SIX_BIT (0<<UCSZ02 | 0<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_SEVEN_BIT (0<<UCSZ02 | 1<<UCSZ01 | 0<<UCSZ00)
|
|
||||||
#define DATA_EIGHT_BIT (0<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
#define DATA_NINE_BIT (1<<UCSZ02 | 1<<UCSZ01 | 1<<UCSZ00)
|
|
||||||
// 20.11.3 : USART Control and Status Register B (UCSRnB)
|
|
||||||
#define RECEIVER_DISABLED (0<<RXEN0)
|
|
||||||
#define RECEIVER_ENABLED (1<<RXEN0)
|
|
||||||
#define TRANSMITTER_DISABLED (0<<TXEN0)
|
|
||||||
#define TRANSMITTER_ENABLED (1<<TXEN0)
|
|
||||||
#define INTERRUPT_RECEIVER_DISABLED (0<<RXCIE0)
|
|
||||||
#define INTERRUPT_RECEIVER_ENABLED (1<<RXCIE0)
|
|
||||||
#define INTERRUPT_TRANSMITTER_DISABLED (0<<TXCIE0)
|
|
||||||
#define INTERRUPT_TRANSMITTER_ENABLED (1<<TXCIE0)
|
|
||||||
|
|
||||||
#endif // USART_H
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
// stringify
|
|
||||||
#define STRINGIFY_HELPER(x) #x
|
|
||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
|
||||||
|
|
||||||
// concatenate
|
|
||||||
#define CONCAT_HELPER(x, y) x ## y
|
|
||||||
#define CONCAT(x, y) CONCAT_HELPER(x, y)
|
|
||||||
|
|
||||||
// mathematics
|
|
||||||
#define PERCENT(percent, total) (((float)percent / 100) * total)
|
|
||||||
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
||||||
|
|
||||||
// text
|
|
||||||
#define SWITCH_CASE(ch) (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ? ((ch) ^ (1 << 5)) : (ch))
|
|
||||||
|
|
||||||
// boolean
|
|
||||||
#define TRUE 1
|
|
||||||
#define FALSE 0
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
|
|
||||||
|
|
||||||
void rgb_d5_roll_colors() {
|
|
||||||
MODE_OUTPUT(RGB5_RED);
|
|
||||||
MODE_OUTPUT(RGB5_GEEN);
|
|
||||||
MODE_OUTPUT(RGB5_BLUE);
|
|
||||||
while(1) {
|
|
||||||
SET_ELEM(RGB5_RED);
|
|
||||||
_delay_ms(1000);
|
|
||||||
CLEAR_ELEM(RGB5_RED);
|
|
||||||
SET_ELEM(RGB5_GEEN);
|
|
||||||
_delay_ms(1000);
|
|
||||||
CLEAR_ELEM(RGB5_GEEN);
|
|
||||||
SET_ELEM(RGB5_BLUE);
|
|
||||||
_delay_ms(1000);
|
|
||||||
CLEAR_ELEM(RGB5_BLUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// led RGB D5 must turns on in red then green then blue in a loop
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
rgb_d5_roll_colors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
|
|
||||||
|
|
||||||
void rgb_d5_roll_colors() {
|
|
||||||
MODE_OUTPUT(RGB5_RED);
|
|
||||||
MODE_OUTPUT(RGB5_GEEN);
|
|
||||||
MODE_OUTPUT(RGB5_BLUE);
|
|
||||||
while(1) {
|
|
||||||
// RED
|
|
||||||
PORTD = (1<<D5R) | (0<<D5G) | (0<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
// GREEN
|
|
||||||
PORTD = (0<<D5R) | (1<<D5G) | (0<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
// BLUE
|
|
||||||
PORTD = (0<<D5R) | (0<<D5G) | (1<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
// YELLOW
|
|
||||||
PORTD = (1<<D5R) | (1<<D5G) | (0<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
// CYAN
|
|
||||||
PORTD = (0<<D5R) | (1<<D5G) | (1<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
// MAGENTA
|
|
||||||
PORTD = (1<<D5R) | (0<<D5G) | (1<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
// WHITE
|
|
||||||
PORTD = (1<<D5R) | (1<<D5G) | (1<<D5B);
|
|
||||||
_delay_ms(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// led RGB D5 must turns on in a loop of colors: red, green, blue, yellow, cyan, magenta, white
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
rgb_d5_roll_colors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
|
|
||||||
void init_rgb();
|
|
||||||
|
|
||||||
void set_rgb(uint8_t r, uint8_t g, uint8_t b);
|
|
||||||
|
|
||||||
void wheel(uint8_t pos) {
|
|
||||||
pos = 255 - pos;
|
|
||||||
if (pos < 85) {
|
|
||||||
set_rgb(255 - pos * 3, 0, pos * 3);
|
|
||||||
} else if (pos < 170) {
|
|
||||||
pos = pos - 85;
|
|
||||||
set_rgb(0, pos * 3, 255 - pos * 3);
|
|
||||||
} else {
|
|
||||||
pos = pos - 170;
|
|
||||||
set_rgb(pos * 3, 255 - pos * 3, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table 14-9 : Port D Pins Alternate Functions
|
|
||||||
// OC2B (PD3) : Red
|
|
||||||
// OC0B (PD5) : Green
|
|
||||||
// OC0A (PD6) : Blue
|
|
||||||
void init_rgb() {
|
|
||||||
MODE_OUTPUT(RGB5_RED);
|
|
||||||
MODE_OUTPUT(RGB5_GEEN);
|
|
||||||
MODE_OUTPUT(RGB5_BLUE);
|
|
||||||
|
|
||||||
TCCR0A = 0; // 15.9.1 : Clear Timer0 control register A
|
|
||||||
TCCR0B = 0; // 15.9.2 : Clear Timer0 control register B
|
|
||||||
TCCR2A = 0; // Clear Timer2 control register A
|
|
||||||
|
|
||||||
TCCR0A |= (1 << WGM00) | (1 << WGM01); // Table 15-8 : Timer0 in Fast PWM mode
|
|
||||||
TCCR2A |= (1 << WGM20) | (1 << WGM21); // Table 18-8 : Timer2 in Fast PWM mode
|
|
||||||
|
|
||||||
TCCR0A |= (1 << COM0A1); // Table 15-3 : BLUE - Timer0 Non-inverting mode for Blue (OC0A -> PD6)
|
|
||||||
TCCR0A |= (1 << COM0B1); // Table 15-6 : GREEN - Timer0 Non-inverting mode for Green (OC0B -> PD5)
|
|
||||||
TCCR2A |= (1 << COM2B1); // Table 18-6 : RED - Timer2 Non-inverting mode for Red (OC2B -> PD3)
|
|
||||||
|
|
||||||
TCCR0B |= (1 << CS01); // Table 15-9 : Prescaler 8 → ~8kHz PWM frequency
|
|
||||||
TCCR2B |= (1 << CS21); // Table 18-9 : Prescaler 8 → ~8kHz PWM frequency
|
|
||||||
|
|
||||||
OCR0A = 0; // Blue OFF
|
|
||||||
OCR0B = 0; // Green OFF
|
|
||||||
OCR2B = 0; // Red OFF
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
OCR2B = r; // Red (PD3, Timer2 OCR2B)
|
|
||||||
OCR0B = g; // Green (PD5, Timer0 OCR0B)
|
|
||||||
OCR0A = b; // Blue (PD6, Timer0 OCR0A)
|
|
||||||
}
|
|
||||||
|
|
||||||
// led RGB D5 must turns on in a loop of colors using PWM
|
|
||||||
int main() {
|
|
||||||
init_rgb();
|
|
||||||
|
|
||||||
uint8_t pos = 0;
|
|
||||||
while (1) {
|
|
||||||
wheel(pos); // Set color based on wheel position
|
|
||||||
_delay_ms(10); // Small delay for smooth transition
|
|
||||||
pos++; // Increment color position
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Table 14-9 : Port D Pins Alternate Functions
|
|
||||||
// OC2B (PD3) : Red
|
|
||||||
// OC0B (PD5) : Green
|
|
||||||
// OC0A (PD6) : Blue
|
|
||||||
void init_rgb() {
|
|
||||||
MODE_OUTPUT(RGB5_RED);
|
|
||||||
MODE_OUTPUT(RGB5_GEEN);
|
|
||||||
MODE_OUTPUT(RGB5_BLUE);
|
|
||||||
|
|
||||||
TCCR0A = 0; // 15.9.1 : Clear Timer0 control register A
|
|
||||||
TCCR0B = 0; // 15.9.2 : Clear Timer0 control register B
|
|
||||||
TCCR2A = 0; // 18.11.1 : Clear Timer2 control register A
|
|
||||||
|
|
||||||
TCCR0A |= (1 << WGM00) | (1 << WGM01); // Table 15-8 : Timer0 in Fast PWM mode
|
|
||||||
TCCR2A |= (1 << WGM20) | (1 << WGM21); // Table 18-8 : Timer2 in Fast PWM mode
|
|
||||||
|
|
||||||
TCCR0A |= (1 << COM0A1); // Table 15-3 : BLUE - Timer0 Non-inverting mode for Blue (OC0A -> PD6)
|
|
||||||
TCCR0A |= (1 << COM0B1); // Table 15-6 : GREEN - Timer0 Non-inverting mode for Green (OC0B -> PD5)
|
|
||||||
TCCR2A |= (1 << COM2B1); // Table 18-6 : RED - Timer2 Non-inverting mode for Red (OC2B -> PD3)
|
|
||||||
|
|
||||||
TCCR0B |= (1 << CS01); // Table 15-9 : Prescaler 8 → ~8kHz PWM frequency
|
|
||||||
TCCR2B |= (1 << CS21); // Table 18-9 : Prescaler 8 → ~8kHz PWM frequency
|
|
||||||
|
|
||||||
OCR0A = 0; // Blue OFF
|
|
||||||
OCR0B = 0; // Green OFF
|
|
||||||
OCR2B = 0; // Red OFF
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
OCR0B = r; // Red (PD3, Timer2)
|
|
||||||
OCR0A = g; // Green (PD5, Timer0)
|
|
||||||
OCR2B = b; // Blue (PD6, Timer0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert hex to int : https://stackoverflow.com/a/39052987
|
|
||||||
uint8_t hex_to_int(char c) {
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
return c - '0';
|
|
||||||
}
|
|
||||||
if (c >= 'A' && c <= 'F') {
|
|
||||||
return c - 'A' + 10;
|
|
||||||
}
|
|
||||||
if (c >= 'a' && c <= 'f') {
|
|
||||||
return c - 'a' + 10;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "<< 4" is equivalent to "* 16"
|
|
||||||
uint8_t get_red(char *input) {
|
|
||||||
if (input[0] != '#') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (hex_to_int(input[1]) << 4) + hex_to_int(input[2]);
|
|
||||||
}
|
|
||||||
uint8_t get_green(char *input) {
|
|
||||||
if (input[0] != '#') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (hex_to_int(input[3]) << 4) + hex_to_int(input[4]);
|
|
||||||
}
|
|
||||||
uint8_t get_blue(char *input) {
|
|
||||||
if (input[0] != '#') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (hex_to_int(input[5]) << 4) + hex_to_int(input[6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_color(char *color_input) {
|
|
||||||
uint8_t r = get_red(color_input);
|
|
||||||
uint8_t g = get_green(color_input);
|
|
||||||
uint8_t b = get_blue(color_input);
|
|
||||||
set_rgb(r, g, b);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#ifndef HEADER_H
|
|
||||||
#define HEADER_H
|
|
||||||
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// PROTOTYPES
|
|
||||||
//
|
|
||||||
// main.c
|
|
||||||
// colors.c
|
|
||||||
void init_rgb();
|
|
||||||
void set_rgb(uint8_t r, uint8_t g, uint8_t b);
|
|
||||||
uint8_t get_red(char *input);
|
|
||||||
uint8_t get_green(char *input);
|
|
||||||
uint8_t get_blue(char *input);
|
|
||||||
uint8_t hex_to_int(char c);
|
|
||||||
void uart_init();
|
|
||||||
void set_color(char *color_input);
|
|
||||||
// uart.c
|
|
||||||
void uart_init();
|
|
||||||
char uart_rx(void);
|
|
||||||
void uart_tx(char c);
|
|
||||||
// void uart_printstr(const char* str);
|
|
||||||
void remove_last_character();
|
|
||||||
void fill_str(char input);
|
|
||||||
int strlength(volatile char *str);
|
|
||||||
void reset_input();
|
|
||||||
int is_valid_color_input(char c);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // HEADER_H
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
|
|
||||||
// led RGB D5 must turns on in a loop of colors using PWM
|
|
||||||
int main() {
|
|
||||||
init_rgb();
|
|
||||||
uart_init();
|
|
||||||
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
// MACROS
|
|
||||||
// USART
|
|
||||||
#define USART_BAUDRATE 115200
|
|
||||||
#define INPUT_SIZE 7
|
|
||||||
|
|
||||||
// GLOBAL VARIABLES
|
|
||||||
volatile char color_input[INPUT_SIZE + 1] = {0};
|
|
||||||
volatile int input_index = 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// FUNCTIONS
|
|
||||||
//
|
|
||||||
void uart_init() {
|
|
||||||
UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers
|
|
||||||
UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE);
|
|
||||||
UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format
|
|
||||||
UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I – Global Interrupt Enable
|
|
||||||
}
|
|
||||||
|
|
||||||
char uart_rx(void) {
|
|
||||||
while (TEST(UCSR0A, RXC0) == 0); // 20.11.2 : do nothing until there are unread data in the receive buffer (UDRn), (RXCn flag in UCSRnA register set to 1 when buffer has data)
|
|
||||||
return UDR0; // 20.11.1 : get data in buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_tx(char c) {
|
|
||||||
while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDRn buffer is empty, (UDREn flag in UCSRnA register set to 1 when buffer empty)
|
|
||||||
UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write)
|
|
||||||
}
|
|
||||||
|
|
||||||
// void uart_printstr(const char* str) {
|
|
||||||
// while (*str) {
|
|
||||||
// uart_tx(*str);
|
|
||||||
// str++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
ISR(USART_RX_vect) { // Table 12-7 : we select the code for USART Receive
|
|
||||||
char received_char = UDR0; // read received character
|
|
||||||
if (received_char == '\b' || received_char == 127) { // if backspace is received
|
|
||||||
if (input_index <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (input_index >= INPUT_SIZE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
remove_last_character();
|
|
||||||
input_index--;
|
|
||||||
uart_tx('\b'); // Move cursor back
|
|
||||||
uart_tx(' '); // Erase the character on screen
|
|
||||||
uart_tx('\b'); // Move cursor back again
|
|
||||||
} else if (received_char == '\n' || received_char == '\r') { // if enter is received
|
|
||||||
if (input_index != INPUT_SIZE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
set_color((char *)color_input);
|
|
||||||
reset_input();
|
|
||||||
} else { // any other character
|
|
||||||
if (input_index >= INPUT_SIZE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!is_valid_color_input(received_char)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fill_str(received_char);
|
|
||||||
uart_tx(received_char);
|
|
||||||
input_index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_valid_color_input(char c) {
|
|
||||||
if (input_index == 0) {
|
|
||||||
if (c == '#') {
|
|
||||||
return TRUE;
|
|
||||||
} else {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (input_index >= INPUT_SIZE) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
return TRUE;
|
|
||||||
} else if (c >= 'A' && c <= 'F') {
|
|
||||||
return TRUE;
|
|
||||||
} else if (c >= 'a' && c <= 'f') {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill_str(char input) {
|
|
||||||
if (input_index >= INPUT_SIZE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
color_input[input_index] = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_last_character() {
|
|
||||||
color_input[input_index] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strlength(volatile char *str) {
|
|
||||||
int length = 0;
|
|
||||||
while (*str) {
|
|
||||||
length++;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_input() {
|
|
||||||
for(int i = 0; i < INPUT_SIZE; i++) {
|
|
||||||
color_input[i] = 0;
|
|
||||||
}
|
|
||||||
uart_tx('\r');
|
|
||||||
uart_tx('\n');
|
|
||||||
input_index = 0;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#ifndef HEADER_H
|
|
||||||
#define HEADER_H
|
|
||||||
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// PROTOTYPES
|
|
||||||
//
|
|
||||||
// main.c
|
|
||||||
|
|
||||||
#endif // HEADER_H
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
// 14.3.3 : alternate functions on port D
|
|
||||||
// PD2 : - INT0 (External Interrupt 0 Input)
|
|
||||||
// - PCINT18 (Pin Change Interrupt 18)
|
|
||||||
// 12.4 : Interrupt Vectors in ATmega328 and ATmega328P
|
|
||||||
// - INT0 : External Interrupt Request 0
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DOWN,
|
|
||||||
UP
|
|
||||||
} State;
|
|
||||||
volatile uint8_t button_state = UP;
|
|
||||||
|
|
||||||
// Table 13-2 : interrupt types
|
|
||||||
#define INT0_LOW ((0 << ISC01) | (0 << ISC00))
|
|
||||||
#define INT0_LOGICAL ((0 << ISC01) | (1 << ISC00))
|
|
||||||
#define INT0_FALLING ((1 << ISC01) | (0 << ISC00))
|
|
||||||
#define INT0_RAISING ((1 << ISC01) | (1 << ISC00))
|
|
||||||
|
|
||||||
// use interruption to change led1 state when button1 is pressed
|
|
||||||
int main() {
|
|
||||||
MODE_OUTPUT(LED1);
|
|
||||||
CLEAR_ELEM(LED1);
|
|
||||||
MODE_INPUT(BUTTON1);
|
|
||||||
PULLUP_ON(BUTTON1);
|
|
||||||
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT;
|
|
||||||
|
|
||||||
EIMSK = (1 << INT0); // 13.2.2 : Enable INT0 interrupt (EIMSK – External Interrupt Mask Register)
|
|
||||||
EICRA = INT0_LOGICAL; // Table 13-2 : trigger type (EICRA – External Interrupt Control Register A)
|
|
||||||
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(INT0_vect) {
|
|
||||||
button_state = (button_state == UP) ? DOWN : UP;
|
|
||||||
if (button_state == UP) {
|
|
||||||
TOGGLE_ELEM(LED1);
|
|
||||||
}
|
|
||||||
_delay_ms(50); // for debounce, bad idea to put it here in more complexe codes, it is blocking
|
|
||||||
EIFR |= (1 << INTF0); // 13.2.3 : clear flag, when the flag is set it triggers the interrupt, and eventhough it should be clear by the trigger, it can be set again by the bouncing
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#ifndef HEADER_H
|
|
||||||
#define HEADER_H
|
|
||||||
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// PROTOTYPES
|
|
||||||
//
|
|
||||||
// main.c
|
|
||||||
void blink_led_1();
|
|
||||||
void vary_duty();
|
|
||||||
|
|
||||||
#endif // HEADER_H
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
// 14.3.1 : alternate functions for led2 PB1
|
|
||||||
// - OC1A (Timer/Counter1 Output Compare Match A Output)
|
|
||||||
// - 16.11.1 controlled by COM1A1:0 in TCCR1A
|
|
||||||
// - Table 16-2 : Compare Output Mode, Fast PWM
|
|
||||||
// (1 << COM1A1) | (0 << COM1A0) -> non-inverting mode
|
|
||||||
// - Table 16-4 : set timer 1 in fast PWM mode, with top as ICR1 or OCR1A
|
|
||||||
// - ICR1 : Input Capture Register ((1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (0 << WGM10))
|
|
||||||
// - OCR1A : Output Compare Register ((1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (1 << WGM10))
|
|
||||||
// -> if OCR1A is top, it's also duty cycle, so changing duty cycle will also change frequency
|
|
||||||
// -> if ICR1 is top, OCR1A is duty cycle, so it can be changed independantly
|
|
||||||
// - PCINT1 (Pin Change Interrupt 1) : to interrupt when pin change, in input mode only
|
|
||||||
|
|
||||||
// calulations
|
|
||||||
// - frequency is 16Mhz -> it means that the clock runs 16 000 000 times per seconds
|
|
||||||
// - and the timer1 can store 16 bits value of cycle -> which is 2^16 = 65536
|
|
||||||
// - so it will only last 65536/16000000 = 0,004096 second
|
|
||||||
// - if i want my cycle to be 0.001 second, prescaler 1 is enough
|
|
||||||
// - if i want my cycle to be 0.01 second, which prescaler ?
|
|
||||||
// - 8 * 0,004096 = 0.032768 -> it is enough
|
|
||||||
// - 64 * 0,004096 = 0.262144 -> it is largely enough
|
|
||||||
// - after how many "ticks" do i need to reset my clock, for a duration of 0.01s, for every prescalers :
|
|
||||||
// - 1 : (16000000 / 1) * 0.01 = 16000000 * 0.01 = 160000 "ticks"
|
|
||||||
// - 8 : (16000000 / 8) * 0.01 = 2000000 * 0.01 = 20000 "ticks"
|
|
||||||
// - 64 : (16000000 / 64) * 0.01 = 250000 * 0.01 = 2500 "ticks"
|
|
||||||
// - 256 : (16000000 / 256) * 0.01 = 62500 * 0.01 = 625 "ticks"
|
|
||||||
// - 1024 : (16000000 / 1024) * 0.01 = 15625 * 0.01 = 156.25 "ticks"
|
|
||||||
// - after how many "ticks" do i need to reset my clock, for a duration of 0.005s (*200/s), for every prescalers :
|
|
||||||
// - 1 : (16000000 / 1) * 0.005 = 16000000 * 0.005 = 80000 "ticks"
|
|
||||||
// - 8 : (16000000 / 8) * 0.005 = 2000000 * 0.005 = 10000 "ticks"
|
|
||||||
// - 64 : (16000000 / 64) * 0.005 = 250000 * 0.005 = 1250 "ticks"
|
|
||||||
// - 256 : (16000000 / 256) * 0.005 = 62500 * 0.005 = 312.5 "ticks"
|
|
||||||
// - 1024 : (16000000 / 1024) * 0.005 = 15625 * 0.005 = 78.125 "ticks"
|
|
||||||
|
|
||||||
// alternatively, can use the default values :
|
|
||||||
// - Fast PWM, 8-bit, TOP 0x00FF (255)
|
|
||||||
// - Fast PWM, 9-bit, TOP 0x01FF (511)
|
|
||||||
// - Fast PWM, 10-bit, TOP 0x03FF (1023)
|
|
||||||
|
|
||||||
// no need to set a second for the "blinking" with PWM and duty cycle :
|
|
||||||
// only need to use a top value convenient, like a multiple of 100
|
|
||||||
// if choose top value of 100 :
|
|
||||||
// - at prescaler 1 : 100 / 16000000 = 0.00000625s (it takes this time to do a cycle)
|
|
||||||
// - at prescaler 8 : (100 * 8) / 16000000 = 0.00005s
|
|
||||||
// - at prescaler 64 : (100 * 64) / 16000000 = 0.0004s
|
|
||||||
// - at prescaler 256 : (100 * 256) / 16000000 = 0.0016s
|
|
||||||
// - at prescaler 1024 : (100 * 1024) / 16000000 = 0.0064s
|
|
||||||
// if choose top value of 1000 :
|
|
||||||
// - at prescaler 1 : 1000 / 16000000 = 0.0000625s (it takes this time to do a cycle)
|
|
||||||
// - at prescaler 8 : (1000 * 8) / 16000000 = 0.0005s
|
|
||||||
// - at prescaler 64 : (1000 * 64) / 16000000 = 0.004s
|
|
||||||
// - at prescaler 256 : (1000 * 256) / 16000000 = 0.016s
|
|
||||||
// - at prescaler 1024 : (1000 * 1024) / 16000000 = 0.064s
|
|
||||||
|
|
||||||
// 16.9.3 : timer1 fast PWM
|
|
||||||
|
|
||||||
// TIMER 1
|
|
||||||
#define T1_PWM_PRESCALER 256 // can be 1, 8, 64, 256, 1024
|
|
||||||
#define T1_DUTY_CYCLE_PERCENT 9
|
|
||||||
// #define FREQUENCY_MS 1
|
|
||||||
#define T1_TOP_VALUE 1000
|
|
||||||
// TIMER 0
|
|
||||||
#define T0_PWM_PRESCALER 1024 // can be 1, 8, 64, 256, 1024
|
|
||||||
#define T0_FREQUENCY_MS 5
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DOWN,
|
|
||||||
UP
|
|
||||||
} Slope;
|
|
||||||
|
|
||||||
volatile uint8_t duty_cycle = T1_DUTY_CYCLE_PERCENT;
|
|
||||||
|
|
||||||
// using TIMER 1
|
|
||||||
void blink_led_1() {
|
|
||||||
TCCR1A = (1 << WGM11); // Table 16-4 : set timer1 in fast PWM mode 14, with TOP ICR1, so we can use OCR1A for duty cycle and keep ICR1 for frequency
|
|
||||||
TCCR1B = (1 << WGM13) | (1 << WGM12); // mode 15 with OCR1A TOP prevent using duty cycle trigger on OC1A (OCR1B is free but triggers OC1B -> PB2)
|
|
||||||
// other fast PWM modes 5, 6, and 7 uses predefined TOP, preventing to define a multiple of 100 for percent accuracy
|
|
||||||
|
|
||||||
TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM (14.3.1 : OC1A is alternate function of PB1)
|
|
||||||
|
|
||||||
TCCR1B |= T1_PRESCALE_SET(T1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values for timer 1
|
|
||||||
|
|
||||||
// ICR1 = TIME_MS(FREQUENCY_MS, T1_PWM_PRESCALER); // top value for Xms
|
|
||||||
ICR1 = T1_TOP_VALUE;
|
|
||||||
OCR1A = PERCENT(duty_cycle, ICR1); // 16.9.3 : duty cycle
|
|
||||||
}
|
|
||||||
|
|
||||||
// using TIMER 0
|
|
||||||
void vary_duty() {
|
|
||||||
TCCR0A = (1 << WGM01); // Table 15-8 : set timer0 in CTC mode, with TOP OCRA (15.9.1 : WGM01 in register TCCR0A)
|
|
||||||
|
|
||||||
OCR0A = TIME_MS(T0_FREQUENCY_MS, T0_PWM_PRESCALER); // 15.9.4 : compare value to trigger an Output Compare interrupt on register A
|
|
||||||
|
|
||||||
TCCR0B |= T0_PRESCALE_SET(T0_PWM_PRESCALER); // 15.9.2 : set the appropriate prescale values for timer 0
|
|
||||||
|
|
||||||
TIMSK0 = (1 << OCIE0A); // 15.9.6 : enable interrupt in timer 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// use timers interruptions to varie led1 intensity using duty cycle, from 0% to 100% to 0% in 1 second
|
|
||||||
// timer1 sets the led duty cycle, timer0 change the duty cycle percentage
|
|
||||||
int main() {
|
|
||||||
MODE_OUTPUT(LED1);
|
|
||||||
CLEAR_ELEM(LED1);
|
|
||||||
MODE_OUTPUT(LED2);
|
|
||||||
CLEAR_ELEM(LED2);
|
|
||||||
MODE_OUTPUT(LED3);
|
|
||||||
CLEAR_ELEM(LED3);
|
|
||||||
MODE_OUTPUT(LED4);
|
|
||||||
CLEAR_ELEM(LED4);
|
|
||||||
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT;
|
|
||||||
|
|
||||||
blink_led_1();
|
|
||||||
vary_duty();
|
|
||||||
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(TIMER0_COMPA_vect) {
|
|
||||||
volatile static Slope slope = UP;
|
|
||||||
if (slope == UP) {
|
|
||||||
if (duty_cycle >= 100) {
|
|
||||||
duty_cycle = 100;
|
|
||||||
slope = DOWN;
|
|
||||||
} else {
|
|
||||||
duty_cycle += 1;
|
|
||||||
}
|
|
||||||
} else if (slope == DOWN) {
|
|
||||||
if (duty_cycle <= 0) {
|
|
||||||
duty_cycle = 0;
|
|
||||||
slope = UP;
|
|
||||||
} else {
|
|
||||||
duty_cycle -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OCR1A = PERCENT(duty_cycle, ICR1);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#ifndef HEADER_H
|
|
||||||
#define HEADER_H
|
|
||||||
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "bitmanip.h"
|
|
||||||
#include "interrupt.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// PROTOTYPES
|
|
||||||
//
|
|
||||||
// main.c
|
|
||||||
void print_binary(int value);
|
|
||||||
void increment_int();
|
|
||||||
void decrement_int();
|
|
||||||
void increment_led();
|
|
||||||
void decrement_led();
|
|
||||||
void on_press(int bit, void (*action)(void));
|
|
||||||
|
|
||||||
//
|
|
||||||
// MACROS
|
|
||||||
//
|
|
||||||
#define MAX 15
|
|
||||||
#define MIN 0
|
|
||||||
|
|
||||||
#endif // HEADER_H
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
// ALTERNATE FUNCTIONS :
|
|
||||||
// Table 14-9 : port D alternate functions
|
|
||||||
// BUTTON1 SW1 PD2 :
|
|
||||||
// -> INT0 (External Interrupt 0 Input)
|
|
||||||
// -> PCINT18 (Pin Change Interrupt 18)
|
|
||||||
// BUTTON2 SW2 PD4 :
|
|
||||||
// -> XCK (USART External Clock Input/Output)
|
|
||||||
// -> T0 (Timer/Counter 0 External Counter Input)
|
|
||||||
// -> PCINT20 (Pin Change Interrupt 20)
|
|
||||||
// EXTERNAL INTERRUPTS GROUP :
|
|
||||||
// 13.2.4 : pin change interrupt controle register (PCICR)
|
|
||||||
// -> bit PCIE2 for PCINT[23:16] (PCI2 Interrupt Vector)
|
|
||||||
// PCMSK2 to enable each pin
|
|
||||||
// INTERRUPT VECTORS NAME :
|
|
||||||
// Table 12-6 : interrupts vectors
|
|
||||||
// -> PCINT2_vect
|
|
||||||
// ENABLE PIN CHANGE INTERRUPT :
|
|
||||||
// 13.2.6 : PCMSK2 – Pin Change Mask Register 2
|
|
||||||
// -> (1 << PCINT20) | (1 << PCINT18)
|
|
||||||
|
|
||||||
#define TIMER_TOP_MS 20
|
|
||||||
|
|
||||||
volatile uint8_t value = 0;
|
|
||||||
volatile Boolean pressed = FALSE;
|
|
||||||
volatile Boolean timer_0_init = FALSE;
|
|
||||||
volatile Boolean timer_delay_enabled = FALSE;
|
|
||||||
volatile uint16_t timer_delay = 0;
|
|
||||||
|
|
||||||
void print_binary(int value) {
|
|
||||||
int mask_3 = 0b1000;
|
|
||||||
int bit_at_3 = value & mask_3;
|
|
||||||
int bit_at_4 = bit_at_3 << 1;
|
|
||||||
PORTB = (value & 0b111) + bit_at_4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void increment_int() {
|
|
||||||
// int *value = params->value;
|
|
||||||
// int max = params->max;
|
|
||||||
value = (value >= MAX) ? MAX : ++value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void decrement_int() {
|
|
||||||
// int *value = params->value;
|
|
||||||
// int min = params->min;
|
|
||||||
value = (value <= MIN) ? MIN : --value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void increment_led() {
|
|
||||||
// IncrementParams *params = (IncrementParams *)param;
|
|
||||||
increment_int();
|
|
||||||
print_binary(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void decrement_led() {
|
|
||||||
// IncrementParams *params = (IncrementParams *)param;
|
|
||||||
decrement_int();
|
|
||||||
print_binary(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer0_init_1_ms() {
|
|
||||||
TCCR0A |= (1 << WGM01); // CTC mode
|
|
||||||
OCR0A = 249; // Compare match every 1ms (F_CPU / Prescaler = 16,000,000 / 64 = 250,000 ticks/sec)
|
|
||||||
TIMSK0 |= (1 << OCIE0A); // Enable Compare Match A interrupt
|
|
||||||
TCCR0B |= (1 << CS01) | (1 << CS00); // Prescaler 64
|
|
||||||
sei(); // Enable global interrupts
|
|
||||||
timer_0_init = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void launch_delay_ms(void) {
|
|
||||||
if (!timer_0_init) {
|
|
||||||
timer0_init_1_ms();
|
|
||||||
}
|
|
||||||
CLEAR(PCICR, PCIE2); // disable interupt PCINT2
|
|
||||||
CLEAR(PCMSK2, PCINT20);
|
|
||||||
CLEAR(PCMSK2, PCINT18);
|
|
||||||
timer_delay = 0;
|
|
||||||
timer_delay_enabled = TRUE;
|
|
||||||
SET(PCIFR, PCIF2); // reset flag interrupt PCINT2
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(TIMER0_COMPA_vect) {
|
|
||||||
if (!timer_delay_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
timer_delay++;
|
|
||||||
if (timer_delay >= TIMER_TOP_MS) {
|
|
||||||
// TOGGLE_ELEM(LED1);
|
|
||||||
timer_delay_enabled = FALSE;
|
|
||||||
SET(PCICR, PCIE2); // re-enable interupt PCINT2
|
|
||||||
SET(PCMSK2, PCINT20);
|
|
||||||
SET(PCMSK2, PCINT18);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_press(int bit, void (*action)(void)) {
|
|
||||||
// if ((TEST(PIND, bit)) == 0) {
|
|
||||||
// action();
|
|
||||||
// _delay_ms(20);
|
|
||||||
// while ((TEST(PIND, bit)) == 0) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// _delay_ms(20);
|
|
||||||
// }
|
|
||||||
launch_delay_ms();
|
|
||||||
if (!pressed) {
|
|
||||||
// if ((TEST(PIND, bit)) == 0) {
|
|
||||||
// }
|
|
||||||
pressed = TRUE;
|
|
||||||
action();
|
|
||||||
} else {
|
|
||||||
pressed = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write a program that incr/decr-ements a number with the buttons, using interrupts, empty infinite loop, and displays the result on LEDs in binary
|
|
||||||
int main() {
|
|
||||||
MODE_OUTPUT(LED1);
|
|
||||||
MODE_OUTPUT(LED2);
|
|
||||||
MODE_OUTPUT(LED3);
|
|
||||||
MODE_OUTPUT(LED4);
|
|
||||||
MODE_INPUT(BUTTON1);
|
|
||||||
MODE_INPUT(BUTTON2);
|
|
||||||
PULLUP_ON(BUTTON1);
|
|
||||||
PULLUP_ON(BUTTON2);
|
|
||||||
|
|
||||||
SREG |= ENABLE_GLOBAL_INTERRUPT;
|
|
||||||
|
|
||||||
PCICR = (1 << PCIE2); // 13.2.4 : enable pin change interrupt, bit PCIE2 for PCINT[23:16], (Table 14-9 : alternates : PD2 - PCINT18, PD4 - PCINT20)
|
|
||||||
PCMSK2 = (1 << PCINT20) | (1 << PCINT18); // 13.2.6 : enable individual pin chang interrupt
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(PCINT2_vect) {
|
|
||||||
if (!TEST_PIN(BUTTON1)) {
|
|
||||||
on_press(SW1, increment_led);
|
|
||||||
}
|
|
||||||
if (!TEST_PIN(BUTTON2)) {
|
|
||||||
on_press(SW2, decrement_led);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
include ../../Makefile
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#include "header.h"
|
|
||||||
|
|
||||||
// 24.2 : The ADC generates a 10-bit result which is presented in the ADC Data Registers, ADCH and ADCL
|
|
||||||
|
|
||||||
void adc_init(uint8_t prescaler_value) {
|
|
||||||
ADMUX = (1 << REFS0); // Table 24-3 : set voltage reference, AVCC with external capacitor at AREF pin
|
|
||||||
ADMUX |= (1 << ADLAR); // 24.9.1 : result is left adjusted, meaning the first 8 bits values are readable in ADCH, (24.9.3.2 : ADC data register is not updated util ADCH is read)
|
|
||||||
ADCSRA = (1 << ADEN); // 24.9.2 : enable ADC
|
|
||||||
ADCSRA |= (1 << ADATE); // 24.9.2 : enable Auto Trigger -> it will start a conversion on the selected channel in ADMUX when the selected source (in ADCSRB) is triggered
|
|
||||||
ADCSRA |= (1 << ADIE); // 24.9.2 : enable ADC Interrupt
|
|
||||||
ADCSRA |= ADC_PRESCALE_SET(prescaler_value); // Table 24-5 : prescaler ADC
|
|
||||||
|
|
||||||
ADCSRB = ADC_TRIGGER_TIMER_1_COMPARE_B; // Table 24-6 : ADC Auto Trigger Source
|
|
||||||
ADMUX = (ADMUX & 0b11110000) | (adc_channel & 0b1111); // Table 24-4 : Select ADC channel 0, (Table 14-6 : alternate function for RV1 on PC0 -> ADC0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void adc_print_hex(uint8_t value) {
|
|
||||||
char buffer[3] = {0};
|
|
||||||
int_to_hex_string(value, buffer, 2);
|
|
||||||
uart_printstr_endl(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(ADC_vect) { // Table 12-6 : interrupt vector for ADC Conversion Complete
|
|
||||||
uint8_t value = ADCH; // 24.9.3.2 : read ADCH 8 bits precision
|
|
||||||
adc_print_hex(value);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user