21 Commits
Author SHA1 Message Date
MightyPorkandGitHub 94bd7b5283 Create README.md 2017-06-11 18:19:30 +02:00
MightyPork 287fa598c5 update docs to indicate that SIPO works also for 595 2015-08-28 16:23:17 +02:00
MightyPork 26eabc9e1c Merge branch 'master' of github.com:MightyPork/avr-lib 2015-08-28 14:42:37 +02:00
MightyPork bc55abc493 new examples 2015-08-28 14:38:17 +02:00
MightyPork 847d2320db Improved examples 2015-08-28 14:31:49 +02:00
MightyPork d154d22eb3 added missing includes & added SIPO PWM module 2015-08-28 14:18:07 +02:00
MightyPork f27b6305f8 Merge pull request #1 from D3add3d/master
Corrected typos in README
2015-08-26 22:30:47 +02:00
Samuel Fichna 8e58a32352 2nd try 2015-08-26 21:25:32 +02:00
Samuel Fichna 1abe245986 Corrected typos in README 2015-08-26 21:23:20 +02:00
MightyPork e6b80dc9d3 renamed ff_open to ff_find, added "savepos" thing to a few funcs 2015-06-10 19:33:14 +02:00
MightyPork 2a92e06d08 HEAVY speed improvement in SD/FAT write. 2015-06-10 19:05:08 +02:00
MightyPork d8e53ac598 lot of work connecting SD I/O with FAT lib, FAT improvements. 2015-06-10 16:54:06 +02:00
MightyPork d3dce4ffa7 added new makefile 2015-06-10 12:02:48 +02:00
MightyPork 3d946abdfd F_CPU/8 speed for SD card 2015-06-10 02:08:12 +02:00
MightyPork 91e227f314 added basic SPI/SD support. To be expanded. 2015-06-10 01:58:38 +02:00
MightyPork 4e2d86f01d Formatted in "Allman" style, added fat16 lib files 2015-06-09 22:11:58 +02:00
MightyPork 49c95d1b6d Added DHT and improved OneWire 2015-05-11 23:10:08 +02:00
MightyPork c51eacf06c split onewire.h into h and c, modified readme 2015-05-11 14:30:52 +02:00
MightyPork a31091d88c set_low to pin_low, added onewire support 2015-05-11 02:55:04 +02:00
MightyPork 72964684e4 refactoring and cleaning 2015-05-10 02:46:55 +02:00
MightyPork 32c1be7e54 new pins system, updated lib files for it 2015-05-10 01:06:41 +02:00
111 changed files with 9434 additions and 625 deletions
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+20 -13
View File
@@ -1,23 +1,30 @@
# MightyPork's AVR Library
**This library is very old and unmaintained.**
I program my Arduinos in plain C, compile it with `avr-gcc` and flash with `avrdude` (all on Linux).
There may be some good bits worth salvaging, but for new projects I recommend the [avr-c-boilerplate](https://github.com/MightyPork/avr-c-boilerplate) as a base instead. Copy and port good modules from this library if you like.
Whenever I learn how to do something, I make a library file and put it here.
---
The code is tested and optimized for **ATmega328P**, which is used in most Arduinos. I use "Pro Mini" and "Nano".
# "porklib", MightyPork's Arduino Library
# How to use
This library aims to make development for AVR in C easy and fun.
Link the `lib/` folder to your project, and make sure you add all lib `.c` files to your `Makefile`, so it builds are the needed code.
Modules of the library provide facilities for pin numbering and aliasing,
bitwise operations and accessing internal and external peripherals of the AVR.
Some library files don't have `.c`, but many do.
It takes some inspiration from Arduino, but is written in pure C, which makes it faster
and smaller.
## Useful things
Pull requests to add new modules are welcome, please go ahead!
- To easily alias I/O pins, use `lib/pins.h`.
- For Arduino pins, there are presets in `lib/arduino_pins.h`
- Binary/byte manipulation utilities are in `lib/calc.h`
- `lib/meta.h` contains some generally useful things that didn't fit elsewhere
## Makefile
Each header file contains a comment block with explanation, which will help you understand them.
You can use the provided Makefile to build your project with this library.
A project typically consists of one `main.c` file, and some `*_config.c` files where the
library headers request it (those define eg. IO pin mapping).
Adjust the Makefile to your needs!
## License
The library is provided under MIT license, see the LICENSE file for more info.
View File
+4 -2
View File
@@ -4,5 +4,7 @@ Library usage examples
Those examples should work, but they are mostly just a reference on how to
use different parts of the library.
To try to build and flash an example, first change the `MAIN` field in the Makefile
to it's name.
Makefiles in the directories should work, but may be outdated. Please
use `Makefile.example` for new projects.
Some more examples can be found in repo `MightyPork/avr-projects`
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
+29
View File
@@ -0,0 +1,29 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "lib/iopins.h"
#include "lib/uart.h"
// Demo for ATMega328p on Arduino Pro Mini / Arduino Nano
// Open serial port monitor to see debug messages.
void main()
{
// also a basic UART example, good for debugging
uart_init(9600);
uart_puts("Starting a blinking DEMO\r\n");
as_output(D13); // configure the pin D13
while(1)
{
uart_puts_P(PSTR("FOO\r\n")); // _P variant - string saved in program memory. Saves RAM space.
toggle_pin(D13); // blink the LED
_delay_ms(500);
}
}
+13 -9
View File
@@ -11,14 +11,20 @@ EFUSE = 0x05
## === Source files ===
# Main C file
MAIN = uart_isr.c
MAIN = main.c
# Extra C files in this folder
LOCAL_SOURCE =
# Library directory (with C files)
EXTRA_SOURCE_DIR = lib/
# C files in the library directory
EXTRA_SOURCE_FILES = uart.c lcd.c sonar.c uart_ansi.c stream.c
EXTRA_SOURCE_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c
#Files that need config file:
# EXTRA_SOURCE_FILES += lcd.c
# EXTRA_SOURCE_FILES += color.c wsrgb.c
# EXTRA_SOURCE_FILES += debouce.c
## === Programmer ===
@@ -87,12 +93,6 @@ debug:
@echo
flser: all flash serial
serial:
gtkterm -p /dev/ttyUSB0
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
@@ -114,7 +114,7 @@ clean:
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ *.pre
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
@@ -128,6 +128,10 @@ flashe: $(TARGET).eeprom
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
gtkterm -p /dev/ttyUSB0
# === fuses ===
+46
View File
@@ -0,0 +1,46 @@
#include <avr/io.h>
#include <stdbool.h>
#include "calc.h"
#include "adc.h"
/** Initialize the ADC */
void adc_init()
{
ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128 prescaler -> 125 kHz
ADMUX |= _BV(REFS0); // Voltage reference
sbi(ADCSRA, ADEN); // Enable ADC
}
/** Disable AD */
void adc_disable()
{
cbi(ADCSRA, ADEN);
}
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel)
{
set_low_nibble(ADMUX, channel); // Select channel to sample
sbi(ADMUX, ADLAR); // Align result to left
sbi(ADCSRA, ADSC); // Start conversion
while(bit_is_high(ADCSRA, ADSC)); // Wait for it...
return ADCH; // The upper 8 bits of ADC result
}
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel)
{
set_low_nibble(ADMUX, channel); // Select channel to sample
cbi(ADMUX, ADLAR); // Align result to right
sbi(ADCSRA, ADSC); // Start conversion
while(get_bit(ADCSRA, ADSC)); // Wait for it...
return ADCW; // The whole ADC word (10 bits)
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
//
// Utilities for build-in A/D converter
//
#include <avr/io.h>
/** Initialize the ADC */
void adc_init();
/** Disable AD (for power saving?) */
void adc_disable();
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel);
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel);
+87
View File
@@ -0,0 +1,87 @@
#pragma once
//
// Bit and byte manipulation utilities
//
// --- 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, bit) do { (reg) |= (1 << (uint8_t)(bit)); } while(0)
// Clear bit
#define cbi(reg, bit) do { (reg) &= ~(1 << (uint8_t)(bit)); } while(0)
// Get n-th bit
#define get_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
// Test n-th bit (Can't use bit_is_set, as it's redefined in sfr_def.h)
#define bit_is_high(reg, bit) get_bit(reg, bit)
#define bit_is_low(reg, bit) (!get_bit(reg, bit))
// Write value to n-th bit
#define set_bit(reg, bit, value) do { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
// Invert n-th bit
#define toggle_bit(reg, bit) do { (reg) ^= (1 << (uint8_t)(bit)); } while(0)
// --- Bit manipulation with pointer to variable ---
// Set n-th bit in pointee
#define sbi_p(reg_p, bit) do { (*(reg_p)) |= (1 << (uint8_t)(bit)); } while(0)
// Clear n-th bit in pointee
#define cbi_p(reg_p, bit) do { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); } while(0)
// Get n-th bit in pointee
#define get_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
// 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, bit, value) do { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define toggle_bit_p(reg_p, bit) do { *(reg_p) ^= (1 << (uint8_t)(bit)); } 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) & 0xF)
#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))) || (((low) > (high)) && ((x) >= (high) && (x) < (low))))
// ..., include greater bound
#define in_rangei(x, low, high) ((((low) <= (high)) && ((x) >= (low) && (x) <= (high))) || (((low) > (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))) || (((low) > (high)) && ((x) >= (low) || (x) < (high))))
// ..., include upper bound
#define in_range_wrapi(x, low, high) ((((low) <= (high)) && ((x) >= (low) && (x) <= (high))) || (((low) > (high)) && ((x) >= (low) || (x) <= (high))))
+10 -4
View File
@@ -1,7 +1,13 @@
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include "colors.h"
#include "hsl.h"
#include "iopins.h"
#include "nsdelay.h"
#include "color.h"
// --- HSL ---
#ifdef HSL_LINEAR
const uint8_t FADE_128[] = {
@@ -17,7 +23,7 @@
#endif
// based on: https://github.com/lewisd32/avr-hsl2rgb
xrgb_t hsl2xrgb(const hsl_t cc)
xrgb_t hsl_xrgb(const hsl_t cc)
{
// 0 .. 256*3
const uint16_t hh = (uint16_t) cc.h * 3;
+15 -44
View File
@@ -1,15 +1,15 @@
#pragma once
//
// Some useful utilities for RGB color manipulation
// --- color types ---
//
// The XXXc macros don't use cast, so they can be used in array initializers.
//
// xrgb ... 3-byte true-color RGB (8 bits per component)
// rgbXX ... XX-bit color value, with equal nr of bits per component
// rgb24 ... 24-bit color value, with equal nr of bits per component
//
// XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
//
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
typedef struct {
@@ -18,11 +18,8 @@ typedef struct {
uint8_t b;
} xrgb_t;
typedef uint32_t rgb24_t;
typedef uint16_t rgb15_t;
typedef uint16_t rgb12_t;
typedef uint8_t rgb6_t;
typedef uint32_t rgb24_t;
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
// xrgb for constant array declarations
@@ -35,7 +32,6 @@ typedef uint8_t rgb6_t;
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
@@ -45,40 +41,15 @@ typedef uint8_t rgb6_t;
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb15(r,g,b) ((rgb15_t) rgb15c(r,g,b))
#define rgb15c(r,g,b) (((r & 0x1F) << 10) | ((g & 0x1F) << 5) | (b & 0x1F))
#define rgb15_r(c) ((((rgb15_t) (c)) & 0x7C00) >> 7)
#define rgb15_g(c) ((((rgb15_t) (c)) & 0x3E0) >> 2)
#define rgb15_b(c) ((((rgb15_t) (c)) & 0x1F) << 3)
#define rgb15_xrgb(c) xrgb(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb15_rgb24(c) rgb24(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb15_rgb24c(c) rgb24c(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb12(r,g,b) ((rgb12_t) rgb12c(r,g,b))
#define rgb12c(r,g,b) (((r & 0xF) << 8) | ((g & 0xF) << 4) | (b & 0xF))
#define rgb12_r(c) ((((rgb12_t) (c)) & 0xF00) >> 4)
#define rgb12_g(c) (((rgb12_t) (c)) & 0xF0)
#define rgb12_b(c) (((r(rgb12_t) (c)gb) & 0x0F) << 4)
#define rgb12_xrgb(c) xrgb(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_xrgbc(c) xrgbc(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_rgb24(c) rgb24(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_rgb24c(c) rgb24c(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb6(r,g,b) ((rgb6_t) rgb6c(r,g,b))
#define rgb6c(r,g,b) (((r & 3) << 4) | ((g & 3) << 2) | (b & 3))
#define rgb6_r(c) ((((rgb6_t) (c)) & 0x30) << 2)
#define rgb6_g(c) ((((rgb6_t) (c)) & 0xC) << 4)
#define rgb6_b(c) ((((rgb6_t) (c)) & 0x3) << 6)
#define rgb6_xrgb(c) xrgb(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_xrgbc(c) xrgbc(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_rgb24(c) rgb24(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_rgb24c(c) rgb24c(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
// HSL data structure
typedef struct {
uint8_t h;
uint8_t s;
uint8_t l;
} hsl_t;
/* Convert HSL to XRGB */
xrgb_t hsl_xrgb(const hsl_t color);
+45
View File
@@ -0,0 +1,45 @@
#include <avr/io.h>
#include <stdbool.h>
#include "debounce.h"
#include "calc.h"
#include "iopins.h"
#include "debo_config.h"
/** Debounce data array */
uint8_t debo_next_slot = 0;
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
{
debo_slots[debo_next_slot] = (debo_slot_t){
.reg = reg,
.bit = bit | ((invert & 1) << 7) | (get_bit_p(reg, bit) << 6), // bit 7 = invert, bit 6 = state
.count = 0,
};
return debo_next_slot++;
}
/** Check debounced pins, should be called periodically. */
void debo_tick()
{
for (uint8_t i = 0; i < debo_next_slot; i++) {
// current pin value (right 3 bits, xored with inverse bit)
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x7);
if (value != get_bit(debo_slots[i].bit, 6)) {
// different pin state than last recorded state
if (debo_slots[i].count < DEBO_TICKS) {
debo_slots[i].count++;
} else {
// overflown -> latch value
set_bit(debo_slots[i].bit, 6, value); // set state bit
debo_slots[i].count = 0;
}
} else {
debo_slots[i].count = 0; // reset the counter
}
}
}
+64
View File
@@ -0,0 +1,64 @@
#pragma once
//
// An implementation of button debouncer.
//
// ----
//
// You must provide a config file debo_config.h (next to your main.c)
//
// A pin is registered like this:
//
// #define BTN1 12 // pin D12
// #define BTN2 13
//
// debo_add(BTN0); // The function returns number assigned to the pin (0, 1, ...)
// debo_add_rev(BTN1); // active low
// debo_register(&PINB, PB2, 0); // direct access - register, pin & invert
//
// Then periodically call the tick function (perhaps in a timer interrupt):
//
// debo_tick();
//
// To check if input is active, use
//
// debo_get_pin(0); // state of input #0 (registered first)
// debo_get_pin(1); // state of input #1 (registered second)
//
#include <avr/io.h>
#include <stdbool.h>
#include "calc.h"
#include "pins.h"
// Your config file
#include "debo_config.h"
/*
#define DEBO_CHANNELS 2
#define DDEBO_TICKS 5
*/
/* Internal deboucer entry */
typedef struct {
PORT_P reg; // pointer to IO register
uint8_t bit; // bits 6 and 7 of this hold "state" & "invert" flag
uint8_t count; // number of ticks this was in the new state
} debo_slot_t;
debo_slot_t debo_slots[DEBO_CHANNELS];
/** Add a pin for debouncing (must be used with constant args) */
#define debo_add_rev(pin) debo_register(&_pin(pin), _pn(pin), 1)
#define debo_add(pin) debo_register(&_pin(pin), _pn(pin), 0)
/** Add a pin for debouncing (low level function) */
uint8_t debo_register(PORT_P pin_reg_pointer, uint8_t bit, bool invert);
/** Check debounced pins, should be called periodically. */
void debo_tick();
/** Get a value of debounced pin */
#define debo_get_pin(i) (get_bit(debo_slots[i].bit, 6) ^ get_bit(debo_slots[i].bit, 7))
+88
View File
@@ -0,0 +1,88 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "dht11.h"
/** Read one bit */
bool _dht11_rxbit(const uint8_t pin)
{
// Wait until start of pulse
while (is_low_n(pin));
uint8_t cnt = 0;
while (is_high_n(pin))
{
cnt++;
_delay_us(5);
}
return (cnt > 8);
}
/** Read one byte */
uint8_t _dht11_rxbyte(const uint8_t pin)
{
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
if (_dht11_rxbit(pin))
byte |= (1 << (7 - i));
}
return byte;
}
/** Read tehmperature and humidity from the DHT11, returns false on failure */
bool dht11_read(const uint8_t pin, dht11_result_t* result)
{
// bus down for > 18 ms
as_output_n(pin);
pin_low_n(pin);
_delay_ms(20);
// bus up for 20-40us
pin_high_n(pin);
_delay_us(20);
// release
as_input_pu_n(pin);
// DHT should send 80us LOW & 80us HIGH
_delay_us(40);
if (!is_low_n(pin))
return false; // init error
_delay_us(80);
if (!is_high_n(pin))
return false; // init error
// skip to start of first bit
_delay_us(50);
// Receive 5 data bytes (Rh int, Rh dec, Temp int, Temp dec, Checksum)
// Decimal bytes are zero for DHT11 -> we can ignore them.
uint8_t bytes[5];
uint8_t sum = 0;
for (uint8_t i = 0; i < 5; i++)
{
uint8_t b = _dht11_rxbyte(pin);
bytes[i] = b;
if (i < 4) sum += b;
}
// Verify checksum
if (sum != bytes[4]) return false;
result->rh = bytes[0];
result->temp = bytes[2];
return true;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
//
// Reading temperature and relative humidity from DHT11
//
#include <stdint.h>
#include <stdbool.h>
typedef struct {
int8_t temp;
int8_t rh;
} dht11_result_t;
/** Read tehmperature and humidity from the DHT11, returns false on failure */
bool dht11_read(const uint8_t pin, dht11_result_t* result);
+276
View File
@@ -0,0 +1,276 @@
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "calc.h"
#include "iopins.h"
void set_dir_n(const uint8_t pin, const 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(const 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(const 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(const 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 set_pin_n(const uint8_t pin, const uint8_t v)
{
switch(pin) {
case 0: set_pin(0, v); return;
case 1: set_pin(1, v); return;
case 2: set_pin(2, v); return;
case 3: set_pin(3, v); return;
case 4: set_pin(4, v); return;
case 5: set_pin(5, v); return;
case 6: set_pin(6, v); return;
case 7: set_pin(7, v); return;
case 8: set_pin(8, v); return;
case 9: set_pin(9, v); return;
case 10: set_pin(10, v); return;
case 11: set_pin(11, v); return;
case 12: set_pin(12, v); return;
case 13: set_pin(13, v); return;
case 14: set_pin(14, v); return;
case 15: set_pin(15, v); return;
case 16: set_pin(16, v); return;
case 17: set_pin(17, v); return;
case 18: set_pin(18, v); return;
case 19: set_pin(19, v); return;
case 20: set_pin(20, v); return;
case 21: set_pin(21, v); return;
}
}
void pin_low_n(const uint8_t pin)
{
switch(pin) {
case 0: pin_low(0); return;
case 1: pin_low(1); return;
case 2: pin_low(2); return;
case 3: pin_low(3); return;
case 4: pin_low(4); return;
case 5: pin_low(5); return;
case 6: pin_low(6); return;
case 7: pin_low(7); return;
case 8: pin_low(8); return;
case 9: pin_low(9); return;
case 10: pin_low(10); return;
case 11: pin_low(11); return;
case 12: pin_low(12); return;
case 13: pin_low(13); return;
case 14: pin_low(14); return;
case 15: pin_low(15); return;
case 16: pin_low(16); return;
case 17: pin_low(17); return;
case 18: pin_low(18); return;
case 19: pin_low(19); return;
case 20: pin_low(20); return;
case 21: pin_low(21); return;
}
}
void pin_high_n(const uint8_t pin)
{
switch(pin) {
case 0: pin_high(0); return;
case 1: pin_high(1); return;
case 2: pin_high(2); return;
case 3: pin_high(3); return;
case 4: pin_high(4); return;
case 5: pin_high(5); return;
case 6: pin_high(6); return;
case 7: pin_high(7); return;
case 8: pin_high(8); return;
case 9: pin_high(9); return;
case 10: pin_high(10); return;
case 11: pin_high(11); return;
case 12: pin_high(12); return;
case 13: pin_high(13); return;
case 14: pin_high(14); return;
case 15: pin_high(15); return;
case 16: pin_high(16); return;
case 17: pin_high(17); return;
case 18: pin_high(18); return;
case 19: pin_high(19); return;
case 20: pin_high(20); return;
case 21: pin_high(21); return;
}
}
void toggle_pin_n(const uint8_t pin)
{
switch(pin) {
case 0: toggle_pin(0); return;
case 1: toggle_pin(1); return;
case 2: toggle_pin(2); return;
case 3: toggle_pin(3); return;
case 4: toggle_pin(4); return;
case 5: toggle_pin(5); return;
case 6: toggle_pin(6); return;
case 7: toggle_pin(7); return;
case 8: toggle_pin(8); return;
case 9: toggle_pin(9); return;
case 10: toggle_pin(10); return;
case 11: toggle_pin(11); return;
case 12: toggle_pin(12); return;
case 13: toggle_pin(13); return;
case 14: toggle_pin(14); return;
case 15: toggle_pin(15); return;
case 16: toggle_pin(16); return;
case 17: toggle_pin(17); return;
case 18: toggle_pin(18); return;
case 19: toggle_pin(19); return;
case 20: toggle_pin(20); return;
case 21: toggle_pin(21); return;
}
}
bool get_pin_n(const uint8_t pin)
{
switch(pin) {
case 0: return get_pin(0);
case 1: return get_pin(1);
case 2: return get_pin(2);
case 3: return get_pin(3);
case 4: return get_pin(4);
case 5: return get_pin(5);
case 6: return get_pin(6);
case 7: return get_pin(7);
case 8: return get_pin(8);
case 9: return get_pin(9);
case 10: return get_pin(10);
case 11: return get_pin(11);
case 12: return get_pin(12);
case 13: return get_pin(13);
case 14: return get_pin(14);
case 15: return get_pin(15);
case 16: return get_pin(16);
case 17: return get_pin(17);
case 18: return get_pin(18);
case 19: return get_pin(19);
case 20: return get_pin(20);
case 21: return get_pin(21);
}
return false;
}
bool is_low_n(const uint8_t pin)
{
return !get_pin_n(pin);
}
bool is_high_n(const uint8_t pin)
{
return get_pin_n(pin);
}
+213
View File
@@ -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_high(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 set_pin(pin, v) set_bit( _port(pin), _pn(pin), v )
void set_pin_n(const uint8_t pin, const uint8_t v);
/** Write 0 to a pin */
#define pin_low(pin) cbi( _port(pin), _pn(pin) )
void pin_low_n(const uint8_t pin);
/** Write 1 to a pin */
#define pin_high(pin) sbi( _port(pin), _pn(pin) )
void pin_high_n(const uint8_t pin);
/** Toggle a pin state */
#define toggle_pin(pin) sbi( _pin(pin), _pn(pin) )
void toggle_pin_n(const uint8_t pin);
/** Read a pin value */
#define get_pin(pin) get_bit( _pin(pin), _pn(pin) )
bool get_pin_n(const uint8_t pin);
/** CHeck if pin is low */
#define is_low(pin) (get_pin(pin) == 0)
bool is_low_n(const uint8_t pin);
/** CHeck if pin is high */
#define is_high(pin) (get_pin(pin) != 0)
bool is_high_n(const 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
+358
View File
@@ -0,0 +1,358 @@
#include <stdbool.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "calc.h"
#include "iopins.h"
#include "nsdelay.h"
#include "lcd.h"
#include "lcd_config.h"
// Start address of rows
const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
// Shared stream instance
static STREAM _lcd_singleton;
STREAM* lcd;
// Internal prototypes
void _lcd_mode_r();
void _lcd_mode_w();
void _lcd_clk();
void _lcd_wait_bf();
void _lcd_write_byte(uint8_t bb);
uint8_t _lcd_read_byte();
// Write utilities
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
#define _lcd_write_nibble(nib) do { \
set_pin(LCD_D7, get_bit((nib), 3)); \
set_pin(LCD_D6, get_bit((nib), 2)); \
set_pin(LCD_D5, get_bit((nib), 1)); \
set_pin(LCD_D4, get_bit((nib), 0)); \
} while(0)
// 0 W, 1 R
bool _lcd_mode;
struct {
uint8_t x;
uint8_t y;
} _pos;
enum {
TEXT = 0,
CG = 1
} _addrtype;
/** Initialize the display */
void lcd_init()
{
// configure pins as output
as_output(LCD_E);
as_output(LCD_RW);
as_output(LCD_RS);
_lcd_mode = 1; // force data pins to output
_lcd_mode_w();
// Magic sequence to invoke Cthulhu (or enter 4-bit mode)
_delay_ms(16);
_lcd_write_nibble(0b0011);
_lcd_clk();
_delay_ms(5);
_lcd_clk();
_delay_ms(5);
_lcd_clk();
_delay_ms(5);
_lcd_write_nibble(0b0010);
_lcd_clk();
_delay_us(100);
// Configure the display
lcd_command(LCD_IFACE_4BIT_2LINE);
lcd_command(LCD_DISABLE);
lcd_command(LCD_CLEAR);
lcd_command(LCD_MODE_INC);
// mark as enabled
lcd_enable();
_lcd_singleton.tx = &lcd_write;
_lcd_singleton.rx = &lcd_read;
// Stream
lcd = &_lcd_singleton;
_pos.x = 0;
_pos.y = 0;
_addrtype = TEXT;
}
/** Send a pulse on the ENABLE line */
void _lcd_clk()
{
pin_high(LCD_E);
delay_ns(450);
pin_low(LCD_E);
}
/** Enter READ mode */
void _lcd_mode_r()
{
if (_lcd_mode == 1) return; // already in R mode
pin_high(LCD_RW);
as_input_pu(LCD_D7);
as_input_pu(LCD_D6);
as_input_pu(LCD_D5);
as_input_pu(LCD_D4);
_lcd_mode = 1;
}
/** Enter WRITE mode */
void _lcd_mode_w()
{
if (_lcd_mode == 0) return; // already in W mode
pin_low(LCD_RW);
as_output(LCD_D7);
as_output(LCD_D6);
as_output(LCD_D5);
as_output(LCD_D4);
_lcd_mode = 0;
}
/** Read a byte */
uint8_t _lcd_read_byte()
{
_lcd_mode_r();
uint8_t res = 0;
_lcd_clk();
res = (get_pin(LCD_D7) << 7) | (get_pin(LCD_D6) << 6) | (get_pin(LCD_D5) << 5) | (get_pin(LCD_D4) << 4);
_lcd_clk();
res |= (get_pin(LCD_D7) << 3) | (get_pin(LCD_D6) << 2) | (get_pin(LCD_D5) << 1) | (get_pin(LCD_D4) << 0);
return res;
}
/** Write an instruction byte */
void lcd_command(uint8_t bb)
{
_lcd_wait_bf();
pin_low(LCD_RS); // select instruction register
_lcd_write_byte(bb); // send instruction byte
}
/** Write a data byte */
void lcd_write(uint8_t bb)
{
if (_addrtype == TEXT) {
if (bb == '\r') {
// CR
_pos.x = 0;
lcd_xy(_pos.x, _pos.y);
return;
}
if (bb == '\n') {
// LF
_pos.y++;
lcd_xy(_pos.x, _pos.y);
return;
}
_pos.x++;
}
_lcd_wait_bf();
pin_high(LCD_RS); // select data register
_lcd_write_byte(bb); // send data byte
}
/** Read BF & Address */
uint8_t lcd_read_bf_addr()
{
pin_low(LCD_RS);
return _lcd_read_byte();
}
/** Read CGRAM or DDRAM */
uint8_t lcd_read()
{
if (_addrtype == TEXT) _pos.x++;
pin_high(LCD_RS);
return _lcd_read_byte();
}
/** Write a byte using the 4-bit interface */
void _lcd_write_byte(uint8_t bb)
{
_lcd_mode_w(); // enter W mode
_lcd_write_high(bb);
_lcd_clk();
_lcd_write_low(bb);
_lcd_clk();
}
/** Wait until the device is ready */
void _lcd_wait_bf()
{
uint8_t d = 0;
while(d++ < 120 && lcd_read_bf_addr() & _BV(7))
_delay_us(1);
}
/** Send a string to LCD */
void lcd_puts(char* str_p)
{
char c;
while ((c = *str_p++))
lcd_putc(c);
}
/** Print from progmem */
void lcd_puts_P(const char* str_p)
{
char c;
while ((c = pgm_read_byte(str_p++)))
lcd_putc(c);
}
/** Sedn a char to LCD */
void lcd_putc(const char c)
{
lcd_write(c);
}
/** Set cursor position */
void lcd_xy(const uint8_t x, const uint8_t y)
{
_pos.x = x;
_pos.y = y;
lcd_addr(LCD_ROW_ADDR[y] + (x));
}
uint8_t _lcd_old_cursor = CURSOR_NONE;
bool _lcd_enabled = false;
/** Set LCD cursor. If not enabled, only remember it. */
void lcd_cursor(uint8_t type)
{
_lcd_old_cursor = (type & CURSOR_BOTH);
if (_lcd_enabled) lcd_command(LCD_CURSOR_NONE | _lcd_old_cursor);
}
/** Display display (preserving cursor) */
void lcd_disable()
{
lcd_command(LCD_DISABLE);
_lcd_enabled = false;
}
/** Enable display (restoring cursor) */
void lcd_enable()
{
_lcd_enabled = true;
lcd_cursor(_lcd_old_cursor);
}
/** Go home */
void lcd_home()
{
lcd_command(LCD_HOME);
_pos.x = 0;
_pos.y = 0;
_addrtype = TEXT;
}
/** Clear the screen */
void lcd_clear()
{
lcd_command(LCD_CLEAR);
_pos.x = 0;
_pos.y = 0;
_addrtype = TEXT;
}
/** Define a glyph */
void lcd_glyph(const uint8_t index, const uint8_t* array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
lcd_write(array[i]);
}
// restore previous position
lcd_xy(_pos.x, _pos.y);
_addrtype = TEXT;
}
/** Define a glyph */
void lcd_glyph_P(const uint8_t index, const uint8_t* array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
lcd_write(pgm_read_byte(&array[i]));
}
// restore previous position
lcd_xy(_pos.x, _pos.y);
_addrtype = TEXT;
}
/** Set address in CGRAM */
void lcd_addr_cg(const uint8_t acg)
{
_addrtype = CG;
lcd_command(0b01000000 | ((acg) & 0b00111111));
}
/** Set address in DDRAM */
void lcd_addr(const uint8_t add)
{
_addrtype = TEXT;
lcd_command(0b10000000 | ((add) & 0b01111111));
}
+146
View File
@@ -0,0 +1,146 @@
#pragma once
// HD44780 LCD display driver - 4-bit mode
//
// LCD pins are configured using a file lcd_config.h, which you
// have to add next to your main.c file.
//
// Content can be something like this:
//
//
#include <stdint.h>
#include <stdbool.h>
#include "stream.h"
// Your file with configs
#include "lcd_config.h"
/*
#define LCD_RS 10
#define LCD_RW 11
#define LCD_E 12
#define LCD_D4 13
#define LCD_D5 14
#define LCD_D6 15
#define LCD_D7 16
*/
// Shared LCD stream object
// Can be used with functions from stream.h once LCD is initialized
extern STREAM* lcd;
// --- Commands ---
// Clear screen (reset)
#define LCD_CLEAR 0b00000001
// Move cursor to (0,0), unshift...
#define LCD_HOME 0b00000010
// Set mode: Increment + NoShift
#define LCD_MODE_INC 0b00000110
// Set mode: Increment + Shift
#define LCD_MODE_INC_SHIFT 0b00000111
// Set mode: Decrement + NoShift
#define LCD_MODE_DEC 0b00000100
// Set mode: Decrement + Shift
#define LCD_MODE_DEC_SHIFT 0b00000101
// Disable display (data remains untouched)
#define LCD_DISABLE 0b00001000
// Disable cursor
#define LCD_CURSOR_NONE 0b00001100
// Set cursor to still underscore
#define LCD_CURSOR_BAR 0b00001110
// Set cursor to blinking block
#define LCD_CURSOR_BLINK 0b00001101
// Set cursor to both of the above at once
#define LCD_CURSOR_BOTH (LCD_CURSOR_BAR | LCD_CURSOR_BLINK)
// Move cursor
#define LCD_MOVE_LEFT 0b00010000
#define LCD_MOVE_RIGHT 0b00010100
// Shift display
#define LCD_SHIFT_LEFT 0b00011000
#define LCD_SHIFT_RIGHT 0b00011100
// Set iface to 5x7 font, 1-line
#define LCD_IFACE_4BIT_1LINE 0b00100000
#define LCD_IFACE_8BIT_1LINE 0b00110000
// Set iface to 5x7 font, 2-line
#define LCD_IFACE_4BIT_2LINE 0b00101000
#define LCD_IFACE_8BIT_2LINE 0b00111000
/** Initialize the display */
void lcd_init();
/** Write an instruction byte */
void lcd_command(uint8_t bb);
/** Write a data byte */
void lcd_write(uint8_t bb);
/** Read BF & Address */
uint8_t lcd_read_bf_addr();
/** Read CGRAM or DDRAM */
uint8_t lcd_read();
/** Send a string to LCD */
void lcd_puts(char* str_p);
/** Send a string to LCD from program memory */
void lcd_puts_P(const char* str_p);
/** Sedn a char to LCD */
void lcd_putc(const char c);
/** Show string at X, Y */
#define lcd_puts_xy(x, y, str_p) do { lcd_xy((x), (y)); lcd_puts((str_p)); } while(0)
/** Show string at X, Y */
#define lcd_puts_xy_P(x, y, str_p) do { lcd_xy((x), (y)); lcd_puts_P((str_p)); } while(0)
/** Show char at X, Y */
#define lcd_putc_xy(x, y, c) do { lcd_xy((x), (y)); lcd_putc((c)); } while(0)
/** Set cursor position */
void lcd_xy(const uint8_t x, const uint8_t y);
/** Set LCD cursor. If not enabled, only remember it. */
#define CURSOR_NONE 0b00
#define CURSOR_BAR 0b10
#define CURSOR_BLINK 0b01
#define CURSOR_BOTH 0b11
void lcd_cursor(uint8_t type);
/** Display display (preserving cursor) */
void lcd_disable();
/** Enable display (restoring cursor) */
void lcd_enable();
/** Go home */
void lcd_home();
/** Clear the screen */
void lcd_clear();
/** Define a glyph - 8 bytes, right 5 bits are used */
void lcd_glyph(const uint8_t index, const uint8_t* array);
/** Define a glyph that's in PROGMEM */
void lcd_glyph_P(const uint8_t index, const uint8_t* array);
/** Set address in CGRAM */
void lcd_addr_cg(const uint8_t acg);
/** Set address in DDRAM */
void lcd_addr(const uint8_t add);
+21
View File
@@ -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))
+225
View File
@@ -0,0 +1,225 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "onewire.h"
/** Perform bus reset. Returns true if any device is connected */
bool ow_reset(const uint8_t pin)
{
as_output_n(pin);
pin_low_n(pin);
_delay_us(480);
as_input_pu_n(pin);
_delay_us(70);
const bool a = get_pin_n(pin);
_delay_us(410);
return a;
}
/** Send a single bit */
void _ow_tx_bit(const uint8_t pin, const bool bit)
{
as_output_n(pin);
pin_low_n(pin);
if (bit) {
_delay_us(6);
as_input_pu_n(pin);
_delay_us(64);
} else {
_delay_us(60);
as_input_pu_n(pin);
_delay_us(10);
}
}
/** Send a single byte */
void ow_send(const uint8_t pin, const uint8_t byte)
{
for (uint8_t i = 0; i < 8; i++)
{
_ow_tx_bit(pin, (byte >> i) & 0x01);
}
}
/** Read a single bit */
bool _ow_rx_bit(const uint8_t pin)
{
as_output_n(pin);
pin_low_n(pin);
_delay_us(6);
as_input_pu_n(pin);
_delay_us(9);
const bool a = get_pin_n(pin);
_delay_us(55);
return a;
}
/** Read a single byte */
uint8_t ow_read(const uint8_t pin)
{
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
byte = (byte >> 1) | (_ow_rx_bit(pin) << 7);
}
return byte;
}
/** Wait until the device is ready. Returns false on timeout */
bool ow_wait_ready(const uint8_t pin)
{
uint16_t timeout = 700;
as_input_pu_n(pin);
while (--timeout > 0)
{
if (is_high_n(pin)) return true;
_delay_ms(1);
}
return false;
}
/** Read bytes into an array */
void ow_read_arr(const uint8_t pin, uint8_t* array, const uint8_t count)
{
for (uint8_t i = 0; i < count; i++)
{
array[i] = ow_read(pin);
}
}
// ---------- CRC utils ----------
/*
Dallas 1-wire CRC routines for Arduino with examples of usage.
The 16-bit routine is new.
The 8-bit routine is from http://github.com/paeaetech/paeae/tree/master/Libraries/ds2482/
Copyright (C) 2010 Kairama Inc
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Dallas 1-wire 16-bit CRC calculation. Developed from Maxim Application Note 27.
/** Compute a CRC16 checksum */
uint16_t crc16( uint8_t *data, uint8_t len)
{
uint16_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
uint8_t inbyte = data[i];
for (uint8_t j = 0; j < 8; j++)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc = crc >> 1;
if (mix)
crc = crc ^ 0xA001;
inbyte = inbyte >> 1;
}
}
return crc;
}
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
/** Compute a CRC8 checksum */
uint8_t crc8(uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
uint8_t inbyte = addr[i];
for (uint8_t j = 0; j < 8; j++)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix)
crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
// --- utils for DS1820 ---
/** Read temperature in 0.0625°C, or TEMP_ERROR on error */
int16_t ds1820_read_temp(uint8_t pin)
{
ow_send(pin, READ_SCRATCHPAD);
uint8_t bytes[9];
ow_read_arr(pin, bytes, 9);
uint8_t crc = crc8(bytes, 8);
if (crc != bytes[8]) {
return TEMP_ERROR;
} else {
int16_t a = ((bytes[1] << 8) | bytes[0]) >> 1;
a = a << 4;
a += (16 - bytes[6]) & 0x0F;
a -= 0x04;
return a;
}
}
/** Read temperature in 0.1°C, or TEMP_ERROR on error */
int16_t ds1820_read_temp_c(uint8_t pin)
{
int32_t temp = ds1820_read_temp(pin);
if (temp == TEMP_ERROR)
return TEMP_ERROR;
temp *= 625;
uint16_t rem = temp % 1000;
temp /= 1000;
if (rem >= 500) temp++;
return (int16_t) temp;
}
+51
View File
@@ -0,0 +1,51 @@
#pragma once
//
// Utils for Dallas OneWire bus (DS1820 etc)
//
#include <stdint.h>
#include <stdbool.h>
#define SKIP_ROM 0xCC
#define CONVERT_T 0x44
#define READ_SCRATCHPAD 0xBE
/** Perform bus reset. Returns true if any device is connected */
bool ow_reset(const uint8_t pin);
/** Send a single byte */
void ow_send(const uint8_t pin, const uint8_t byte);
/** Read a single byte */
uint8_t ow_read(const uint8_t pin);
/** Wait until the device is ready. Returns false on timeout */
bool ow_wait_ready(const uint8_t pin);
/** Read bytes into an array */
void ow_read_arr(const uint8_t pin, uint8_t* array, const uint8_t count);
/** Compute a CRC16 checksum */
uint16_t crc16( uint8_t *data, uint8_t len);
/** Compute a CRC8 checksum */
uint8_t crc8(uint8_t *addr, uint8_t len);
// --- utils for DS1820 ---
#define TEMP_ERROR -32768
/**
* Read temperature in 0.0625°C, or TEMP_ERROR on error
* Use this where you'd normally use READ_SCRATCHPAD
*/
int16_t ds1820_read_temp(uint8_t pin);
/**
* Read temperature in 0.1°C, or TEMP_ERROR on error
* Use this where you'd normally use READ_SCRATCHPAD
*/
int16_t ds1820_read_temp_c(uint8_t pin);
+139
View File
@@ -0,0 +1,139 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "sonar.h"
// Currently measured sonar
static sonar_t* _so;
// Flag that measurement is in progress
volatile bool sonar_busy;
// Result of last measurement, in millimeters
volatile int16_t sonar_result;
void _sonar_init_do(sonar_t* so, PORT_P port, uint8_t ntx, PORT_P pin, uint8_t nrx)
{
so->port = port;
so->ntx = ntx;
so->pin = pin;
so->nrx = nrx;
switch((const uint16_t) pin) {
case ((const uint16_t) &PINB): so->bank = 0; break;
case ((const uint16_t) &PINC): so->bank = 1; break;
case ((const uint16_t) &PIND): so->bank = 2; break;
}
}
/**
* Start sonar measurement
* Interrupts must be enabled
* TIMER 1 will be used for the async measurement
* Timer 1 overflow and Pin Change interrupts must invoke Sonar handlers.
*/
bool sonar_start(sonar_t* so)
{
if (sonar_busy) return false;
_so = so;
sonar_busy = true;
// make sure the timer is stopped (set clock to NONE)
TCCR1B = 0;
// Timer overflow interrupt enable
// We'll stop measuring on overflow
sbi(TIMSK1, TOIE1);
// Clear the timer value
TCNT1 = 0;
// Set up pin change interrupt mask for the RX pin
switch(so->bank) {
case 0: sbi(PCMSK0, so->nrx); break;
case 1: sbi(PCMSK1, so->nrx); break;
case 2: sbi(PCMSK2, so->nrx); break;
}
// send positive pulse
sbi_p(so->port, so->ntx);
_delay_us(_SNR_TRIG_TIME);
cbi_p(so->port, so->ntx);
// Wait for start of response
while (bit_is_low_p(so->pin, so->nrx));
// Set timer clock source: F_CPU / 8 (0.5 us resolution)
TCCR1B = (0b010 << CS10);
// Enable pin change interrupt
sbi(PCICR, so->bank);
return true;
}
/** Stop the timer */
void _sonar_stop()
{
// stop timer
TCCR1B = 0;
// Disable RX pin interrupt mask
switch(_so->bank) {
case 0: PCMSK0 &= ~(1 << (_so->nrx)); break;
case 1: PCMSK1 &= ~(1 << (_so->nrx)); break;
case 2: PCMSK2 &= ~(1 << (_so->nrx)); break;
}
// Disable timer1 overflow interrupt
cbi(TIMSK1, TOIE1);
sonar_busy = false;
}
/** Handle TIMER1_OVF (returns true if consumed) */
inline bool sonar_handle_t1ovf()
{
if (!sonar_busy) return false; // nothing
sonar_result = -1;
_sonar_stop();
return true;
}
/** Handle pin change interrupt (returns true if consumed) */
inline bool sonar_handle_pci()
{
if (!sonar_busy) {
return false; // nothing
}
if (bit_is_high_p(_so->pin, _so->nrx)) {
// rx is high, not our pin change event
return false;
}
uint64_t x = TCNT1;
x /= _SNR_DIV_CONST;
x *= 100000000L;
x /= F_CPU;
sonar_result = (int16_t) x;
// no obstacle
if (sonar_result > _SNR_MAX_DIST) sonar_result = -1;
_sonar_stop();
return true;
}
+66
View File
@@ -0,0 +1,66 @@
#pragma once
//
// Utilities for working with the HC-SR04 ultrasonic sensor
// Can be easily modified to work with other similar modules
//
// It's required that you call the sonar_handle_* functions from your ISRs
// See example program for more info.
//
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
// Calib constant for the module
// CM = uS / _DIV_CONST
#define _SNR_DIV_CONST 58
// Max module distance in MM
#define _SNR_MAX_DIST 4000
// Trigger time in uS
#define _SNR_TRIG_TIME 10
// Sonar data object
typedef struct {
PORT_P port; // Tx PORT
uint8_t ntx; // Tx bit number
PORT_P pin; // Rx PIN
uint8_t nrx; // Rx bit number
uint8_t bank; // Rx PCINT bank
} sonar_t;
extern volatile bool sonar_busy;
extern volatile int16_t sonar_result;
// Create a Sonar port
// Args: sonar_t* so, Trig pin, Echo pin
#define sonar_init(so, trig, echo) do { \
as_output(trig); \
as_input_pu(echo); \
_sonar_init_do(so, &_port(trig), _pn(trig), &_pin(echo), _pn(echo)); \
} while(0)
// private, in header because of the macro.
void _sonar_init_do(sonar_t* so, PORT_P port, uint8_t ntx, PORT_P pin, uint8_t nrx);
/**
* Start sonar measurement
* Interrupts must be enabled
* TIMER 1 will be used for the async measurement
*/
bool sonar_start(sonar_t* so);
/** Handle TIMER1_OVF (returns true if consumed) */
bool sonar_handle_t1ovf();
/** Handle pin change interrupt (returns true if consumed) */
bool sonar_handle_pci();
+213
View File
@@ -0,0 +1,213 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include "stream.h"
#include "calc.h"
static char tmpstr[20]; // buffer for number rendering
void put_str(const STREAM *p, char* str)
{
char c;
while ((c = *str++)) {
p->tx(c);
}
}
void put_str_P(const STREAM *p, const char* str)
{
char c;
while ((c = pgm_read_byte(str++))) {
p->tx(c);
}
}
static void _putnf(const STREAM *p, const uint8_t places);
/** Send signed int8 */
void put_u8(const STREAM *p, const uint8_t num)
{
utoa(num, tmpstr, 10);
put_str(p, tmpstr);
}
/** Send unsigned int8 */
void put_i8(const STREAM *p, const int8_t num)
{
itoa(num, tmpstr, 10);
put_str(p, tmpstr);
}
/** Send unsigned int */
void put_u16(const STREAM *p, const uint16_t num)
{
utoa(num, tmpstr, 10);
put_str(p, tmpstr);
}
/** Send signed int */
void put_i16(const STREAM *p, const int16_t num)
{
itoa(num, tmpstr, 10);
put_str(p, tmpstr);
}
/** Send unsigned long */
void put_u32(const STREAM *p, const uint32_t num)
{
ultoa(num, tmpstr, 10);
put_str(p, tmpstr);
}
/** Send signed long */
void put_i32(const STREAM *p, const int32_t num)
{
ltoa(num, tmpstr, 10);
put_str(p, tmpstr);
}
/** Print number as hex */
void _print_hex(const STREAM *p, uint8_t* start, uint8_t bytes)
{
for (; bytes > 0; bytes--) {
uint8_t b = *(start + bytes - 1);
for(uint8_t j = 0; j < 2; j++) {
uint8_t x = high_nibble(b);
b = b << 4;
if (x < 0xA) {
p->tx('0' + x);
} else {
p->tx('A' + (x - 0xA));
}
}
}
}
/** Send unsigned int8 */
void put_x8(const STREAM *p, const uint8_t num)
{
_print_hex(p, (uint8_t*) &num, 1);
}
/** Send int as hex */
void put_x16(const STREAM *p, const uint16_t num)
{
_print_hex(p, (uint8_t*) &num, 2);
}
/** Send long as hex */
void put_x32(const STREAM *p, const uint32_t num)
{
_print_hex(p, (uint8_t*) &num, 4);
}
/** Send long long as hex */
void put_x64(const STREAM *p, const uint64_t num)
{
_print_hex(p, (uint8_t*) &num, 8);
}
// float variant doesn't make sense for 8-bit int
/** Send unsigned int as float */
void put_u16f(const STREAM *p, const uint16_t num, const uint8_t places)
{
utoa(num, tmpstr, 10);
_putnf(p, places);
}
/** Send signed int as float */
void put_i16f(const STREAM *p, const int16_t num, const uint8_t places)
{
if (num < 0) {
p->tx('-');
itoa(-num, tmpstr, 10);
} else {
itoa(num, tmpstr, 10);
}
_putnf(p, places);
}
/** Send unsigned long as float */
void put_u32f(const STREAM *p, const uint32_t num, const uint8_t places)
{
ultoa(num, tmpstr, 10);
_putnf(p, places);
}
/** Send signed long as float */
void put_i32f(const STREAM *p, const int32_t num, const uint8_t places)
{
if (num < 0) {
p->tx('-');
ltoa(-num, tmpstr, 10);
} else {
ltoa(num, tmpstr, 10);
}
_putnf(p, places);
}
/** Print number in tmp string as float with given decimal point position */
void _putnf(const STREAM *p, const uint8_t places)
{
// measure text length
uint8_t len = 0;
while(tmpstr[len] != 0) len++;
int8_t at = len - places;
// print virtual zeros
if (at <= 0) {
p->tx('0');
p->tx('.');
while(at <= -1) {
p->tx('0');
at++;
}
at = -1;
}
// print the number
uint8_t i = 0;
while(i < len) {
if (at-- == 0) {
p->tx('.');
}
p->tx(tmpstr[i++]);
}
}
/** Print CR LF */
void put_nl(const STREAM *p)
{
p->tx(13);
p->tx(10);
}
+100
View File
@@ -0,0 +1,100 @@
#pragma once
//
// Streams -- in this library -- are instances of type STREAM.
//
// A stream can be used for receiving and sending bytes, generally
// it's a pipe to a device.
//
// They are designed for printing numbers and strings, but can
// also be used for general data transfer.
//
// Examples of streams:
// "uart.h" -> declares global variable "uart" which is a pointer to the UART stream
// "lcd.h" -> declares a global variable "lcd" (pointer to LCD scho stream)
//
// Streams help avoid code duplication, since the same functions can be used
// to format and print data to different device types.
//
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <avr/pgmspace.h>
/** Stream structure */
typedef struct {
void (*tx) (uint8_t b);
uint8_t (*rx) (void);
} STREAM;
/** Print string into a stream */
void put_str(const STREAM *p, char* str);
/** Print a programspace string into a stream */
void put_str_P(const STREAM *p, const char* str);
/** Send signed int8 */
#define put_char(p, c) (p)->tx((c))
void put_u8(const STREAM *p, const uint8_t num);
/** Send unsigned int8 */
void put_i8(const STREAM *p, const int8_t num);
/** Send unsigned int */
void put_u16(const STREAM *p, const uint16_t num);
/** Send signed int */
void put_i16(const STREAM *p, const int16_t num);
/** Send unsigned long */
void put_u32(const STREAM *p, const uint32_t num);
/** Send signed long */
void put_i32(const STREAM *p, const int32_t num);
/** Send unsigned int8 */
void put_x8(const STREAM *p, const uint8_t num);
/** Send int as hex */
void put_x16(const STREAM *p, const uint16_t num);
/** Send long as hex */
void put_x32(const STREAM *p, const uint32_t num);
/** Send long long as hex */
void put_x64(const STREAM *p, const uint64_t num);
// float variant doesn't make sense for 8-bit int
/** Send unsigned int as float */
void put_u16f(const STREAM *p, const uint16_t num, const uint8_t places);
/** Send signed int as float */
void put_i16f(const STREAM *p, const int16_t num, const uint8_t places);
/** Send unsigned long as float */
void put_u32f(const STREAM *p, const uint32_t num, const uint8_t places);
/** Send signed long as float */
void put_i32f(const STREAM *p, const int32_t num, const uint8_t places);
/** Print CR LF */
void put_nl(const STREAM *p);
+99 -2
View File
@@ -1,13 +1,110 @@
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "calc.h"
#include "uart.h"
#include "uart_ansi.h"
#include "stream.h"
// Shared stream instance
static STREAM _uart_singleton;
STREAM* uart;
void _uart_init_do(uint16_t ubrr) {
/*Set baud rate */
UBRR0H = (uint8_t) (ubrr >> 8);
UBRR0L = (uint8_t) ubrr;
// Enable Rx and Tx
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
// 8-bit data, 1 stop bit
UCSR0C = (0b11 << UCSZ00);
_uart_singleton.tx = &uart_tx;
_uart_singleton.rx = &uart_rx;
uart = &_uart_singleton;
}
/** Enable or disable RX ISR */
void uart_isr_rx(bool yes)
{
set_bit(UCSR0B, RXCIE0, yes);
}
/** Enable or disable TX ISR (1 byte is sent) */
void uart_isr_tx(bool yes)
{
set_bit(UCSR0B, TXCIE0, yes);
}
/** Enable or disable DRE ISR (all is sent) */
void uart_isr_dre(bool yes)
{
set_bit(UCSR0B, UDRIE0, yes);
}
/** Send byte over UART */
void uart_tx(uint8_t data)
{
// Wait for transmit buffer
while (!uart_tx_ready());
// send it
UDR0 = data;
}
/** Receive one byte over UART */
uint8_t uart_rx()
{
// Wait for data to be received
while (!uart_rx_ready());
// Get and return received data from buffer
return UDR0;
}
/** Send string over UART */
void uart_puts(const char* str)
{
while (*str) {
uart_tx(*str++);
}
}
/** Send progmem string over UART */
void uart_puts_P(const char* str)
{
char c;
while ((c = pgm_read_byte(str++))) {
uart_tx(c);
}
}
/** Clear receive buffer */
void uart_flush()
{
uint8_t dummy;
while (bit_is_high(UCSR0A, RXC0)) {
dummy = UDR0;
}
}
// ------------- VT100 extension --------------
void _vt_apply_style();
void _vt_reset_attribs_do();
void _vt_style_do();
+68 -7
View File
@@ -1,5 +1,73 @@
#pragma once
//
// Utilities for UART communication.
//
// First, init uart with desired baud rate using uart_init(baud).
// Then enable interrupts you want with uart_isr_XXX().
//
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include "stream.h"
// Shared UART stream object
// Can be used with functions from stream.h once UART is initialized
extern STREAM* uart;
/** Init UART for given baudrate */
void _uart_init_do(uint16_t ubrr); // internal, needed for the macro.
#define uart_init(baud) _uart_init_do(F_CPU / 16 / (baud) - 1)
/** Check if there's a byte in the RX register */
#define uart_rx_ready() (0 != (UCSR0A & (1 << RXC0)))
/** Check if transmission of everything is done */
#define uart_tx_ready() (0 != (UCSR0A & (1 << UDRE0)))
// Enable UART interrupts
/** Enable or disable RX ISR */
void uart_isr_rx(bool enable);
/** Enable or disable TX ISR (1 byte is sent) */
void uart_isr_tx(bool enable);
/** Enable or disable DRE ISR (all is sent) */
void uart_isr_dre(bool enable);
// Basic IO
/** Receive one byte over UART */
uint8_t uart_rx();
/** Send byte over UART */
#define uart_putc(data) uart_tx((data))
void uart_tx(uint8_t data);
/** Clear receive buffer */
void uart_flush();
// Strings
/** Send string over UART */
void uart_puts(const char* str);
/** Send progmem string over UART */
void uart_puts_P(const char* str);
//
// ANSI / VT100 utilities for UART
//
@@ -7,13 +75,6 @@
// To print stuff on the screen, use uart_puts() etc from uart.h
//
#include <avr/io.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include "uart.h"
// INIT
+132
View File
@@ -0,0 +1,132 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include "iopins.h"
#include "nsdelay.h"
#include "wsrgb.h"
#include "color.h"
#include "ws_config.h"
/* Driver code for WS2812B */
void ws_init()
{
as_output(WS_PIN);
}
/** Wait long enough for the colors to show */
void ws_show() {
delay_ns_c(WS_T_LATCH, 0);
}
/** Send one byte to the RGB strip */
void ws_send_byte(const uint8_t bb)
{
for (volatile int8_t i = 7; i >= 0; --i) {
if ((bb) & (1 << i)) {
pin_high(WS_PIN);
delay_ns_c(WS_T_1H, -2);
pin_low(WS_PIN);
delay_ns_c(WS_T_1L, -10);
} else {
pin_high(WS_PIN);
delay_ns_c(WS_T_0H, -2);
pin_low(WS_PIN);
delay_ns_c(WS_T_0L, -10);
}
}
}
/** Send R,G,B color to the strip */
void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b)
{
ws_send_byte(g);
ws_send_byte(r);
ws_send_byte(b);
}
/** Send a RGB struct */
void ws_send_xrgb(xrgb_t xrgb)
{
ws_send_byte(xrgb.g);
ws_send_byte(xrgb.r);
ws_send_byte(xrgb.b);
}
/** Send color hex */
void ws_send_rgb24(rgb24_t rgb)
{
ws_send_byte(rgb24_g(rgb));
ws_send_byte(rgb24_r(rgb));
ws_send_byte(rgb24_b(rgb));
}
/** Send array of colors */
void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length)
{
for (uint8_t i = 0; i < length; i++) {
const xrgb_t c = rgbs[i];
ws_send_byte(c.g);
ws_send_byte(c.r);
ws_send_byte(c.b);
}
}
/** Send array of colors */
void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length)
{
for (uint8_t i = 0; i < length; i++) {
const rgb24_t c = rgbs[i];
ws_send_byte(rgb24_g(c));
ws_send_byte(rgb24_r(c));
ws_send_byte(rgb24_b(c));
}
}
//#define ws_send_rgb24_array(rgbs, length) __ws_send_array_proto((rgbs), (length), rgb24)
// prototype for sending array. it's ugly, sorry.
/*#define __ws_send_array_proto(rgbs, length, style) { \
for (uint8_t __rgb_sap_i = 0; __rgb_sap_i < length; __rgb_sap_i++) { \
style ## _t __rgb_sap2 = (rgbs)[__rgb_sap_i]; \
ws_send_ ## style(__rgb_sap2); \
} \
}*/
// /** Send a 2D array to a zig-zag display */
// #define ws_send_xrgb_array_zigzag(rgbs, width, height) { \
// int8_t __rgb_sxaz_y, __rgb_sxaz_x; \
// for(__rgb_sxaz_y = 0; __rgb_sxaz_y < (height); __rgb_sxaz_y ++) { \
// for(__rgb_sxaz_x = 0; __rgb_sxaz_x < (width); __rgb_sxaz_x++) { \
// ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]); \
// } \
// __rgb_sxaz_y++; \
// for(__rgb_sxaz_x = (width) - 1; __rgb_sxaz_x >= 0; __rgb_sxaz_x--) { \
// ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]); \
// } \
// } \
// }
// /* Send a linear array to a zig-zag display as a n*m board (row-by-row)
// #define ws_send_xrgb_array_zigzag_linear(rgbs, width, height) { \
// int8_t __rgb_sxazl_x, __rgb_sxazl_y; \
// for(__rgb_sxazl_y = 0; __rgb_sxazl_y < (height); __rgb_sxazl_y++) { \
// for(__rgb_sxazl_x = 0; __rgb_sxazl_x < (width); __rgb_sxazl_x++) { \
// ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]); \
// } \
// __rgb_sxazl_y++; \
// for(__rgb_sxazl_x = width-1; __rgb_sxazl_x >=0; __rgb_sxazl_x--) { \
// ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]); \
// } \
// } \
// }
+51
View File
@@ -0,0 +1,51 @@
#pragma once
//
// Utils for driving a WS2812 RGB LED strips, and color manipulation in general.
//
// Timing is critical!
//
// Create a config file rgb_config.h next to your main.c
//
#include "iopins.h"
#include "color.h"
// Your config file
#include "ws_config.h"
/*
#define WS_T_1H 700
#define WS_T_1L 150
#define WS_T_0H 150
#define WS_T_0L 700
#define WS_T_LATCH 7000
#define WS_PIN 2
*/
// --- functions for RGB strips ---
/** Initialize OI */
void ws_init();
/** Wait long enough for the colors to show */
void ws_show();
/** Send one byte to the RGB strip */
void ws_send_byte(const uint8_t bb);
/** Send R,G,B color to the strip */
void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b);
/** Send a RGB struct */
void ws_send_xrgb(xrgb_t xrgb);
/** Send color hex */
void ws_send_rgb24(rgb24_t rgb);
/** Send array of colors */
void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length);
/** Send array of colors */
void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length);
+34
View File
@@ -0,0 +1,34 @@
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "lib/uart.h"
#include "lib/stream.h"
#include "lib/dht11.h"
void main()
{
uart_init(9600);
uart_puts_P(PSTR("*** DHT11 test ***\r\n"));
while(1)
{
dht11_result_t result;
if (dht11_read(2, &result))
{
put_i8(uart, result.temp);
uart_puts_P(PSTR(" °C, "));
put_i8(uart, result.rh);
uart_puts_P(PSTR(" %r.H\r\n"));
}
else
{
uart_puts_P(PSTR("Read error!\r\n"));
}
_delay_ms(500);
}
}
-13
View File
@@ -1,13 +0,0 @@
#pragma once
// Pin config file for LCD.
#include "lib/arduino_pins.h"
#define LCD_RS D2
#define LCD_RW D3
#define LCD_E D4
#define LCD_D4 D5
#define LCD_D5 D6
#define LCD_D6 D7
#define LCD_D7 D8
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+11
View File
@@ -0,0 +1,11 @@
#pragma once
// Pin config file for LCD.
#define LCD_RS 2
#define LCD_RW 3
#define LCD_E 4
#define LCD_D4 5
#define LCD_D5 6
#define LCD_D6 7
#define LCD_D7 8
+1
View File
@@ -0,0 +1 @@
../../lib
-1
View File
@@ -1 +0,0 @@
/home/ondra/elektro/avr-lib/lib
@@ -18,7 +18,7 @@ LOCAL_SOURCE =
# Library directory (with C files)
EXTRA_SOURCE_DIR = lib/
# C files in the library directory
EXTRA_SOURCE_FILES = uart.c
EXTRA_SOURCE_FILES = uart.c iopins.c stream.c onewire.c
## === Programmer ===
@@ -122,6 +122,10 @@ flashe: $(TARGET).eeprom
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
gtkterm -p /dev/ttyUSB0
# === fuses ===
+1
View File
@@ -0,0 +1 @@
../../lib
+41
View File
@@ -0,0 +1,41 @@
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdint.h>
#include "lib/uart.h"
#include "lib/stream.h"
#include "lib/onewire.h"
#define T 2
void main()
{
uart_init(9600);
uart_puts_P(PSTR("*** OneWire test ***\r\n"));
while(1)
{
_delay_ms(100);
ow_reset(T);
ow_send(T, SKIP_ROM);
ow_send(T, CONVERT_T);
if(!ow_wait_ready(T)) {
uart_puts_P(PSTR("Wait timeout!\r\n"));
continue;
}
ow_reset(T);
ow_send(T, SKIP_ROM);
int16_t temp = ds1820_read_temp_c(T);
if (temp == TEMP_ERROR) {
uart_puts_P(PSTR("Read error!\r\n"));
} else {
put_i16f(uart, temp, 1);
uart_puts_P(PSTR(" °C\r\n"));
}
}
}
+150
View File
@@ -0,0 +1,150 @@
## === CPU settings ===
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
## === Source files ===
# Main C file
MAIN = main.c
# Extra C files in this folder
LOCAL_SOURCE =
# Library directory (with C files)
EXTRA_SOURCE_DIR = lib/
# C files in the library directory
EXTRA_SOURCE_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c
# Files that need config file - uncomment when needed, but also add the configs!
EXTRA_SOURCE_FILES += sipo_pwm.c
# EXTRA_SOURCE_FILES += lcd.c
# EXTRA_SOURCE_FILES += color.c wsrgb.c
# EXTRA_SOURCE_FILES += debouce.c
## === Programmer ===
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## === C flags ===
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(EXTRA_SOURCE_DIR)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
CFLAGS += -g2 -Wextra -Wfatal-errors -Wno-unused-but-set-variable
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
# CFLAGS += -lm ## Math
# CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
# CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
CFLAGS_BUILD = $(CFLAGS) -Os
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
SRC += $(EXTRA_SOURCE)
SRC += $(LOCAL_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC)
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
gtkterm -p /dev/ttyUSB0
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
+44
View File
@@ -0,0 +1,44 @@
#include <stdint.h>
#include "lib/iopins.h"
#include "lib/sipo_pwm.h"
#include "sipo_pwm_config.h"
// Example with 3 chained 74HC4094
// Pins configured in sipo_pwm_config.h
const uint8_t rainbow[] = {
128, 161, 192, 218, 238, 251, 255, 251,
238, 218, 191, 161, 128, 95, 64, 38, 18,
5, 1, 5, 18, 38, 65, 95
};
void main()
{
// Initialize SIPO PWM module (74HC4094)
spwm_init();
// Tnitialize the array with default values
for (uint8_t i = 0; i < SPWM_CHANNELS; i++) {
spwm_levels[i] = rainbow[i];
}
// Animation
while(1)
{
// SHOW THE PWM
spwm_send();
// Make a change - effect
uint8_t first = spwm_levels[0];
for (uint8_t bit = 0; bit < SPWM_CHANNELS - 1; bit++)
{
spwm_levels[bit] = spwm_levels[bit + 1];
}
spwm_levels[SPWM_CHANNELS - 1] = first;
}
}
@@ -0,0 +1,22 @@
/* Config for SIPO PWM */
// --- PWM pin aliases ---
// Store signal
#define SPWM_STR D2
// Shift/clock signal
#define SPWM_CLK D3
// Data signal
#define SPWM_DATA D4
// --- Other settings ---
// Number of PWM levels (color depth)
#define SPWM_COLOR_DEPTH 256
// Number of SIPO channels
#define SPWM_CHANNELS 24
// Invert outputs (for Common Anode LEDs)
#define SPWM_INVERT 1
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+11
View File
@@ -0,0 +1,11 @@
#pragma once
// Pin config file for LCD.
#define LCD_RS 2
#define LCD_RW 3
#define LCD_E 4
#define LCD_D4 5
#define LCD_D5 6
#define LCD_D6 7
#define LCD_D7 8
+1
View File
@@ -0,0 +1 @@
../../lib
@@ -8,7 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "lib/arduino_pins.h"
#include "lib/iopins.h"
#include "lib/sonar.h"
#include "lib/stream.h"
#include "lib/lcd.h"
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
@@ -9,7 +9,6 @@
#include <stdbool.h>
#include "lib/uart.h"
#include "lib/arduino_pins.h"
#include "lib/sonar.h"
#include "lib/stream.h"
@@ -73,7 +72,6 @@ void main()
int16_t res = sonar_result;
// Print
if (res < 0) {
put_str(uart, "NO OBSTACLES\r\n");
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
@@ -2,7 +2,6 @@
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "lib/meta.h"
#include "lib/uart.h"
//
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
@@ -4,17 +4,13 @@
#include <stdint.h>
#include "lib/uart.h"
#include "lib/uart_ansi.h"
#include "lib/stream.h"
//
// Example of asynchronous UART key handling
//
// It recognizes special keys like arrows and some F keys,
// check the header file for full list.
//
// You need uart_ansi for this.
//
// check uart.h file for full list.
ISR(USART_RX_vect)
{
@@ -28,8 +24,8 @@ ISR(USART_RX_vect)
void key_handler(uint8_t code, bool special)
{
put_str_P(uart, special ? PSTR("Special: ") : PSTR("Char: "));
put_char(uart, code); // the actual character
put_char(uart, ' '); // space
put_c(uart, code); // the actual character
put_c(uart, ' '); // space
put_u8(uart, code); // as number
put_nl(uart); // crlf
}
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
@@ -3,11 +3,8 @@
//
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <stdlib.h>
#include "lib/uart.h"
+181
View File
@@ -0,0 +1,181 @@
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
# Main C file
MAIN = main.c
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
## === File generation ===
all: $(TARGET).hex size
pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
$(CC) $(CFLAGS) -E $(SRC1) --output $@
%.eeprom: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
# Show debug info
debug:
@echo
@echo "Source files:" $(SRC)
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
@echo
# Disassemble the ELF
disassemble: $(TARGET).lst
dis: disassemble
lst: disassemble
# Make eeprom file
eeprom: $(TARGET).eeprom
# Show how big the resulting program is
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
# Clean all produced trash
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
# Clean all trash
purge:
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
## === avrdude ===
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
flashe: $(TARGET).eeprom
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
$(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses: fuses
+1
View File
@@ -0,0 +1 @@
../../lib
@@ -3,11 +3,8 @@
//
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <stdlib.h>
#include "lib/uart.h"
#include "lib/stream.h"
+5 -4
View File
@@ -1,5 +1,6 @@
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "calc.h"
#include "adc.h"
@@ -23,11 +24,11 @@ void adc_disable()
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel)
{
write_low_nibble(ADMUX, channel); // Select channel to sample
set_low_nibble(ADMUX, channel); // Select channel to sample
sbi(ADMUX, ADLAR); // Align result to left
sbi(ADCSRA, ADSC); // Start conversion
while(bit_is_high(ADCSRA, ADSC)); // Wait for it...
while (bit_is_high(ADCSRA, ADSC)); // Wait for it...
return ADCH; // The upper 8 bits of ADC result
}
@@ -36,11 +37,11 @@ uint8_t adc_read_byte(uint8_t channel)
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel)
{
write_low_nibble(ADMUX, channel); // Select channel to sample
set_low_nibble(ADMUX, channel); // Select channel to sample
cbi(ADMUX, ADLAR); // Align result to right
sbi(ADCSRA, ADSC); // Start conversion
while(get_bit(ADCSRA, ADSC)); // Wait for it...
while (get_bit(ADCSRA, ADSC)); // Wait for it...
return ADCW; // The whole ADC word (10 bits)
}
+1
View File
@@ -5,6 +5,7 @@
//
#include <avr/io.h>
#include <stdint.h>
/** Initialize the ADC */
void adc_init();
-42
View File
@@ -1,42 +0,0 @@
#pragma once
//
// Pin definitions for Arduino (Pro Mini with ATmega328P)
//
#include "pins.h"
#define D0 D,0
#define D1 D,1
#define D2 D,2
#define D3 D,3
#define D4 D,4
#define D5 D,5
#define D6 D,6
#define D7 D,7
#define D8 B,0
#define D9 B,1
#define D10 B,2
// MOSI MISO SCK - not good for input
#define D11 B,3
#define D12 B,4
#define D13 B,5
#define D14 C,0
#define D15 C,1
#define D16 C,2
#define D17 C,3
#define D18 C,4
#define D19 C,5
#define D20 C,6
#define D21 C,7
#define A0 C,0
#define A1 C,1
#define A2 C,2
#define A3 C,3
#define A4 C,4
#define A5 C,5
#define A6 C,6
#define A7 C,7
+66
View File
@@ -0,0 +1,66 @@
#pragma once
//
// Block device interface, somewhat akin to stream.h
// Used for filesystem implementations.
//
#include <stdint.h>
/** Abstract block device interface
*
* Populate an instance of this with pointers to your I/O functions.
*/
typedef struct
{
/** Sequential read at cursor
* @param dest destination memory structure
* @param len number of bytes to load and store in {dest}
*/
void (*load)(void* dest, const uint16_t len);
/** Sequential write at cursor
* @param src source memory structure
* @param len number of bytes to write
*/
void (*store)(const void* src, const uint16_t len);
/** Write one byte at cursor
* @param b byte to write
*/
void (*write)(const uint8_t b);
/** Read one byte at cursor
* @return the read byte
*/
uint8_t (*read)(void);
/** Absolute seek - set cursor
* @param addr new cursor address
*/
void (*seek)(const uint32_t addr);
/** Relative seek - move cursor
* @param offset cursor address change
*/
void (*rseek)(const int16_t offset);
/** Flush the data buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*
* Tmplementations that do not need this should provide
* a no-op function.
*/
void (*flush)(void);
} BLOCKDEV;
+22 -24
View File
@@ -4,11 +4,13 @@
// 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)
#define inc_wrap(var, min, max) { if ((var) >= (max - 1)) { (var) = (min); } else { (var)++; } }
// ..., upper bound included
#define inc_wrapi(var, min, max) inc_wrap((var), (min), (max) + 1)
@@ -16,7 +18,7 @@
// --- 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)
#define dec_wrap(var, min, max) { if ((var) <= (min)) { (var) = (max) - 1; } else { (var)--; } }
// ..., upper bound included
#define dec_wrapi(var, min, max) dec_wrap((var), (min), (max) + 1)
@@ -24,56 +26,52 @@
// --- Bit manipulation --
// Set bit
#define sbi(reg, bit) do { (reg) |= (1 << (uint8_t)(bit)); } while(0)
#define sbi(reg, bit) { (reg) |= (1 << (uint8_t)(bit)); }
// Clear bit
#define cbi(reg, bit) do { (reg) &= ~(1 << (uint8_t)(bit)); } while(0)
#define cbi(reg, bit) { (reg) &= ~(1 << (uint8_t)(bit)); }
// Get n-th bit
#define read_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
#define get_bit(reg, bit) read_bit(reg, bit)
#define get_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
// Test n-th bit (Can't use bit_is_set, as it's redefined in sfr_def.h)
#define bit_is_high(reg, bit) read_bit(reg, bit)
#define bit_is_low(reg, bit) (!read_bit(reg, bit))
#define bit_is_high(reg, bit) get_bit(reg, bit)
#define bit_is_low(reg, bit) (!get_bit(reg, bit))
// Write value to n-th bit
#define write_bit(reg, bit, value) do { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define set_bit(reg, bit, value) write_bit(reg, bit, value)
#define set_bit(reg, bit, value) { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); }
// Invert n-th bit
#define toggle_bit(reg, bit) do { (reg) ^= (1 << (uint8_t)(bit)); } while(0)
#define toggle_bit(reg, bit) { (reg) ^= (1 << (uint8_t)(bit)); }
// --- Bit manipulation with pointer to variable ---
// Set n-th bit in pointee
#define sbi_p(reg_p, bit) do { (*(reg_p)) |= (1 << (uint8_t)(bit)); } while(0)
#define sbi_p(reg_p, bit) { (*(reg_p)) |= (1 << (uint8_t)(bit)); }
// Clear n-th bit in pointee
#define cbi_p(reg_p, bit) do { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); } while(0)
#define cbi_p(reg_p, bit) { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); }
// Get n-th bit in pointee
#define read_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
#define get_bit_p(reg_p, bit) read_bit_p(reg_p, bit)
#define get_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
// 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) read_bit_p(reg_p, bit)
#define bit_is_low_p(reg_p, bit) (!read_bit_p(reg_p, bit))
#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 write_bit_p(reg_p, bit, value) do { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define set_bit_p(reg_p, bit, value) write_bit_p(reg_p, bit, value)
#define toggle_bit_p(reg_p, bit) do { *(reg_p) ^= (1 << (uint8_t)(bit)); } while(0)
#define set_bit_p(reg_p, bit, value) { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); }
#define toggle_bit_p(reg_p, bit) { *(reg_p) ^= (1 << (uint8_t)(bit)); }
// --- Nibble manipulation ---
// Replace nibble in a byte
#define write_low_nibble(reg, value) do { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define write_high_nibble(reg, value) do { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define set_low_nibble(reg, value) { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); }
#define set_high_nibble(reg, value) { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); }
#define write_low_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define write_high_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define set_low_nibble_p(reg_p, value) { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); }
#define set_high_nibble_p(reg_p, value) { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); }
#define low_nibble(x) ((uint8_t)(x) & 0xF)
#define high_nibble(x) (((uint8_t)(x) & 0xF0) >> 4)
+103
View File
@@ -0,0 +1,103 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include "iopins.h"
#include "nsdelay.h"
#include "color.h"
// --- HSL ---
#ifdef HSL_LINEAR
const uint8_t FADE_128[] =
{
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4,
5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14,
14, 15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36,
38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 54, 56, 58, 59, 61, 63,
65, 67, 68, 69, 71, 72, 74, 76, 78, 80, 82, 85, 88, 90, 92, 95, 98, 100,
103, 106, 109, 112, 116, 119, 122, 125, 129, 134, 138, 142, 147, 151,
153, 156, 160, 163, 165, 170, 175, 180, 185, 190, 195, 200, 207, 214, 218,
221, 225, 228, 232, 234, 241, 248, 254, 255
};
#endif
// based on: https://github.com/lewisd32/avr-hsl2rgb
xrgb_t hsl_xrgb(const hsl_t cc)
{
// 0 .. 256*3
const uint16_t hh = (uint16_t) cc.h * 3;
const uint8_t hue_mod = hh % 256;
uint8_t r_temp, g_temp, b_temp;
if (hh < 256)
{
r_temp = hue_mod ^ 255;
g_temp = hue_mod;
b_temp = 0;
}
else if (hh < 512)
{
r_temp = 0;
g_temp = hue_mod ^ 255;
b_temp = hue_mod;
}
else if (hh < 768)
{
r_temp = hue_mod;
g_temp = 0;
b_temp = hue_mod ^ 255;
}
else
{
r_temp = 0;
g_temp = 0;
b_temp = 0;
}
const uint8_t inverse_sat = (cc.s ^ 255);
xrgb_t rgb;
uint8_t t8;
uint16_t t16;
#ifdef HSL_LINEAR
const uint8_t bri = FADE_128[cc.l >> 1];
#else
const uint8_t bri = cc.l;
#endif
t8 = r_temp;
t16 = t8 * cc.s + t8;
t16 = t16 + t8;
t8 = t16 >> 8;
t8 = t8 + inverse_sat;
t16 = t8 * bri;
t16 = t16 + t8;
t8 = t16 >> 8;
rgb.r = t8;
t8 = g_temp;
t16 = t8 * cc.s;
t16 = t16 + t8;
t8 = t16 >> 8;
t8 = t8 + inverse_sat;
t16 = t8 * bri;
t16 = t16 + t8;
t8 = t16 >> 8;
rgb.g = t8;
t8 = b_temp;
t16 = t8 * cc.s;
t16 = t16 + t8;
t8 = t16 >> 8;
t8 = t8 + inverse_sat;
t16 = t8 * bri;
t16 = t16 + t8;
t8 = t16 >> 8;
rgb.b = t8;
return rgb;
}
+57
View File
@@ -0,0 +1,57 @@
#pragma once
// --- color types ---
//
// The XXXc macros don't use cast, so they can be used in array initializers.
//
// xrgb ... 3-byte true-color RGB (8 bits per component)
// rgb24 ... 24-bit color value, with equal nr of bits per component
//
// XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
typedef struct
{
uint8_t r;
uint8_t g;
uint8_t b;
} xrgb_t;
typedef uint32_t rgb24_t;
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
// xrgb for constant array declarations
#define xrgbc(rr, gg, bb) { .r = ((uint8_t)(rr)), .g = ((uint8_t)(gg)), .b = ((uint8_t)(bb)) }
#define xrgb_r(c) ((uint8_t)(c.r))
#define xrgb_g(c) ((uint8_t)(c.g))
#define xrgb_b(c) ((uint8_t)(c.b))
#define xrgb_rgb24(c) ((((rgb24_t)c.r) << 16) | (((rgb24_t)c.g) << 8) | (((rgb24_t)c.b)))
#define xrgb_rgb15(c) (((((rgb15_t)c.r) & 0xF8) << 7) | ((((rgb15_t)c.g) & 0xF8) << 2) | ((((rgb15_t)c.b) & 0xF8) >> 3))
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF)
#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF)
#define rgb24_b(c) ((((rgb24_t) (c)) >> 0) & 0xFF)
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
// HSL data structure
typedef struct
{
uint8_t h;
uint8_t s;
uint8_t l;
} hsl_t;
/* Convert HSL to XRGB */
xrgb_t hsl_xrgb(const hsl_t color);
+15 -8
View File
@@ -3,7 +3,7 @@
#include "debounce.h"
#include "calc.h"
#include "pins.h"
#include "iopins.h"
#include "debo_config.h"
/** Debounce data array */
@@ -11,11 +11,11 @@ uint8_t debo_next_slot = 0;
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
{
debo_slots[debo_next_slot] = (debo_slot_t){
debo_slots[debo_next_slot] = (debo_slot_t)({
.reg = reg,
.bit = bit | ((invert & 1) << 7) | (get_bit_p(reg, bit) << 6), // bit 7 = invert, bit 6 = state
.count = 0,
};
});
return debo_next_slot++;
}
@@ -24,21 +24,28 @@ uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
/** Check debounced pins, should be called periodically. */
void debo_tick()
{
for (uint8_t i = 0; i < debo_next_slot; i++) {
for (uint8_t i = 0; i < debo_next_slot; i++)
{
// current pin value (right 3 bits, xored with inverse bit)
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x7);
if (value != get_bit(debo_slots[i].bit, 6)) {
if (value != get_bit(debo_slots[i].bit, 6))
{
// different pin state than last recorded state
if (debo_slots[i].count < DEBO_TICKS) {
if (debo_slots[i].count < DEBO_TICKS)
{
debo_slots[i].count++;
} else {
}
else
{
// overflown -> latch value
set_bit(debo_slots[i].bit, 6, value); // set state bit
debo_slots[i].count = 0;
}
} else {
}
else
{
debo_slots[i].count = 0; // reset the counter
}
}
+16 -14
View File
@@ -7,17 +7,10 @@
//
// You must provide a config file debo_config.h (next to your main.c)
//
// Example:
// #pragma once
// #define DEBO_CHANNELS 2
// #define DDEBO_TICKS 5
//
// ----
//
// A pin is registered like this:
//
// #define BTN1 B,0
// #define BTN2 B,1
// #define BTN1 12 // pin D12
// #define BTN2 13
//
// debo_add(BTN0); // The function returns number assigned to the pin (0, 1, ...)
// debo_add_rev(BTN1); // active low
@@ -36,13 +29,22 @@
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "calc.h"
#include "pins.h"
#include "iopins.h"
// Your config file
#include "debo_config.h"
/*
#define DEBO_CHANNELS 2
#define DDEBO_TICKS 5
*/
/* Internal deboucer entry */
typedef struct {
typedef struct
{
PORT_P reg; // pointer to IO register
uint8_t bit; // bits 6 and 7 of this hold "state" & "invert" flag
uint8_t count; // number of ticks this was in the new state
@@ -50,9 +52,9 @@ typedef struct {
debo_slot_t debo_slots[DEBO_CHANNELS];
/** Add a pin for debouncing */
#define debo_add_rev(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 1)
#define debo_add(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 0)
/** Add a pin for debouncing (must be used with constant args) */
#define debo_add_rev(pin) debo_register(&_pin(pin), _pn(pin), 1)
#define debo_add(pin) debo_register(&_pin(pin), _pn(pin), 0)
/** Add a pin for debouncing (low level function) */
uint8_t debo_register(PORT_P pin_reg_pointer, uint8_t bit, bool invert);
+88
View File
@@ -0,0 +1,88 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "dht11.h"
/** Read one bit */
bool _dht11_rxbit(const uint8_t pin)
{
// Wait until start of pulse
while (is_low_n(pin));
uint8_t cnt = 0;
while (is_high_n(pin))
{
cnt++;
_delay_us(5);
}
return (cnt > 8);
}
/** Read one byte */
uint8_t _dht11_rxbyte(const uint8_t pin)
{
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
if (_dht11_rxbit(pin))
byte |= (1 << (7 - i));
}
return byte;
}
/** Read tehmperature and humidity from the DHT11, returns false on failure */
bool dht11_read(const uint8_t pin, dht11_result_t* result)
{
// bus down for > 18 ms
as_output_n(pin);
pin_low_n(pin);
_delay_ms(20);
// bus up for 20-40us
pin_high_n(pin);
_delay_us(20);
// release
as_input_pu_n(pin);
// DHT should send 80us LOW & 80us HIGH
_delay_us(40);
if (!is_low_n(pin))
return false; // init error
_delay_us(80);
if (!is_high_n(pin))
return false; // init error
// skip to start of first bit
_delay_us(50);
// Receive 5 data bytes (Rh int, Rh dec, Temp int, Temp dec, Checksum)
// Decimal bytes are zero for DHT11 -> we can ignore them.
uint8_t bytes[5];
uint8_t sum = 0;
for (uint8_t i = 0; i < 5; i++)
{
uint8_t b = _dht11_rxbyte(pin);
bytes[i] = b;
if (i < 4) sum += b;
}
// Verify checksum
if (sum != bytes[4]) return false;
result->rh = bytes[0];
result->temp = bytes[2];
return true;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
//
// Reading temperature and relative humidity from DHT11
//
#include <stdint.h>
#include <stdbool.h>
typedef struct
{
int8_t temp;
int8_t rh;
} dht11_result_t;
/** Read tehmperature and humidity from the DHT11, returns false on failure */
bool dht11_read(const uint8_t pin, dht11_result_t* result);
+1253
View File
File diff suppressed because it is too large Load Diff
+276
View File
@@ -0,0 +1,276 @@
#pragma once
//
// Simple FAT16 library.
//
// To use it, implement BLOCKDEV functions
// and attach them to it's instance.
//
#include <stdint.h>
#include <stdbool.h>
#include "blockdev.h"
// -------------------------------
/**
* File types (values can be used for debug printing).
* Accessible using file->type
*/
typedef enum
{
FT_NONE = '-',
FT_DELETED = 'x',
FT_SUBDIR = 'D',
FT_PARENT = 'P',
FT_LABEL = 'L',
FT_LFN = '~',
FT_INVALID = '?', // not recognized weird file
FT_SELF = '.',
FT_FILE = 'F'
} FAT16_FT;
/** "File address" for saving and restoring file */
typedef struct
{
uint16_t clu;
uint16_t num;
uint32_t cur_rel;
} FSAVEPOS;
// Include definitions of fully internal structs
#include "fat16_internal.h"
/**
* File handle struct.
*
* File handle contains cursor, file name, type, size etc.
* Everything (files, dirs) is accessed using this.
*/
typedef struct __attribute__((packed))
{
/**
* Raw file name. Starting 0x05 was converted to 0xE5.
* To get PRINTABLE file name, use fat16_dispname()
*/
uint8_t name[11];
/**
* File attributes - bit field composed of FA_* flags
* (internal)
*/
uint8_t attribs;
// 14 bytes skipped (10 reserved, date, time)
/** First cluster of the file. (internal) */
uint16_t clu_start;
/**
* File size in bytes.
* This is the current allocated and readable file size.
*/
uint32_t size;
// --- the following fields are added when reading ---
/** File type. */
FAT16_FT type;
// --- INTERNAL FIELDS ---
// Cursor variables. (internal)
uint32_t cur_abs; // absolute position in device
uint32_t cur_rel; // relative position in file
uint16_t cur_clu; // cluster where the cursor is
uint16_t cur_ofs; // offset within the active cluster
// File position in the directory. (internal)
uint16_t clu; // first cluster of directory
uint16_t num; // file entry number
// Pointer to the FAT16 handle. (internal)
const FAT16* fat;
}
FFILE;
/**
* Store modified file metadata and flush it to disk.
*/
void ff_flush_file(FFILE* file);
/**
* Save a file "position" into a struct, for later restoration.
* Cursor is also saved.
*/
FSAVEPOS ff_savepos(const FFILE* file);
/**
* Restore a file from a saved position.
*/
void ff_reopen(FFILE* file, const FSAVEPOS* pos);
/**
* Initialize the file system - store into "fat"
*/
bool ff_init(const BLOCKDEV* dev, FAT16* fat);
/**
* Open the first file of the root directory.
* The file may be invalid (eg. a volume label, deleted etc),
* or blank (type FT_NONE) if the filesystem is empty.
*/
void ff_root(const FAT16* fat, FFILE* file);
/**
* Resolve the disk label.
* That can be in the Boot Sector, or in the first root directory entry.
*
* @param fat the FAT handle
* @param label_out string to store the label in. Should have at least 12 bytes.
*/
char* ff_disk_label(const FAT16* fat, char* label_out);
// ----------- FILE I/O -------------
/**
* Move file cursor to a position relative to file start
* Returns false on I/O error (bad file, out of range...)
*/
bool ff_seek(FFILE* file, uint32_t addr);
/**
* Read bytes from file into memory
* Returns number of bytes read, 0 on error.
*/
uint16_t ff_read(FFILE* file, void* target, uint16_t len);
/**
* Write into file at a "seek" position.
*/
bool ff_write(FFILE* file, const void* source, uint32_t len);
/**
* Store a 0-terminated string at cursor.
*/
bool ff_write_str(FFILE* file, const char* source);
/**
* Create a new file in given folder
*
* file ... open directory; new file is opened into this handle.
* name ... name of the new file, including extension
*/
bool ff_newfile(FFILE* file, const char* name);
/**
* Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".."
*/
bool ff_mkdir(FFILE* file, const char* name);
/**
* Set new file size.
* Allocates / frees needed clusters, does NOT erase them.
*
* Useful mainly for shrinking.
*/
void set_file_size(FFILE* file, uint32_t size);
/**
* Delete a *FILE* and free it's clusters.
*/
bool ff_rmfile(FFILE* file);
/**
* Delete an empty *DIRECTORY* and free it's clusters.
*/
bool ff_rmdir(FFILE* file);
/**
* Delete a file or directory, even FT_LFN and FT_INVALID.
* Directories are deleted recursively (!)
*/
bool ff_delete(FFILE* file);
// --------- NAVIGATION ------------
/** Go to previous file in the directory (false = no prev file) */
bool ff_prev(FFILE* file);
/** Go to next file in directory (false = no next file) */
bool ff_next(FFILE* file);
/**
* Open a subdirectory denoted by the file.
* Provided handle changes to the first entry of the directory.
*/
bool ff_opendir(FFILE* dir);
/**
* Open a parent directory. Fails in root.
* Provided handle changes to the first entry of the parent directory.
*/
bool ff_parent(FFILE* file);
/** Jump to first file in this directory */
void ff_first(FFILE* file);
/**
* Find a file with given "display name" in this directory, and open it.
* If file is found, "file" will contain it's handle.
* Otherwise, the handle is unchanged.
*/
bool ff_find(FFILE* file, const char* name);
// -------- FILE INSPECTION -----------
/** Check if file is a valid entry, or long-name/label/deleted */
bool ff_is_regular(const FFILE* file);
/**
* Resolve a file name, trim spaces and add null terminator.
* Returns the passed char*, or NULL on error.
*/
char* ff_dispname(const FFILE* file, char* disp_out);
/**
* Convert filename to zero-padded fixed length one
* Returns the passed char*.
*/
char* ff_rawname(const char* disp_in, char* raw_out);
+64
View File
@@ -0,0 +1,64 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
// Internal types and stuff that is needed in the header for declarations,
// but is not a part of the public API.
/** Boot Sector structure */
typedef struct __attribute__((packed))
{
// Fields loaded directly from disk:
// 13 bytes skipped
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t num_fats;
uint16_t root_entries;
// 3 bytes skipped
uint16_t fat_size_sectors;
// 8 bytes skipped
uint32_t total_sectors; // if "short size sectors" is used, it's copied here too
// 7 bytes skipped
char volume_label[11]; // space padded, no terminator
// Added fields:
uint32_t bytes_per_cluster;
}
Fat16BootSector;
/** FAT filesystem handle */
typedef struct __attribute__((packed))
{
// Backing block device
const BLOCKDEV* dev;
// Root directory sector start
uint32_t rd_addr;
// Start of first cluster (number "2")
uint32_t data_addr;
// Start of fat table
uint32_t fat_addr;
// Boot sector data struct
Fat16BootSector bs;
}
FAT16;
/**
* File Attributes (bit flags)
* Accessible using file->attribs
*/
#define FA_READONLY 0x01 // read only file
#define FA_HIDDEN 0x02 // hidden file
#define FA_SYSTEM 0x04 // system file
#define FA_LABEL 0x08 // volume label entry, found only in root directory.
#define FA_DIR 0x10 // subdirectory
#define FA_ARCHIVE 0x20 // archive flag
-19
View File
@@ -1,19 +0,0 @@
#pragma once
//
// HSL support (addition to colors.h)
//
#include "colors.h"
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
// HSL data structure
typedef struct {
uint8_t h;
uint8_t s;
uint8_t l;
} hsl_t;
/* Convert HSL to XRGB */
xrgb_t hsl2xrgb(const hsl_t color);
+276
View File
@@ -0,0 +1,276 @@
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "calc.h"
#include "iopins.h"
void set_dir_n(const uint8_t pin, const 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(const 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(const 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(const 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 set_pin_n(const uint8_t pin, const uint8_t v)
{
switch(pin) {
case 0: set_pin(0, v); return;
case 1: set_pin(1, v); return;
case 2: set_pin(2, v); return;
case 3: set_pin(3, v); return;
case 4: set_pin(4, v); return;
case 5: set_pin(5, v); return;
case 6: set_pin(6, v); return;
case 7: set_pin(7, v); return;
case 8: set_pin(8, v); return;
case 9: set_pin(9, v); return;
case 10: set_pin(10, v); return;
case 11: set_pin(11, v); return;
case 12: set_pin(12, v); return;
case 13: set_pin(13, v); return;
case 14: set_pin(14, v); return;
case 15: set_pin(15, v); return;
case 16: set_pin(16, v); return;
case 17: set_pin(17, v); return;
case 18: set_pin(18, v); return;
case 19: set_pin(19, v); return;
case 20: set_pin(20, v); return;
case 21: set_pin(21, v); return;
}
}
void pin_low_n(const uint8_t pin)
{
switch(pin) {
case 0: pin_low(0); return;
case 1: pin_low(1); return;
case 2: pin_low(2); return;
case 3: pin_low(3); return;
case 4: pin_low(4); return;
case 5: pin_low(5); return;
case 6: pin_low(6); return;
case 7: pin_low(7); return;
case 8: pin_low(8); return;
case 9: pin_low(9); return;
case 10: pin_low(10); return;
case 11: pin_low(11); return;
case 12: pin_low(12); return;
case 13: pin_low(13); return;
case 14: pin_low(14); return;
case 15: pin_low(15); return;
case 16: pin_low(16); return;
case 17: pin_low(17); return;
case 18: pin_low(18); return;
case 19: pin_low(19); return;
case 20: pin_low(20); return;
case 21: pin_low(21); return;
}
}
void pin_high_n(const uint8_t pin)
{
switch(pin) {
case 0: pin_high(0); return;
case 1: pin_high(1); return;
case 2: pin_high(2); return;
case 3: pin_high(3); return;
case 4: pin_high(4); return;
case 5: pin_high(5); return;
case 6: pin_high(6); return;
case 7: pin_high(7); return;
case 8: pin_high(8); return;
case 9: pin_high(9); return;
case 10: pin_high(10); return;
case 11: pin_high(11); return;
case 12: pin_high(12); return;
case 13: pin_high(13); return;
case 14: pin_high(14); return;
case 15: pin_high(15); return;
case 16: pin_high(16); return;
case 17: pin_high(17); return;
case 18: pin_high(18); return;
case 19: pin_high(19); return;
case 20: pin_high(20); return;
case 21: pin_high(21); return;
}
}
void toggle_pin_n(const uint8_t pin)
{
switch(pin) {
case 0: toggle_pin(0); return;
case 1: toggle_pin(1); return;
case 2: toggle_pin(2); return;
case 3: toggle_pin(3); return;
case 4: toggle_pin(4); return;
case 5: toggle_pin(5); return;
case 6: toggle_pin(6); return;
case 7: toggle_pin(7); return;
case 8: toggle_pin(8); return;
case 9: toggle_pin(9); return;
case 10: toggle_pin(10); return;
case 11: toggle_pin(11); return;
case 12: toggle_pin(12); return;
case 13: toggle_pin(13); return;
case 14: toggle_pin(14); return;
case 15: toggle_pin(15); return;
case 16: toggle_pin(16); return;
case 17: toggle_pin(17); return;
case 18: toggle_pin(18); return;
case 19: toggle_pin(19); return;
case 20: toggle_pin(20); return;
case 21: toggle_pin(21); return;
}
}
bool get_pin_n(const uint8_t pin)
{
switch(pin) {
case 0: return get_pin(0);
case 1: return get_pin(1);
case 2: return get_pin(2);
case 3: return get_pin(3);
case 4: return get_pin(4);
case 5: return get_pin(5);
case 6: return get_pin(6);
case 7: return get_pin(7);
case 8: return get_pin(8);
case 9: return get_pin(9);
case 10: return get_pin(10);
case 11: return get_pin(11);
case 12: return get_pin(12);
case 13: return get_pin(13);
case 14: return get_pin(14);
case 15: return get_pin(15);
case 16: return get_pin(16);
case 17: return get_pin(17);
case 18: return get_pin(18);
case 19: return get_pin(19);
case 20: return get_pin(20);
case 21: return get_pin(21);
}
return false;
}
bool is_low_n(const uint8_t pin)
{
return !get_pin_n(pin);
}
bool is_high_n(const uint8_t pin)
{
return get_pin_n(pin);
}
+213
View File
@@ -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_high(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 set_pin(pin, v) set_bit( _port(pin), _pn(pin), v )
void set_pin_n(const uint8_t pin, const uint8_t v);
/** Write 0 to a pin */
#define pin_low(pin) cbi( _port(pin), _pn(pin) )
void pin_low_n(const uint8_t pin);
/** Write 1 to a pin */
#define pin_high(pin) sbi( _port(pin), _pn(pin) )
void pin_high_n(const uint8_t pin);
/** Toggle a pin state */
#define toggle_pin(pin) sbi( _pin(pin), _pn(pin) )
void toggle_pin_n(const uint8_t pin);
/** Read a pin value */
#define get_pin(pin) get_bit( _pin(pin), _pn(pin) )
bool get_pin_n(const uint8_t pin);
/** CHeck if pin is low */
#define is_low(pin) (get_pin(pin) == 0)
bool is_low_n(const uint8_t pin);
/** CHeck if pin is high */
#define is_high(pin) (get_pin(pin) != 0)
bool is_high_n(const 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
+30 -23
View File
@@ -5,7 +5,7 @@
#include <util/delay.h>
#include "calc.h"
#include "pins.h"
#include "iopins.h"
#include "nsdelay.h"
#include "lcd.h"
#include "lcd_config.h"
@@ -32,22 +32,24 @@ uint8_t _lcd_read_byte();
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
#define _lcd_write_nibble(nib) do { \
write_pin(LCD_D7, get_bit((nib), 3)); \
write_pin(LCD_D6, get_bit((nib), 2)); \
write_pin(LCD_D5, get_bit((nib), 1)); \
write_pin(LCD_D4, get_bit((nib), 0)); \
set_pin(LCD_D7, get_bit((nib), 3)); \
set_pin(LCD_D6, get_bit((nib), 2)); \
set_pin(LCD_D5, get_bit((nib), 1)); \
set_pin(LCD_D4, get_bit((nib), 0)); \
} while(0)
// 0 W, 1 R
bool _lcd_mode;
struct {
struct
{
uint8_t x;
uint8_t y;
} _pos;
enum {
enum
{
TEXT = 0,
CG = 1
} _addrtype;
@@ -100,9 +102,9 @@ void lcd_init()
/** Send a pulse on the ENABLE line */
void _lcd_clk()
{
pin_up(LCD_E);
pin_high(LCD_E);
delay_ns(450);
pin_down(LCD_E);
pin_low(LCD_E);
}
@@ -111,7 +113,7 @@ void _lcd_mode_r()
{
if (_lcd_mode == 1) return; // already in R mode
pin_up(LCD_RW);
pin_high(LCD_RW);
as_input_pu(LCD_D7);
as_input_pu(LCD_D6);
@@ -127,7 +129,7 @@ void _lcd_mode_w()
{
if (_lcd_mode == 0) return; // already in W mode
pin_down(LCD_RW);
pin_low(LCD_RW);
as_output(LCD_D7);
as_output(LCD_D6);
@@ -146,10 +148,10 @@ uint8_t _lcd_read_byte()
uint8_t res = 0;
_lcd_clk();
res = (read_pin(LCD_D7) << 7) | (read_pin(LCD_D6) << 6) | (read_pin(LCD_D5) << 5) | (read_pin(LCD_D4) << 4);
res = (get_pin(LCD_D7) << 7) | (get_pin(LCD_D6) << 6) | (get_pin(LCD_D5) << 5) | (get_pin(LCD_D4) << 4);
_lcd_clk();
res |= (read_pin(LCD_D7) << 3) | (read_pin(LCD_D6) << 2) | (read_pin(LCD_D5) << 1) | (read_pin(LCD_D4) << 0);
res |= (get_pin(LCD_D7) << 3) | (get_pin(LCD_D6) << 2) | (get_pin(LCD_D5) << 1) | (get_pin(LCD_D4) << 0);
return res;
}
@@ -159,7 +161,7 @@ uint8_t _lcd_read_byte()
void lcd_command(uint8_t bb)
{
_lcd_wait_bf();
pin_down(LCD_RS); // select instruction register
pin_low(LCD_RS); // select instruction register
_lcd_write_byte(bb); // send instruction byte
}
@@ -167,15 +169,18 @@ void lcd_command(uint8_t bb)
/** Write a data byte */
void lcd_write(uint8_t bb)
{
if (_addrtype == TEXT) {
if (bb == '\r') {
if (_addrtype == TEXT)
{
if (bb == '\r')
{
// CR
_pos.x = 0;
lcd_xy(_pos.x, _pos.y);
return;
}
if (bb == '\n') {
if (bb == '\n')
{
// LF
_pos.y++;
lcd_xy(_pos.x, _pos.y);
@@ -186,7 +191,7 @@ void lcd_write(uint8_t bb)
}
_lcd_wait_bf();
pin_up(LCD_RS); // select data register
pin_high(LCD_RS); // select data register
_lcd_write_byte(bb); // send data byte
}
@@ -194,7 +199,7 @@ void lcd_write(uint8_t bb)
/** Read BF & Address */
uint8_t lcd_read_bf_addr()
{
pin_down(LCD_RS);
pin_low(LCD_RS);
return _lcd_read_byte();
}
@@ -204,7 +209,7 @@ uint8_t lcd_read()
{
if (_addrtype == TEXT) _pos.x++;
pin_up(LCD_RS);
pin_high(LCD_RS);
return _lcd_read_byte();
}
@@ -227,7 +232,7 @@ void _lcd_write_byte(uint8_t bb)
void _lcd_wait_bf()
{
uint8_t d = 0;
while(d++ < 120 && lcd_read_bf_addr() & _BV(7))
while (d++ < 120 && lcd_read_bf_addr() & _BV(7))
_delay_us(1);
}
@@ -318,7 +323,8 @@ void lcd_clear()
void lcd_glyph(const uint8_t index, const uint8_t* array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
for (uint8_t i = 0; i < 8; ++i)
{
lcd_write(array[i]);
}
@@ -332,7 +338,8 @@ void lcd_glyph(const uint8_t index, const uint8_t* array)
void lcd_glyph_P(const uint8_t index, const uint8_t* array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
for (uint8_t i = 0; i < 8; ++i)
{
lcd_write(pgm_read_byte(&array[i]));
}
+10 -10
View File
@@ -7,15 +7,6 @@
//
// Content can be something like this:
//
// #pragma once
// #include "lib/arduino_pins.h"
// #define LCD_RS D10
// #define LCD_RW D11
// #define LCD_E D12
// #define LCD_D4 D13
// #define LCD_D5 D14
// #define LCD_D6 D15
// #define LCD_D7 D16
//
#include <stdint.h>
@@ -23,8 +14,17 @@
#include "stream.h"
// File with configs
// Your file with configs
#include "lcd_config.h"
/*
#define LCD_RS 10
#define LCD_RW 11
#define LCD_E 12
#define LCD_D4 13
#define LCD_D5 14
#define LCD_D6 15
#define LCD_D7 16
*/
-22
View File
@@ -1,22 +0,0 @@
#pragma once
//
// Custom loops
//
// Repeat code n times (uint8_t counter)
#define repeat(count) repeat_aux(count, _repeat_##__COUNTER__)
#define repeat_aux(count, cntvar) for (uint8_t cntvar = 0; cntvar < (count); cntvar++)
// Repeat code n times (uint16_t counter)
#define repeatx(count) repeatx_aux(count, _repeatx_##__COUNTER__)
#define repeatx_aux(count, cntvar) for (uint16_t cntvar = 0; cntvar < (count); cntvar++)
// Repeat with custom counter name (uint8_t)
#define loop(var, count) repeat_aux(count, var)
// ..., uint16_t
#define loopx(var, count) repeatx_aux(count, var)
// Do until condition is met
#define until(what) while(!(what))
-6
View File
@@ -1,6 +0,0 @@
#pragma once
// Weird constructs for the compiler
// general macros
#define SECTION(pos) __attribute__((naked, used, section(pos)))
+248
View File
@@ -0,0 +1,248 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "onewire.h"
/** Perform bus reset. Returns true if any device is connected */
bool ow_reset(const uint8_t pin)
{
as_output_n(pin);
pin_low_n(pin);
_delay_us(480);
as_input_pu_n(pin);
_delay_us(70);
const bool a = get_pin_n(pin);
_delay_us(410);
return a;
}
/** Send a single bit */
void _ow_tx_bit(const uint8_t pin, const bool bit)
{
as_output_n(pin);
pin_low_n(pin);
if (bit)
{
_delay_us(6);
as_input_pu_n(pin);
_delay_us(64);
}
else
{
_delay_us(60);
as_input_pu_n(pin);
_delay_us(10);
}
}
/** Send a single byte */
void ow_send(const uint8_t pin, const uint8_t byte)
{
for (uint8_t i = 0; i < 8; i++)
{
_ow_tx_bit(pin, (byte >> i) & 0x01);
}
}
/** Read a single bit */
bool _ow_rx_bit(const uint8_t pin)
{
as_output_n(pin);
pin_low_n(pin);
_delay_us(6);
as_input_pu_n(pin);
_delay_us(9);
const bool a = get_pin_n(pin);
_delay_us(55);
return a;
}
/** Read a single byte */
uint8_t ow_read(const uint8_t pin)
{
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
byte = (byte >> 1) | (_ow_rx_bit(pin) << 7);
}
return byte;
}
/** Wait until the device is ready. Returns false on timeout */
bool ow_wait_ready(const uint8_t pin)
{
uint16_t timeout = 700;
as_input_pu_n(pin);
while (--timeout > 0)
{
if (is_high_n(pin)) return true;
_delay_ms(1);
}
return false;
}
/** Read bytes into an array */
void ow_read_arr(const uint8_t pin, uint8_t* array, const uint8_t count)
{
for (uint8_t i = 0; i < count; i++)
{
array[i] = ow_read(pin);
}
}
// ---------- CRC utils ----------
/*
Dallas 1-wire CRC routines for Arduino with examples of usage.
The 16-bit routine is new.
The 8-bit routine is from http://github.com/paeaetech/paeae/tree/master/Libraries/ds2482/
Copyright (C) 2010 Kairama Inc
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Dallas 1-wire 16-bit CRC calculation. Developed from Maxim Application Note 27.
/** Compute a CRC16 checksum */
uint16_t crc16(uint8_t *data, uint8_t len)
{
uint16_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
uint8_t inbyte = data[i];
for (uint8_t j = 0; j < 8; j++)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc = crc >> 1;
if (mix)
crc = crc ^ 0xA001;
inbyte = inbyte >> 1;
}
}
return crc;
}
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
/** Compute a CRC8 checksum */
uint8_t crc8(uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
uint8_t inbyte = addr[i];
for (uint8_t j = 0; j < 8; j++)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix)
crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
// --- utils for DS1820 ---
/** Read temperature in 0.0625°C, or TEMP_ERROR on error */
int16_t ds1820_read_temp(uint8_t pin)
{
ow_send(pin, READ_SCRATCHPAD);
uint8_t bytes[9];
ow_read_arr(pin, bytes, 9);
uint8_t crc = crc8(bytes, 8);
if (crc != bytes[8])
{
return TEMP_ERROR;
}
else
{
int16_t a = ((bytes[1] << 8) | bytes[0]) >> 1;
a = a << 4;
a += (16 - bytes[6]) & 0x0F;
a -= 0x04;
return a;
}
}
/** Read temperature in 0.1°C, or TEMP_ERROR on error */
int16_t ds1820_read_temp_c(uint8_t pin)
{
int32_t temp = ds1820_read_temp(pin);
if (temp == TEMP_ERROR)
return TEMP_ERROR;
temp *= 625;
uint16_t rem = temp % 1000;
temp /= 1000;
if (rem >= 500) temp++;
return (int16_t) temp;
}
bool ds1820_single_measure(uint8_t pin)
{
ow_reset(pin);
ow_send(pin, SKIP_ROM);
ow_send(pin, CONVERT_T);
if (!ow_wait_ready(pin))
{
return false;
}
ow_reset(pin);
ow_send(pin, SKIP_ROM);
return true;
}
+58
View File
@@ -0,0 +1,58 @@
#pragma once
//
// Utils for Dallas OneWire bus (DS1820 etc)
//
#include <stdint.h>
#include <stdbool.h>
#define SKIP_ROM 0xCC
#define CONVERT_T 0x44
#define READ_SCRATCHPAD 0xBE
/** Perform bus reset. Returns true if any device is connected */
bool ow_reset(const uint8_t pin);
/** Send a single byte */
void ow_send(const uint8_t pin, const uint8_t byte);
/** Read a single byte */
uint8_t ow_read(const uint8_t pin);
/** Wait until the device is ready. Returns false on timeout */
bool ow_wait_ready(const uint8_t pin);
/** Read bytes into an array */
void ow_read_arr(const uint8_t pin, uint8_t* array, const uint8_t count);
/** Compute a CRC16 checksum */
uint16_t crc16(uint8_t *data, uint8_t len);
/** Compute a CRC8 checksum */
uint8_t crc8(uint8_t *addr, uint8_t len);
// --- utils for DS1820 ---
#define TEMP_ERROR -32768
/**
* Read temperature in 0.0625°C, or TEMP_ERROR on error
* Use this where you'd normally use READ_SCRATCHPAD
*/
int16_t ds1820_read_temp(uint8_t pin);
/**
* Read temperature in 0.1°C, or TEMP_ERROR on error
* Use this where you'd normally use READ_SCRATCHPAD
*/
int16_t ds1820_read_temp_c(uint8_t pin);
/**
* Perform a temperature measurement with single DS1820 device on the line
* Can be followed by a call to read temperature (READ_SCRATCHPAD).
*
* Returns false on failure (device not connected)
*/
bool ds1820_single_measure(uint8_t pin);
-129
View File
@@ -1,129 +0,0 @@
#pragma once
//
// This file provides macros for pin manipulation.
//
// You can define your application pins like so:
//
// // Led at PORTB, pin 1
// #define LED B,1
//
// // Switch at PORTD, pin 7
// #define SW1 D,7
//
// Now you can use macros from this file to wirh with the pins, eg:
//
// as_output(LED);
// as_input(SW1);
// pullup_on(SW1);
//
// toggle_pin(LED);
// while (pin_is_low(SW1));
//
// - The macros io2XXX() can be used to get literal name of register associated with the pin.
// - io2n() provides pin number.
// - The underscored and _aux macros are internal and should not be used elsewhere.
// - The io_pack() macro is used to pass pin (io) to other macro without expanding it.
//
#include <avr/io.h>
#include "calc.h"
// Helpers
// Get particular register associated with the name X (eg. D -> PORTD)
#define _reg_ddr(X) DDR ## X
#define _reg_port(X) PORT ## X
#define _reg_pin(X) PIN ## X
#define _io2ddr_aux(reg, bit) _reg_ddr(reg)
#define _io2port_aux(reg, bit) _reg_port(reg)
#define _io2pin_aux(reg, bit) _reg_pin(reg)
#define _io2n_aux(reg, bit) bit
// === Convert A,1 to corresponding register and pin number ===
#define io2ddr(io) _io2ddr_aux(io)
#define io2port(io) _io2port_aux(io)
#define io2pin(io) _io2pin_aux(io)
#define io2n(io) _io2n_aux(io)
// === covert "A", "1" to "A,1" for passing on to another macro ===
#define io_pack(port, bit) port, bit
// === Useful types for ports and pins ===
// pointer to port
typedef volatile uint8_t* PORT_P;
// number of bit in port
typedef uint8_t BIT_N;
// === pin manipulation ===
// Helpers
#define _set_pin_aux(port, bit) sbi(_reg_port(port), (bit))
#define _clear_pin_aux(port, bit) cbi(_reg_port(port), (bit))
#define _read_pin_aux(port, bit) get_bit(_reg_pin(port), (bit))
#define _write_pin_aux(port, bit, value) set_bit(_reg_port(port), (bit), (value))
#define _toggle_pin_aux(port, bit) sbi(_reg_pin(port), (bit))
// Set pin to HIGH
#define pin_up(io) _set_pin_aux(io)
#define pin_high(io) _set_pin_aux(io)
// Set pin to LOW
#define pin_down(io) _clear_pin_aux(io)
#define pin_low(io) _clear_pin_aux(io)
// Get input pin value
#define get_pin(io) _read_pin_aux(io)
#define read_pin(io) _read_pin_aux(io)
// Check if pin is low or high
#define pin_is_low(io) !_read_pin_aux(io)
#define pin_is_high(io) _read_pin_aux(io)
// Write a value to pin
#define set_pin(io, value) _write_pin_aux(io, (value))
#define write_pin(io, value) _write_pin_aux(io, (value))
#define toggle_pin(io) _toggle_pin_aux(io)
// === Setting pin direction ===
// Helpers
#define _as_input_aux(port, bit) cbi(_reg_ddr(port), (bit))
#define _as_output_aux(port, bit) sbi(_reg_ddr(port), (bit))
#define _set_dir_aux(port, bit, dir) write_bit(_reg_ddr(port), (bit), (dir))
// Pin as input (_pu ... with pull-up)
#define as_input(io) _as_input_aux(io)
#define as_input_pu(io) do { _as_input_aux(io); _pullup_enable_aux(io); } while(0)
// Pin as output
#define as_output(io) _as_output_aux(io)
// Set direction (1 ... output)
#define set_dir(io, dir) _set_dir_aux(io, (dir))
// === Setting pullup ===
// Helpers
#define _pullup_enable_aux(port, bit) sbi(_reg_port(port), (bit))
#define _pullup_disable_aux(port, bit) cbi(_reg_port(port), (bit))
#define _set_pullup_aux(port, bit, on) write_bit(_reg_port(port), (bit), (on))
// Enable pullup
#define pullup_enable(io) _pullup_enable_aux(io)
#define pullup_on(io) _pullup_enable_aux(io)
// Disable pullup
#define pullup_disable(io) _pullup_disable_aux(io)
#define pullup_off(io) _pullup_disable_aux(io)
// Set pullup to value (1 ... pullup enabled)
#define set_pullup(io, on) _set_pullup_aux(io, on)
+202
View File
@@ -0,0 +1,202 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "spi.h"
#include "sd.h"
#define SD_RESET 0x40 // used to make card enter SPI mode
#define SD_GET_STATUS 0x41 // used to check if card left IDLE - should return 0
#define SD_SET_BLOCKLEN 0x50 // used to check if card left IDLE - should return 0
#define SD_READ_BLOCK 0x51 // read single block
#define SD_WRITE_BLOCK 0x58 // write single block
bool sd_inited = false;
bool sd_init()
{
if (sd_inited) return true;
sd_inited = true;
uint8_t i;
spi_init();
spi_ss_disable(); // needed for init sequence, first command will enable it again
// idle for 10 bytes / 80 clocks
for (i = 0; i < 10; i++)
{
spi_write(0xFF);
}
// Send "Go to SPI mode" command, which should return "1"
for (i = 0; i < 100 && sd_command(SD_RESET, 0) != 1; i++)
_delay_ms(10);
if (i == 100)
return false; // timeout
// CMD1 until card comes out of "idle" mode
for (i = 0; i < 100 && sd_command(SD_GET_STATUS, 0) != 0; i++)
_delay_ms(10);
if (i == 100)
return false; // timeout
// f_cpu/8 speed (-> 2 MHz)
SPSR |= _BV(SPI2X);
SPCR &= 0xFC | _BV(SPR0);
// Set block size to 512 bytes (SD card default)
sd_command(SD_SET_BLOCKLEN, 512);
return true;
}
uint8_t sd_command(const uint8_t cmd, const uint32_t arg)
{
spi_ss_enable();
spi_write(cmd);
spi_write(arg >> 24);
spi_write(arg >> 16);
spi_write(arg >> 8);
spi_write(arg);
spi_write(0x95); // CRC for the "init" command, later is ignored
// Send 8 bytes of 0xFF
// SD card replies with non-0xFF once it's done processing the command
uint8_t i, tmp, ret = 0xFF;
for (i = 0; i < 8; i++)
{
tmp = spi_write(0xFF);
if (tmp != 0xFF)
ret = tmp;
}
spi_ss_disable();
return ret;
}
bool sd_read(const uint32_t sector, const uint16_t read_at, uint8_t * buffer, const uint16_t write_at, const uint16_t len)
{
if (read_at + len > 512) return false;
uint16_t i;
spi_ss_enable();
spi_write(SD_READ_BLOCK);
spi_write(sector >> 15); // sector * 512 >> 24
spi_write(sector >> 7); // sector * 512 >> 16
spi_write(sector << 1); // sector * 512 >> 8
spi_write(0); // sector * 512
spi_write(0xFF);
// wait for 0 (ready)
for (i = 0; i < 100 && spi_write(0xFF) != 0x00; i++);
if (i == 100)
{
spi_ss_disable();
return false; // timeout
}
// wait for 0xFE (data start)
for (i = 0; i < 100 && spi_write(0xFF) != 0xFE; i++);
if (i == 100)
{
spi_ss_disable();
return false; // timeout
}
// skip "offset" bytes
for (i = 0; i < read_at; i++)
spi_write(0xFF);
// read "len" bytes
for (i = write_at; i < write_at + len; i++)
buffer[i] = spi_write(0xFF);
// skip remaining bytes in the sector
for (i = read_at + len; i < 512; i++)
spi_write(0xFF);
// skip checksum
spi_write(0xFF);
spi_write(0xFF);
spi_ss_disable();
return true;
}
bool sd_write(const uint32_t sector, const uint8_t * buffer512)
{
uint16_t i;
spi_ss_enable();
spi_write(SD_WRITE_BLOCK);
spi_write(sector >> 15); // sector * 512 >> 24
spi_write(sector >> 7); // sector * 512 >> 16
spi_write(sector << 1); // sector * 512 >> 8
spi_write(0); // sector * 512
spi_write(0xFF);
// wait for 0 (ready)
for (i = 0; i < 100 && spi_write(0xFF) != 0x00; i++);
if (i == 100)
{
spi_ss_disable();
return false; // timeout
}
// Start of data
spi_write(0xFE);
// Data
for (i = 0; i < 512; i++)
{
spi_write(buffer512[i]);
}
// Fake CRC
spi_write(0xFF);
spi_write(0xFF);
// Should contain flag that data was accepted
uint8_t resp = spi_write(0xFF);
if ((resp & 0x0F) != 0x05)
{
// Data not accepted
spi_ss_disable();
return false;
}
else
{
// Data accepted, wait for write complete
for (i = 0; i < 0xFFFF && spi_write(0xFF) == 0x00; i++);
if (i == 0xFFFF)
{
spi_ss_disable();
return false; // timeout
}
}
spi_write(0xFF); // 8 clocks
spi_ss_disable();
return true;
}
+53
View File
@@ -0,0 +1,53 @@
#pragma once
//
// SD card low-level I/O utilities
//
// Inspired by:
// http://www.avrfreaks.net/forum/tutc-simple-fat-and-sd-tutorial
//
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "spi.h"
/** Init SD card on SPI */
bool sd_init();
/**
* Send a command to the SD card
*
* @param cmd command to send
* @param arg command argument
* @return return value on success, 0xFF if nothing received back.
*/
uint8_t sd_command(uint8_t cmd, uint32_t arg);
/**
* Read from a sector into a buffer memory structure.
*
* @param sector sector to read (512 bytes long each)
* @param read_at offset within the sector
* @param buffer target buffer
* @param write_at target starting address
* @param len number of bytes to read
* @return true on success
*/
bool sd_read(uint32_t sector, uint16_t read_at, uint8_t * buffer, uint16_t write_at, uint16_t len);
/**
* Write bytes from a buffer into a sector.
*
* @param sector sector to write (512 bytes long each)
* @param buffer512 source buffer
* @return true on success
*/
bool sd_write(uint32_t sector, const uint8_t * buffer512);
+184
View File
@@ -0,0 +1,184 @@
#include <stdint.h>
#include <stdbool.h>
#include "sd_blockdev.h"
#include "sd.h"
// helpers
void load_sector(const uint32_t addr);
void store_sector();
void handle_cursor_ov();
// blockdev methods
void dev_load(void* dest, const uint16_t len);
void dev_store(const void* src, const uint16_t len);
uint8_t dev_read();
void dev_write(const uint8_t b);
void dev_seek(const uint32_t addr);
void dev_rseek(const int16_t offset);
void dev_flush();
/** Sector buffer */
uint8_t buff[512];
/** Address of the buffered sector */
uint32_t buff_addr;
/** Buffer needs to be flushed before next read */
bool buff_dirty = false;
/** Buffer holds a valid sector */
bool buff_valid = false;
/** seek cursor */
uint32_t cursor_sec;
uint16_t cursor_offs;
/** Flush the buffer, if it's dirty */
void dev_flush()
{
if (buff_dirty)
{
store_sector();
buff_dirty = false;
}
}
void load_sector(const uint32_t addr)
{
// do not load if already loaded
if (buff_valid && buff_addr == addr)
{
return;
}
dev_flush();
// read entire sector
sd_read(addr, 0, buff, 0, 512);
buff_valid = true;
buff_addr = addr;
}
void store_sector()
{
// Do not store if not laoded.
if (!buff_dirty) return;
if (!buff_valid) return;
sd_write(buff_addr, buff);
}
/**
* Handle cursor overflow.
* MUST ABSOLUTELY NOT load/store buffer or change buffer addr!
*/
inline void handle_cursor_ov()
{
if (cursor_offs >= 512)
{
cursor_sec++;
cursor_offs = 0;
}
}
void dev_write(const uint8_t b)
{
load_sector(cursor_sec);
// dirty only if changed
if (buff[cursor_offs] != b)
{
buff[cursor_offs++] = b;
buff_dirty = true;
}
else
{
cursor_offs++;
}
handle_cursor_ov();
}
uint8_t dev_read()
{
load_sector(cursor_sec);
const uint8_t b = buff[cursor_offs++];
handle_cursor_ov();
return b;
}
void dev_load(void* dest, const uint16_t len)
{
for (uint16_t a = 0; a < len; a++)
{
*((uint8_t*)dest++) = dev_read();
}
}
void dev_store(const void* src, const uint16_t len)
{
for (uint16_t a = 0; a < len; a++)
{
dev_write(*((uint8_t*)src++));
}
}
void dev_seek(const uint32_t addr)
{
// compute sector and offset counters
cursor_sec = addr >> 9;
cursor_offs = addr & 0x1FF;
}
void dev_rseek(const int16_t offset)
{
// add WITHIN the same sector
if (offset > 0 && cursor_offs + offset < 512)
{
cursor_offs += offset;
return;
}
// subtract WITHIN the same sector
if (offset < 0 && ((uint16_t)(-offset) <= cursor_offs))
{
cursor_offs += offset;
return;
}
// abs addr change
dev_seek(((cursor_sec << 9) + cursor_offs) + offset);
}
/** Init SD card block device */
bool sdb_init(BLOCKDEV* dev)
{
if (!sd_init()) return false;
dev->load = &dev_load;
dev->store = &dev_store;
dev->read = &dev_read;
dev->write = &dev_write;
dev->seek = &dev_seek;
dev->rseek = &dev_rseek;
dev->flush = &dev_flush;
return true;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "blockdev.h"
#include <stdbool.h>
/** Initialize the SD card block device */
bool sdb_init(BLOCKDEV* dev);
+67
View File
@@ -0,0 +1,67 @@
#include <stdint.h>
#include <stdbool.h>
#include "sd_blockdev.h"
#include "sd_fat.h"
#include "fat16.h"
FAT16 _fat;
BLOCKDEV _dev;
static STREAM _s;
STREAM* sdf_stream = &_s;
FFILE* stream_file;
bool stream_active = false;
void stream_tx(uint8_t b)
{
if (!stream_active) return;
ff_write(stream_file, &b, 1);
}
uint8_t stream_rx()
{
if (!stream_active) return 0;
uint8_t b;
ff_read(stream_file, &b, 1);
return b;
}
void sdf_open_stream(FFILE* file)
{
stream_active = true;
stream_file = file;
}
bool sdfat_inited = false;
bool sdf_init()
{
if (sdfat_inited) return true;
sdfat_inited = true;
if (!sdb_init(&_dev)) return false;
if (!ff_init(&_dev, &_fat)) return false;
sdf_stream->rx = &stream_rx;
sdf_stream->tx = &stream_tx;
return true;
}
void sdf_root(FFILE* file)
{
ff_root(&_fat, file);
}
void sdf_disk_label(char* str)
{
ff_disk_label(&_fat, str);
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
//
// FAT-on-SD helpers.
//
// This can be used for convenience, as it does all the init for you
// and hides the implementation. All regular ff_* functions will work on the FFILE.
//
#include <stdint.h>
#include "fat16.h"
#include "stream.h"
/** Initialize FAT16 filesystem on a SPI-connected SD card */
bool sdf_init();
/** Get first file of the root folder. */
void sdf_root(FFILE* file);
/** Get a disk label. Str should have 12 chars. */
void sdf_disk_label(char* str);
extern STREAM* sdf_stream;
/**
* Open a stream for a file. There can be only one stream at a time.
*
* The stream will operate at the current file's cursor, just like
* ff_read and ff_write.
*/
void sdf_open_stream(FFILE* file);
+83
View File
@@ -0,0 +1,83 @@
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "sipo_pwm.h"
#include "iopins.h"
#include "sipo_pwm_config.h"
/* -------- SIPO PWM MODULE ---------- */
/** Buffer for sending bits to SIPO */
bool _buff[SPWM_CHANNELS];
uint8_t spwm_levels[SPWM_CHANNELS];
/** Send _buff to SIPO */
void _send_buffer()
{
for (int8_t i = SPWM_CHANNELS - 1; i >= 0; i--)
{
#if (SPWM_INVERT)
set_pin(SPWM_DATA, !_buff[i]); /* Common anode */
#else
set_pin(SPWM_DATA, _buff[i]); /* Common cathode */
#endif
// send a CLK pulse
pin_high(SPWM_CLK);
pin_low(SPWM_CLK);
}
// send a STR pulse
pin_high(SPWM_STR);
pin_low(SPWM_STR);
}
void spwm_init()
{
// Pin directions
as_output(SPWM_CLK);
as_output(SPWM_STR);
as_output(SPWM_DATA);
// Initial states
pin_low(SPWM_CLK);
pin_low(SPWM_STR);
}
/**
* Display PWM channels.
* This could be called in a Timer ISR.
*/
void spwm_send()
{
// Set all bits to 1 (if their PWM level is 0, set to 0)
for (uint8_t bit = 0; bit < SPWM_CHANNELS; bit++)
{
_buff[bit] = (bool) spwm_levels[bit];
}
// Show initial state
_send_buffer();
// For each PWM level...
for (uint16_t pwm = 0; pwm < SPWM_COLOR_DEPTH; pwm++)
{
// Turn OFF bits that are below the level
for (uint8_t bit = 0; bit < SPWM_CHANNELS; bit++)
{
if (spwm_levels[bit] < pwm)
{
_buff[bit] = 0;
}
}
// And show...
_send_buffer();
}
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
// --- SIPO PWM Module ---
//
// SIPO = shift register with paralel output.
//
// This module lets you use SIPO outputs as a "software PWM".
//
// Tested to work on 74hc4094 and 74hc595
#include <stdint.h>
// Your file with configs
#include "sipo_pwm_config.h"
/*
// --- PWM pin aliases ---
// Store signal
#define SPWM_STR D2
// Shift/clock signal
#define SPWM_CLK D3
// Data signal
#define SPWM_DATA D4
// --- Other settings ---
// Number of PWM levels (color depth)
#define SPWM_COLOR_DEPTH 256
// Number of SIPO channels
#define SPWM_CHANNELS 24
// Invert outputs (for Common Anode LEDs)
#define SPWM_INVERT 1
*/
// Array for setting PWM levels (PWM_CHANNELS-long)
extern uint8_t spwm_levels[SPWM_CHANNELS];
/** Configure output pins etc */
void spwm_init();
/** Perform one PWM cycle.
* This should be called in a Timer ISR or a loop.
*/
void spwm_send();

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