commit
9463a6ba2f
@ -0,0 +1,47 @@ |
||||
# Object files |
||||
*.o |
||||
*.ko |
||||
*.obj |
||||
*.elf |
||||
*.axf |
||||
|
||||
# Precompiled Headers |
||||
*.gch |
||||
*.pch |
||||
|
||||
# Libraries |
||||
*.lib |
||||
*.a |
||||
*.la |
||||
*.lo |
||||
|
||||
# Shared objects (inc. Windows DLLs) |
||||
*.dll |
||||
*.so |
||||
*.so.* |
||||
*.dylib |
||||
|
||||
# Executables |
||||
*.exe |
||||
*.out |
||||
*.app |
||||
*.i*86 |
||||
*.x86_64 |
||||
*.hex |
||||
|
||||
# Debug files |
||||
*.dSYM/ |
||||
|
||||
# AVR specific stuff |
||||
*.lst |
||||
*.dis |
||||
*.disasm |
||||
*.list |
||||
*.eeprom |
||||
*.pre |
||||
|
||||
# QtCreator user-specific |
||||
*.pro.user |
||||
|
||||
.idea/ |
||||
cmake-build-debug/ |
@ -0,0 +1,25 @@ |
||||
cmake_minimum_required(VERSION 3.7) |
||||
project(firmware) |
||||
|
||||
# Fake CMake config for CLion |
||||
|
||||
set(CMAKE_CXX_STANDARD GNU99) |
||||
|
||||
set(SOURCE_FILES |
||||
main.c |
||||
lib/calc.h |
||||
lib/iopins.c |
||||
lib/iopins.h |
||||
lib/nsdelay.h |
||||
lib/spi.c |
||||
lib/spi.h |
||||
lib/usart.c |
||||
lib/usart.h |
||||
) |
||||
|
||||
include_directories(lib |
||||
/usr/avr/include/) |
||||
|
||||
add_definitions(-D__AVR_ATmega328P__) |
||||
|
||||
add_executable(firmware ${SOURCE_FILES}) |
@ -0,0 +1,21 @@ |
||||
The MIT License (MIT) |
||||
|
||||
Copyright (c) 2016 Ondřej Hruška |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,138 @@ |
||||
#############################################
|
||||
|
||||
# CPU type
|
||||
MCU = atmega328p
|
||||
|
||||
# CPU frequency [Hz]
|
||||
F_CPU = 16000000
|
||||
|
||||
# Fuses (refer to datasheet)
|
||||
LFUSE = 0xFF
|
||||
HFUSE = 0xDE
|
||||
EFUSE = 0x05
|
||||
|
||||
# AVRDUDE settings
|
||||
PROG_BAUD = 57600
|
||||
PROG_DEV = /dev/ttyUSB0
|
||||
PROG_TYPE = arduino
|
||||
|
||||
# Build the final AVRDUDE arguments
|
||||
PROG_ARGS = -c $(PROG_TYPE) -p $(MCU) -b $(PROG_BAUD) -P $(PROG_DEV)
|
||||
|
||||
#############################################
|
||||
|
||||
# Main file
|
||||
BINARY = main
|
||||
|
||||
# Obj files to be built <- add .o for any .c files you add!
|
||||
OBJS = $(BINARY).o
|
||||
OBJS += lib/usart.o
|
||||
OBJS += lib/iopins.o
|
||||
OBJS += lib/spi.o
|
||||
|
||||
# Dirs with header files
|
||||
INCL_DIRS = . lib/
|
||||
|
||||
# Pre-defined macros
|
||||
DEFS = -DF_CPU=$(F_CPU)UL
|
||||
|
||||
#############################################
|
||||
|
||||
# C flags
|
||||
CFLAGS = -std=gnu99 -mmcu=$(MCU) $(DEFS) $(INCL_DIRS:%=-I%)
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffreestanding
|
||||
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
|
||||
CFLAGS += -g2 -Wextra -Wfatal-errors -Wno-unused-but-set-variable
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Os
|
||||
|
||||
LDFLAGS = -Wl,--gc-sections -Wl,--relax -lm
|
||||
|
||||
#LD_FLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
#LD_FLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
|
||||
#############################################
|
||||
|
||||
## Defined programs / locations
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
JUNK = *.o *.d *.elf *.bin *.hex *.srec *.list *.lst *.map *.dis *.disasm *.eep *.eeprom *.lss
|
||||
|
||||
.SUFFIXES: .elf .bin .hex .lst .map .eeprom .pre |
||||
.SECONDEXPANSION: |
||||
.SECONDARY: |
||||
|
||||
.PHONY: all elf bin hex lst pre ee eeprom dis size clean flash flashe shell fuses show_fuses set_default_fuses |
||||
|
||||
all: hex size |
||||
|
||||
elf: $(BINARY).elf |
||||
bin: $(BINARY).bin |
||||
hex: $(BINARY).hex |
||||
lst: $(BINARY).lst |
||||
pre: $(BINARY).pre |
||||
ee: $(BINARY).eeprom |
||||
eeprom: $(BINARY).eeprom |
||||
dis: lst |
||||
|
||||
# Show how big the resulting program is
|
||||
size: elf |
||||
$(AVRSIZE) -C --mcu=$(MCU) $(BINARY).elf
|
||||
|
||||
|
||||
|
||||
# --- Magic build targets ----------------
|
||||
|
||||
%.hex: %.elf |
||||
$(OBJCOPY) -R .eeprom -O ihex $< $@
|
||||
|
||||
%.elf %.map: $(OBJS) |
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(*).elf
|
||||
|
||||
%.pre: %.c |
||||
$(CC) $(CFLAGS) -E $(*).c --output $@
|
||||
|
||||
%.eeprom: %.elf |
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
%.lst: %.elf |
||||
$(Q)$(OBJDUMP) -S $(*).elf > $(*).lst
|
||||
|
||||
%.o: %.c |
||||
$(CC) $(CFLAGS) -o $(*).o -c $(*).c
|
||||
|
||||
%.o: %.s |
||||
$(CC) $(CFLAGS) -o $(*).o -c $(*).s
|
||||
|
||||
|
||||
# Clean all produced trash
|
||||
clean: |
||||
rm -f $(JUNK)
|
||||
cd lib && rm -f $(JUNK)
|
||||
|
||||
|
||||
## === avrdude ===
|
||||
|
||||
flash: $(BINARY).hex |
||||
$(AVRDUDE) $(PROG_ARGS) -U flash:w:$<
|
||||
|
||||
flashe: $(BINARY).eeprom |
||||
$(AVRDUDE) $(PROG_ARGS) -U eeprom:w:$<
|
||||
|
||||
shell: |
||||
$(AVRDUDE) $(PROG_ARGS) -nt
|
||||
|
||||
# === fuses ===
|
||||
|
||||
# this may not work with the arduino programmer, I haven't tried.
|
||||
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses: |
||||
$(AVRDUDE) $(PROG_ARGS) $(FUSE_STRING)
|
||||
|
||||
show_fuses: |
||||
$(AVRDUDE) $(PROG_ARGS) -nv
|
@ -0,0 +1,78 @@ |
||||
# AVR C Boilerplate |
||||
|
||||
This is a basic boilerplate for programming AVRs in C. |
||||
|
||||
The project aims to make programming Arduinos in C fun by |
||||
providing support for basic functionality like GPIO and USART, |
||||
so you can start developing without having the datasheet open |
||||
all the time. |
||||
|
||||
It is intended for **ATmega328P** (the chip in Arduinos), |
||||
but can be easily adapted to other parts. |
||||
|
||||
## Requirements |
||||
|
||||
Before you can start coding, you need to install a few software packages: |
||||
|
||||
- `avrdude` - the flash tool |
||||
- `avr-gcc` - compiler |
||||
- `avr-libc` - libc implementation for AVR |
||||
- `avr-binutils` - utils for manipulating AVR binaries |
||||
- `make` - to run the Makefile |
||||
|
||||
There's a good chance you already have `make`, the rest should be in your |
||||
distribution's repos. |
||||
|
||||
If you're on Arch: |
||||
|
||||
``` |
||||
# pacman -S base-devel avr-gcc avr-binutils avr-libc avrdude |
||||
``` |
||||
|
||||
If you're on Mac, you should be able to pull the stuff with *brew*. |
||||
|
||||
## Getting started |
||||
|
||||
The provided `main.c` is a good starting point - it contains some simple demo code. |
||||
|
||||
You can compile it with `make` and flash with `make flash`. |
||||
|
||||
### Before you can flash |
||||
|
||||
First, check that the `avrdude` options in the file are correct for your system - especially |
||||
the device and speed. |
||||
|
||||
```ini |
||||
# AVRDUDE settings |
||||
PROG_BAUD = 57600 |
||||
PROG_DEV = /dev/ttyUSB0 |
||||
PROG_TYPE = arduino |
||||
|
||||
# Build the final AVRDUDE arguments |
||||
PROG_ARGS = -c $(PROG_TYPE) -p $(MCU) -b $(PROG_BAUD) -P $(PROG_DEV) |
||||
``` |
||||
|
||||
- Adjust `PROG_DEV` to the device your board is connected to. On Linux it's usually |
||||
`/dev/ttyUSB0`, but it can also be `/dev/ttyACM0` or something else. On Mac, it'll be |
||||
`/dev/cu.xxx`. On Windows it's some `COMx`.<br> |
||||
Linux and Mac users can use `ls /dev` to see their devices. Windows users will find |
||||
this in their Device Manager. |
||||
- You may also adjust the baudrate (`PROG_BAUD`). Some boards need `115200`. |
||||
|
||||
**TIP:** You can look what the Arduino IDE is using - it's running avrdude too. |
||||
|
||||
### Adding new files |
||||
|
||||
- If you *add a new C file* to the project, add an entry for it's `.o` (object file, |
||||
created by the compiler before linking) to the `OBJS` list in the Makefile. |
||||
- Similarly, if you *add a new folder with header files*, add it to `INCL_DIRS`. |
||||
- In case you need `printf` (or `printf` with floats), enable the appropriate LD_FLAGS |
||||
in the Makefile (it's well commented). Code size will - obviously - grow quite a bit. |
||||
|
||||
## Notes |
||||
|
||||
- The **Arduino UNO** bootloader has a quirk where `Double Speed Asynchronous Mode` for USART |
||||
is enabled by default, so if you set your baud rate to 9600, you'd really get 19200.<br> |
||||
We correct this in the `usart_init()` function to keep things consistent and to avoid |
||||
confusion.<br> |
||||
*If you wish to turn this on* however, you can do so by using `usart_set_2x(true)`. |
@ -0,0 +1,50 @@ |
||||
TEMPLATE = app |
||||
CONFIG += console |
||||
CONFIG -= app_bundle |
||||
CONFIG -= qt |
||||
|
||||
INCLUDEPATH += \ |
||||
lib \ |
||||
/usr/avr/include |
||||
|
||||
DEFINES += __AVR_ATmega328P__ F_CPU=16000000UL |
||||
|
||||
DISTFILES += \ |
||||
style.astylerc \ |
||||
Makefile \ |
||||
README.md \ |
||||
LICENSE |
||||
|
||||
HEADERS += \ |
||||
lib/calc.h \ |
||||
lib/iopins.h \ |
||||
lib/usart.h \ |
||||
lib/nsdelay.h \ |
||||
lib/spi.h |
||||
|
||||
SOURCES += \ |
||||
lib/iopins.c \ |
||||
main.c \ |
||||
lib/usart.c \ |
||||
lib/spi.c |
||||
|
||||
# === Flags for the Clang code model=== |
||||
# |
||||
#-Weverything |
||||
#-Wno-c++98-compat |
||||
#-Wno-c++98-compat-pedantic |
||||
#-Wno-unused-macros |
||||
#-Wno-newline-eof |
||||
#-Wno-exit-time-destructors |
||||
#-Wno-global-constructors |
||||
#-Wno-gnu-zero-variadic-macro-arguments |
||||
#-Wno-documentation |
||||
#-Wno-missing-prototypes |
||||
#-std=gnu99 |
||||
#-Wno-gnu |
||||
#-Wno-format-nonliteral |
||||
#-Wno-conversion |
||||
#-Wno-pointer-sign |
||||
#-Wno-unknown-attributes |
||||
#-Wno-main-return-type |
||||
#-Wno-missing-noreturn |
@ -0,0 +1,154 @@ |
||||
#pragma once |
||||
|
||||
//
|
||||
// Bit and byte manipulation utilities
|
||||
//
|
||||
|
||||
#include <stdint.h> |
||||
|
||||
|
||||
// --- Increment in range ---
|
||||
// when overflown, wraps within range. Lower bound < upper bound.
|
||||
// ..., upper bound excluded
|
||||
#define inc_wrap(var, min, max) \ |
||||
do { \
|
||||
if ((var) >= ((max) - 1)) { \
|
||||
(var) = (min); \
|
||||
} else { \
|
||||
(var)++; \
|
||||
} \
|
||||
} while(0) |
||||
|
||||
// ..., upper bound included
|
||||
#define inc_wrapi(var, min, max) inc_wrap((var), (min), (max) + 1) |
||||
|
||||
|
||||
// --- Decrement in range ---
|
||||
// when underflown, wraps within range. Lower bound < upper bound.
|
||||
// ..., upper bound excluded
|
||||
#define dec_wrap(var, min, max) \ |
||||
do { \
|
||||
if ((var) <= (min)) { \
|
||||
(var) = (max) - 1; \
|
||||
} else { \
|
||||
(var)--; \
|
||||
} \
|
||||
} while(0) |
||||
|
||||
|
||||
// ..., upper bound included
|
||||
#define dec_wrapi(var, min, max) dec_wrap((var), (min), (max) + 1) |
||||
|
||||
|
||||
// --- Bit manipulation --
|
||||
|
||||
// Set bit
|
||||
#define sbi(reg, n) do { (reg) |= (1 << (uint8_t)(n)); } while(0) |
||||
|
||||
// Clear bit
|
||||
#define cbi(reg, n) do { (reg) &= ~(1 << (uint8_t)(n)); } while(0) |
||||
|
||||
// Get n-th bit
|
||||
#define get_bit(reg, n) (((reg) >> (uint8_t)(n)) & 1) |
||||
|
||||
|
||||
// Test n-th bit (Can't use bit_is_set, as it's defined in sfr_def.h)
|
||||
#define bit_is_high(reg, n) get_bit((reg), (n)) |
||||
#define bit_is_low(reg, n) (!get_bit((reg), (n))) |
||||
|
||||
// Write value to n-th bit
|
||||
#define set_bit(reg, n, val) \ |
||||
do { \
|
||||
(reg) = ((reg) & ~(1 << (uint8_t)(n))) \
|
||||
| (((val) & 1) << (uint8_t)(n)); \
|
||||
} while(0) |
||||
|
||||
// Invert n-th bit
|
||||
#define toggle_bit(reg, n) do { (reg) ^= (1 << (uint8_t)(n)); } while(0) |
||||
|
||||
|
||||
// --- Bit manipulation with pointer to variable ---
|
||||
|
||||
// Set n-th bit in pointee
|
||||
#define sbi_p(reg_p, n) do { (*(reg_p)) |= (1 << (uint8_t)(n)); } while(0) |
||||
// Clear n-th bit in pointee
|
||||
#define cbi_p(reg_p, n) do { (*(reg_p)) &= ~(1 << (uint8_t)(n)); } while(0) |
||||
|
||||
// Get n-th bit in pointee
|
||||
#define get_bit_p(reg_p, n) ((*(reg_p) >> (uint8_t)(n)) & 1) |
||||
|
||||
// Test n-th bit in pointee (Can't use bit_is_set, as it's redefined in sfr_def.h)
|
||||
#define bit_is_high_p(reg_p, bit) get_bit_p(reg_p, bit) |
||||
#define bit_is_low_p(reg_p, bit) (!get_bit_p(reg_p, bit)) |
||||
|
||||
|
||||
// Write value to a bit in pointee
|
||||
#define set_bit_p(reg_p, n, value) \ |
||||
do { \
|
||||
*(reg_p) = (*(reg_p) & ~(1 << (uint8_t)(n))) \
|
||||
| (((value) & 1) << (uint8_t)(n)); \
|
||||
} while(0) |
||||
|
||||
|
||||
#define toggle_bit_p(reg_p, n) do { *(reg_p) ^= (1 << (uint8_t)(n)); } while(0) |
||||
|
||||
|
||||
// --- Nibble manipulation ---
|
||||
|
||||
// Replace nibble in a byte
|
||||
#define set_low_nibble(reg, value) \ |
||||
do { \
|
||||
(reg) = ((reg) & 0xF0) \
|
||||
| ((uint8_t)(value) & 0xF); \
|
||||
} while(0) |
||||
|
||||
|
||||
#define set_high_nibble(reg, value) \ |
||||
do { \
|
||||
(reg) = ((reg) & 0x0F) \
|
||||
| (((uint8_t)(value) & 0xF) << 4); \
|
||||
} while(0) |
||||
|
||||
|
||||
#define set_low_nibble_p(reg_p, value) \ |
||||
do { \
|
||||
*(reg_p) = (*(reg_p) & 0xF0) \
|
||||
| ((uint8_t)(value) & 0xF); \
|
||||
} while(0) |
||||
|
||||
|
||||
#define set_high_nibble_p(reg_p, value) \ |
||||
do { \
|
||||
*(reg_p) = (*(reg_p) & 0x0F) \
|
||||
| (((uint8_t)(value) & 0xF) << 4); \
|
||||
} while(0) |
||||
|
||||
|
||||
#define low_nibble(x) ((uint8_t)(x) & 0x0F) |
||||
#define high_nibble(x) (((uint8_t)(x) & 0xF0) >> 4) |
||||
|
||||
|
||||
// --- Range tests ---
|
||||
|
||||
// Test if X is within low..high, regardless of bounds order
|
||||
#define in_range(x, low, high) \ |
||||
((low) < (high) ? ((x) >= (low) && (x) < (high)) \
|
||||
: ((x) >= (high) && (x) < (low))) \
|
||||
|
||||
|
||||
// ..., include greater bound
|
||||
#define in_rangei(x, low, high) \ |
||||
((low) < (high) ? ((x) >= (low) && (x) <= (high)) \
|
||||
: ((x) >= (high) && (x) <= (low))) \
|
||||
|
||||
|
||||
// Test if X in low..high, wrap around ends if needed.
|
||||
#define in_range_wrap(x, low, high) \ |
||||
(((low) < (high)) ? ((x) >= (low) && (x) < (high)) \
|
||||
: ((x) >= (low) || (x) < (high))) |
||||
|
||||
|
||||
// ..., include upper bound
|
||||
#define in_range_wrapi(x, low, high) \ |
||||
(((low) <= (high)) ? ((x) >= (low) && (x) <= (high)) \
|
||||
: ((x) >= (low) || (x) <= (high))) |
@ -0,0 +1,277 @@ |
||||
#include <avr/io.h> |
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
#include "iopins.h" |
||||
|
||||
|
||||
void set_dir_n(uint8_t pin, uint8_t d) |
||||
{ |
||||
switch(pin) { |
||||
case 0: set_dir(0, d); return; |
||||
case 1: set_dir(1, d); return; |
||||
case 2: set_dir(2, d); return; |
||||
case 3: set_dir(3, d); return; |
||||
case 4: set_dir(4, d); return; |
||||
case 5: set_dir(5, d); return; |
||||
case 6: set_dir(6, d); return; |
||||
case 7: set_dir(7, d); return; |
||||
case 8: set_dir(8, d); return; |
||||
case 9: set_dir(9, d); return; |
||||
case 10: set_dir(10, d); return; |
||||
case 11: set_dir(11, d); return; |
||||
case 12: set_dir(12, d); return; |
||||
case 13: set_dir(13, d); return; |
||||
case 14: set_dir(14, d); return; |
||||
case 15: set_dir(15, d); return; |
||||
case 16: set_dir(16, d); return; |
||||
case 17: set_dir(17, d); return; |
||||
case 18: set_dir(18, d); return; |
||||
case 19: set_dir(19, d); return; |
||||
case 20: set_dir(20, d); return; |
||||
case 21: set_dir(21, d); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void as_input_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: as_input(0); return; |
||||
case 1: as_input(1); return; |
||||
case 2: as_input(2); return; |
||||
case 3: as_input(3); return; |
||||
case 4: as_input(4); return; |
||||
case 5: as_input(5); return; |
||||
case 6: as_input(6); return; |
||||
case 7: as_input(7); return; |
||||
case 8: as_input(8); return; |
||||
case 9: as_input(9); return; |
||||
case 10: as_input(10); return; |
||||
case 11: as_input(11); return; |
||||
case 12: as_input(12); return; |
||||
case 13: as_input(13); return; |
||||
case 14: as_input(14); return; |
||||
case 15: as_input(15); return; |
||||
case 16: as_input(16); return; |
||||
case 17: as_input(17); return; |
||||
case 18: as_input(18); return; |
||||
case 19: as_input(19); return; |
||||
case 20: as_input(20); return; |
||||
case 21: as_input(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void as_input_pu_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: as_input_pu(0); return; |
||||
case 1: as_input_pu(1); return; |
||||
case 2: as_input_pu(2); return; |
||||
case 3: as_input_pu(3); return; |
||||
case 4: as_input_pu(4); return; |
||||
case 5: as_input_pu(5); return; |
||||
case 6: as_input_pu(6); return; |
||||
case 7: as_input_pu(7); return; |
||||
case 8: as_input_pu(8); return; |
||||
case 9: as_input_pu(9); return; |
||||
case 10: as_input_pu(10); return; |
||||
case 11: as_input_pu(11); return; |
||||
case 12: as_input_pu(12); return; |
||||
case 13: as_input_pu(13); return; |
||||
case 14: as_input_pu(14); return; |
||||
case 15: as_input_pu(15); return; |
||||
case 16: as_input_pu(16); return; |
||||
case 17: as_input_pu(17); return; |
||||
case 18: as_input_pu(18); return; |
||||
case 19: as_input_pu(19); return; |
||||
case 20: as_input_pu(20); return; |
||||
case 21: as_input_pu(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void as_output_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: as_output(0); return; |
||||
case 1: as_output(1); return; |
||||
case 2: as_output(2); return; |
||||
case 3: as_output(3); return; |
||||
case 4: as_output(4); return; |
||||
case 5: as_output(5); return; |
||||
case 6: as_output(6); return; |
||||
case 7: as_output(7); return; |
||||
case 8: as_output(8); return; |
||||
case 9: as_output(9); return; |
||||
case 10: as_output(10); return; |
||||
case 11: as_output(11); return; |
||||
case 12: as_output(12); return; |
||||
case 13: as_output(13); return; |
||||
case 14: as_output(14); return; |
||||
case 15: as_output(15); return; |
||||
case 16: as_output(16); return; |
||||
case 17: as_output(17); return; |
||||
case 18: as_output(18); return; |
||||
case 19: as_output(19); return; |
||||
case 20: as_output(20); return; |
||||
case 21: as_output(21); return; |
||||
} |
||||
} |
||||
|
||||
void pin_set_n(uint8_t pin, uint8_t v) |
||||
{ |
||||
switch(pin) { |
||||
case 0: pin_set(0, v); return; |
||||
case 1: pin_set(1, v); return; |
||||
case 2: pin_set(2, v); return; |
||||
case 3: pin_set(3, v); return; |
||||
case 4: pin_set(4, v); return; |
||||
case 5: pin_set(5, v); return; |
||||
case 6: pin_set(6, v); return; |
||||
case 7: pin_set(7, v); return; |
||||
case 8: pin_set(8, v); return; |
||||
case 9: pin_set(9, v); return; |
||||
case 10: pin_set(10, v); return; |
||||
case 11: pin_set(11, v); return; |
||||
case 12: pin_set(12, v); return; |
||||
case 13: pin_set(13, v); return; |
||||
case 14: pin_set(14, v); return; |
||||
case 15: pin_set(15, v); return; |
||||
case 16: pin_set(16, v); return; |
||||
case 17: pin_set(17, v); return; |
||||
case 18: pin_set(18, v); return; |
||||
case 19: pin_set(19, v); return; |
||||
case 20: pin_set(20, v); return; |
||||
case 21: pin_set(21, v); return; |
||||
} |
||||
} |
||||
|
||||
void pin_down_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: pin_down(0); return; |
||||
case 1: pin_down(1); return; |
||||
case 2: pin_down(2); return; |
||||
case 3: pin_down(3); return; |
||||
case 4: pin_down(4); return; |
||||
case 5: pin_down(5); return; |
||||
case 6: pin_down(6); return; |
||||
case 7: pin_down(7); return; |
||||
case 8: pin_down(8); return; |
||||
case 9: pin_down(9); return; |
||||
case 10: pin_down(10); return; |
||||
case 11: pin_down(11); return; |
||||
case 12: pin_down(12); return; |
||||
case 13: pin_down(13); return; |
||||
case 14: pin_down(14); return; |
||||
case 15: pin_down(15); return; |
||||
case 16: pin_down(16); return; |
||||
case 17: pin_down(17); return; |
||||
case 18: pin_down(18); return; |
||||
case 19: pin_down(19); return; |
||||
case 20: pin_down(20); return; |
||||
case 21: pin_down(21); return; |
||||
} |
||||
} |
||||
|
||||
void pin_up_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: pin_up(0); return; |
||||
case 1: pin_up(1); return; |
||||
case 2: pin_up(2); return; |
||||
case 3: pin_up(3); return; |
||||
case 4: pin_up(4); return; |
||||
case 5: pin_up(5); return; |
||||
case 6: pin_up(6); return; |
||||
case 7: pin_up(7); return; |
||||
case 8: pin_up(8); return; |
||||
case 9: pin_up(9); return; |
||||
case 10: pin_up(10); return; |
||||
case 11: pin_up(11); return; |
||||
case 12: pin_up(12); return; |
||||
case 13: pin_up(13); return; |
||||
case 14: pin_up(14); return; |
||||
case 15: pin_up(15); return; |
||||
case 16: pin_up(16); return; |
||||
case 17: pin_up(17); return; |
||||
case 18: pin_up(18); return; |
||||
case 19: pin_up(19); return; |
||||
case 20: pin_up(20); return; |
||||
case 21: pin_up(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void pin_toggle_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: pin_toggle(0); return; |
||||
case 1: pin_toggle(1); return; |
||||
case 2: pin_toggle(2); return; |
||||
case 3: pin_toggle(3); return; |
||||
case 4: pin_toggle(4); return; |
||||
case 5: pin_toggle(5); return; |
||||
case 6: pin_toggle(6); return; |
||||
case 7: pin_toggle(7); return; |
||||
case 8: pin_toggle(8); return; |
||||
case 9: pin_toggle(9); return; |
||||
case 10: pin_toggle(10); return; |
||||
case 11: pin_toggle(11); return; |
||||
case 12: pin_toggle(12); return; |
||||
case 13: pin_toggle(13); return; |
||||
case 14: pin_toggle(14); return; |
||||
case 15: pin_toggle(15); return; |
||||
case 16: pin_toggle(16); return; |
||||
case 17: pin_toggle(17); return; |
||||
case 18: pin_toggle(18); return; |
||||
case 19: pin_toggle(19); return; |
||||
case 20: pin_toggle(20); return; |
||||
case 21: pin_toggle(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
bool pin_read_n(uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: return pin_read(0); |
||||
case 1: return pin_read(1); |
||||
case 2: return pin_read(2); |
||||
case 3: return pin_read(3); |
||||
case 4: return pin_read(4); |
||||
case 5: return pin_read(5); |
||||
case 6: return pin_read(6); |
||||
case 7: return pin_read(7); |
||||
case 8: return pin_read(8); |
||||
case 9: return pin_read(9); |
||||
case 10: return pin_read(10); |
||||
case 11: return pin_read(11); |
||||
case 12: return pin_read(12); |
||||
case 13: return pin_read(13); |
||||
case 14: return pin_read(14); |
||||
case 15: return pin_read(15); |
||||
case 16: return pin_read(16); |
||||
case 17: return pin_read(17); |
||||
case 18: return pin_read(18); |
||||
case 19: return pin_read(19); |
||||
case 20: return pin_read(20); |
||||
case 21: return pin_read(21); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
bool pin_is_low_n(uint8_t pin) |
||||
{ |
||||
return !pin_read_n(pin); |
||||
} |
||||
|
||||
|
||||
bool pin_is_high_n(uint8_t pin) |
||||
{ |
||||
return pin_read_n(pin); |
||||
} |
@ -0,0 +1,213 @@ |
||||
#pragma once |
||||
|
||||
//
|
||||
// * Utilities for pin aliasing / numbering. *
|
||||
//
|
||||
// Designed for Arduino.
|
||||
//
|
||||
// If you know the pin number beforehand, you can use the macros.
|
||||
//
|
||||
// If you need to use a variable for pin number, use the `_n` functions.
|
||||
// They are much slower, so always check if you really need them
|
||||
// - and they aren't fit for things where precise timing is required.
|
||||
//
|
||||
|
||||
#include <avr/io.h> |
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
|
||||
|
||||
// type: pointer to port
|
||||
typedef volatile uint8_t* PORT_P; |
||||
|
||||
|
||||
/** Pin numbering reference */ |
||||
#define D0 0 |
||||
#define D1 1 |
||||
#define D2 2 |
||||
#define D3 3 |
||||
#define D4 4 |
||||
#define D5 5 |
||||
#define D6 6 |
||||
#define D7 7 |
||||
#define D8 8 |
||||
#define D9 9 |
||||
#define D10 10 |
||||
#define D11 11 |
||||
#define D12 12 |
||||
#define D13 13 |
||||
#define D14 14 |
||||
#define D15 15 |
||||
#define D16 16 |
||||
#define D17 17 |
||||
#define D18 18 |
||||
#define D19 19 |
||||
#define D20 20 |
||||
#define D21 21 |
||||
#define A0 14 |
||||
#define A1 15 |
||||
#define A2 16 |
||||
#define A3 17 |
||||
#define A4 18 |
||||
#define A5 19 |
||||
#define A6 20 |
||||
#define A7 21 |
||||
|
||||
|
||||
#define _ddr(pin) _DDR_##pin |
||||
#define _pin(pin) _PIN_##pin |
||||
#define _pn(pin) _PN_##pin |
||||
#define _port(pin) _PORT_##pin |
||||
|
||||
|
||||
/** Set pin direction */ |
||||
#define set_dir(pin, d) set_bit( _ddr(pin), _pn(pin), d ) |
||||
void set_dir_n(const uint8_t pin, const uint8_t d); |
||||
|
||||
|
||||
/** Configure pin as input */ |
||||
#define as_input(pin) cbi( _ddr(pin), _pn(pin) ) |
||||
void as_input_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Configure pin as input, with pull-up enabled */ |
||||
#define as_input_pu(pin) { as_input(pin); pin_up(pin); } |
||||
void as_input_pu_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Configure pin as output */ |
||||
#define as_output(pin) sbi( _ddr(pin), _pn(pin) ) |
||||
void as_output_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Write value to a pin */ |
||||
#define pin_set(pin, v) set_bit( _port(pin), _pn(pin), v ) |
||||
void pin_set_n(const uint8_t pin, const uint8_t v); |
||||
|
||||
|
||||
/** Write 0 to a pin */ |
||||
#define pin_down(pin) cbi( _port(pin), _pn(pin) ) |
||||
void pin_down_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Write 1 to a pin */ |
||||
#define pin_up(pin) sbi( _port(pin), _pn(pin) ) |
||||
void pin_up_n(uint8_t pin); |
||||
|
||||
|
||||
/** Toggle a pin state */ |
||||
#define pin_toggle(pin) sbi( _pin(pin), _pn(pin) ) |
||||
void pin_toggle_n(uint8_t pin); |
||||
|
||||
|
||||
/** Read a pin value */ |
||||
#define pin_read(pin) get_bit( _pin(pin), _pn(pin) ) |
||||
bool pin_read_n(uint8_t pin); |
||||
|
||||
|
||||
/** CHeck if pin is low */ |
||||
#define pin_is_low(pin) (get_pin(pin) == 0) |
||||
bool pin_is_low_n(uint8_t pin); |
||||
|
||||
|
||||
/** CHeck if pin is high */ |
||||
#define pin_is_high(pin) (get_pin(pin) != 0) |
||||
bool pin_is_high_n(uint8_t pin); |
||||
|
||||
|
||||
|
||||
// Helper macros
|
||||
|
||||
#define _PORT_0 PORTD |
||||
#define _PORT_1 PORTD |
||||
#define _PORT_2 PORTD |
||||
#define _PORT_3 PORTD |
||||
#define _PORT_4 PORTD |
||||
#define _PORT_5 PORTD |
||||
#define _PORT_6 PORTD |
||||
#define _PORT_7 PORTD |
||||
#define _PORT_8 PORTB |
||||
#define _PORT_9 PORTB |
||||
#define _PORT_10 PORTB |
||||
#define _PORT_11 PORTB |
||||
#define _PORT_12 PORTB |
||||
#define _PORT_13 PORTB |
||||
#define _PORT_14 PORTC |
||||
#define _PORT_15 PORTC |
||||
#define _PORT_16 PORTC |
||||
#define _PORT_17 PORTC |
||||
#define _PORT_18 PORTC |
||||
#define _PORT_19 PORTC |
||||
#define _PORT_20 PORTC |
||||
#define _PORT_21 PORTC |
||||
|
||||
#define _PIN_0 PIND |
||||
#define _PIN_1 PIND |
||||
#define _PIN_2 PIND |
||||
#define _PIN_3 PIND |
||||
#define _PIN_4 PIND |
||||
#define _PIN_5 PIND |
||||
#define _PIN_6 PIND |
||||
#define _PIN_7 PIND |
||||
#define _PIN_8 PINB |
||||
#define _PIN_9 PINB |
||||
#define _PIN_10 PINB |
||||
#define _PIN_11 PINB |
||||
#define _PIN_12 PINB |
||||
#define _PIN_13 PINB |
||||
#define _PIN_14 PINC |
||||
#define _PIN_15 PINC |
||||
#define _PIN_16 PINC |
||||
#define _PIN_17 PINC |
||||
#define _PIN_18 PINC |
||||
#define _PIN_19 PINC |
||||
#define _PIN_20 PINC |
||||
#define _PIN_21 PINC |
||||
|
||||
#define _DDR_0 DDRD |
||||
#define _DDR_1 DDRD |
||||
#define _DDR_2 DDRD |
||||
#define _DDR_3 DDRD |
||||
#define _DDR_4 DDRD |
||||
#define _DDR_5 DDRD |
||||
#define _DDR_6 DDRD |
||||
#define _DDR_7 DDRD |
||||
#define _DDR_8 DDRB |
||||
#define _DDR_9 DDRB |
||||
#define _DDR_10 DDRB |
||||
#define _DDR_11 DDRB |
||||
#define _DDR_12 DDRB |
||||
#define _DDR_13 DDRB |
||||
#define _DDR_14 DDRC |
||||
#define _DDR_15 DDRC |
||||
#define _DDR_16 DDRC |
||||
#define _DDR_17 DDRC |
||||
#define _DDR_18 DDRC |
||||
#define _DDR_19 DDRC |
||||
#define _DDR_20 DDRC |
||||
#define _DDR_21 DDRC |
||||
|
||||
#define _PN_0 0 |
||||
#define _PN_1 1 |
||||
#define _PN_2 2 |
||||
#define _PN_3 3 |
||||
#define _PN_4 4 |
||||
#define _PN_5 5 |
||||
#define _PN_6 6 |
||||
#define _PN_7 7 |
||||
#define _PN_8 0 |
||||
#define _PN_9 1 |
||||
#define _PN_10 2 |
||||
#define _PN_11 3 |
||||
#define _PN_12 4 |
||||
#define _PN_13 5 |
||||
#define _PN_14 0 |
||||
#define _PN_15 1 |
||||
#define _PN_16 2 |
||||
#define _PN_17 3 |
||||
#define _PN_18 4 |
||||
#define _PN_19 5 |
||||
#define _PN_20 6 |
||||
#define _PN_21 7 |
@ -0,0 +1,21 @@ |
||||
#pragma once |
||||
|
||||
//
|
||||
// Functions for precise delays (nanoseconds / cycles)
|
||||
//
|
||||
|
||||
#include <avr/io.h> |
||||
#include <util/delay_basic.h> |
||||
#include <stdint.h> |
||||
|
||||
/* Convert nanoseconds to cycle count */ |
||||
#define ns2cycles(ns) ( (ns) / (1000000000L / (signed long) F_CPU) ) |
||||
|
||||
/** Wait c cycles */ |
||||
#define delay_c(c) (((c) > 0) ? __builtin_avr_delay_cycles(c) : __builtin_avr_delay_cycles(0)) |
||||
|
||||
/** Wait n nanoseconds, plus c cycles */ |
||||
#define delay_ns_c(ns, c) delay_c(ns2cycles(ns) + (c)) |
||||
|
||||
/** Wait n nanoseconds */ |
||||
#define delay_ns(ns) delay_c(ns2cycles(ns)) |
@ -0,0 +1,62 @@ |
||||
#include <avr/io.h> |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "iopins.h" |
||||
#include "spi.h" |
||||
|
||||
|
||||
/** Init SPI (for SD card communication) */ |
||||
void spi_init_master(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha, enum SPI_clk_div clkdiv) |
||||
{ |
||||
as_output(PIN_SS); // SS output - we control slave
|
||||
as_output(PIN_MOSI); // MOSI output - we talk to slave
|
||||
as_output(PIN_SCK); // SCK output - we're generating clock
|
||||
// MISO is configured automatically as input
|
||||
|
||||
SPCR = 0; |
||||
SPCR |= (1 << MSTR); |
||||
SPCR |= (order << DORD); |
||||
SPCR |= (cpol << CPOL); |
||||
SPCR |= (cpha << CPHA); |
||||
|
||||
// speed
|
||||
SPCR |= (clkdiv & 0b11); |
||||
SPSR = (bool)(clkdiv & 0b100); // write SPI2X flag
|
||||
|
||||
// enable SPI
|
||||
SPCR |= (1 << SPE); |
||||
} |
||||
|
||||
|
||||
/** Init SPI (for SD card communication) */ |
||||
void spi_init_slave(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha) |
||||
{ |
||||
as_output(PIN_MISO); // we're listening to master
|
||||
// MOSI, SS, SCK are configured automatically
|
||||
|
||||
SPCR = 0; |
||||
SPCR |= (order << DORD); |
||||
SPCR |= (cpol << CPOL); |
||||
SPCR |= (cpha << CPHA); |
||||
|
||||
// enable SPI
|
||||
SPCR |= (1 << SPE); |
||||
} |
||||
|
||||
/** Write a byte to SPI. Returns received byte. */ |
||||
uint8_t spi_send(uint8_t byte) |
||||
{ |
||||
SPDR = byte; |
||||
while (bit_is_low(SPSR, SPIF)); |
||||
|
||||
return SPDR; |
||||
} |
||||
|
||||
/** Receive (as slave). Blocking. */ |
||||
uint8_t spi_receive(uint8_t reply) |
||||
{ |
||||
SPDR = reply; |
||||
while (bit_is_low(SPSR, SPIF)); |
||||
return SPDR; |
||||
} |
@ -0,0 +1,69 @@ |
||||
#pragma once |
||||
|
||||
#include <avr/io.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
#include "iopins.h" |
||||
|
||||
#define PIN_MISO 12 |
||||
#define PIN_MOSI 11 |
||||
#define PIN_SCK 13 |
||||
#define PIN_SS 10 |
||||
|
||||
/** Bit order */ |
||||
enum SPI_order { |
||||
SPI_LSB_FIRST = 0, |
||||
SPI_MSB_FIRST = 1 |
||||
}; |
||||
|
||||
/** Clock polarity */ |
||||
enum SPI_cpol { |
||||
CPOL_0 = 0, |
||||
CPOL_1 = 1 |
||||
}; |
||||
|
||||
/** Clock phase */ |
||||
enum SPI_cpha { |
||||
CPHA_0 = 0, |
||||
CPHA_1 = 1 |
||||
}; |
||||
|
||||
/** Clock prescaller <SPI2X><SPR1><SPR0> */ |
||||
enum SPI_clk_div { |
||||
SPI_DIV_2 = 0b100, // 2x (master only, can't receive at this speed)
|
||||
SPI_DIV_4 = 0b000, |
||||
SPI_DIV_8 = 0b101, // 2x
|
||||
SPI_DIV_16 = 0b001, |
||||
SPI_DIV_32 = 0b110, // 2x
|
||||
SPI_DIV_64 = 0b010, |
||||
SPI_DIV_128 = 0b011 |
||||
}; |
||||
|
||||
|
||||
/** Set SS to active state (LOW) */ |
||||
#define spi_ss_enable() pin_down(PIN_SS) |
||||
|
||||
|
||||
/** Set SS to disabled state (HIGH) */ |
||||
#define spi_ss_disable() pin_up(PIN_SS) |
||||
|
||||
|
||||
/** Enable SPI ISR */ |
||||
#define spi_isr_enable(yes) set_bit(SPCR, SPIE, yes) |
||||
|
||||
|
||||
/** Init SPI (for SD card communication) */ |
||||
void spi_init_master(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha, enum SPI_clk_div clkdiv); |
||||
|
||||
|
||||
/** Init SPI (for SD card communication) */ |
||||
void spi_init_slave(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha); |
||||
|
||||
|
||||
/** Write a byte to SPI. Returns received byte. */ |
||||
uint8_t spi_send(uint8_t byte); |
||||
|
||||
|
||||
/** Receive (as slave). Blocking. */ |
||||
uint8_t spi_receive(uint8_t reply); |
@ -0,0 +1,83 @@ |
||||
#include <avr/io.h> |
||||
#include <avr/pgmspace.h> |
||||
#include <util/delay.h> |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "calc.h" |
||||
#include "usart.h" |
||||
|
||||
|
||||
void usart_init(uint16_t ubrr) |
||||
{ |
||||
/*Set baud rate */ |
||||
UBRR0H = (uint8_t)(ubrr >> 8); |
||||
UBRR0L = (uint8_t) ubrr; |
||||
|
||||
// Enable Rx and Tx
|
||||
UCSR0B = (1 << RXEN0) | (1 << TXEN0); |
||||
|
||||
// Clear U2X0
|
||||
cbi(UCSR0A, U2X0); |
||||
|
||||
// 8-bit data, 1 stop bit
|
||||
UCSR0C = (0b11 << UCSZ00); |
||||
} |
||||
|
||||
|
||||
/** Set Double Speed Asynchronous mode */ |
||||
void usart_set_2x(bool set) |
||||
{ |
||||
set_bit(UCSR0A, U2X0, set); |
||||
} |
||||
|
||||
|
||||
/** Send byte over USART */ |
||||
void usart_tx(uint8_t data) |
||||
{ |
||||
// Wait for transmit buffer
|
||||
while (!usart_tx_ready()); |
||||
// send it
|
||||
UDR0 = data; |
||||
} |
||||
|
||||
|
||||
/** Receive one byte over USART */ |
||||
uint8_t usart_rx(void) |
||||
{ |
||||
// Wait for data to be received
|
||||
while (!usart_rx_ready()); |
||||
// Get and return received data from buffer
|
||||
return UDR0; |
||||
} |
||||
|
||||
|
||||
/** Send string over USART */ |
||||
void usart_puts(const char* str) |
||||
{ |
||||
while (*str) { |
||||
usart_tx(*str++); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** Send progmem string over USART */ |
||||
void usart_puts_P(const char* str) |
||||
{ |
||||
char c; |
||||
while ((c = pgm_read_byte(str++))) { |
||||
usart_tx(c); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** Clear receive buffer */ |
||||
void usart_flush_rx(void) |
||||
{ |
||||
uint8_t dummy; |
||||
while (bit_is_high(UCSR0A, RXC0)) { |
||||
dummy = UDR0; |
||||
} |
||||
} |
@ -0,0 +1,86 @@ |
||||
#pragma once |
||||
|
||||
//
|
||||
// Utilities for UART communication.
|
||||
//
|
||||
// First, init uart with usart_init().
|
||||
// Then enable interrupts you want with usart_XXX_isr_enable().
|
||||
//
|
||||
|
||||
#include <avr/io.h> |
||||
#include <avr/pgmspace.h> |
||||
#include <util/delay.h> |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
|
||||
|
||||
/* USART BAUD RATE REGISTER values at 16 MHz */ |
||||
enum { |
||||
BAUD_9600 = 103, |
||||
BAUD_14400 = 68, |
||||
BAUD_19200 = 51, |
||||
BAUD_28800 = 34, |
||||
BAUD_38400 = 25, |
||||
BAUD_57600 = 16, |
||||
BAUD_76800 = 12, |
||||
BAUD_115200 = 8, |
||||
BAUD_250k = 3, |
||||
BAUD_500k = 1, |
||||
BAUD_1M = 0, |
||||
}; |
||||
|
||||
/** Init UART with a UBRR value - can use the BAUD_* constants for 16 MHz */ |
||||
void usart_init(uint16_t ubrr); |
||||
|
||||
|
||||
/** Set Double Speed Asynchronous mode on or off */ |
||||
void usart_set_2x(bool set); |
||||
|
||||
|
||||
/** Check if there's a byte in the RX register */ |
||||
#define usart_rx_ready() bit_is_high(UCSR0A, RXC0) |
||||
|
||||
|
||||
/** Check if USART is ready to accept new byte to send */ |
||||
#define usart_tx_ready() bit_is_high(UCSR0A, UDRE0) |
||||
|
||||
|
||||
// ---- Enable UART interrupts ------------
|
||||
|
||||
/** Enable or disable RX ISR */ |
||||
#define usart_isr_rx_enable(yes) set_bit(UCSR0B, RXCIE0, (yes)) |
||||
|
||||
|
||||
/** Enable or disable TX ISR (all data sent) */ |
||||
#define usart_isr_tx_enable(yes) set_bit(UCSR0B, TXCIE0, (yes)) |
||||
|
||||
|
||||
/** Enable or disable DRE ISR (data register empty) */ |
||||
#define usart_isr_dre_enable(yes) set_bit(UCSR0B, UDRIE0, (yes)) |
||||
|
||||
|
||||
// ---- Basic IO --------------------------
|
||||
|
||||
/** Send byte over USART */ |
||||
void usart_tx(uint8_t data); |
||||
|
||||
|
||||
/** Receive one byte over USART */ |
||||
uint8_t usart_rx(void); |
||||
|
||||
|
||||
/** Clear receive buffer */ |
||||
void usart_flush_rx(void); |
||||
|
||||
|
||||
// ---- Strings ---------------------------
|
||||
|
||||
/** Send string over UART */ |
||||
void usart_puts(const char* str); |
||||
|
||||
|
||||
/** Send progmem string `PSTR("foobar")` over UART */ |
||||
void usart_puts_P(const char* str); |
@ -0,0 +1,45 @@ |
||||
#include <avr/io.h> // register definitions |
||||
#include <avr/pgmspace.h> // storing data in program memory |
||||
#include <avr/interrupt.h> // interrupt vectors |
||||
#include <util/delay.h> // delay functions |
||||
|
||||
#include <stdint.h> // C header for int types like uint8_t |
||||
#include <stdbool.h> // C header for the bool type |
||||
|
||||
// Include stuff from the library
|
||||
#include "lib/iopins.h" |
||||
#include "lib/usart.h" |
||||
|
||||
|
||||
// Pins
|
||||
#define LED 13 |
||||
|
||||
|
||||
// UART receive handler
|
||||
ISR(USART_RX_vect) |
||||
{ |
||||
// "ECHO" function:
|
||||
uint8_t b = usart_rx(); |
||||
usart_tx(b); // send back
|
||||
} |
||||
|
||||
|
||||
void main() |
||||
{ |
||||
usart_init(BAUD_115200); |
||||
usart_isr_rx_enable(true); // enable RX interrupt handler
|
||||
|
||||
// configure pins
|
||||
as_output(LED); |
||||
|
||||
// globally enable interrupts (for the USART_RX handler)
|
||||
sei(); |
||||
|
||||
while (1) { |
||||
usart_puts("Hello World!\r\n"); |
||||
|
||||
pin_toggle(13); // blink the LED
|
||||
|
||||
_delay_ms(500); |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
style=kr |
||||
indent=tab |
||||
max-instatement-indent=60 |
||||
|
||||
convert-tabs |
||||
|
||||
indent-switches |
||||
keep-one-line-statements |
||||
|
||||
pad-oper |
||||
unpad-paren |
||||
pad-header |
||||
|
||||
verbose |
Loading…
Reference in new issue