11 Commits
84 changed files with 6003 additions and 186 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
+8 -2
View File
@@ -1,3 +1,9 @@
**This library is very old and unmaintained.**
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.
---
# "porklib", MightyPork's Arduino Library # "porklib", MightyPork's Arduino Library
This library aims to make development for AVR in C easy and fun. This library aims to make development for AVR in C easy and fun.
@@ -12,12 +18,12 @@ Pull requests to add new modules are welcome, please go ahead!
## Makefile ## Makefile
You can use the provided Makefile to boild your project with this library. 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 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). library headers request it (those define eg. IO pin mapping).
Adjust the Makefile to yoru needs! Adjust the Makefile to your needs!
## License ## License
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 Those examples should work, but they are mostly just a reference on how to
use different parts of the library. use different parts of the library.
To try to build and flash an example, first change the `MAIN` field in the Makefile Makefiles in the directories should work, but may be outdated. Please
to it's name. use `Makefile.example` for new projects.
Some more examples can be found in repo `MightyPork/avr-projects`
+3 -1
View File
@@ -30,12 +30,14 @@ LIB_DIR = lib/
# C files in the library directory # 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 LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# Extra Files that need config file: # C files that need aconfig file - uncomment when needed, but also add the configs!
#LIB_C_FILES += lcd.c #LIB_C_FILES += lcd.c
#LIB_C_FILES += sipo_pwm.c
#LIB_C_FILES += color.c wsrgb.c #LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.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 = 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 LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
+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);
}
}
+147
View File
@@ -0,0 +1,147 @@
## === 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:
# 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
+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))))
+95
View File
@@ -0,0 +1,95 @@
#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;
}
+55
View File
@@ -0,0 +1,55 @@
#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);
+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);
+678
View File
@@ -0,0 +1,678 @@
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "calc.h"
#include "uart.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();
void _vt_color_do();
void vt_goto(uint8_t x, uint8_t y)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, y+1); // one-based !
uart_tx(';');
put_u8(uart, x+1);
uart_tx('H');
}
void vt_goto_x(uint8_t x)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, x+1);
uart_tx('`');
}
void vt_goto_y(uint8_t y)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, y+1);
uart_tx('d');
}
void vt_move(int8_t x, int8_t y)
{
vt_move_x(x);
vt_move_y(y);
}
void vt_move_x(int8_t x)
{
if (x < 0) {
vt_left(-x);
} else {
vt_right(x);
}
}
void vt_move_y(int8_t y)
{
if (y < 0) {
vt_up(-y);
} else {
vt_down(y);
}
}
void vt_up(uint8_t y)
{
if (y == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, y);
uart_tx('A');
}
void vt_down(uint8_t y)
{
if (y == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, y);
uart_tx('B');
}
void vt_left(uint8_t x)
{
if (x == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, x);
uart_tx('D');
}
void vt_right(uint8_t x)
{
if (x == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, x);
uart_tx('C');
}
void vt_scroll(int8_t y)
{
while (y < 0) {
uart_tx(27);
uart_tx('D'); // up
y++;
}
while (y > 0) {
uart_tx(27);
uart_tx('M'); // down
y--;
}
}
void vt_scroll_set(uint8_t from, uint8_t to)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, from);
uart_tx(';');
put_u8(uart, to);
uart_tx('r');
}
void vt_scroll_reset()
{
uart_tx(27);
uart_tx('[');
uart_tx('r');
}
typedef struct {
uint8_t flags;
uint8_t fg;
uint8_t bg;
} vt_style_t;
vt_style_t saved_style;
vt_style_t current_style;
void vt_save()
{
uart_puts_P(PSTR("\x1B[s"));
saved_style = current_style;
}
void vt_restore()
{
uart_puts_P(PSTR("\x1B[u"));
current_style = saved_style;
}
/** Disable all text attributes (excluding color) */
void vt_attr_reset()
{
current_style.flags = 0;
_vt_reset_attribs_do();
_vt_apply_style();
}
/** Set color to white on black */
void vt_color_reset()
{
current_style.fg = VT_WHITE;
current_style.bg = VT_BLACK;
_vt_color_do();
}
/** Enable or disable a text attribute */
void vt_attr(uint8_t attribute, bool on)
{
// flags are powers of two
// so this can handle multiple OR'd flags
for(uint8_t c = 1; c <= VT_FAINT; c *= 2) {
if (attribute & c) {
if (on) {
current_style.flags |= c;
} else {
current_style.flags &= ~c;
}
}
}
_vt_apply_style();
}
/** Send style and color commands */
void _vt_apply_style()
{
_vt_reset_attribs_do();
_vt_style_do();
_vt_color_do();
}
/** Set color 0..7 */
void vt_color(uint8_t fg, uint8_t bg)
{
current_style.fg = fg;
current_style.bg = bg;
_vt_color_do();
}
/** Set FG color 0..7 */
void vt_color_fg(uint8_t fg)
{
current_style.fg = fg;
_vt_color_do();
}
/** Set BG color 0..7 */
void vt_color_bg(uint8_t bg)
{
current_style.bg = bg;
_vt_color_do();
}
/** Send reset command */
inline void _vt_reset_attribs_do()
{
uart_puts_P(PSTR("\x1B[m")); // reset
}
/** Send commands for text attribs */
void _vt_style_do()
{
if (current_style.flags & VT_BOLD) {
uart_puts_P(PSTR("\x1B[1m"));
}
if (current_style.flags & VT_FAINT) {
uart_puts_P(PSTR("\x1B[2m"));
}
if (current_style.flags & VT_ITALIC) {
uart_puts_P(PSTR("\x1B[3m"));
}
if (current_style.flags & VT_UNDERLINE) {
uart_puts_P(PSTR("\x1B[4m"));
}
if (current_style.flags & VT_BLINK) {
uart_puts_P(PSTR("\x1B[5m"));
}
if (current_style.flags & VT_REVERSE) {
uart_puts_P(PSTR("\x1B[7m"));
}
}
/** Send commands for xolor */
void _vt_color_do()
{
uart_tx(27);
uart_tx('[');
put_u8(uart, 30 + current_style.fg);
uart_tx(';');
put_u8(uart, 40 + current_style.bg);
uart_tx('m');
}
/** Insert blank lines febore the current line */
void vt_insert_lines(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('L');
}
/** Delete lines from the current line down */
void vt_delete_lines(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('M');
}
/** Insert empty characters at cursor */
void vt_insert_chars(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('@');
}
/** Delete characters at cursor */
void vt_delete_chars(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('P');
}
void vt_clear()
{
uart_puts_P(PSTR("\x1B[2J"));
}
void vt_erase_forth()
{
uart_puts_P(PSTR("\x1B[K"));
}
void vt_erase_back()
{
uart_puts_P(PSTR("\x1B[1K"));
}
void vt_erase_line()
{
uart_puts_P(PSTR("\x1B[2K"));
}
void vt_erase_above()
{
uart_puts_P(PSTR("\x1B[1J"));
}
void vt_erase_below()
{
uart_puts_P(PSTR("\x1B[J"));
}
void vt_home()
{
uart_puts_P(PSTR("\x1B[H"));
}
/** Initialize helper variables */
void vt_init()
{
vt_reset();
}
/** Reset state and clear screen */
void vt_reset()
{
// reset color and attributes
vt_color_reset();
vt_attr_reset();
vt_scroll_reset();
// clear screen
vt_clear();
// go to top left
vt_home();
// overwrite saved state
vt_save();
}
// Assigned keyhandler
void (*_vt_kh)(uint8_t, bool) = NULL;
/** Assign a key handler (later used with vt_handle_key) */
void vt_set_key_handler(void (*handler)(uint8_t, bool))
{
_vt_kh = handler;
}
// state machine states
typedef enum {
GROUND = 0,
ESC = 1,
BR = 2,
O = 3,
WAITING_TILDE = 4
} KSTATE;
// code received before started to wait for a tilde
uint8_t _before_wtilde;
// current state
KSTATE _kstate = GROUND;
void _vt_kh_abort()
{
switch (_kstate) {
case ESC:
_vt_kh(VK_ESC, true);
break;
case BR:
_vt_kh(VK_ESC, true);
_vt_kh('[', false);
break;
case O:
_vt_kh(VK_ESC, true);
_vt_kh('O', false);
break;
case WAITING_TILDE:
_vt_kh(VK_ESC, true);
_vt_kh('[', false);
vt_handle_key(_before_wtilde);
break;
case GROUND:
// nop
break;
}
_kstate = GROUND;
}
/**
* Handle a key received over UART
* Takes care of multi-byte keys and translates them to special
* constants.
*/
void vt_handle_key(uint8_t c)
{
if (_vt_kh == NULL) return;
switch (_kstate) {
case GROUND:
switch (c) {
case 27:
_kstate = ESC;
break;
case VK_ENTER:
case VK_TAB:
case VK_BACKSPACE:
_vt_kh(c, true);
return;
default:
_vt_kh(c, false);
return;
}
break; // continue to next char
case ESC:
switch (c) {
case '[':
_kstate = BR;
break; // continue to next char
case 'O':
_kstate = O;
break; // continue to next char
default:
// bad code
_vt_kh_abort();
vt_handle_key(c);
return;
}
break;
case BR:
switch (c) {
// arrows
case 65:
case 66:
case 67:
case 68:
_vt_kh(c, true);
_kstate = GROUND;
return;
// ins del pgup pgdn
case 50:
case 51:
case 53:
case 54:
// wait for terminating tilde
_before_wtilde = c;
_kstate = WAITING_TILDE;
break; // continue to next char
// bad key
default:
_vt_kh_abort();
vt_handle_key(c);
return;
}
break;
case O:
switch (c) {
// F keys
case 80:
case 81:
case 82:
case 83:
// home, end
case 72:
case 70:
_vt_kh(c, true);
_kstate = GROUND;
return;
// bad key
default:
_vt_kh_abort();
vt_handle_key(c);
return;
}
case WAITING_TILDE:
if (c != '~') {
_vt_kh_abort();
vt_handle_key(c);
return;
} else {
_vt_kh(_before_wtilde, true);
_kstate = GROUND;
return;
}
}
// wait for next key
if (_kstate != GROUND) {
_delay_ms(2);
if (!uart_rx_ready()) {
// abort receiving
_vt_kh_abort();
} else {
vt_handle_key(uart_rx());
}
}
}
+253
View File
@@ -0,0 +1,253 @@
#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
//
// To use this, first call uart_init(baud) and vt_init()
// To print stuff on the screen, use uart_puts() etc from uart.h
//
// INIT
/** Initialize helper variables */
void vt_init();
/** Reset state and clear screen */
void vt_reset();
// CURSOR MOVE
/** Move cursor to top left corner */
void vt_home();
/** Jump to a location on the screen */
void vt_goto(uint8_t x, uint8_t y);
/** Jump to given X, keep Y */
void vt_goto_x(uint8_t x);
/** Jump to given Y, keep X */
void vt_goto_y(uint8_t y);
/** Move cursor relative to current location */
void vt_move(int8_t x, int8_t y);
/** Move cursor horizontally */
void vt_move_x(int8_t x);
/** Move cursor vertically */
void vt_move_y(int8_t y);
/** Move cursor up y cells */
void vt_up(uint8_t y);
/** Move cursor down y cells */
void vt_down(uint8_t y);
/** Move cursor left x cells */
void vt_left(uint8_t x);
/** Move cursor right x cells */
void vt_right(uint8_t x);
// SCROLLING
/** Scroll y lines down (like up/down, but moves window if needed) */
void vt_scroll(int8_t down);
/** Set scrolling region (lines) */
void vt_scroll_set(uint8_t from, uint8_t to);
/** Sets scrolling region to the entire screen. */
void vt_scroll_reset();
// COLOR
#define VT_BLACK 0
#define VT_RED 1
#define VT_GREEN 2
#define VT_YELLOW 3
#define VT_BLUE 4
#define VT_MAGENTA 5
#define VT_CYAN 6
#define VT_WHITE 7
/** Set color 0..7 */
void vt_color(uint8_t fg, uint8_t bg);
/** Set FG color 0..7 */
void vt_color_fg(uint8_t fg);
/** Set BG color 0..7 */
void vt_color_bg(uint8_t bg);
/** Set color to white on black */
void vt_color_reset();
// STYLES
#define VT_BOLD 1
#define VT_UNDERLINE 2
#define VT_BLINK 4
#define VT_REVERSE 8
#define VT_ITALIC 16
#define VT_FAINT 32
/** Enable or disable a text attribute */
void vt_attr(uint8_t attribute, bool on);
/** Disable all text attributes (excluding color) */
void vt_attr_reset();
// SAVE & RESTORE
/** Save cursor position & text attributes */
void vt_save();
/** Restore cursor to saved values */
void vt_restore();
// MODIFY
/** Insert blank lines febore the current line */
void vt_insert_lines(uint8_t count);
/** Delete lines from the current line down */
void vt_delete_lines(uint8_t count);
/** Insert empty characters at cursor */
void vt_insert_chars(uint8_t count);
/** Delete characters at cursor */
void vt_delete_chars(uint8_t count);
// ERASING
/** Clear the screen */
void vt_clear();
/** Erase to the end of line */
void vt_erase_forth();
/** Erase line to cursor */
void vt_erase_back();
/** Erase entire line */
void vt_erase_line();
/** Erase screen below the line */
void vt_erase_above();
/** Erase screen above the line */
void vt_erase_below();
// KEY HANDLER
// Special keys from key handler
#define VK_LEFT 68
#define VK_RIGHT 67
#define VK_UP 65
#define VK_DOWN 66
#define VK_DELETE 51
#define VK_INSERT 50
#define VK_PGUP 53
#define VK_PGDN 54
#define VK_HOME 72
#define VK_END 70
#define VK_F1 80
#define VK_F2 81
#define VK_F3 82
#define VK_F4 83
#define VK_BACKSPACE 8
#define VK_TAB 9
#define VK_ENTER 13
#define VK_ESC 27
void vt_handle_key(uint8_t c);
void vt_set_key_handler(void (*handler)(uint8_t, bool));
+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);
}
}
+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
-1
View File
@@ -1 +0,0 @@
/home/ondra/elektro/avr-lib/lib
@@ -11,14 +11,14 @@ EFUSE = 0x05
## === Source files === ## === Source files ===
# Main C file # Main C file
MAIN = sonar_to_lcd.c MAIN = main.c
# Extra C files in this folder # Extra C files in this folder
LOCAL_SOURCE = LOCAL_SOURCE =
# Library directory (with C files) # Library directory (with C files)
EXTRA_SOURCE_DIR = lib/ EXTRA_SOURCE_DIR = lib/
# C files in the library directory # C files in the library directory
EXTRA_SOURCE_FILES = uart.c lcd.c sonar.c stream.c EXTRA_SOURCE_FILES = uart.c iopins.c stream.c onewire.c
## === Programmer === ## === Programmer ===
@@ -87,12 +87,6 @@ debug:
@echo @echo
flser: all flash serial
serial:
gtkterm -p /dev/ttyUSB0
# Disassemble the ELF # Disassemble the ELF
disassemble: $(TARGET).lst disassemble: $(TARGET).lst
dis: disassemble dis: disassemble
@@ -114,7 +108,7 @@ clean:
# Clean all trash # Clean all trash
purge: 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 === ## === avrdude ===
@@ -128,6 +122,10 @@ flashe: $(TARGET).eeprom
shell: shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
gtkterm -p /dev/ttyUSB0
# === fuses === # === 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
+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 <stdbool.h>
#include "lib/uart.h" #include "lib/uart.h"
#include "lib/arduino_pins.h"
#include "lib/sonar.h" #include "lib/sonar.h"
#include "lib/stream.h" #include "lib/stream.h"
@@ -73,7 +72,6 @@ void main()
int16_t res = sonar_result; int16_t res = sonar_result;
// Print // Print
if (res < 0) { if (res < 0) {
put_str(uart, "NO OBSTACLES\r\n"); 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/pgmspace.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include "lib/meta.h"
#include "lib/uart.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
@@ -10,10 +10,7 @@
// Example of asynchronous UART key handling // Example of asynchronous UART key handling
// //
// It recognizes special keys like arrows and some F keys, // It recognizes special keys like arrows and some F keys,
// check the header file for full list. // check uart.h file for full list.
//
// You need uart_ansi for this.
//
ISR(USART_RX_vect) ISR(USART_RX_vect)
{ {
@@ -27,8 +24,8 @@ ISR(USART_RX_vect)
void key_handler(uint8_t code, bool special) void key_handler(uint8_t code, bool special)
{ {
put_str_P(uart, special ? PSTR("Special: ") : PSTR("Char: ")); put_str_P(uart, special ? PSTR("Special: ") : PSTR("Char: "));
put_char(uart, code); // the actual character put_c(uart, code); // the actual character
put_char(uart, ' '); // space put_c(uart, ' '); // space
put_u8(uart, code); // as number put_u8(uart, code); // as number
put_nl(uart); // crlf 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 <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "lib/uart.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 <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "lib/uart.h" #include "lib/uart.h"
#include "lib/stream.h" #include "lib/stream.h"
+1
View File
@@ -1,5 +1,6 @@
#include <avr/io.h> #include <avr/io.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "calc.h" #include "calc.h"
#include "adc.h" #include "adc.h"
+1
View File
@@ -5,6 +5,7 @@
// //
#include <avr/io.h> #include <avr/io.h>
#include <stdint.h>
/** Initialize the ADC */ /** Initialize the ADC */
void adc_init(); void adc_init();
+12
View File
@@ -50,5 +50,17 @@ typedef struct
*/ */
void (*rseek)(const int16_t offset); 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; } BLOCKDEV;
+2
View File
@@ -4,6 +4,8 @@
// Bit and byte manipulation utilities // Bit and byte manipulation utilities
// //
#include <stdint.h>
// --- Increment in range --- // --- Increment in range ---
// when overflown, wraps within range. Lower bound < upper bound. // when overflown, wraps within range. Lower bound < upper bound.
+1
View File
@@ -29,6 +29,7 @@
#include <avr/io.h> #include <avr/io.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "calc.h" #include "calc.h"
#include "iopins.h" #include "iopins.h"
+124 -75
View File
@@ -24,7 +24,7 @@ uint16_t next_clu(const FAT16* fat, uint16_t cluster);
uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr); uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr);
/** Read a file entry from directory (dir starting cluster, entry number) */ /** Read a file entry from directory (dir starting cluster, entry number) */
void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num); void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num);
/** Allocate and chain new cluster to a chain starting at given cluster */ /** Allocate and chain new cluster to a chain starting at given cluster */
bool append_cluster(const FAT16* fat, const uint16_t clu); bool append_cluster(const FAT16* fat, const uint16_t clu);
@@ -42,7 +42,7 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu);
* Check if there is already a file of given RAW name * Check if there is already a file of given RAW name
* Raw name - name as found on disk, not "display name". * Raw name - name as found on disk, not "display name".
*/ */
bool dir_find_file_raw(FAT16_FILE* dir, const char* fname); bool dir_find_file_raw(FFILE* dir, const char* fname);
/** Write a value into FAT */ /** Write a value into FAT */
void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value); void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value);
@@ -276,10 +276,10 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu)
* Check if there is already a file of given RAW name * Check if there is already a file of given RAW name
* Raw name - name as found on disk, not "display name". * Raw name - name as found on disk, not "display name".
*/ */
bool dir_find_file_raw(FAT16_FILE* dir, const char* fname) bool dir_find_file_raw(FFILE* dir, const char* fname)
{ {
// rewind // rewind
fat16_first(dir); ff_first(dir);
do do
{ {
@@ -299,7 +299,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
return true; // file is already open. return true; // file is already open.
} }
} }
while (fat16_next(dir)); while (ff_next(dir));
return false; return false;
} }
@@ -311,7 +311,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
* dir_cluster ... directory start cluster * dir_cluster ... directory start cluster
* num ... entry number in the directory * num ... entry number in the directory
*/ */
void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num) void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num)
{ {
// Resolve starting address // Resolve starting address
uint32_t addr; uint32_t addr;
@@ -397,7 +397,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
} }
// Init cursors // Init cursors
fat16_seek(file, 0); ff_seek(file, 0);
} }
@@ -406,7 +406,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
* Write information into a file header. * Write information into a file header.
* "file" is an open handle. * "file" is an open handle.
*/ */
void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start) void write_file_header(FFILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start)
{ {
const BLOCKDEV* dev = file->fat->dev; const BLOCKDEV* dev = file->fat->dev;
@@ -442,7 +442,7 @@ void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t at
// =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= // =============== PUBLIC FUNCTION IMPLEMENTATIONS =================
/** Initialize a FAT16 handle */ /** Initialize a FAT16 handle */
bool fat16_init(const BLOCKDEV* dev, FAT16* fat) bool ff_init(const BLOCKDEV* dev, FAT16* fat)
{ {
const uint32_t bs_a = find_bs(dev); const uint32_t bs_a = find_bs(dev);
@@ -464,7 +464,7 @@ bool fat16_init(const BLOCKDEV* dev, FAT16* fat)
* Move file cursor to a position relative to file start * Move file cursor to a position relative to file start
* Allows seek past end of file, will allocate new cluster if needed. * Allows seek past end of file, will allocate new cluster if needed.
*/ */
bool fat16_seek(FAT16_FILE* file, uint32_t addr) bool ff_seek(FFILE* file, uint32_t addr)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
@@ -512,7 +512,7 @@ bool fat16_seek(FAT16_FILE* file, uint32_t addr)
* Check if file is a regular file or directory entry. * Check if file is a regular file or directory entry.
* Those files can be shown to user. * Those files can be shown to user.
*/ */
bool fat16_is_regular(const FAT16_FILE* file) bool ff_is_regular(const FFILE* file)
{ {
switch (file->type) switch (file->type)
{ {
@@ -530,7 +530,7 @@ bool fat16_is_regular(const FAT16_FILE* file)
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len) uint16_t ff_read(FFILE* file, void* target, uint16_t len)
{ {
if (file->cur_abs == 0xFFFF) if (file->cur_abs == 0xFFFF)
return 0; // file at the end already return 0; // file at the end already
@@ -580,14 +580,23 @@ uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len)
} }
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len) bool ff_write_str(FFILE* file, const char* source)
{
uint16_t len = 0;
for (; source[len] != 0; len++);
return ff_write(file, source, len);
}
bool ff_write(FFILE* file, const void* source, uint32_t len)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
if (file->cur_abs == 0xFFFF) if (file->cur_abs == 0xFFFF)
return false; // file at the end already return false; // file past it's end (rare)
// Attempt to write past end of file // Attempt to write past end of file
if (file->cur_rel + len >= file->size) if (file->cur_rel + len >= file->size)
@@ -596,14 +605,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
// Seek to the last position // Seek to the last position
// -> fseek will allocate clusters // -> fseek will allocate clusters
if (!fat16_seek(file, pos_start + len)) if (!ff_seek(file, pos_start + len))
return false; // error in seek return false; // error in seek
// Write starts beyond EOF - creating a zero-filled "hole" // Write starts beyond EOF - creating a zero-filled "hole"
if (file->cur_rel > file->size) if (pos_start > file->size + 1)
{ {
// Seek to the end of valid data // Seek to the end of valid data
fat16_seek(file, file->size); ff_seek(file, file->size);
// fill space between EOF and start-of-write with zeros // fill space between EOF and start-of-write with zeros
uint32_t fill = pos_start - file->size; uint32_t fill = pos_start - file->size;
@@ -631,22 +640,34 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
} }
} }
// Save new size // Store new size
fat16_resize(file, pos_start + len); file->size = pos_start + len;
// Seek back to where it was before // Seek back to where it was before
fat16_seek(file, pos_start); ff_seek(file, pos_start);
} // (end zerofill) } // (end zerofill)
// write the data // write the data
while (len > 0) while (len > 0)
{ {
// How much can be stored in this cluster
const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len);
// store the chunk
dev->seek(file->cur_abs); dev->seek(file->cur_abs);
uint16_t chunk;
if (len == 1)
{
dev->write(*((uint8_t*)source));
file->cur_abs++;
file->cur_rel++;
file->cur_ofs++;
chunk = 1;
}
else
{
// How much can be stored in this cluster
chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len);
dev->store(source, chunk); dev->store(source, chunk);
// advance cursors // advance cursors
@@ -656,6 +677,7 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
// Pointer arith! // Pointer arith!
source += chunk; // advance the source pointer source += chunk; // advance the source pointer
}
// detect cluster overflow // detect cluster overflow
if (file->cur_ofs >= fat->bs.bytes_per_cluster) if (file->cur_ofs >= fat->bs.bytes_per_cluster)
@@ -676,7 +698,7 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
/** Open next file in the directory */ /** Open next file in the directory */
bool fat16_next(FAT16_FILE* file) bool ff_next(FFILE* file)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
@@ -700,7 +722,7 @@ bool fat16_next(FAT16_FILE* file)
/** Open previous file in the directory */ /** Open previous file in the directory */
bool fat16_prev(FAT16_FILE* file) bool ff_prev(FFILE* file)
{ {
if (file->num == 0) if (file->num == 0)
return false; // first file already return false; // first file already
@@ -712,14 +734,14 @@ bool fat16_prev(FAT16_FILE* file)
/** Rewind to first file in directory */ /** Rewind to first file in directory */
void fat16_first(FAT16_FILE* file) void ff_first(FFILE* file)
{ {
open_file(file->fat, file, file->clu, 0); open_file(file->fat, file, file->clu, 0);
} }
/** Open a directory denoted by the file. */ /** Open a directory denoted by the file. */
bool fat16_opendir(FAT16_FILE* dir) bool ff_opendir(FFILE* dir)
{ {
// Don't open non-dirs and "." directory. // Don't open non-dirs and "." directory.
if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF) if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF)
@@ -730,7 +752,7 @@ bool fat16_opendir(FAT16_FILE* dir)
} }
void fat16_root(const FAT16* fat, FAT16_FILE* file) void ff_root(const FAT16* fat, FFILE* file)
{ {
open_file(fat, file, 0, 0); open_file(fat, file, 0, 0);
} }
@@ -739,18 +761,25 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file)
/** /**
* Find a file with given "display name" in this directory. * Find a file with given "display name" in this directory.
* If file is found, "dir" will contain it's handle. * If file is found, "dir" will contain it's handle.
* Either way, "dir" gets modified and you may need to rewind it afterwards.
*/ */
bool fat16_find(FAT16_FILE* dir, const char* name) bool ff_find(FFILE* file, const char* name)
{ {
// save orig pos
FSAVEPOS orig = ff_savepos(file);
char fname[11]; char fname[11];
fat16_rawname(name, fname); ff_rawname(name, fname);
return dir_find_file_raw(dir, fname); bool ret = dir_find_file_raw(file, fname);
if (!ret)
ff_reopen(file, &orig);
return ret;
} }
/** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */ /** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */
bool find_empty_file_slot(FAT16_FILE* file) bool find_empty_file_slot(FFILE* file)
{ {
const uint16_t clu = file->clu; const uint16_t clu = file->clu;
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
@@ -795,21 +824,29 @@ bool find_empty_file_slot(FAT16_FILE* file)
bool fat16_mkfile(FAT16_FILE* file, const char* name) bool ff_newfile(FFILE* file, const char* name)
{ {
const FSAVEPOS orig = ff_savepos(file);
// Convert filename to zero padded raw string // Convert filename to zero padded raw string
char fname[11]; char fname[11];
fat16_rawname(name, fname); ff_rawname(name, fname);
// Abort if file already exists // Abort if file already exists
bool exists = dir_find_file_raw(file, fname); bool exists = dir_find_file_raw(file, fname);
fat16_first(file); // rewind dir ff_first(file); // rewind dir
if (exists) if (exists)
{
ff_reopen(file, &orig);
return false; // file already exists in the dir. return false; // file already exists in the dir.
}
if (!find_empty_file_slot(file)) if (!find_empty_file_slot(file))
{
ff_reopen(file, &orig);
return false; // error finding a slot return false; // error finding a slot
}
// Write into the new slot // Write into the new slot
const uint16_t newclu = alloc_cluster(file->fat); const uint16_t newclu = alloc_cluster(file->fat);
@@ -823,21 +860,28 @@ bool fat16_mkfile(FAT16_FILE* file, const char* name)
* Create a sub-directory of given name. * Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".." * Directory is allocated and populated with entries "." and ".."
*/ */
bool fat16_mkdir(FAT16_FILE* file, const char* name) bool ff_mkdir(FFILE* file, const char* name)
{ {
const FSAVEPOS orig = ff_savepos(file);
// Convert filename to zero padded raw string // Convert filename to zero padded raw string
char fname[11]; char fname[11];
fat16_rawname(name, fname); ff_rawname(name, fname);
// Abort if file already exists // Abort if file already exists
bool exists = dir_find_file_raw(file, fname); bool exists = dir_find_file_raw(file, fname);
fat16_first(file); // rewind dir ff_first(file); // rewind dir
if (exists) if (exists)
{
ff_reopen(file, &orig);
return false; // file already exusts in the dir. return false; // file already exusts in the dir.
}
if (!find_empty_file_slot(file)) if (!find_empty_file_slot(file))
{
ff_reopen(file, &orig);
return false; // error finding a slot return false; // error finding a slot
}
// Write into the new slot // Write into the new slot
const uint16_t newclu = alloc_cluster(file->fat); const uint16_t newclu = alloc_cluster(file->fat);
@@ -854,20 +898,20 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name)
write_file_header(file, ".. ", FA_DIR, parent_clu); write_file_header(file, ".. ", FA_DIR, parent_clu);
// rewind. // rewind.
fat16_first(file); ff_first(file);
return true; return true;
} }
char* fat16_disk_label(const FAT16* fat, char* label_out) char* ff_disk_label(const FAT16* fat, char* label_out)
{ {
FAT16_FILE first; FFILE first;
fat16_root(fat, &first); ff_root(fat, &first);
if (first.type == FT_LABEL) if (first.type == FT_LABEL)
{ {
return fat16_dispname(&first, label_out); return ff_dispname(&first, label_out);
} }
// find where spaces end // find where spaces end
@@ -890,7 +934,7 @@ char* fat16_disk_label(const FAT16* fat, char* label_out)
} }
char* fat16_dispname(const FAT16_FILE* file, char* disp_out) char* ff_dispname(const FFILE* file, char* disp_out)
{ {
// Cannot get name for special files // Cannot get name for special files
if (file->type == FT_NONE || // not-yet-used directory location if (file->type == FT_NONE || // not-yet-used directory location
@@ -940,7 +984,7 @@ char* fat16_dispname(const FAT16_FILE* file, char* disp_out)
} }
char* fat16_rawname(const char* disp_in, char* raw_out) char* ff_rawname(const char* disp_in, char* raw_out)
{ {
uint8_t name_c = 0, wr_c = 0; uint8_t name_c = 0, wr_c = 0;
bool filling = false; bool filling = false;
@@ -1014,7 +1058,7 @@ char* fat16_rawname(const char* disp_in, char* raw_out)
} }
FSAVEPOS fat16_savepos(const FAT16_FILE* file) FSAVEPOS ff_savepos(const FFILE* file)
{ {
FSAVEPOS fsp; FSAVEPOS fsp;
fsp.clu = file->clu; fsp.clu = file->clu;
@@ -1024,28 +1068,31 @@ FSAVEPOS fat16_savepos(const FAT16_FILE* file)
} }
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos) void ff_reopen(FFILE* file, const FSAVEPOS* pos)
{ {
open_file(file->fat, file, pos->clu, pos->num); open_file(file->fat, file, pos->clu, pos->num);
fat16_seek(file, pos->cur_rel); ff_seek(file, pos->cur_rel);
} }
/** Write new file size (also to the disk). Does not allocate clusters. */ void ff_flush_file(FFILE* file)
void fat16_resize(FAT16_FILE* file, uint32_t size)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = file->fat->dev; const BLOCKDEV* dev = file->fat->dev;
// Store open page
dev->flush();
// Store file size
// Find address for storing the size // Find address for storing the size
const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28); const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28);
file->size = size;
dev->seek(addr); dev->seek(addr);
dev->store(&size, 4); dev->store(&(file->size), 4);
// Seek to the end of the file, to make sure clusters are allocated // Seek to the end of the file, to make sure clusters are allocated
fat16_seek(file, size - 1); ff_seek(file, file->size - 1);
const uint16_t next = next_clu(fat, file->cur_clu); const uint16_t next = next_clu(fat, file->cur_clu);
if (next != 0xFFFF) if (next != 0xFFFF)
@@ -1057,8 +1104,10 @@ void fat16_resize(FAT16_FILE* file, uint32_t size)
} }
} }
/** Low level no-check file delete and free */ /** Low level no-check file delete and free */
void delete_file_do(FAT16_FILE* file) void delete_file_do(FFILE* file)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
@@ -1080,7 +1129,7 @@ void delete_file_do(FAT16_FILE* file)
/** Delete a simple file */ /** Delete a simple file */
bool fat16_rmfile(FAT16_FILE* file) bool ff_rmfile(FFILE* file)
{ {
switch (file->type) switch (file->type)
{ {
@@ -1099,15 +1148,15 @@ bool fat16_rmfile(FAT16_FILE* file)
/** Delete an empty directory */ /** Delete an empty directory */
bool fat16_rmdir(FAT16_FILE* file) bool ff_rmdir(FFILE* file)
{ {
if (file->type != FT_SUBDIR) if (file->type != FT_SUBDIR)
return false; // not a subdirectory entry return false; // not a subdirectory entry
const FSAVEPOS orig = fat16_savepos(file); const FSAVEPOS orig = ff_savepos(file);
// Open the subdir // Open the subdir
if (!fat16_opendir(file)) if (!ff_opendir(file))
return false; // could not open return false; // could not open
// Look for valid files and subdirs in the directory // Look for valid files and subdirs in the directory
@@ -1124,16 +1173,16 @@ bool fat16_rmdir(FAT16_FILE* file)
{ {
// Valid child file was found, aborting. // Valid child file was found, aborting.
// reopen original file // reopen original file
fat16_reopen(file, &orig); ff_reopen(file, &orig);
return false; return false;
} }
if (cnt < 2) cnt++; if (cnt < 2) cnt++;
} }
while (fat16_next(file)); while (ff_next(file));
// reopen original file // reopen original file
fat16_reopen(file, &orig); ff_reopen(file, &orig);
// and delete as ordinary file // and delete as ordinary file
delete_file_do(file); delete_file_do(file);
@@ -1142,7 +1191,7 @@ bool fat16_rmdir(FAT16_FILE* file)
} }
bool fat16_delete(FAT16_FILE* file) bool ff_delete(FFILE* file)
{ {
switch (file->type) switch (file->type)
{ {
@@ -1153,7 +1202,7 @@ bool fat16_delete(FAT16_FILE* file)
case FT_SUBDIR:; // semicolon needed to allow declaration after "case" case FT_SUBDIR:; // semicolon needed to allow declaration after "case"
// store original file location // store original file location
const FSAVEPOS orig = fat16_savepos(file); const FSAVEPOS orig = ff_savepos(file);
// open the directory (skip "." and "..") // open the directory (skip "." and "..")
open_file(file->fat, file, file->clu_start, 2); open_file(file->fat, file, file->clu_start, 2);
@@ -1161,32 +1210,32 @@ bool fat16_delete(FAT16_FILE* file)
// delete all children // delete all children
do do
{ {
if (!fat16_delete(file)) if (!ff_delete(file))
{ {
// failure // failure
// reopen original file // reopen original file
fat16_reopen(file, &orig); ff_reopen(file, &orig);
return false; return false;
} }
} }
while (fat16_next(file)); while (ff_next(file));
// go up and delete the dir // go up and delete the dir
fat16_reopen(file, &orig); ff_reopen(file, &orig);
return fat16_rmdir(file); return ff_rmdir(file);
default: default:
// try to delete as a regular file // try to delete as a regular file
return fat16_rmfile(file); return ff_rmfile(file);
} }
} }
bool fat16_parent(FAT16_FILE* file) bool ff_parent(FFILE* file)
{ {
// open second entry of the directory // open second entry of the directory
open_file(file->fat, file, file->clu, 1); open_file(file->fat, file, file->clu, 1);
const FSAVEPOS orig = fat16_savepos(file); const FSAVEPOS orig = ff_savepos(file);
// if it's a valid PARENT link, follow it. // if it's a valid PARENT link, follow it.
if (file->type == FT_PARENT) if (file->type == FT_PARENT)
@@ -1198,7 +1247,7 @@ bool fat16_parent(FAT16_FILE* file)
{ {
// in root already? // in root already?
// reopen original file // reopen original file
fat16_reopen(file, &orig); ff_reopen(file, &orig);
return false; return false;
} }
} }
+40 -28
View File
@@ -99,24 +99,31 @@ typedef struct __attribute__((packed))
// Pointer to the FAT16 handle. (internal) // Pointer to the FAT16 handle. (internal)
const FAT16* fat; const FAT16* fat;
} }
FAT16_FILE; 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. * Save a file "position" into a struct, for later restoration.
* Cursor is also saved. * Cursor is also saved.
*/ */
FSAVEPOS fat16_savepos(const FAT16_FILE* file); FSAVEPOS ff_savepos(const FFILE* file);
/** /**
* Restore a file from a saved position. * Restore a file from a saved position.
*/ */
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos); void ff_reopen(FFILE* file, const FSAVEPOS* pos);
/** /**
* Initialize the file system - store into "fat" * Initialize the file system - store into "fat"
*/ */
bool fat16_init(const BLOCKDEV* dev, FAT16* fat); bool ff_init(const BLOCKDEV* dev, FAT16* fat);
/** /**
@@ -124,7 +131,7 @@ bool fat16_init(const BLOCKDEV* dev, FAT16* fat);
* The file may be invalid (eg. a volume label, deleted etc), * The file may be invalid (eg. a volume label, deleted etc),
* or blank (type FT_NONE) if the filesystem is empty. * or blank (type FT_NONE) if the filesystem is empty.
*/ */
void fat16_root(const FAT16* fat, FAT16_FILE* file); void ff_root(const FAT16* fat, FFILE* file);
/** /**
@@ -134,7 +141,7 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file);
* @param fat the FAT handle * @param fat the FAT handle
* @param label_out string to store the label in. Should have at least 12 bytes. * @param label_out string to store the label in. Should have at least 12 bytes.
*/ */
char* fat16_disk_label(const FAT16* fat, char* label_out); char* ff_disk_label(const FAT16* fat, char* label_out);
// ----------- FILE I/O ------------- // ----------- FILE I/O -------------
@@ -144,21 +151,26 @@ char* fat16_disk_label(const FAT16* fat, char* label_out);
* Move file cursor to a position relative to file start * Move file cursor to a position relative to file start
* Returns false on I/O error (bad file, out of range...) * Returns false on I/O error (bad file, out of range...)
*/ */
bool fat16_seek(FAT16_FILE* file, uint32_t addr); bool ff_seek(FFILE* file, uint32_t addr);
/** /**
* Read bytes from file into memory * Read bytes from file into memory
* Returns number of bytes read, 0 on error. * Returns number of bytes read, 0 on error.
*/ */
uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len); uint16_t ff_read(FFILE* file, void* target, uint16_t len);
/** /**
* Write into file at a "seek" position. * Write into file at a "seek" position.
* "seek" cursor must be within (0..filesize)
*/ */
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len); 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);
/** /**
@@ -167,14 +179,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len);
* file ... open directory; new file is opened into this handle. * file ... open directory; new file is opened into this handle.
* name ... name of the new file, including extension * name ... name of the new file, including extension
*/ */
bool fat16_mkfile(FAT16_FILE* file, const char* name); bool ff_newfile(FFILE* file, const char* name);
/** /**
* Create a sub-directory of given name. * Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".." * Directory is allocated and populated with entries "." and ".."
*/ */
bool fat16_mkdir(FAT16_FILE* file, const char* name); bool ff_mkdir(FFILE* file, const char* name);
/** /**
@@ -183,26 +195,26 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name);
* *
* Useful mainly for shrinking. * Useful mainly for shrinking.
*/ */
void fat16_resize(FAT16_FILE* file, uint32_t size); void set_file_size(FFILE* file, uint32_t size);
/** /**
* Delete a *FILE* and free it's clusters. * Delete a *FILE* and free it's clusters.
*/ */
bool fat16_rmfile(FAT16_FILE* file); bool ff_rmfile(FFILE* file);
/** /**
* Delete an empty *DIRECTORY* and free it's clusters. * Delete an empty *DIRECTORY* and free it's clusters.
*/ */
bool fat16_rmdir(FAT16_FILE* file); bool ff_rmdir(FFILE* file);
/** /**
* Delete a file or directory, even FT_LFN and FT_INVALID. * Delete a file or directory, even FT_LFN and FT_INVALID.
* Directories are deleted recursively (!) * Directories are deleted recursively (!)
*/ */
bool fat16_delete(FAT16_FILE* file); bool ff_delete(FFILE* file);
@@ -210,55 +222,55 @@ bool fat16_delete(FAT16_FILE* file);
/** Go to previous file in the directory (false = no prev file) */ /** Go to previous file in the directory (false = no prev file) */
bool fat16_prev(FAT16_FILE* file); bool ff_prev(FFILE* file);
/** Go to next file in directory (false = no next file) */ /** Go to next file in directory (false = no next file) */
bool fat16_next(FAT16_FILE* file); bool ff_next(FFILE* file);
/** /**
* Open a subdirectory denoted by the file. * Open a subdirectory denoted by the file.
* Provided handle changes to the first entry of the directory. * Provided handle changes to the first entry of the directory.
*/ */
bool fat16_opendir(FAT16_FILE* dir); bool ff_opendir(FFILE* dir);
/** /**
* Open a parent directory. Fails in root. * Open a parent directory. Fails in root.
* Provided handle changes to the first entry of the parent directory. * Provided handle changes to the first entry of the parent directory.
*/ */
bool fat16_parent(FAT16_FILE* file); bool ff_parent(FFILE* file);
/** Jump to first file in this directory */ /** Jump to first file in this directory */
void fat16_first(FAT16_FILE* file); void ff_first(FFILE* file);
/** /**
* Find a file with given "display name" in this directory. * Find a file with given "display name" in this directory, and open it.
* If file is found, "dir" will contain it's handle. * If file is found, "file" will contain it's handle.
* If file is NOT found, the handle points to the last entry of the directory. * Otherwise, the handle is unchanged.
*/ */
bool fat16_find(FAT16_FILE* dir, const char* name); bool ff_find(FFILE* file, const char* name);
// -------- FILE INSPECTION ----------- // -------- FILE INSPECTION -----------
/** Check if file is a valid entry, or long-name/label/deleted */ /** Check if file is a valid entry, or long-name/label/deleted */
bool fat16_is_regular(const FAT16_FILE* file); bool ff_is_regular(const FFILE* file);
/** /**
* Resolve a file name, trim spaces and add null terminator. * Resolve a file name, trim spaces and add null terminator.
* Returns the passed char*, or NULL on error. * Returns the passed char*, or NULL on error.
*/ */
char* fat16_dispname(const FAT16_FILE* file, char* disp_out); char* ff_dispname(const FFILE* file, char* disp_out);
/** /**
* Convert filename to zero-padded fixed length one * Convert filename to zero-padded fixed length one
* Returns the passed char*. * Returns the passed char*.
*/ */
char* fat16_rawname(const char* disp_in, char* raw_out); char* ff_rawname(const char* disp_in, char* raw_out);
-2
View File
@@ -15,8 +15,6 @@
#include "iopins.h" #include "iopins.h"
#include "spi.h" #include "spi.h"
#include "uart.h"
#include "stream.h"
/** Init SD card on SPI */ /** Init SD card on SPI */
bool sd_init(); bool sd_init();
+15 -3
View File
@@ -16,6 +16,7 @@ uint8_t dev_read();
void dev_write(const uint8_t b); void dev_write(const uint8_t b);
void dev_seek(const uint32_t addr); void dev_seek(const uint32_t addr);
void dev_rseek(const int16_t offset); void dev_rseek(const int16_t offset);
void dev_flush();
/** Sector buffer */ /** Sector buffer */
@@ -36,7 +37,7 @@ uint16_t cursor_offs;
/** Flush the buffer, if it's dirty */ /** Flush the buffer, if it's dirty */
void sdb_flush() void dev_flush()
{ {
if (buff_dirty) if (buff_dirty)
{ {
@@ -49,11 +50,12 @@ void sdb_flush()
void load_sector(const uint32_t addr) void load_sector(const uint32_t addr)
{ {
// do not load if already loaded // do not load if already loaded
if (buff_valid && buff_addr == addr) { if (buff_valid && buff_addr == addr)
{
return; return;
} }
sdb_flush(); dev_flush();
// read entire sector // read entire sector
sd_read(addr, 0, buff, 0, 512); sd_read(addr, 0, buff, 0, 512);
@@ -90,8 +92,17 @@ inline void handle_cursor_ov()
void dev_write(const uint8_t b) void dev_write(const uint8_t b)
{ {
load_sector(cursor_sec); load_sector(cursor_sec);
// dirty only if changed
if (buff[cursor_offs] != b)
{
buff[cursor_offs++] = b; buff[cursor_offs++] = b;
buff_dirty = true; buff_dirty = true;
}
else
{
cursor_offs++;
}
handle_cursor_ov(); handle_cursor_ov();
} }
@@ -166,6 +177,7 @@ bool sdb_init(BLOCKDEV* dev)
dev->write = &dev_write; dev->write = &dev_write;
dev->seek = &dev_seek; dev->seek = &dev_seek;
dev->rseek = &dev_rseek; dev->rseek = &dev_rseek;
dev->flush = &dev_flush;
return true; return true;
} }
+1 -8
View File
@@ -1,14 +1,7 @@
#pragma once #pragma once
#include "blockdev.h" #include "blockdev.h"
#include <stdbool.h>
/**
* Flush the sector buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*/
void sdb_flush();
/** Initialize the SD card block device */ /** Initialize the SD card block device */
bool sdb_init(BLOCKDEV* dev); bool sdb_init(BLOCKDEV* dev);
+39 -6
View File
@@ -8,27 +8,60 @@
FAT16 _fat; FAT16 _fat;
BLOCKDEV _dev; 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 sdfat_inited = false;
bool sdfat_init() bool sdf_init()
{ {
if (sdfat_inited) return true; if (sdfat_inited) return true;
sdfat_inited = true; sdfat_inited = true;
if (!sdb_init(&_dev)) return false; if (!sdb_init(&_dev)) return false;
if (!fat16_init(&_dev, &_fat)) return false; if (!ff_init(&_dev, &_fat)) return false;
sdf_stream->rx = &stream_rx;
sdf_stream->tx = &stream_tx;
return true; return true;
} }
void sdfat_root(FAT16_FILE* file) void sdf_root(FFILE* file)
{ {
fat16_root(&_fat, file); ff_root(&_fat, file);
} }
void sdfat_disk_label(char* str) void sdf_disk_label(char* str)
{ {
fat16_disk_label(&_fat, str); ff_disk_label(&_fat, str);
} }
+19 -6
View File
@@ -1,19 +1,32 @@
#pragma once #pragma once
// //
// FAT-on-SD helpers // 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 "fat16.h"
#include "stream.h"
/** Initialize FAT16 filesystem on a SPI-connected SD card */ /** Initialize FAT16 filesystem on a SPI-connected SD card */
bool sdfat_init(); bool sdf_init();
/** Get first file of the root folder. */ /** Get first file of the root folder. */
void sdfat_root(FAT16_FILE* file); void sdf_root(FFILE* file);
/** Get a disk label. Str should have 12 chars. */ /** Get a disk label. Str should have 12 chars. */
void sdfat_disk_label(char* str); void sdf_disk_label(char* str);
/** Flush the SD buffer (alis of sdb_flush()) */ extern STREAM* sdf_stream;
#define sdfat_flush() sdb_flush()
/**
* 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();
+6 -1
View File
@@ -18,7 +18,7 @@ void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len)
} }
void put_str(const STREAM *p, char* str) void put_str(const STREAM *p, const char *str)
{ {
char c; char c;
while ((c = *str++)) while ((c = *str++))
@@ -41,6 +41,11 @@ void put_str_P(const STREAM *p, const char* str)
static void _putnf(const STREAM *p, const uint8_t places); static void _putnf(const STREAM *p, const uint8_t places);
void put_c(const STREAM *p, const uint8_t c)
{
p->tx(c);
}
/** Send signed int8 */ /** Send signed int8 */
void put_u8(const STREAM *p, const uint8_t num) void put_u8(const STREAM *p, const uint8_t num)
{ {
+18 -17
View File
@@ -31,74 +31,75 @@ typedef struct
/** Send bytes to stream */ /** Send bytes to stream */
void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len); void put_bytes(const STREAM *p, const uint8_t* str, uint16_t len);
/** Print string into a stream */ /** Print string into a stream */
void put_str(const STREAM *p, char* str); void put_str(const STREAM *p, const char *str);
/** Print a programspace string into a stream */ /** Print a programspace string into a stream */
void put_str_P(const STREAM *p, const char* str); void put_str_P(const STREAM *p, const char* str);
/** Put a char/byte. Basically the same as p->tx() */
void put_c(const STREAM *p, uint8_t c);
/** Send signed int8 */ /** Send signed int8 */
#define put_char(p, c) (p)->tx((c)) void put_u8(const STREAM *p, uint8_t num);
void put_u8(const STREAM *p, const uint8_t num);
/** Send unsigned int8 */ /** Send unsigned int8 */
void put_i8(const STREAM *p, const int8_t num); void put_i8(const STREAM *p, int8_t num);
/** Send unsigned int */ /** Send unsigned int */
void put_u16(const STREAM *p, const uint16_t num); void put_u16(const STREAM *p, uint16_t num);
/** Send signed int */ /** Send signed int */
void put_i16(const STREAM *p, const int16_t num); void put_i16(const STREAM *p, int16_t num);
/** Send unsigned long */ /** Send unsigned long */
void put_u32(const STREAM *p, const uint32_t num); void put_u32(const STREAM *p, uint32_t num);
/** Send signed long */ /** Send signed long */
void put_i32(const STREAM *p, const int32_t num); void put_i32(const STREAM *p, int32_t num);
/** Send unsigned int8 */ /** Send unsigned int8 */
void put_x8(const STREAM *p, const uint8_t num); void put_x8(const STREAM *p, uint8_t num);
/** Send int as hex */ /** Send int as hex */
void put_x16(const STREAM *p, const uint16_t num); void put_x16(const STREAM *p, uint16_t num);
/** Send long as hex */ /** Send long as hex */
void put_x32(const STREAM *p, const uint32_t num); void put_x32(const STREAM *p, uint32_t num);
/** Send long long as hex */ /** Send long long as hex */
void put_x64(const STREAM *p, const uint64_t num); void put_x64(const STREAM *p, uint64_t num);
// float variant doesn't make sense for 8-bit int // float variant doesn't make sense for 8-bit int
/** Send unsigned int as float */ /** Send unsigned int as float */
void put_u16f(const STREAM *p, const uint16_t num, const uint8_t places); void put_u16f(const STREAM *p, uint16_t num, uint8_t places);
/** Send signed int as float */ /** Send signed int as float */
void put_i16f(const STREAM *p, const int16_t num, const uint8_t places); void put_i16f(const STREAM *p, int16_t num, uint8_t places);
/** Send unsigned long as float */ /** Send unsigned long as float */
void put_u32f(const STREAM *p, const uint32_t num, const uint8_t places); void put_u32f(const STREAM *p, uint32_t num, uint8_t places);
/** Send signed long as float */ /** Send signed long as float */
void put_i32f(const STREAM *p, const int32_t num, const uint8_t places); void put_i32f(const STREAM *p, int32_t num, uint8_t places);
/** Print CR LF */ /** Print CR LF */
+2
View File
@@ -8,6 +8,8 @@
// Create a config file rgb_config.h next to your main.c // Create a config file rgb_config.h next to your main.c
// //
#include <stdint.h>
#include "iopins.h" #include "iopins.h"
#include "color.h" #include "color.h"