diff --git a/.gitignore b/.gitignore index 37ad9be..934c62e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,3 @@ *.so *.out *.hex - -devel/ diff --git a/devel/README.md b/devel/README.md new file mode 100644 index 0000000..18568a3 --- /dev/null +++ b/devel/README.md @@ -0,0 +1,5 @@ +**Files in this folder are experimental, work-in-progress projects.** + +Do not expect them to work. + +For finished stuff, look into the /projects folder. diff --git a/devel/dht11/Makefile b/devel/dht11/Makefile new file mode 100644 index 0000000..6ed6ce1 --- /dev/null +++ b/devel/dht11/Makefile @@ -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 diff --git a/devel/dht11/lib b/devel/dht11/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/dht11/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/dht11/main.c b/devel/dht11/main.c new file mode 100644 index 0000000..157c43c --- /dev/null +++ b/devel/dht11/main.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.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)) { + // Temperature + put_i8(uart, result.temp); + uart_puts_P(PSTR(" °C, ")); + // Humidity + 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); + } +} diff --git a/devel/iopins/Makefile b/devel/iopins/Makefile new file mode 100644 index 0000000..b7fde89 --- /dev/null +++ b/devel/iopins/Makefile @@ -0,0 +1,137 @@ +## === 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 uart_ansi.c iopins.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 + + +# === 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 diff --git a/devel/iopins/avrlib_1-0-0.zip b/devel/iopins/avrlib_1-0-0.zip new file mode 100644 index 0000000..fbe89ed Binary files /dev/null and b/devel/iopins/avrlib_1-0-0.zip differ diff --git a/devel/iopins/iopins.c b/devel/iopins/iopins.c new file mode 100644 index 0000000..f775e6f --- /dev/null +++ b/devel/iopins/iopins.c @@ -0,0 +1,276 @@ +#include +#include +#include + +#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 set_low_n(const uint8_t pin) +{ + switch(pin) { + case 0: set_low(0); return; + case 1: set_low(1); return; + case 2: set_low(2); return; + case 3: set_low(3); return; + case 4: set_low(4); return; + case 5: set_low(5); return; + case 6: set_low(6); return; + case 7: set_low(7); return; + case 8: set_low(8); return; + case 9: set_low(9); return; + case 10: set_low(10); return; + case 11: set_low(11); return; + case 12: set_low(12); return; + case 13: set_low(13); return; + case 14: set_low(14); return; + case 15: set_low(15); return; + case 16: set_low(16); return; + case 17: set_low(17); return; + case 18: set_low(18); return; + case 19: set_low(19); return; + case 20: set_low(20); return; + case 21: set_low(21); return; + } +} + +void set_high_n(const uint8_t pin) +{ + switch(pin) { + case 0: set_high(0); return; + case 1: set_high(1); return; + case 2: set_high(2); return; + case 3: set_high(3); return; + case 4: set_high(4); return; + case 5: set_high(5); return; + case 6: set_high(6); return; + case 7: set_high(7); return; + case 8: set_high(8); return; + case 9: set_high(9); return; + case 10: set_high(10); return; + case 11: set_high(11); return; + case 12: set_high(12); return; + case 13: set_high(13); return; + case 14: set_high(14); return; + case 15: set_high(15); return; + case 16: set_high(16); return; + case 17: set_high(17); return; + case 18: set_high(18); return; + case 19: set_high(19); return; + case 20: set_high(20); return; + case 21: set_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); +} diff --git a/devel/iopins/iopins.h b/devel/iopins/iopins.h new file mode 100644 index 0000000..ba2354e --- /dev/null +++ b/devel/iopins/iopins.h @@ -0,0 +1,190 @@ +#pragma once + +#include +#include +#include + +#include "calc.h" + +/** 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 + + +/** 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); set_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 set_low(pin) cbi(_PORT_##pin, _PN_##pin) +void set_low_n(const uint8_t pin); + + +/** Write 1 to a pin */ +#define set_high(pin) sbi(_PORT_##pin, _PN_##pin) +void set_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 diff --git a/devel/iopins/lib b/devel/iopins/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/iopins/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/iopins/main.c b/devel/iopins/main.c new file mode 100644 index 0000000..f9817cc --- /dev/null +++ b/devel/iopins/main.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.h" + +void main() +{ + for (int i = 2; i <= 5; i++) { + as_output_n(i); + } + + as_input_pu(12); + + while(1) { + for (int i = 2; i <= 5; i++) { + if (is_low(12)) { + set_high_n(i); + _delay_ms(100); + set_low_n(i); + } + } + } +} diff --git a/devel/lcdsnake/Makefile b/devel/lcdsnake/Makefile new file mode 100644 index 0000000..3b7b0bb --- /dev/null +++ b/devel/lcdsnake/Makefile @@ -0,0 +1,167 @@ + +MCU = atmega328p + +F_CPU = 16000000 + +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + +MAIN = main.c + +## If you've split your program into multiple files, +## include the additional .c source (in same directory) here +## (and include the .h files in your foo.c) +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ +EXTRA_SOURCE_DIR = lib/ +EXTRA_SOURCE_FILES = debounce.c lcd.c adc.c + +EXTRA_CFLAGS = + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## +#19200 +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## Compilation options, type man avr-gcc if you're curious. +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 +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += $(EXTRA_CFLAGS) + +CFLAGS_BUILD = $(CFLAGS) -Os + +# CFLAGS += -lm +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +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 $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +dis: disassemble +lst: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +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 + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +flash_arduino: PROGRAMMER_TYPE = arduino +flash_arduino: PROGRAMMER_ARGS = +flash_arduino: flash + +flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp +flash_dragon_isp: PROGRAMMER_ARGS = +flash_dragon_isp: flash + + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Generic +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 + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/lcdsnake/README.md b/devel/lcdsnake/README.md new file mode 100644 index 0000000..10be780 --- /dev/null +++ b/devel/lcdsnake/README.md @@ -0,0 +1,10 @@ +Snake for HD44780 +================= + +This is a Snake game (known from old Nokia phones) played on a character display with HD44780. + +Program tested on Arduino Pro Mini (flashed with avrdude using the Makefile). + +**Connections** are `#define`d in `main.c`, board size and snake speed can also be adjusted. No external parts except the display and buttons required. + +Best works with a gamepad, but any buttons will work. diff --git a/devel/lcdsnake/debo_config.h b/devel/lcdsnake/debo_config.h new file mode 100644 index 0000000..3b06634 --- /dev/null +++ b/devel/lcdsnake/debo_config.h @@ -0,0 +1,5 @@ +#pragma once + +// Config file for debouncer +#define DEBO_CHANNELS 6 +#define DEBO_TICKS 1 diff --git a/devel/lcdsnake/lcd_config.h b/devel/lcdsnake/lcd_config.h new file mode 100644 index 0000000..82e8a80 --- /dev/null +++ b/devel/lcdsnake/lcd_config.h @@ -0,0 +1,13 @@ +#pragma once + +// Config file for LCD. + +#include "lib/arduino_pins.h" + +#define LCD_RS D2 +#define LCD_RW D3 +#define LCD_E D4 +#define LCD_D4 D5 +#define LCD_D5 D6 +#define LCD_D6 D7 +#define LCD_D7 D8 diff --git a/devel/lcdsnake/lib b/devel/lcdsnake/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/lcdsnake/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/lcdsnake/main.c b/devel/lcdsnake/main.c new file mode 100644 index 0000000..85114a3 --- /dev/null +++ b/devel/lcdsnake/main.c @@ -0,0 +1,429 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" +#include "lib/adc.h" +#include "lib/lcd.h" +#include "lib/debounce.h" + +// Buttons (to ground) +#define BTN_LEFT A0 +#define BTN_RIGHT A1 +#define BTN_UP A2 +#define BTN_DOWN A3 +#define BTN_PAUSE A4 +#define BTN_RESTART A5 + +// Debouncer channels for buttons +// (Must be added in this order to debouncer) +#define D_LEFT 0 +#define D_RIGHT 1 +#define D_UP 2 +#define D_DOWN 3 +#define D_PAUSE 4 +#define D_RESTART 5 + +// Board size (!!! rows = 2x number of display lines, max 2*4 = 8 !!!) +#define ROWS 8 +#define COLS 20 + +// Delay between snake steps, in 10 ms +#define STEP_DELAY 24 + +// proto +void update(); +void init_cgram(); +void init_gameboard(); + +void init() +{ + // Randomize RNG + adc_init(); + srand(adc_read_word(3)); + + // Init LCD + lcd_init(); + init_cgram(); // load default glyphs + + // Init game board. + init_gameboard(); + + // gamepad buttons + as_input_pu(BTN_LEFT); + as_input_pu(BTN_RIGHT); + as_input_pu(BTN_UP); + as_input_pu(BTN_DOWN); + as_input_pu(BTN_PAUSE); + as_input_pu(BTN_RESTART); + + // add buttons to debouncer + debo_add_rev(BTN_LEFT); + debo_add_rev(BTN_RIGHT); + debo_add_rev(BTN_UP); + debo_add_rev(BTN_DOWN); + debo_add_rev(BTN_PAUSE); + debo_add_rev(BTN_RESTART); + + // setup timer + TCCR0A = _BV(WGM01); // CTC + TCCR0B = _BV(CS02) | _BV(CS00); // prescaler 1024 + OCR0A = 156; // interrupt every 10 ms + sbi(TIMSK0, OCIE0A); + sei(); +} + + +/** timer 0 interrupt vector */ +ISR(TIMER0_COMPA_vect) +{ + debo_tick(); // poll debouncer + update(); // update and display +} + + + +// sub-glyphs +#define _HEAD_ 15, 21, 21, 30 +#define _BODY_ 15, 31, 31, 30 +#define _FOOD_ 10, 21, 17, 14 +//14, 17, 17, 14 +#define _NONE_ 0, 0, 0, 0 + +// complete glyphs for loading into memory + +// Only one food & one head glyph have to be loaded at a time. + +// Body - Body +const uint8_t SYMBOL_BB[] PROGMEM = {_BODY_, _BODY_}; + +// Body - None +const uint8_t SYMBOL_BX[] PROGMEM = {_BODY_, _NONE_}; +const uint8_t SYMBOL_XB[] PROGMEM = {_NONE_, _BODY_}; + +// Head - None +const uint8_t SYMBOL_HX[] PROGMEM = {_HEAD_, _NONE_}; +const uint8_t SYMBOL_XH[] PROGMEM = {_NONE_, _HEAD_}; + +// Body - Head +const uint8_t SYMBOL_BH[] PROGMEM = {_BODY_, _HEAD_}; +const uint8_t SYMBOL_HB[] PROGMEM = {_HEAD_, _BODY_}; + +// Head - Food +const uint8_t SYMBOL_HF[] PROGMEM = {_HEAD_, _FOOD_}; +const uint8_t SYMBOL_FH[] PROGMEM = {_FOOD_, _HEAD_}; + +// Food - None +const uint8_t SYMBOL_FX[] PROGMEM = {_FOOD_, _NONE_}; +const uint8_t SYMBOL_XF[] PROGMEM = {_NONE_, _FOOD_}; + +// Body - Food +const uint8_t SYMBOL_BF[] PROGMEM = {_BODY_, _FOOD_}; +const uint8_t SYMBOL_FB[] PROGMEM = {_FOOD_, _BODY_}; + + +// board block (snake, food...) +typedef enum { + bEMPTY = 0x00, + bHEAD = 0x01, + bFOOD = 0x02, + bBODY_LEFT = 0x80, + bBODY_RIGHT = 0x81, + bBODY_UP = 0x82, + bBODY_DOWN = 0x83, +} block_t; + +// Snake direction +typedef enum { + dLEFT = 0x00, + dRIGHT = 0x01, + dUP = 0x02, + dDOWN = 0x03, +} dir_t; + +// Coordinate on board +typedef struct { + int8_t x; + int8_t y; +} coord_t; + +#define is_body(blk) (((blk) & 0x80) != 0) +#define mk_body_dir(dir) (0x80 + (dir)) + +// compare two coords +#define coord_eq(a, b) (((a).x == (b).x) && ((a).y == (b).y)) + + +bool crashed; +uint8_t snake_len; + +// y, x indexing +block_t board[ROWS][COLS]; + +coord_t head_pos; +coord_t tail_pos; +dir_t head_dir; + +const uint8_t CODE_BB = 0; +const uint8_t CODE_BX = 1; +const uint8_t CODE_XB = 2; +const uint8_t CODE_H = 3; // glyph with head, dynamic +const uint8_t CODE_F = 4; // glyph with food, dynamic +const uint8_t CODE_XX = 32; // space + + +// Set a block in board +#define set_block_xy(x, y, block) do { board[y][x] = (block); } while(0) +#define get_block_xy(x, y) board[y][x] +#define get_block(pos) get_block_xy((pos).x, (pos).y) +#define set_block(pos, block) set_block_xy((pos).x, (pos).y, (block)) + + +void init_cgram() +{ + // those will be always the same + lcd_glyph_P(CODE_BB, SYMBOL_BB); + lcd_glyph_P(CODE_BX, SYMBOL_BX); + lcd_glyph_P(CODE_XB, SYMBOL_XB); + lcd_glyph_P(5, SYMBOL_XF); +} + + +void place_food() +{ + while(1) { + const uint8_t xx = rand() % COLS; + const uint8_t yy = rand() % ROWS; + + if (get_block_xy(xx, yy) == bEMPTY) { + set_block_xy(xx, yy, bFOOD); + break; + } + } +} + + +void init_gameboard() +{ + //erase the board + for (uint8_t x = 0; x < COLS; x++) { + for (uint8_t y = 0; y < ROWS; y++) { + set_block_xy(x, y, bEMPTY); + } + } + + lcd_clear(); + + tail_pos = (coord_t) {.x = 0, .y = 0}; + + set_block_xy(0, 0, bBODY_RIGHT); + set_block_xy(1, 0, bBODY_RIGHT); + set_block_xy(2, 0, bBODY_RIGHT); + set_block_xy(3, 0, bHEAD); + + head_pos = (coord_t) {.x = 3, .y = 0}; + + snake_len = 4; // includes head + + head_dir = dRIGHT; + crashed = false; + + place_food(); +} + + +uint8_t presc = 0; + +bool restart_held; +bool pause_held; +bool paused; +void update() +{ + if (debo_get_pin(D_RESTART)) { + + if (!restart_held) { + // restart + init_gameboard(); + presc = 0; + restart_held = true; + } + + } else { + restart_held = false; + } + + if (debo_get_pin(D_PAUSE)) { + + if (!pause_held) { + paused ^= true; + pause_held = true; + } + + } else { + pause_held = false; + } + + if(!crashed && !paused) { + + // resolve movement direction + if (debo_get_pin(D_LEFT)) + head_dir = dLEFT; + else if (debo_get_pin(D_RIGHT)) + head_dir = dRIGHT; + else if (debo_get_pin(D_UP)) + head_dir = dUP; + else if (debo_get_pin(D_DOWN)) + head_dir = dDOWN; + + // time's up for a move + if (presc++ == STEP_DELAY) { + presc = 0; + + // move snake + const coord_t oldpos = head_pos; + + switch (head_dir) { + case dLEFT: head_pos.x--; break; + case dRIGHT: head_pos.x++; break; + case dUP: head_pos.y--; break; + case dDOWN: head_pos.y++; break; + } + + bool do_move = false; + bool do_grow = false; + + if (head_pos.x < 0 || head_pos.x >= COLS || head_pos.y < 0 || head_pos.y >= ROWS) { + // ouch, a wall! + crashed = true; + } else { + // check if tile occupied or not + if (coord_eq(head_pos, tail_pos)) { + // head moved in previous tail, that's OK. + do_move = true; + } else { + // moved to other tile than tail + switch (get_block(head_pos)) { + + case bFOOD: + do_grow = true; // fall through + case bEMPTY: + do_move = true; + break; + + default: // includes all BODY_xxx + crashed = true; // snake crashed into some block + } + } + } + + if (do_move) { + // Move tail + if (do_grow) { + // let tail as is + snake_len++; // grow the counter + } else { + // tail dir + dir_t td = get_block(tail_pos) & 0xF; + + // clean tail + set_block(tail_pos, bEMPTY); + + // move tail based on old direction of tail block + switch (td) { + case dLEFT: tail_pos.x--; break; + case dRIGHT: tail_pos.x++; break; + case dUP: tail_pos.y--; break; + case dDOWN: tail_pos.y++; break; + } + } + + // Move head + set_block(head_pos, bHEAD); // place head in new pos + set_block(oldpos, mk_body_dir(head_dir)); // directional body in old head pos + + if (do_grow) { + // food eaten, place new + place_food(); + } + } + } + } // end !crashed + + + // Render the board + for (uint8_t r = 0; r < ROWS / 2; r++) { + lcd_xy(0, r); + for (uint8_t c = 0; c < COLS; c++) { + const block_t t1 = get_block_xy(c, r * 2); + const block_t t2 = get_block_xy(c, (r * 2) + 1); + + uint8_t code = '!'; // ! marks fail + + if ((t1 == bEMPTY) && (t2 == bEMPTY)) { + code = CODE_XX; + if (crashed) code = '*'; + } else if (is_body(t1) && is_body(t2)) + code = CODE_BB; + else if (is_body(t1) && (t2 == bEMPTY)) + code = CODE_BX; + else if (t1 == bEMPTY && is_body(t2)) + code = CODE_XB; + else if ((t1 == bFOOD) || (t2 == bFOOD)) { + // one is food + + code = CODE_F; + + if (t1 == bFOOD) { + if (t2 == bEMPTY) + lcd_glyph_P(code, SYMBOL_FX); + else if (t2 == bHEAD) + lcd_glyph_P(code, SYMBOL_FH); + else if (is_body(t2)) + lcd_glyph_P(code, SYMBOL_FB); + } else { // t2 is food + if (t1 == bEMPTY) + lcd_glyph_P(code, SYMBOL_XF); + else if (t1 == bHEAD) + lcd_glyph_P(code, SYMBOL_HF); + else if (is_body(t1)) + lcd_glyph_P(code, SYMBOL_BF); + } + lcd_xy(c,r); + + } else if ((t1 == bHEAD )|| (t2 == bHEAD)) { + // one is head + + code = CODE_H; + + if (t1 == bHEAD) { + if (t2 == bEMPTY) + lcd_glyph_P(code, SYMBOL_HX); + else if (is_body(t2)) + lcd_glyph_P(code, SYMBOL_HB); + } else { // t2 is head + if (t1 == bEMPTY) + lcd_glyph_P(code, SYMBOL_XH); + else if (is_body(t1)) + lcd_glyph_P(code, SYMBOL_BH); + } + + lcd_xy(c,r); + } + + lcd_putc(code); + } + } +} + +void main() +{ + init(); + + while(1); // timer does everything +} diff --git a/devel/onewire/Makefile b/devel/onewire/Makefile new file mode 100644 index 0000000..fb45811 --- /dev/null +++ b/devel/onewire/Makefile @@ -0,0 +1,141 @@ +## === 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 onewire.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 diff --git a/devel/onewire/lib b/devel/onewire/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/onewire/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/onewire/main.c b/devel/onewire/main.c new file mode 100644 index 0000000..a678e44 --- /dev/null +++ b/devel/onewire/main.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.h" +#include "lib/uart.h" +#include "lib/stream.h" +#include "lib/onewire.h" + +void main() +{ + uart_init(9600); + uart_puts_P(PSTR("*** OneWire test ***\r\n")); + + while(1) + { + _delay_ms(100); + + if (ds1820_single_measure(2)) + { + int16_t temp = ds1820_read_temp_c(2); + + if (temp == TEMP_ERROR) { + // Checksum mismatch + uart_puts_P(PSTR("Corrupt data!\r\n")); + } else { + put_i16f(uart, temp, 1); + uart_puts_P(PSTR(" °C\r\n")); + } + + } else { + uart_puts_P(PSTR("Device not connected!\r\n")); + } + } +} diff --git a/devel/rgb_hsl/Makefile b/devel/rgb_hsl/Makefile new file mode 100644 index 0000000..820f029 --- /dev/null +++ b/devel/rgb_hsl/Makefile @@ -0,0 +1,170 @@ + +MCU = atmega328p + +F_CPU = 16000000 + +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + +MAIN = main.c + +## If you've split your program into multiple files, +## include the additional .c source (in same directory) here +## (and include the .h files in your foo.c) +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ +EXTRA_SOURCE_DIR = lib/ +EXTRA_SOURCE_FILES = adc.c hsl.c + +EXTRA_FLAGS = +#-DHSL_LINEAR=1 + + + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## +#19200 +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## Compilation options, type man avr-gcc if you're curious. +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 -pedantic -Wfatal-errors +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += $(EXTRA_FLAGS) + +CFLAGS_BUILD = $(CFLAGS) -Os + +# CFLAGS += -lm +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +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 $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +dis: disassemble +lst: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +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 + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +flash_arduino: PROGRAMMER_TYPE = arduino +flash_arduino: PROGRAMMER_ARGS = +flash_arduino: flash + +flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp +flash_dragon_isp: PROGRAMMER_ARGS = +flash_dragon_isp: flash + + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Generic +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 + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/rgb_hsl/README.md b/devel/rgb_hsl/README.md new file mode 100644 index 0000000..c4480bd --- /dev/null +++ b/devel/rgb_hsl/README.md @@ -0,0 +1,11 @@ +Random color flasher, with fading. + +Color is atm restricted to hues of blue-cyan. + +Works with a 4x4 zigzag screen + +0->1->2->3 +7<-6<-5<-4 +8->... + +(But will work with any screen since there's no pattern to be preserved) diff --git a/devel/rgb_hsl/lib b/devel/rgb_hsl/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/rgb_hsl/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/rgb_hsl/main.c b/devel/rgb_hsl/main.c new file mode 100644 index 0000000..6f7bc78 --- /dev/null +++ b/devel/rgb_hsl/main.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" + +#include "lib/colors.h" +#include "lib/hsl.h" +#include "lib/adc.h" + +#define WS_T_1H 650 +#define WS_T_1L 200 +#define WS_T_0H 120 +#define WS_T_0L 650 + +#include "lib/ws_rgb.h" + +#define WS1 D2 + +void SECTION(".init8") init() +{ + adc_init(); + srand(adc_read_word(0)); + + as_output(WS1); +} + + +void main() +{ + #define WIDTH 4 + #define HEIGHT 4 + #define SIZE (WIDTH*HEIGHT) + hsl_t board[SIZE]; + xrgb_t screen[SIZE]; + + for (uint8_t i = 0; i < SIZE; i++) { + board[i] = (hsl_t) {.h=0, .s=255, .l=0}; + screen[i] = (xrgb_t) {.r=0, .g=0, .b=0}; + } + + while(1) { + for(uint8_t i = 0; i < SIZE; i++) { + if (board[i].l > 0) { + board[i].l--; + } + + screen[i] = hsl2xrgb(board[i]); + } + + if (rand() % 4 == 0) { + uint8_t i = rand() % SIZE; + + if (board[i].l == 0) { + board[i].h = 125 + rand() % 57; + board[i].s = 200 + rand() % 56; + board[i].l = 150 + rand() % 106; + } + } + + //ws_send_xrgb_array_zigzag_linear(WS1, screen, 4, 4); + ws_send_xrgb_array_zigzag_linear(WS1, screen, 4, 4); + _delay_ms(10); + } +} diff --git a/devel/sd_bad/Makefile b/devel/sd_bad/Makefile new file mode 100644 index 0000000..6ed6ce1 --- /dev/null +++ b/devel/sd_bad/Makefile @@ -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 diff --git a/devel/sd_bad/deployment.pri b/devel/sd_bad/deployment.pri new file mode 100644 index 0000000..5f1749f --- /dev/null +++ b/devel/sd_bad/deployment.pri @@ -0,0 +1,191 @@ +# This file was generated by an application wizard of Qt Creator. +# The code below handles deployment to Android and Maemo, aswell as copying +# of the application data to shadow build directories on desktop. +# It is recommended not to modify this file, since newer versions of Qt Creator +# may offer an updated version of it. + +defineTest(qtcAddDeployment) { +for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + greaterThan(QT_MAJOR_VERSION, 4) { + itemsources = $${item}.files + } else { + itemsources = $${item}.sources + } + $$itemsources = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath= $$eval($${deploymentfolder}.target) + export($$itemsources) + export($$itempath) + DEPLOYMENT += $$item +} + +MAINPROFILEPWD = $$PWD + +android-no-sdk { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + target.path = /data/user/qt + + export(target.path) + INSTALLS += target +} else:android { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /assets/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + x86 { + target.path = /libs/x86 + } else: armeabi-v7a { + target.path = /libs/armeabi-v7a + } else { + target.path = /libs/armeabi + } + + export(target.path) + INSTALLS += target +} else:win32 { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, /, \\) + sourcePathSegments = $$split(source, \\) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments) + target = $$replace(target, /, \\) + target ~= s,\\\\\\.?\\\\,\\, + !isEqual(source,$$target) { + !isEmpty(copyCommand):copyCommand += && + isEqual(QMAKE_DIR_SEP, \\) { + copyCommand += $(COPY_DIR) \"$$source\" \"$$target\" + } else { + source = $$replace(source, \\\\, /) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\" + } + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } +} else:ios { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + target = $CODESIGNING_FOLDER_PATH/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += mkdir -p \"$$target\" + copyCommand += && cp -r \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = echo Copying application data... && $$copyCommand + !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK += ";" + QMAKE_POST_LINK += "$$copyCommand" + export(QMAKE_POST_LINK) + } +} else:unix { + maemo5 { + desktopfile.files = $${TARGET}.desktop + desktopfile.path = /usr/share/applications/hildon + icon.files = $${TARGET}64.png + icon.path = /usr/share/icons/hicolor/64x64/apps + } else:!isEmpty(MEEGO_VERSION_MAJOR) { + desktopfile.files = $${TARGET}_harmattan.desktop + desktopfile.path = /usr/share/applications + icon.files = $${TARGET}80.png + icon.path = /usr/share/icons/hicolor/80x80/apps + } else { # Assumed to be a Desktop Unix + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + macx { + target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target) + } else { + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + } + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += $(MKDIR) \"$$target\" + copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } + } + !isEmpty(target.path) { + installPrefix = $${target.path} + } else { + installPrefix = /opt/$${TARGET} + } + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + !isEmpty(desktopfile.path) { + export(icon.files) + export(icon.path) + export(desktopfile.files) + export(desktopfile.path) + INSTALLS += icon desktopfile + } + + isEmpty(target.path) { + target.path = $${installPrefix}/bin + export(target.path) + } + INSTALLS += target +} + +export (ICON) +export (INSTALLS) +export (DEPLOYMENT) +export (LIBS) +export (QMAKE_EXTRA_TARGETS) +} + diff --git a/devel/sd_bad/main.c b/devel/sd_bad/main.c new file mode 100644 index 0000000..69f92b5 --- /dev/null +++ b/devel/sd_bad/main.c @@ -0,0 +1,57 @@ +#include "main.h" +#include "sd.h" +#include "spi.h" + +static uint8_t sd_buffer[512]; +static sd_context_t sdc; + +void main(void) +{ + int j, ok; + ok = 0; + + /* Stop the watchdog timer */ + WDTCTL = WDTPW | WDTHOLD; + + /* Set some reasonable values for the timeouts. + */ + sdc.timeout_write = PERIPH_CLOCKRATE / 8; + sdc.timeout_read = PERIPH_CLOCKRATE / 20; + + sdc.busyflag = 0; + for (j = 0; j < SD_INIT_TRY && ok != 1; j++) + { + ok = do_sd_initialize(&sdc); + } + + /* Read in the first block on the SD Card */ + if (ok == 1) + { + sd_read_block(&sdc, 0, sd_buffer); + sd_wait_notbusy(&sdc); + } + + /* Wait forever */ + while (1) { } +} + + +int do_sd_initialize(sd_context_t *sdc) +{ + /* Initialize the SPI controller */ + spi_initialize(); + + /* Start out with a slow SPI clock, 400kHz, as required + by the SD spec + (for MMC compatibility). */ + spi_set_divisor(PERIPH_CLOCKRATE / 400000); + + /* Initialization OK? */ + if (sd_initialize(sdc) != 1) + return 0; + + /* Set the maximum SPI clock rate possible */ + spi_set_divisor(2); + + return 1; +} diff --git a/devel/sd_bad/main.h b/devel/sd_bad/main.h new file mode 100644 index 0000000..b0e53a6 --- /dev/null +++ b/devel/sd_bad/main.h @@ -0,0 +1,10 @@ +#ifndef MAIN_H +#define MAIN_H + +#include "sdcomm_spi.h" + +/* Peripheral clock rate, in Hz, used for timing. */ +#define PERIPH_CLOCKRATE 8000000 +int do_sd_initialize(sd_context_t *sdc); + +#endif diff --git a/devel/sd_bad/sd.c b/devel/sd_bad/sd.c new file mode 100644 index 0000000..ef364ce --- /dev/null +++ b/devel/sd_bad/sd.c @@ -0,0 +1,467 @@ +#include "main.h" +#include "sd.h" +#include "sdcomm_spi.h" +#include "spi.h" + +static uint8_t response[5]; +static uint8_t argument[4]; + +int sd_card_present() +{ + return (!(P3IN & 0x01)); +} + +/* This function initializes the SD card. It returns 1 if + initialization was successful, 0 otherwise. + + sd_context_t *sdc -- pointer to a data structure containing + information about the card. For now, the + timeouts MUST be specified in advance. This + function does not yet calculate them from the + card data. +*/ + +int sd_initialize(sd_context_t *sdc) +{ + char i, j; + /* SPI SD initialization sequence: + * CMD0 + * CMD55 + * ACMD41 + * CMD58 + * (Note there is no CMD2 or CMD3 in SPI mode. These + * instructions are devoted to addressing on the SD bus.) + * + * SD memory card SD initialization sequence: + * CMD0 + * CMD55 + * ACMD41 + * CMD2 + * CMD3 + */ + sdc->busyflag = 0; + for (i = 0; i < 4; i++) + argument[i] = 0; + + /* Delay for at least 74 clock cycles. This means to actually + * *clock* out at least 74 clock cycles with no data present on + * the clock. In SPI mode, send at least 10 idle bytes (0xFF). */ + + spi_cs_assert(); + sd_delay(100); + spi_cs_deassert(); + sd_delay(2); + + /* Put the card in the idle state */ + if (sd_send_command(sdc, CMD0, CMD0_R, response, argument) == 0) + return 0; + + /* Now wait until the card goes idle. Retry at most SD_IDLE_WAIT_MAX + times */ + + j = 0; + do + { + j++; + /* Flag the next command as an application-specific command */ + if (sd_send_command(sdc, CMD55, CMD55_R, response, argument) == 1) + { + /* Tell the card to send its OCR */ + sd_send_command(sdc, ACMD41, ACMD41_R, response, argument); + } + else + { + /* No response, bail early */ + j = SD_IDLE_WAIT_MAX; + } + } + while ((response[0] & MSK_IDLE) == MSK_IDLE && j < SD_IDLE_WAIT_MAX); + + /* As long as we didn’t hit the timeout, assume we’re OK. */ + if (j >= SD_IDLE_WAIT_MAX) + return 0; + + if (sd_send_command(sdc, CMD58, CMD58_R, response, argument) == 0) + return 0; + + /* At a very minimum, we must allow 3.3V. */ + if ((response[2] & MSK_OCR_33) != MSK_OCR_33) + return 0; + + /* Set the block length */ + if (sd_set_blocklen(sdc, SD_BLOCKSIZE) != 1) + return 0; + + /* If we got this far, initialization was OK. + */ + return 1; +} + +/* + This function reads a single block from the SD card at block + blockaddr. The buffer must be preallocated. Returns 1 if the + command was successful, zero otherwise. + + This is an ASYNCHRONOUS call. + + The transfer will not be complete when the function returns. + If you want to explicitly wait until any pending transfers are + finished, use the command sd_wait_notbusy(sdc). + + sd_context_t *sdc + -- a pointer to an sd device context structure, + populated by the function sd_initialize() + + u32 blockaddr + -- The block address to read from the card. + This is a block address, not a linear address. + + uint8_t *data + -- The data, a pointer to an array of uint8_ts. +*/ + +int sd_read_block(sd_context_t *sdc, uint32_t blockaddr, + uint8_t *data) +{ + unsigned long int i = 0; + uint8_t tmp; + uint8_t blank = 0xFF; + + /* Adjust the block address to a linear address */ + blockaddr <<= SD_BLOCKSIZE_NBITS; + + /* Wait until any old transfers are finished */ + sd_wait_notbusy(sdc); + + /* Pack the address */ + sd_packarg(argument, blockaddr); + + /* Need to add size checking */ + if (sd_send_command(sdc, CMD17, CMD17_R, response, argument) == 0) + return 0; + + /* Check for an error, like a misaligned read */ + if (response[0] != 0) + return 0; + + /* Re-assert CS to continue the transfer */ + spi_cs_assert(); + + /* Wait for the token */ + i = 0; + do + { + tmp = spi_rcv_byte(); + i++; + } + while ((tmp == 0xFF) && i < sdc->timeout_read); + + if ((tmp & MSK_TOK_DATAERROR) == 0) + { + /* Clock out a byte before returning */ + spi_send_byte(0xFF); + + /* The card returned an error response. Bail and return 0 */ + return 0; + } + + /* Prime the interrupt flags so things happen in the correct order. */ + IFG1 &= ~URXIFG0; + IFG1 &= ~UTXIFG0; + + /* Get the block */ + /* Source DMA address: receive register. */ + DMA0SA = U0RXBUF_; + + /* Destination DMA address: the user data buffer. */ + DMA0DA = (unsigned short) data; + + /* The size of the block to be transferred */ + DMA0SZ = SD_BLOCKSIZE; + + /* Configure the DMA transfer*/ + DMA0CTL = + DMADT_0 | /* Single transfer mode */ + DMASBDB | /* Byte mode */ + DMAEN | /* Enable DMA */ + DMADSTINCR1 | DMADSTINCR0; /* Increment the destination address */ + + /* We depend on the DMA priorities here. Both triggers occur at + the same time, since the source is identical. DMA0 is handled + first, and retrieves the byte. DMA1 is triggered next, and + sends the next byte. */ + + /* Source DMA address: constant 0xFF (don’t increment)*/ + DMA1SA = (unsigned short) ␣ + + /* Destination DMA address: the transmit buffer. */ + DMA1DA = U0TXBUF_; + + /* Increment the destination address */ + /* The size of the block to be transferred */ + DMA1SZ = SD_BLOCKSIZE - 1; + + /* Configure the DMA transfer*/ + DMA1CTL = + DMADT_0 | /* Single transfer mode */ + DMASBDB | /* Byte mode */ + DMAEN; /* Enable DMA */ + + /* DMA trigger is UART receive for both DMA0 and DMA1 */ + DMACTL0 = DMA0TSEL_3 | DMA1TSEL_3; + + /* Kick off the transfer by sending the first byte */ + U0TXBUF = 0xFF; + + return 1; +} + + +/* + This function writes a single block to the SD card at block + blockaddr. Returns 1 if the command was successful, zero + otherwise. + + This is an ASYNCHRONOUS call. The transfer will not be complete + when the function returns. If you want to explicitly wait until + any pending transfers are finished, use the command + sd_wait_notbusy(sdc). + + sd_context_t *sdc + -- a pointer to an sd device context structure, + populated by the function sd_initialize() + + u32 blockaddr + -- The block address to read from the card. + This is a block address, not a linear address. + + uint8_t *data + -- The data, a pointer to an array of unsigned + chars. +*/ +int sd_write_block(sd_context_t *sdc, uint32_t blockaddr, + uint8_t *data) +{ + /* Adjust the block address to a linear address */ + blockaddr <<= SD_BLOCKSIZE_NBITS; + + /* Wait until any old transfers are finished */ + sd_wait_notbusy(sdc); + + /* Pack the address */ + sd_packarg(argument, blockaddr); + + if (sd_send_command(sdc, CMD24, CMD24_R, response, argument) == 0) + return 0; + + /* Check for an error, like a misaligned write */ + if (response[0] != 0) + return 0; + + /* Re-assert CS to continue the transfer */ + spi_cs_assert(); + + /* The write command needs an additional 8 clock cycles before + * the block write is started. */ + spi_rcv_byte(); + + /* Clear any pending flags */ + IFG1 &= ~(URXIFG0 | UTXIFG0); + + /* Get the block */ + /* Source DMA address: the data buffer. */ + DMA0SA = (unsigned short)data; + + /* Destination DMA address: the UART send register. */ + DMA0DA = U0TXBUF_; + + /* The size of the block to be transferred */ + DMA0SZ = SD_BLOCKSIZE; + + /* Configure the DMA transfer*/ + DMA0CTL = + DMADT_0 | /* Single transfer mode */ + DMASBDB | /* Byte mode */ + DMAEN | /* Enable DMA */ + DMASRCINCR1 | DMASRCINCR0; /* Increment the source address */ + + /* DMA trigger is UART send */ + DMACTL0 = DMA0TSEL_3; + + /* Kick off the transfer by sending the first byte, the "start block" + * token */ + U0TXBUF = SD_TOK_WRITE_STARTBLOCK; + + /* Signal that the card may be busy, so any subsequent commands + should wait for the busy signalling to end (indicated by a + nonzero response). */ + sdc->busyflag = 1; + + return 1; +} + +/* + This function synchronously waits until any pending block transfers + are finished. If your program needs to ensure a block has finished + transferring, call this function. + + Note that sd_read_block() and sd_write_block() already call this + function internally before attempting a new transfer, so there are + only two times when a user would need to use this function. + + 1) When the processor will be shutting down. All pending + writes should be finished first. + + 2) When the user needs the results of an sd_read_block() call + right away. +*/ +void sd_wait_notbusy(sd_context_t *sdc) +{ + /* Just twiddle our thumbs until the transfer’s done */ + while ((DMA0CTL & DMAEN) != 0) { } + + /* Reset the DMA controller */ + DMACTL0 = 0; + + /* Ignore the checksum */ + sd_delay(4); + + /* Check for the busy flag (set on a write block) */ + if (sdc->busyflag == 1) + { + while (spi_rcv_byte() != 0xFF); + } + + sdc->busyflag = 0; + + /* Deassert CS */ + spi_cs_deassert(); + + /* Send some extra clocks so the card can resynchronize on the next + transfer */ + + sd_delay(2); +} + + +void sd_packarg(uint8_t *argument, uint32_t value) +{ + argument[3] = (uint8_t)(value >> 24); + argument[2] = (uint8_t)(value >> 16); + argument[1] = (uint8_t)(value >> 8); + argument[0] = (uint8_t)(value); +} + +int sd_send_command(sd_context_t *sdc, + uint8_t cmd, uint8_t response_type, + uint8_t *response, uint8_t *argument) +{ + int i; + char response_length; + uint8_t tmp; + spi_cs_assert(); + + /* All data is sent MSB first, and MSb first */ + /* Send the header/command */ + /* Format: + cmd[7:6] : 01 + cmd[5:0] : command */ + spi_send_byte((cmd & 0x3F) | 0x40); + for (i = 3; i >= 0; i--) + { + spi_send_byte(argument[i]); + } + + /* This is the CRC. It only matters what we put here for the first + command. Otherwise, the CRC is ignored for SPI mode unless we + enable CRC checking. */ + spi_send_byte(0x95); + + response_length = 0; + switch (response_type) + { + case R1: + case R1B: + response_length = 1; + break; + case R2: + response_length = 2; + break; + case R3: + response_length = 5; + break; + default: + break; + } + + /* Wait for a response. A response can be recognized by the + start bit (a zero) */ + i = 0; + do + { + tmp = spi_rcv_byte(); + i++; + } + while (((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT); + + /* Just bail if we never got a response */ + if (i >= SD_CMD_TIMEOUT) + { + spi_cs_deassert(); + return 0; + } + + for (i = response_length - 1; i >= 0; i--) + { + response[i] = tmp; + /* This handles the trailing-byte requirement. */ + tmp = spi_rcv_byte(); + } + + /* If the response is a "busy" type (R1B), then there’s some + * special handling that needs to be done. The card will + * output a continuous stream of zeros, so the end of the BUSY + * state is signaled by any nonzero response. The bus idles + * high. + */ + i = 0; + if (response_type == R1B) + { + do + { + i++; + tmp = spi_rcv_byte(); + } + /* This should never time out, unless SDI is grounded. + * Don’t bother forcing a timeout condition here. */ + while (tmp != 0xFF); + + spi_send_byte(0xFF); + } + + spi_cs_deassert(); + return 1; +} + +void sd_delay(char number) +{ + char i; + + /* Null for now */ + for (i = 0; i < number; i++) + { + /* Clock out an idle byte (0xFF) */ + spi_send_byte(0xFF); + } +} + +/* Set the block length for all future block transactions */ +/* Returns 1 if the function was successful */ +int sd_set_blocklen(sd_context_t *sdc, uint32_t length) +{ + /* Pack the block length */ + sd_packarg(argument, length); + + return (sd_send_command(sdc, CMD16, CMD16_R, response, argument)); +} + diff --git a/devel/sd_bad/sd.h b/devel/sd_bad/sd.h new file mode 100644 index 0000000..d041d32 --- /dev/null +++ b/devel/sd_bad/sd.h @@ -0,0 +1,25 @@ +#ifndef SD_H +#define SD_H + +#include "sdcomm_spi.h" +#include + +#define SD_BLOCKSIZE 512 +#define SD_BLOCKSIZE_NBITS 9 + +/* User functions */ +int sd_card_present(); +int sd_initialize(sd_context_t *sdc); +int sd_read_block(sd_context_t *sdc, uint32_t blockaddr, uint8_t *data); +int sd_write_block(sd_context_t *sdc, uint32_t blockaddr, uint8_t *data); +void sd_wait_notbusy(sd_context_t *sdc); + +/* Internal functions, used for SD card communications. */ +void sd_packarg(uint8_t *argument, uint32_t value); +int sd_set_blocklen(sd_context_t *sdc, uint32_t length); +int sd_send_command(sd_context_t *sdc, + uint8_t cmd, uint8_t response_type, + uint8_t *response, uint8_t *argument); +void sd_delay(char number); + +#endif diff --git a/devel/sd_bad/sd_bad.pro b/devel/sd_bad/sd_bad.pro new file mode 100644 index 0000000..6cc0902 --- /dev/null +++ b/devel/sd_bad/sd_bad.pro @@ -0,0 +1,25 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +INCLUDEPATH += /usr/avr/include + +include(deployment.pri) +qtcAddDeployment() + +DISTFILES += \ + Makefile \ + style.astylerc + +HEADERS += \ + main.h \ + sd.h \ + sdcomm_spi.h \ + spi.h + +SOURCES += \ + main.c \ + sd.c \ + spi.c + diff --git a/devel/sd_bad/sd_bad.pro.user b/devel/sd_bad/sd_bad.pro.user new file mode 100644 index 0000000..1a24635 --- /dev/null +++ b/devel/sd_bad/sd_bad.pro.user @@ -0,0 +1,250 @@ + + + + + + EnvironmentId + {dfe3cb4a-0f3e-4da9-9c52-5d2c464adafb} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + 1 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + 1 + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {ee748544-c6c0-4f44-9cef-fbb65dc2525a} + 0 + 0 + 0 + + /home/ondra/git/avr-projects/devel/sdcard/ + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/ondra/git/avr-projects/devel/sdcard/build-sdcard-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + + true + flash + make + %{buildDir} + Custom Process Step + + ProjectExplorer.ProcessStep + + 1 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + 2 + + -p /dev/ttyUSB0 + gtkterm + false + %{buildDir} + Run gtkterm + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + + 2 + + sd_bad + + Qt4ProjectManager.Qt4RunConfiguration:/home/ondra/git/avr-projects/devel/sd_bad/sd_bad.pro + + sd_bad.pro + false + true + + 3768 + false + true + false + false + true + + 2 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/devel/sd_bad/sdcomm_spi.h b/devel/sd_bad/sdcomm_spi.h new file mode 100644 index 0000000..ad13e60 --- /dev/null +++ b/devel/sd_bad/sdcomm_spi.h @@ -0,0 +1,152 @@ +#ifndef SDCOMM_SPI_H +#define SDCOMM_SPI_H + +typedef struct +{ + unsigned long int timeout_write; + unsigned long int timeout_read; + char busyflag; +} sd_context_t; + +#define R1 1 +#define R1B 2 +#define R2 3 +#define R3 4 + +#define MSK_IDLE 0x01 +#define MSK_ERASE_RST 0x02 +#define MSK_ILL_CMD 0x04 +#define MSK_CRC_ERR 0x08 +#define MSK_ERASE_SEQ_ERR 0x10 +#define MSK_ADDR_ERR 0x20 +#define MSK_PARAM_ERR 0x40 +#define SD_TOK_READ_STARTBLOCK 0xFE +#define SD_TOK_WRITE_STARTBLOCK 0xFE +#define SD_TOK_READ_STARTBLOCK_M 0xFE +#define SD_TOK_WRITE_STARTBLOCK_M 0xFC +#define SD_TOK_STOP_MULTI 0xFD + +/* Error token is 111XXXXX */ +#define MSK_TOK_DATAERROR 0xE0 + +/* Bit fields */ +#define MSK_TOK_ERROR 0x01 +#define MSK_TOK_CC_ERROR 0x02 +#define MSK_TOK_ECC_FAILED 0x04 +#define MSK_TOK_CC_OUTOFRANGE 0x08 +#define MSK_TOK_CC_LOCKED 0x10 + +/* Mask off the bits in the OCR corresponding to voltage range 3.2V to +* 3.4V, OCR bits 20 and 21 */ +#define MSK_OCR_33 0xC0 + +/* Number of times to retry the probe cycle during initialization */ +#define SD_INIT_TRY 50 +/* Number of tries to wait for the card to go idle during initialization */ +#define SD_IDLE_WAIT_MAX 100 +/* Hardcoded timeout for commands. 8 words, or 64 clocks. Do 10 +* words instead */ +#define SD_CMD_TIMEOUT 100 + +/******************************** Basic command set **************************/ +/* Reset cards to idle state */ +#define CMD0 0 +#define CMD0_R R1 +/* Read the OCR (MMC mode, do not use for SD cards) */ +#define CMD1 1 +#define CMD1_R R1 +/* Card sends the CSD */ +#define CMD9 9 +#define CMD9_R R1 +/* Card sends CID */ +#define CMD10 10 +#define CMD10_R R1 +/* Stop a multiple block (stream) read/write operation */ +#define CMD12 12 +#define CMD12_R R1B +/* Get the addressed card’s status register */ +#define CMD13 13 +#define CMD13_R R2 + +/***************************** Block read commands **************************/ +/* Set the block length */ +#define CMD16 16 +#define CMD16_R R1 +/* Read a single block */ +#define CMD17 17 +#define CMD17_R R1 +/* Read multiple blocks until a CMD12 */ +#define CMD18 18 +#define CMD18_R R1 + +/***************************** Block write commands *************************/ +/* Write a block of the size selected with CMD16 */ +#define CMD24 24 +#define CMD24_R R1 +/* Multiple block write until a CMD12 */ +#define CMD25 25 +#define CMD25_R R1 +/* Program the programmable bits of the CSD */ +#define CMD27 27 +#define CMD27_R R1 + +/***************************** Write protection *****************************/ +/* Set the write protection bit of the addressed group */ +#define CMD28 28 +#define CMD28_R R1B +/* Clear the write protection bit of the addressed group */ +#define CMD29 29 +#define CMD29_R R1B +/* Ask the card for the status of the write protection bits */ +#define CMD30 30 +#define CMD30_R R1 + +/***************************** Erase commands *******************************/ +/* Set the address of the first write block to be erased */ +#define CMD32 32 +#define CMD32_R R1 +/* Set the address of the last write block to be erased */ +#define CMD33 33 +#define CMD33_R R1 +/* Erase the selected write blocks */ +#define CMD38 38 +#define CMD38_R R1B + +/***************************** Lock Card commands ***************************/ +/* Commands from 42 to 54, not defined here */ +/***************************** Application-specific commands ****************/ +/* Flag that the next command is application-specific */ +#define CMD55 55 +#define CMD55_R R1 +/* General purpose I/O for application-specific commands */ +#define CMD56 56 +#define CMD56_R R1 +/* Read the OCR (SPI mode only) */ +#define CMD58 58 +#define CMD58_R R3 +/* Turn CRC on or off */ +#define CMD59 59 +#define CMD59_R R1 + +/***************************** Application-specific commands ***************/ +/* Get the SD card’s status */ +#define ACMD13 13 +#define ACMD13_R R2 +/* Get the number of written write blocks (Minus errors ) */ +#define ACMD22 22 +#define ACMD22_R R1 +/* Set the number of write blocks to be pre-erased before writing */ +#define ACMD23 23 +#define ACMD23_R R1 +/* Get the card’s OCR (SD mode) */ +#define ACMD41 41 +#define ACMD41_R R1 +/* Connect or disconnect the 50kOhm internal pull-up on CD/DAT[3] */ +#define ACMD42 42 +#define ACMD42_R R1 +/* Get the SD configuration register */ +#define ACMD51 42 +#define ACMD51_R R1 + +#endif + diff --git a/devel/sd_bad/spi.c b/devel/sd_bad/spi.c new file mode 100644 index 0000000..a9b28a3 --- /dev/null +++ b/devel/sd_bad/spi.c @@ -0,0 +1,88 @@ +#include "main.h" +#include "spi.h" + +/* Initialize and enable the SPI module */ +void spi_initialize() +{ + P3SEL = 0x00E; // Setup P3 for SPI mode + P3OUT |= 0x010; // Setup P3.4 as the SS signal, active low. So, initialize it high. + P3DIR |= 0x010; // Set up P3.4 as an output + + U0CTL = (CHAR | SYNC | MM | SWRST); // 8-bit, SPI, Master + U0TCTL = (SSEL1 | STC | CKPH); // Normal polarity, 3-wire + U0BR0 = 0x002; // SPICLK = SMCLK/2 (2=Minimum divisor) + U0BR1 = 0x000; + U0MCTL = 0x000; + ME1 |= USPIE0; // Module enable + U0CTL &= ~SWRST; // SPI enable +} + +/* Set the baud-rate divisor. The correct value is computed by dividing + the clock rate by the desired baud rate. The minimum divisor allowed + is 2. */ + +void spi_set_divisor(unsigned int divisor) +{ + U0CTL |= SWRST; // Temporarily disable the SPI module + U0BR1 = divisor >> 8; + U0BR0 = divisor; + U0CTL &= ~SWRST; // Re-enable SPI +} + +/* Assert the CS signal, active low (CS=0) */ +void spi_cs_assert() +{ + // Pin 3.4, Pin 32 + P3OUT &= ~0x010; +} + +/* Deassert the CS signal (CS=1) */ +void spi_cs_deassert() +{ + // Pin 3.4, Pin 32 + P3OUT |= 0x010; +} + + +/* Send a single byte over the SPI port */ +void spi_send_byte(uint8_t input) +{ + IFG1 &= ~URXIFG0; + /* Send the byte */ + TXBUF0 = input; + /* Wait for the byte to be sent */ + while ((IFG1 & URXIFG0) == 0) { } +} + + +/* Receive a byte. Output an 0xFF (the bus idles high) to receive the byte */ +uint8_t spi_rcv_byte() +{ + uint8_t tmp; + IFG1 &= ~URXIFG0; + /* Send the byte */ + TXBUF0 = 0xFF; + /* Wait for the byte to be received */ + while ((IFG1 & URXIFG0) == 0) { } + tmp = U0RXBUF; + return (tmp); +} + + +/* Disable the SPI module. This function assumes the module had + * already been initialized. */ +void spi_disable() +{ + /* Put the SPI module in reset mode */ + U0CTL |= SWRST; + /* Disable the USART module */ + ME1 &= ~USPIE0; +} + +void spi_enable() +{ + /* Enable the USART module */ + ME1 |= USPIE0; + /* Take the SPI module out of reset mode */ + U0CTL &= ~SWRST; +} diff --git a/devel/sd_bad/spi.h b/devel/sd_bad/spi.h new file mode 100644 index 0000000..b67a1c0 --- /dev/null +++ b/devel/sd_bad/spi.h @@ -0,0 +1,15 @@ +#ifndef SPI_H +#define SPI_H + +#include + +void spi_initialize(); +void spi_set_divisor(unsigned int divisor); +void spi_cs_assert(); +void spi_cs_deassert(); +void spi_send_byte(uint8_t input); +uint8_t spi_rcv_byte(); +void spi_enable(); +void spi_disable(); + +#endif diff --git a/devel/sd_bad/style.astylerc b/devel/sd_bad/style.astylerc new file mode 100644 index 0000000..f6ea396 --- /dev/null +++ b/devel/sd_bad/style.astylerc @@ -0,0 +1,13 @@ +style=allman +indent=tab +max-instatement-indent=60 + +convert-tabs + +indent-switches + +pad-oper +unpad-paren +pad-header + +verbose diff --git a/devel/sdcard/Makefile b/devel/sdcard/Makefile new file mode 100644 index 0000000..4dba31f --- /dev/null +++ b/devel/sdcard/Makefile @@ -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 spi.c sd.c fat16.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 diff --git a/devel/sdcard/deployment.pri b/devel/sdcard/deployment.pri new file mode 100644 index 0000000..5f1749f --- /dev/null +++ b/devel/sdcard/deployment.pri @@ -0,0 +1,191 @@ +# This file was generated by an application wizard of Qt Creator. +# The code below handles deployment to Android and Maemo, aswell as copying +# of the application data to shadow build directories on desktop. +# It is recommended not to modify this file, since newer versions of Qt Creator +# may offer an updated version of it. + +defineTest(qtcAddDeployment) { +for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + greaterThan(QT_MAJOR_VERSION, 4) { + itemsources = $${item}.files + } else { + itemsources = $${item}.sources + } + $$itemsources = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath= $$eval($${deploymentfolder}.target) + export($$itemsources) + export($$itempath) + DEPLOYMENT += $$item +} + +MAINPROFILEPWD = $$PWD + +android-no-sdk { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + target.path = /data/user/qt + + export(target.path) + INSTALLS += target +} else:android { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /assets/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + x86 { + target.path = /libs/x86 + } else: armeabi-v7a { + target.path = /libs/armeabi-v7a + } else { + target.path = /libs/armeabi + } + + export(target.path) + INSTALLS += target +} else:win32 { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, /, \\) + sourcePathSegments = $$split(source, \\) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments) + target = $$replace(target, /, \\) + target ~= s,\\\\\\.?\\\\,\\, + !isEqual(source,$$target) { + !isEmpty(copyCommand):copyCommand += && + isEqual(QMAKE_DIR_SEP, \\) { + copyCommand += $(COPY_DIR) \"$$source\" \"$$target\" + } else { + source = $$replace(source, \\\\, /) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\" + } + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } +} else:ios { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + target = $CODESIGNING_FOLDER_PATH/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += mkdir -p \"$$target\" + copyCommand += && cp -r \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = echo Copying application data... && $$copyCommand + !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK += ";" + QMAKE_POST_LINK += "$$copyCommand" + export(QMAKE_POST_LINK) + } +} else:unix { + maemo5 { + desktopfile.files = $${TARGET}.desktop + desktopfile.path = /usr/share/applications/hildon + icon.files = $${TARGET}64.png + icon.path = /usr/share/icons/hicolor/64x64/apps + } else:!isEmpty(MEEGO_VERSION_MAJOR) { + desktopfile.files = $${TARGET}_harmattan.desktop + desktopfile.path = /usr/share/applications + icon.files = $${TARGET}80.png + icon.path = /usr/share/icons/hicolor/80x80/apps + } else { # Assumed to be a Desktop Unix + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + macx { + target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target) + } else { + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + } + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += $(MKDIR) \"$$target\" + copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } + } + !isEmpty(target.path) { + installPrefix = $${target.path} + } else { + installPrefix = /opt/$${TARGET} + } + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + !isEmpty(desktopfile.path) { + export(icon.files) + export(icon.path) + export(desktopfile.files) + export(desktopfile.path) + INSTALLS += icon desktopfile + } + + isEmpty(target.path) { + target.path = $${installPrefix}/bin + export(target.path) + } + INSTALLS += target +} + +export (ICON) +export (INSTALLS) +export (DEPLOYMENT) +export (LIBS) +export (QMAKE_EXTRA_TARGETS) +} + diff --git a/devel/sdcard/lib b/devel/sdcard/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/sdcard/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/sdcard/main.c b/devel/sdcard/main.c new file mode 100644 index 0000000..960cb0d --- /dev/null +++ b/devel/sdcard/main.c @@ -0,0 +1,64 @@ +#include +#include + +#include "lib/uart.h" +#include "lib/stream.h" +#include "lib/sd.h" + +void main() +{ + uart_init(9600); + uart_puts_P(PSTR("*** SD CARD SPI TEST ***\r\n")); + + if (!sd_init()) + { + put_str_P(uart, PSTR("Failed to init.")); + while (1); + } + + + uint8_t text[512]; + + + + put_str_P(uart, PSTR("\r\nReading...\r\n")); + if (sd_read(0, 0, text, 0, 512)) + { + put_bytes(uart, text, 512); + put_nl(uart); + put_nl(uart); + + for (uint8_t i = 0; i < 60; i++) + { + text[i] = ('A' + i); + } + + put_str_P(uart, PSTR("\r\nWriting...\r\n")); + sd_write(1, text); + put_str_P(uart, PSTR("\r\nWrite done.\r\n")); + + for (uint16_t i = 0; i < 512; i++) + { + text[i] = 0; + } + + if (sd_read(1, 0, text, 0, 512)) + { + put_str_P(uart, PSTR("\r\nWritten, result: \r\n")); + put_bytes(uart, text, 512); + put_nl(uart); + put_nl(uart); + } + else + { + put_str_P(uart, PSTR("\r\nRead failed.\r\n")); + } + } + else + { + put_str_P(uart, PSTR("Failed to read.")); + while (1); + } + + while (1); +} diff --git a/devel/sdcard/sdcard.pro b/devel/sdcard/sdcard.pro new file mode 100644 index 0000000..b856652 --- /dev/null +++ b/devel/sdcard/sdcard.pro @@ -0,0 +1,56 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +INCLUDEPATH += /usr/avr/include + +SOURCES += main.c \ + lib/adc.c \ + lib/color.c \ + lib/debounce.c \ + lib/dht11.c \ + lib/iopins.c \ + lib/lcd.c \ + lib/onewire.c \ + lib/sonar.c \ + lib/stream.c \ + lib/uart.c \ + lib/wsrgb.c \ + sd/main.c \ + sd/sd.c \ + sd/spi.c \ + lib/fat16.c \ + lib/sd.c \ + lib/spi.c + +include(deployment.pri) +qtcAddDeployment() + +HEADERS += \ + lib/adc.h \ + lib/calc.h \ + lib/color.h \ + lib/debounce.h \ + lib/dht11.h \ + lib/iopins.h \ + lib/lcd.h \ + lib/nsdelay.h \ + lib/onewire.h \ + lib/sonar.h \ + lib/stream.h \ + lib/uart.h \ + lib/wsrgb.h \ + sd/main.h \ + sd/sd.h \ + sd/sdcomm_spi.h \ + sd/spi.h \ + lib/fat16.h \ + lib/fat16_internal.h \ + lib/spi.h \ + lib/sd.h + +DISTFILES += \ + Makefile \ + style.astylerc + diff --git a/devel/sdcard/sdcard.pro.user b/devel/sdcard/sdcard.pro.user new file mode 100644 index 0000000..28194b6 --- /dev/null +++ b/devel/sdcard/sdcard.pro.user @@ -0,0 +1,250 @@ + + + + + + EnvironmentId + {dfe3cb4a-0f3e-4da9-9c52-5d2c464adafb} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + 1 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + 1 + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {ee748544-c6c0-4f44-9cef-fbb65dc2525a} + 0 + 0 + 1 + + /home/ondra/git/avr-projects/devel/sdcard/ + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + -B + + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/ondra/git/avr-projects/devel/sdcard/build-sdcard-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + + true + flash -B + make + %{buildDir} + Custom Process Step + + ProjectExplorer.ProcessStep + + 1 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + 2 + + sdcard + sdcard2 + Qt4ProjectManager.Qt4RunConfiguration:/home/ondra/git/avr-projects/devel/sdcard/sdcard.pro + + sdcard.pro + false + true + + 3768 + false + true + false + false + true + + + 2 + + -p /dev/ttyUSB0 + gtkterm + false + %{buildDir} + Run gtkterm + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 2 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/devel/sdcard/style.astylerc b/devel/sdcard/style.astylerc new file mode 100644 index 0000000..f6ea396 --- /dev/null +++ b/devel/sdcard/style.astylerc @@ -0,0 +1,13 @@ +style=allman +indent=tab +max-instatement-indent=60 + +convert-tabs + +indent-switches + +pad-oper +unpad-paren +pad-header + +verbose diff --git a/devel/snake/Makefile b/devel/snake/Makefile new file mode 100644 index 0000000..56fe6f8 --- /dev/null +++ b/devel/snake/Makefile @@ -0,0 +1,166 @@ + +MCU = atmega328p + +F_CPU = 16000000 + +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + +MAIN = main.c + +## If you've split your program into multiple files, +## include the additional .c source (in same directory) here +## (and include the .h files in your foo.c) +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ +EXTRA_SOURCE_DIR = +EXTRA_SOURCE_FILES = + + + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## +#19200 +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = sudo avrdude + +## Compilation options, type man avr-gcc if you're curious. +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 +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax + +CFLAGS_BUILD = $(CFLAGS) -Os + +# CFLAGS += -lm +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +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 $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +dis: disassemble +lst: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +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 + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +flash_arduino: PROGRAMMER_TYPE = arduino +flash_arduino: PROGRAMMER_ARGS = +flash_arduino: flash + +flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp +flash_dragon_isp: PROGRAMMER_ARGS = +flash_dragon_isp: flash + + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Generic +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 + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/snake/lcd_default.asm b/devel/snake/lcd_default.asm new file mode 100644 index 0000000..05e064a --- /dev/null +++ b/devel/snake/lcd_default.asm @@ -0,0 +1,351 @@ +; Zapojeni (Připojen DMC-50399 v 4-bitovem modu): +; +------u------+ +; Vcc -> reset --+ /RST Vcc +-- napajeni +5V +; --+ PD0 PB7 +-- RS (0=instr W, BF+addr R; 1=data W/R) +; --+ PD1 PB6 +-- R/W (1=read,0=write) +; --+ PA1 PB5 +-- E (clock, active falling edge) +; --+ PA0 PB4 +-- +; --+ PD2 PB3 +-- DATA 7 +; --+ PD3 PB2 +-- DATA 6 +; --+ PD4 PB1 +-- DATA 5 +; --+ PD5 PB0 +-- DATA 4 +; GND --+ GND PD6 +-- +; +-------------+ + +;DMC-50399: +; 1 - GND +; 2 - +5V +; 3 - 0V (lcd driver) +; 4 - RS +; 5 - R/W +; 6 - E +; 7 - DATA 0 +; 8 - DATA 1 +;... +;14 - DATA 7 + +.device attiny2313 +;běží na 4MHz, ckdiv8=1 (vypnuto) +;250x16=1ms=1000us + +;LFUSE: 0xE2 -U lfuse:w:0xE2:m +;HFUSE: 0xDF -U hfuse:w:0xDF:m + + +;K O N S T A N T Y + P R E Z D I V K Y P O R T U A P I N U +.equ LCDPORT = PORTB +.equ LCDPIN = PINB +.equ LCDDDR = DDRB + +.equ RS = 7 +.equ RW = 6 +.equ E = 5 + +.equ LCD_CLEAR = 0b00000001 +.equ LCD_HOME = 0b00000010 + +.equ LCD_MODE_INC_NOSHIFT = 0b00000110 +.equ LCD_MODE_INC_SHIFT = 0b00000111 +.equ LCD_MODE_DEC_NOSHIFT = 0b00000100 +.equ LCD_MODE_DEC_SHIFT = 0b00000101 + +.equ LCD_DISPLAY_DISABLED = 0b00001000 +.equ LCD_DISPLAY_NOCURSOR = 0b00001100 +.equ LCD_DISPLAY_CURSOR = 0b00001110 +.equ LCD_DISPLAY_ALTER = 0b00001101 +.equ LCD_DISPLAY_CURSOR_ALTER = 0b00001111 + +.equ LCD_CURSOR_LEFT = 0b00010000 +.equ LCD_CURSOR_RIGHT = 0b00010100 +.equ LCD_SHIFT_LEFT = 0b00011000 +.equ LCD_SHIFT_RIGHT = 0b00011100 + + +;5x7 font, 1-line +.equ LCD_MODE_4BIT_1LINE = 0b00100000 +;.equ LCD_MODE_8BIT_1LINE = 0b00110000 +;5x7 font, 2-line +.equ LCD_MODE_4BIT_2LINE = 0b00101000 +;.equ LCD_MODE_8BIT_2LINE = 0b00111000 + +.equ ROW1_ADDR = 0x00 +.equ ROW2_ADDR = 0x40 +.equ ROW3_ADDR = 0x14 +.equ ROW4_ADDR = 0x54 + + + +;aliases +.def ZH = r31 +.def ZL = r30 +.def YH = r29 +.def YL = r28 +.def XH = r27 +.def XL = r26 + +; Z A C A T E K P R O G R A M U +;vektory preruseni +.org 0x0000 ;RESET + rjmp RESET ;skok na start po resetu + +.org 0x0013 + +;nastaveni po resetu +.DB "HD44780 INTERFACE" ;(nazev programu) +RESET: + ldi r16,low(RAMEND) ;nastavi stack pointer + out SPL,r16 + cli ;zakazat vsechna preruseni + +; Nastaveni portu + ;PORTB = LCDPORT + ldi r16,0b11111111 ;smer portu B + out LCDDDR,r16 + ldi r16,0b00000000 ;vypnout B + out LCDPORT,r16 + + sei ;Global Interrupt Enable + +; == display init == + rcall LCD_INIT + + ldi r17,LCD_MODE_INC_NOSHIFT + rcall TX_INSTR + + ldi r17,LCD_DISPLAY_NOCURSOR + rcall TX_INSTR + +; == load user-defined characters to CGRAM == (default, array label named MYCHARS, end-mark=0xFE) + ldi r17,0 + rcall CGRAM_SET_ADDR + + ldi ZH,high(MYCHARS*2) + ldi ZL,low(MYCHARS*2) +CGRAM_loop: + lpm r17,Z+ + cpi r17,0xFE + breq CGRAM_loop_end + rcall TX_DATA + rjmp CGRAM_loop +CGRAM_loop_end: + + +; == pgm body == + +;load text to DDRAM + ldi r17,ROW1_ADDR + rcall DDRAM_SET_ADDR + + ldi ZH,high(MYTEXT1*2) + ldi ZL,low(MYTEXT1*2) +DDRAM_loop: + lpm r17,Z+ + cpi r17,0xFE + breq DDRAM_loop_end + rcall TX_DATA + rjmp DDRAM_loop +DDRAM_loop_end: + +;load text to DDRAM + ldi r17,ROW2_ADDR + rcall DDRAM_SET_ADDR + + ldi ZH,high(MYTEXT2*2) + ldi ZL,low(MYTEXT2*2) +DDRAM2_loop: + lpm r17,Z+ + cpi r17,0xFE + breq DDRAM2_loop_end + rcall TX_DATA + rjmp DDRAM2_loop +DDRAM2_loop_end: + +;direct write to X,Y - example + ldi r16,3 ;Y, zacina 0 a roste smerem dolu + ldi r17,5 ;X, zacina nulou a roste smerem doprava + rcall LCD_CURSOR_XY + ldi r17,"%" + rcall TX_DATA + ldi r17,"%" + rcall TX_DATA + ldi r17,"%" + rcall TX_DATA +;infinite loop +loop: rjmp loop + + +MYTEXT1: +.DB 0,0,0," POKUSNY TEXT ",0,0,0,0xFE +MYTEXT2: +.DB "Opravdu pekny text!",0xFE + + + +; == USER-DEFINED CHARS == +MYCHARS: +; 5x8, first 3 bits are not used +;end of mychars +.DB 0xe,0x1f,0x15,0x1f,0x1f,0x1f,0x15 ;smajlik + +;konec +.DB 0xFE + + + + + +;r16=Y +;r17=X +LCD_CURSOR_XY: + cpi r16,0 + brne test1 +fail: ldi r16,ROW1_ADDR + rjmp addrdone +test1: + cpi r16,1 + brne test2 + ldi r16,ROW2_ADDR + rjmp addrdone +test2: + cpi r16,2 + brne test3 + ldi r16,ROW3_ADDR + rjmp addrdone +test3: + cpi r16,3 + brne fail + ldi r16,ROW4_ADDR +addrdone: + add r17,r16 + rcall DDRAM_SET_ADDR + ret + +;r16=počet ms (cca) +delay: + push r17 ;2 + push r18 ;2 +d1: + ldi r17,250 ;1 +d2: + ldi r18,14 ;1 +d3: + dec r18 ;1 + nop + brne d3 ;2 (1 + dec r17 ; +1) + brne d2 ;2 (1 + dec r16 ; +1) + brne d1 ;2 (1) + + pop r18 ;2 + pop r17 ;2 + ret + + +LCD_INIT: + ldi r16,16 + rcall delay + ldi r16,0b00000010 ;4bit + out PORTB,r16 + rcall LCD_CLK + ldi r16,5 + rcall delay + ldi r17,LCD_MODE_4BIT_2LINE ;set 4-bit mode + rcall TX_INSTR + ret + +;r17 +TX_INSTR: + swap r17 ;send high nibble + mov r16,r17 + andi r16,0b00001111 + out LCDPORT,r16 + rcall LCD_CLK + + swap r17 ;send low nibble + mov r16,r17 + andi r16,0b00001111 + out LCDPORT,r16 + rcall LCD_CLK + + ret + +;r17 +TX_DATA: + swap r17 ;send high nibble + mov r16,r17 + andi r16,0b00001111 + sbr r16,(1< +#include +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" +#include "lib/adc.h" + +#define LCD_PIN_RS D10 +#define LCD_PIN_RW D11 +#define LCD_PIN_E D12 +#define LCD_PIN_D4 D13 +#define LCD_PIN_D5 D14 +#define LCD_PIN_D6 D15 +#define LCD_PIN_D7 D16 +// D17 = A3 = source of entropy for random. + +#include "lib/lcd.h" + + +// Buttons (to ground) +#define BTN_LEFT D2 +#define BTN_RIGHT D3 +#define BTN_UP D4 +#define BTN_DOWN D5 +#define BTN_SELECT D6 +#define BTN_RESTART D7 + +// Debouncer channels for buttons +// (Must be added in this order to debouncer) +#define D_LEFT 0 +#define D_RIGHT 1 +#define D_UP 2 +#define D_DOWN 3 +#define D_SELECT 4 +#define D_RESTART 5 + +#define DEBO_CHANNELS 6 +#define DEBO_TICKS 1 // in 0.01s + +#include "lib/debounce.h" + +// Board size (!!! rows = 2x number of display lines, max 2*4 = 8 !!!) +#define ROWS 4 +#define COLS 20 + +// Delay between snake steps, in 10 ms +#define STEP_DELAY 24 + +// proto +void update(); +void init_cgram(); +void init_gameboard(); + +void SECTION(".init8") init() +{ + // Randomize RNG + adc_init(); + srand(adc_read_word(3)); + + // Init LCD + lcd_init(); + init_cgram(); // load default glyphs + + // Init game board. + init_gameboard(); + + // gamepad buttons + as_input_pu(BTN_LEFT); + as_input_pu(BTN_RIGHT); + as_input_pu(BTN_UP); + as_input_pu(BTN_DOWN); + as_input_pu(BTN_SELECT); + as_input_pu(BTN_RESTART); + + // add buttons to debouncer + debo_add_rev(BTN_LEFT); + debo_add_rev(BTN_RIGHT); + debo_add_rev(BTN_UP); + debo_add_rev(BTN_DOWN); + debo_add_rev(BTN_SELECT); + debo_add_rev(BTN_RESTART); + + // setup timer + TCCR0A = _BV(WGM01); // CTC + TCCR0B = _BV(CS02) | _BV(CS00); // prescaler 1024 + OCR0A = 156; // interrupt every 10 ms + sbi(TIMSK0, OCIE0A); + sei(); +} + + +/** timer 0 interrupt vector */ +ISR(TIMER0_COMPA_vect) +{ + debo_tick(); // poll debouncer + update(); // update and display +} + + + +// sub-glyphs +#define _HEAD_ 15, 21, 21, 30 +#define _BODY_ 15, 31, 31, 30 +#define _FOOD_ 10, 21, 17, 14 +//14, 17, 17, 14 +#define _NONE_ 0, 0, 0, 0 + +// complete glyphs for loading into memory + +// Only one food & one head glyph have to be loaded at a time. + +// Body - Body +const uint8_t SYMBOL_BB[] PROGMEM = {_BODY_, _BODY_}; + +// Body - None +const uint8_t SYMBOL_BX[] PROGMEM = {_BODY_, _NONE_}; +const uint8_t SYMBOL_XB[] PROGMEM = {_NONE_, _BODY_}; + +// Head - None +const uint8_t SYMBOL_HX[] PROGMEM = {_HEAD_, _NONE_}; +const uint8_t SYMBOL_XH[] PROGMEM = {_NONE_, _HEAD_}; + +// Body - Head +const uint8_t SYMBOL_BH[] PROGMEM = {_BODY_, _HEAD_}; +const uint8_t SYMBOL_HB[] PROGMEM = {_HEAD_, _BODY_}; + +// Head - Food +const uint8_t SYMBOL_HF[] PROGMEM = {_HEAD_, _FOOD_}; +const uint8_t SYMBOL_FH[] PROGMEM = {_FOOD_, _HEAD_}; + +// Food - None +const uint8_t SYMBOL_FX[] PROGMEM = {_FOOD_, _NONE_}; +const uint8_t SYMBOL_XF[] PROGMEM = {_NONE_, _FOOD_}; + +// Body - Food +const uint8_t SYMBOL_BF[] PROGMEM = {_BODY_, _FOOD_}; +const uint8_t SYMBOL_FB[] PROGMEM = {_FOOD_, _BODY_}; + + +// board block (snake, food...) +typedef enum { + bEMPTY = 0x00, + bHEAD = 0x01, + bFOOD = 0x02, + bBODY_LEFT = 0x80, + bBODY_RIGHT = 0x81, + bBODY_UP = 0x82, + bBODY_DOWN = 0x83, +} block_t; + +// Snake direction +typedef enum { + dLEFT = 0x00, + dRIGHT = 0x01, + dUP = 0x02, + dDOWN = 0x03, +} dir_t; + +// Coordinate on board +typedef struct { + int8_t x; + int8_t y; +} coord_t; + +#define is_body(blk) (((blk) & 0x80) != 0) +#define mk_body_dir(dir) (0x80 + (dir)) + +// compare two coords +#define coord_eq(a, b) (((a).x == (b).x) && ((a).y == (b).y)) + + +bool crashed; +uint8_t snake_len; + +// y, x indexing +block_t board[ROWS][COLS]; + +coord_t head_pos; +coord_t tail_pos; +dir_t head_dir; + +const uint8_t CODE_BB = 0; +const uint8_t CODE_BX = 1; +const uint8_t CODE_XB = 2; +const uint8_t CODE_H = 3; // glyph with head, dynamic +const uint8_t CODE_F = 4; // glyph with food, dynamic +const uint8_t CODE_XX = 32; // space + + +// Set a block in board +#define set_block_xy(x, y, block) do { board[y][x] = (block); } while(0) +#define get_block_xy(x, y) board[y][x] +#define get_block(pos) get_block_xy((pos).x, (pos).y) +#define set_block(pos, block) set_block_xy((pos).x, (pos).y, (block)) + + +void init_cgram() +{ + // those will be always the same + lcd_define_glyph_pgm(CODE_BB, SYMBOL_BB); + lcd_define_glyph_pgm(CODE_BX, SYMBOL_BX); + lcd_define_glyph_pgm(CODE_XB, SYMBOL_XB); + lcd_define_glyph_pgm(5, SYMBOL_XF); +} + + +void place_food() +{ + while(1) { + const uint8_t xx = rand() % COLS; + const uint8_t yy = rand() % ROWS; + + if (get_block_xy(xx, yy) == bEMPTY) { + set_block_xy(xx, yy, bFOOD); + break; + } + } +} + + +void init_gameboard() +{ + //erase the board + for (uint8_t x = 0; x < COLS; x++) { + for (uint8_t y = 0; y < ROWS; y++) { + set_block_xy(x, y, bEMPTY); + } + } + + lcd_clear(); + + tail_pos = (coord_t) {.x = 0, .y = 0}; + + set_block_xy(0, 0, bBODY_RIGHT); + set_block_xy(1, 0, bBODY_RIGHT); + set_block_xy(2, 0, bBODY_RIGHT); + set_block_xy(3, 0, bHEAD); + + head_pos = (coord_t) {.x = 3, .y = 0}; + + snake_len = 4; // includes head + + head_dir = dRIGHT; + crashed = false; + + place_food(); +} + + +uint8_t presc = 0; + +bool restart_held; +void update() +{ + if (debo_get_pin(D_RESTART)) { + + if (!restart_held) { + // restart + init_gameboard(); + presc = 0; + restart_held = true; + } + + } else { + restart_held = false; + } + + if(!crashed) { + + // resolve movement direction + if (debo_get_pin(D_LEFT)) + head_dir = dLEFT; + else if (debo_get_pin(D_RIGHT)) + head_dir = dRIGHT; + else if (debo_get_pin(D_UP)) + head_dir = dUP; + else if (debo_get_pin(D_DOWN)) + head_dir = dDOWN; + + // time's up for a move + if (presc++ == STEP_DELAY) { + presc = 0; + + // move snake + const coord_t oldpos = head_pos; + + switch (head_dir) { + case dLEFT: head_pos.x--; break; + case dRIGHT: head_pos.x++; break; + case dUP: head_pos.y--; break; + case dDOWN: head_pos.y++; break; + } + + bool do_move = false; + bool do_grow = false; + + if (head_pos.x < 0 || head_pos.x >= COLS || head_pos.y < 0 || head_pos.y >= ROWS) { + // ouch, a wall! + crashed = true; + } else { + // check if tile occupied or not + if (coord_eq(head_pos, tail_pos)) { + // head moved in previous tail, that's OK. + do_move = true; + } else { + // moved to other tile than tail + switch (get_block(head_pos)) { + + case bFOOD: + do_grow = true; // fall through + case bEMPTY: + do_move = true; + break; + + default: // includes all BODY_xxx + crashed = true; // snake crashed into some block + } + } + } + + if (do_move) { + // Move tail + if (do_grow) { + // let tail as is + snake_len++; // grow the counter + } else { + // tail dir + dir_t td = get_block(tail_pos) & 0xF; + + // clean tail + set_block(tail_pos, bEMPTY); + + // move tail based on old direction of tail block + switch (td) { + case dLEFT: tail_pos.x--; break; + case dRIGHT: tail_pos.x++; break; + case dUP: tail_pos.y--; break; + case dDOWN: tail_pos.y++; break; + } + } + + // Move head + set_block(head_pos, bHEAD); // place head in new pos + set_block(oldpos, mk_body_dir(head_dir)); // directional body in old head pos + + if (do_grow) { + // food eaten, place new + place_food(); + } + } + } + } // end !crashed + + + // Render the board + for (uint8_t r = 0; r < ROWS / 2; r++) { + lcd_xy(0, r); + for (uint8_t c = 0; c < COLS; c++) { + const block_t t1 = get_block_xy(c, r * 2); + const block_t t2 = get_block_xy(c, (r * 2) + 1); + + uint8_t code = '!'; // ! marks fail + + if ((t1 == bEMPTY) && (t2 == bEMPTY)) { + code = CODE_XX; + if (crashed) code = '*'; + } else if (is_body(t1) && is_body(t2)) + code = CODE_BB; + else if (is_body(t1) && (t2 == bEMPTY)) + code = CODE_BX; + else if (t1 == bEMPTY && is_body(t2)) + code = CODE_XB; + else if ((t1 == bFOOD) || (t2 == bFOOD)) { + // one is food + + code = CODE_F; + + if (t1 == bFOOD) { + if (t2 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_FX); + else if (t2 == bHEAD) + lcd_define_glyph_pgm(code, SYMBOL_FH); + else if (is_body(t2)) + lcd_define_glyph_pgm(code, SYMBOL_FB); + } else { // t2 is food + if (t1 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_XF); + else if (t1 == bHEAD) + lcd_define_glyph_pgm(code, SYMBOL_HF); + else if (is_body(t1)) + lcd_define_glyph_pgm(code, SYMBOL_BF); + } + lcd_xy(c,r); + + } else if ((t1 == bHEAD )|| (t2 == bHEAD)) { + // one is head + + code = CODE_H; + + if (t1 == bHEAD) { + if (t2 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_HX); + else if (is_body(t2)) + lcd_define_glyph_pgm(code, SYMBOL_HB); + } else { // t2 is head + if (t1 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_XH); + else if (is_body(t1)) + lcd_define_glyph_pgm(code, SYMBOL_BH); + } + + lcd_xy(c,r); + } + + lcd_char(code); + } + } +} + +void main() { while(1); } // timer does everything diff --git a/devel/try_ws/Makefile b/devel/try_ws/Makefile new file mode 100644 index 0000000..9735d38 --- /dev/null +++ b/devel/try_ws/Makefile @@ -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 color.c wsrgb.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 + +cl: + ./client /dev/ttyUSB0 9600 + +fcl: all flash + ./client /dev/ttyUSB0 9600 + +# === 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 diff --git a/devel/try_ws/client b/devel/try_ws/client new file mode 100755 index 0000000..02f9449 Binary files /dev/null and b/devel/try_ws/client differ diff --git a/devel/try_ws/lib b/devel/try_ws/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/try_ws/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/try_ws/main.c b/devel/try_ws/main.c new file mode 100644 index 0000000..47cc020 --- /dev/null +++ b/devel/try_ws/main.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.h" +#include "lib/wsrgb.h" +#include "lib/uart.h" + +void main() +{ + ws_init(); + + xrgb_t c[3]; + c[0] = xrgb(255, 0, 255); + c[1] = xrgb(0, 255, 255); + c[2] = xrgb(255, 255, 0); + + while(1) { + ws_send_xrgb_array(c, 3); + + ws_show(); + + c[0].r++; + c[1].b++; + c[2].g++; + + _delay_ms(10); + } +} diff --git a/devel/try_ws/ws_config.h b/devel/try_ws/ws_config.h new file mode 100644 index 0000000..f7315b2 --- /dev/null +++ b/devel/try_ws/ws_config.h @@ -0,0 +1,7 @@ +#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 diff --git a/devel/uart/Makefile b/devel/uart/Makefile new file mode 100644 index 0000000..659c3d1 --- /dev/null +++ b/devel/uart/Makefile @@ -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 uart_ansi.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 serial + +ser: + gtkterm -p /dev/ttyUSB0 + +cl: + ./client /dev/ttyUSB0 9600 + +fcl: all flash + ./client /dev/ttyUSB0 9600 + +# === 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 diff --git a/devel/uart/client b/devel/uart/client new file mode 100755 index 0000000..02f9449 Binary files /dev/null and b/devel/uart/client differ diff --git a/devel/uart/clientd/Makefile b/devel/uart/clientd/Makefile new file mode 100644 index 0000000..4b30453 --- /dev/null +++ b/devel/uart/clientd/Makefile @@ -0,0 +1,7 @@ +all: client + +client: main.c + gcc -std=gnu99 main.c serial.c -o client + +run: client + ./client /dev/ttyUSB0 9600 diff --git a/devel/uart/clientd/client b/devel/uart/clientd/client new file mode 100755 index 0000000..02f9449 Binary files /dev/null and b/devel/uart/clientd/client differ diff --git a/devel/uart/clientd/main b/devel/uart/clientd/main new file mode 100644 index 0000000..e69de29 diff --git a/devel/uart/clientd/main.c b/devel/uart/clientd/main.c new file mode 100644 index 0000000..bd5262f --- /dev/null +++ b/devel/uart/clientd/main.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#include "serial.h" + +int main(int argc, char const *argv[]) +{ + if (argc < 2) { fprintf(stderr, "Missing parameter \n"); return 1; } + + int baud = 9600; + if (argc == 3) sscanf(argv[2], "%d", &baud); + + int fd = serial_open(argv[1], baud); + + // Wait for the Arduino to start + usleep(1500000); + + // Redirecting stdin/stdout to arduino + while(1) { + char buf[1]; + if (fread(buf, 1, 1, stdin) > 0) { + serial_write(fd, buf[0]); + fflush(stdout); + } + + char c; + c = serial_read(fd, 10); + if (c > 0) { + putchar(c); + fflush(stdout); + } + } +} + diff --git a/devel/uart/clientd/serial.c b/devel/uart/clientd/serial.c new file mode 100644 index 0000000..5516304 --- /dev/null +++ b/devel/uart/clientd/serial.c @@ -0,0 +1,89 @@ +#define _POSIX_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "serial.h" + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud) +{ + int fd = open(port, O_RDWR | O_NONBLOCK); + + struct termios tio; + memset(&tio, 0, sizeof(tio)); + + speed_t bd = baud; + switch(bd) { + case 1200: bd = B1200; break; + case 1800: bd = B1800; break; + case 2400: bd = B2400; break; + case 4800: bd = B4800; break; + case 9600: bd = B9600; break; + case 19200: bd = B19200; break; + case 38400: bd = B38400; break; + } + + tio.c_cflag = bd | CS8 | CLOCAL | CREAD | CRTSCTS; + tio.c_iflag = IGNPAR; + + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &tio); + return fd; +} + + +/** Close a serial port */ +int serial_close(int fd) +{ + return close(fd); +} + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b) +{ + return write(fd, &b, 1); +} + + +int serial_puts(int fd, const char* str) +{ + int len = strlen(str); + return write(fd, str, len); +} + + +uint8_t serial_read(int fd, int timeout) +{ + uint8_t b[1]; + do { + int n = read(fd, b, 1); + if (n == -1) return -1; + if (n == 0) { + usleep(1 * 1000); // wait 1 ms + timeout--; + continue; + } + return b[0]; + } while(timeout > 0); + return -1; +} + + +int serial_flush(int fd) +{ + sleep(2); + return tcflush(fd, TCIOFLUSH); +} diff --git a/devel/uart/clientd/serial.h b/devel/uart/clientd/serial.h new file mode 100644 index 0000000..aebcbf7 --- /dev/null +++ b/devel/uart/clientd/serial.h @@ -0,0 +1,27 @@ +#pragma once + +#include + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud); + + +/** Close a serial port */ +int serial_close(int fd); + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b); + + +/** Send a string */ +int serial_puts(int fd, const char* str); + + +/** Read a byte */ +uint8_t serial_read(int fd, int timeout); + + +/** Flush */ +int serial_flush(int fd); diff --git a/devel/uart/lib b/devel/uart/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/uart/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/uart/main.c b/devel/uart/main.c new file mode 100644 index 0000000..44735a3 --- /dev/null +++ b/devel/uart/main.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lib/uart.h" + +ISR(USART_RX_vect) +{ + uint8_t x = uart_rx(); + uart_tx(x); +} + +void main() +{ + uart_init(9600); + uart_isr_rx(1); + sei(); + while(1) { + //uart_puts_P(PSTR("TEST")); + } +} diff --git a/devel/uart/special_keys.txt b/devel/uart/special_keys.txt new file mode 100644 index 0000000..5f63c5f --- /dev/null +++ b/devel/uart/special_keys.txt @@ -0,0 +1,25 @@ + + Es [ ? +left 27 91 68 +right 27 91 67 +up 27 91 65 +down 27 91 66 + + Es [ ? ~ +insert 27 91 50 126 +delete 27 91 51 126 +pgup 27 91 53 126 +pgdn 27 91 54 126 + + Es O ? +f1 27 79 80 +f2 27 79 81 +f3 27 79 82 +f4 27 79 83 +home 27 79 72 +end 27 79 70 + +back 8 +tab 9 +enter 13 +esc 27 diff --git a/devel/ultrasonic/Makefile b/devel/ultrasonic/Makefile new file mode 100644 index 0000000..bfd145e --- /dev/null +++ b/devel/ultrasonic/Makefile @@ -0,0 +1,137 @@ +## === 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 uart_ansi.c sonar.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 + + +# === 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 diff --git a/devel/ultrasonic/lcd_config.h b/devel/ultrasonic/lcd_config.h new file mode 100644 index 0000000..594b506 --- /dev/null +++ b/devel/ultrasonic/lcd_config.h @@ -0,0 +1,13 @@ +#pragma once + +// Pin config file for LCD. + +#include "lib/arduino_pins.h" + +#define LCD_RS D2 +#define LCD_RW D3 +#define LCD_E D4 +#define LCD_D4 D5 +#define LCD_D5 D6 +#define LCD_D6 D7 +#define LCD_D7 D8 diff --git a/devel/ultrasonic/lib b/devel/ultrasonic/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/ultrasonic/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/ultrasonic/main.c b/devel/ultrasonic/main.c new file mode 100644 index 0000000..871f7a2 --- /dev/null +++ b/devel/ultrasonic/main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/calc.h" +#include "lib/uart.h" +#include "lib/uart_ansi.h" +#include "lib/pins.h" +#include "lib/arduino_pins.h" +#include "lib/sonar.h" + +ISR(PCINT0_vect) +{ + if (sonar_handle_pci()) return; +} + +// All PCINT vectors must call sonar_handle_pci +// This way, they are linked to PCINT0 +// so we can avoid code duplication +ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); +ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); + + +// Timer overflow - if sonar has a timeout -> 0xFFFF in result. +ISR(TIMER1_OVF_vect) +{ + if (sonar_handle_t1ovf()) return; +} + + +void main() +{ + uart_init(9600); + vt_init(); + + sonar_t so; + sonar_t so2; + + sonar_init(&so, A0, A1); + sonar_init(&so2, A2, A3); + + sei(); + + // end + int16_t res; + while(1) { + vt_clear(); + vt_home(); + uart_puts_pgm(PSTR("SONAR\r\n===================")); + + // first + vt_goto(99, 99); // move cursor away + sonar_start(&so); + while(sonar_busy()); + res = sonar_result(); + + // print value + vt_goto(0, 2); + uart_puts_pgm(PSTR("A: ")); + + if (res < 0) { + uart_puts_pgm(PSTR("No Obstacle")); + } else { + uart_puti(res, 1); + uart_puts_pgm(PSTR(" cm")); + } + + // second + vt_goto(99, 99); // move cursor away + sonar_start(&so2); + while(sonar_busy()); + res = sonar_result(); + + // print value + vt_goto(0, 3); + uart_puts_pgm(PSTR("B: ")); + + if (res < 0) { + uart_puts_pgm(PSTR("No Obstacle")); + } else { + uart_puti(res, 1); + uart_puts_pgm(PSTR(" cm")); + } + + vt_goto(99, 99); // move cursor away + _delay_ms(200); + } +} diff --git a/devel/xxx/Makefile b/devel/xxx/Makefile new file mode 100644 index 0000000..45868f3 --- /dev/null +++ b/devel/xxx/Makefile @@ -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 = fat16.c + +# Library directory (with C files) +EXTRA_SOURCE_DIR = lib/ +# C files in the library directory +EXTRA_SOURCE_FILES = + + +## === 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 serial + +ser: + gtkterm -p /dev/ttyUSB0 + +cl: + ./client /dev/ttyUSB0 9600 + +fcl: all flash + ./client /dev/ttyUSB0 9600 + +# === 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 diff --git a/devel/xxx/client b/devel/xxx/client new file mode 100755 index 0000000..02f9449 Binary files /dev/null and b/devel/xxx/client differ diff --git a/devel/xxx/clientd/Makefile b/devel/xxx/clientd/Makefile new file mode 100644 index 0000000..4b30453 --- /dev/null +++ b/devel/xxx/clientd/Makefile @@ -0,0 +1,7 @@ +all: client + +client: main.c + gcc -std=gnu99 main.c serial.c -o client + +run: client + ./client /dev/ttyUSB0 9600 diff --git a/devel/xxx/clientd/client b/devel/xxx/clientd/client new file mode 100755 index 0000000..02f9449 Binary files /dev/null and b/devel/xxx/clientd/client differ diff --git a/devel/xxx/clientd/main b/devel/xxx/clientd/main new file mode 100644 index 0000000..e69de29 diff --git a/devel/xxx/clientd/main.c b/devel/xxx/clientd/main.c new file mode 100644 index 0000000..bd5262f --- /dev/null +++ b/devel/xxx/clientd/main.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#include "serial.h" + +int main(int argc, char const *argv[]) +{ + if (argc < 2) { fprintf(stderr, "Missing parameter \n"); return 1; } + + int baud = 9600; + if (argc == 3) sscanf(argv[2], "%d", &baud); + + int fd = serial_open(argv[1], baud); + + // Wait for the Arduino to start + usleep(1500000); + + // Redirecting stdin/stdout to arduino + while(1) { + char buf[1]; + if (fread(buf, 1, 1, stdin) > 0) { + serial_write(fd, buf[0]); + fflush(stdout); + } + + char c; + c = serial_read(fd, 10); + if (c > 0) { + putchar(c); + fflush(stdout); + } + } +} + diff --git a/devel/xxx/clientd/serial.c b/devel/xxx/clientd/serial.c new file mode 100644 index 0000000..5516304 --- /dev/null +++ b/devel/xxx/clientd/serial.c @@ -0,0 +1,89 @@ +#define _POSIX_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "serial.h" + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud) +{ + int fd = open(port, O_RDWR | O_NONBLOCK); + + struct termios tio; + memset(&tio, 0, sizeof(tio)); + + speed_t bd = baud; + switch(bd) { + case 1200: bd = B1200; break; + case 1800: bd = B1800; break; + case 2400: bd = B2400; break; + case 4800: bd = B4800; break; + case 9600: bd = B9600; break; + case 19200: bd = B19200; break; + case 38400: bd = B38400; break; + } + + tio.c_cflag = bd | CS8 | CLOCAL | CREAD | CRTSCTS; + tio.c_iflag = IGNPAR; + + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &tio); + return fd; +} + + +/** Close a serial port */ +int serial_close(int fd) +{ + return close(fd); +} + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b) +{ + return write(fd, &b, 1); +} + + +int serial_puts(int fd, const char* str) +{ + int len = strlen(str); + return write(fd, str, len); +} + + +uint8_t serial_read(int fd, int timeout) +{ + uint8_t b[1]; + do { + int n = read(fd, b, 1); + if (n == -1) return -1; + if (n == 0) { + usleep(1 * 1000); // wait 1 ms + timeout--; + continue; + } + return b[0]; + } while(timeout > 0); + return -1; +} + + +int serial_flush(int fd) +{ + sleep(2); + return tcflush(fd, TCIOFLUSH); +} diff --git a/devel/xxx/clientd/serial.h b/devel/xxx/clientd/serial.h new file mode 100644 index 0000000..aebcbf7 --- /dev/null +++ b/devel/xxx/clientd/serial.h @@ -0,0 +1,27 @@ +#pragma once + +#include + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud); + + +/** Close a serial port */ +int serial_close(int fd); + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b); + + +/** Send a string */ +int serial_puts(int fd, const char* str); + + +/** Read a byte */ +uint8_t serial_read(int fd, int timeout); + + +/** Flush */ +int serial_flush(int fd); diff --git a/devel/xxx/fat16.c b/devel/xxx/fat16.c new file mode 100644 index 0000000..6658830 --- /dev/null +++ b/devel/xxx/fat16.c @@ -0,0 +1,1112 @@ +//#include +#include +#include +#include + +#include "fat16.h" + + + +// ============== INTERNAL PROTOTYPES ================== + +/** Read boot sector from given address */ +void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr); + +/** Find absolute address of first BootSector. Returns 0 on failure. */ +uint32_t find_bs(const BLOCKDEV* dev); + +/** Get cluster's starting address */ +uint32_t clu_addr(const FAT16* fat, const uint16_t cluster); + +/** Find following cluster using FAT for jumps */ +uint16_t next_clu(const FAT16* fat, uint16_t cluster); + +/** Find relative address in a file, using FAT for cluster lookup */ +uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr); + +/** 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); + +/** Allocate and chain new cluster to a chain starting at given cluster */ +bool append_cluster(const FAT16* fat, const uint16_t clu); + +/** Allocate a new cluster, clean it, and mark with 0xFFFF in FAT */ +uint16_t alloc_cluster(const FAT16* fat); + +/** Zero out entire cluster. */ +void wipe_cluster(const FAT16* fat, const uint16_t clu); + +/** Free cluster chain, starting at given number */ +void free_cluster_chain(const FAT16* fat, uint16_t clu); + +/** + * Check if there is already a file of given RAW name + * Raw name - name as found on disk, not "display name". + */ +bool dir_contains_file_raw(FAT16_FILE* dir, char* fname); + +/** Write a value into FAT */ +void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value); + +/** Read a value from FAT */ +uint16_t read_fat(const FAT16* fat, const uint16_t cluster); + +/** Go through a directory, and open first NONE or DELETED file. */ +bool find_empty_file_slot(FAT16_FILE* file); + + +// =========== INTERNAL FUNCTION IMPLEMENTATIONS ========= + + +uint16_t read16(const BLOCKDEV* dev) +{ + uint16_t a; + dev->load(&a, 2); + return a; +} + + +void write16(const BLOCKDEV* dev, const uint16_t val) +{ + dev->store(&val, 2); +} + +/** Find absolute address of first boot sector. Returns 0 on failure. */ +uint32_t find_bs(const BLOCKDEV* dev) +{ + // Reference structure: + // + // typedef struct __attribute__((packed)) { + // uint8_t first_byte; + // uint8_t start_chs[3]; + // uint8_t partition_type; + // uint8_t end_chs[3]; + // uint32_t start_sector; + // uint32_t length_sectors; + // } PartitionTable; + + uint16_t addr = 0x1BE + 4; // fourth byte of structure is the type. + uint32_t tmp = 0; + uint16_t tmp2; + + for (uint8_t i = 0; i < 4; i++, addr += 16) + { + // Read partition type + dev->seek(addr); + tmp = dev->read(); + + // Check if type is valid + if (tmp == 4 || tmp == 6 || tmp == 14) + { + // read MBR address + dev->rseek(3);// skip 3 bytes + dev->load(&tmp, 4); + + tmp = tmp << 9; // multiply address by 512 (sector size) + + // Verify that the boot sector has a valid signature mark + dev->seek(tmp + 510); + dev->load(&tmp2, 2); + if (tmp2 != 0xAA55) continue; // continue to next entry + + // return absolute MBR address + return tmp; + } + } + + return 0; +} + + +/** Read the boot sector */ +void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr) +{ + dev->seek(addr + 13); // skip 13 + + dev->load(&(info->sectors_per_cluster), 6); // spc, rs, nf, re + + info->total_sectors = 0; + dev->load(&(info->total_sectors), 2); // short sectors + + dev->rseek(1); // md + + dev->load(&(info->fat_size_sectors), 2); + + dev->rseek(8); // spt, noh, hs + + // read or skip long sectors field + if (info->total_sectors == 0) + { + dev->load(&(info->total_sectors), 4); + } + else + { + dev->rseek(4); // tsl + } + + dev->rseek(7); // dn, ch, bs, vi + + dev->load(&(info->volume_label), 11); +} + + +void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value) +{ + fat->dev->seek(fat->fat_addr + (cluster * 2)); + write16(fat->dev, value); +} + + +uint16_t read_fat(const FAT16* fat, const uint16_t cluster) +{ + fat->dev->seek(fat->fat_addr + (cluster * 2)); + return read16(fat->dev); +} + + +/** Get cluster starting address */ +uint32_t clu_addr(const FAT16* fat, const uint16_t cluster) +{ + if (cluster < 2) return fat->rd_addr; + return fat->data_addr + (cluster - 2) * fat->bs.bytes_per_cluster; +} + + +uint16_t next_clu(const FAT16* fat, uint16_t cluster) +{ + return read_fat(fat, cluster); +} + + +/** Find file-relative address in fat table */ +uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr) +{ + while (addr >= fat->bs.bytes_per_cluster) + { + cluster = next_clu(fat, cluster); + if (cluster == 0xFFFF) return 0xFFFF; // fail + addr -= fat->bs.bytes_per_cluster; + } + + return clu_addr(fat, cluster) + addr; +} + + +/** + * Zero out entire cluster + * This is important only for directory clusters, so we can + * zero only every first byte of each file entry, to indicate + * that it is unused (FT_NONE). + */ +void wipe_cluster(const FAT16* fat, const uint16_t clu) +{ + uint32_t addr = clu_addr(fat, clu); + + const BLOCKDEV* dev = fat->dev; + + dev->seek(addr); + + for (uint32_t b = 0; b < fat->bs.bytes_per_cluster; b += 32) + { + dev->write(0); + dev->rseek(32); + } +} + + +/** Allocate a new cluster, clean it, and mark with 0xFFFF in FAT */ +uint16_t alloc_cluster(const FAT16* fat) +{ + // find new unclaimed cluster that can be added to the chain. + uint16_t i, b; + for (i = 2; i < fat->bs.fat_size_sectors * 256; i++) + { + // read value from FAT + b = read_fat(fat, i); + if (b == 0) // unused cluster + { + // Write FFFF to "i", to mark end of file + write_fat(fat, i, 0xFFFF); + + // Wipe the cluster + wipe_cluster(fat, i); + + return i; + } + } + + return 0xFFFF;//error code +} + + +/** Allocate and chain new cluster to a chain starting at given cluster */ +bool append_cluster(const FAT16* fat, const uint16_t clu) +{ + uint16_t clu2 = alloc_cluster(fat); + if (clu2 == 0xFFFF) return false; + + // Write "i" to "clu" + write_fat(fat, clu, clu2); + + return true; +} + + +void free_cluster_chain(const FAT16* fat, uint16_t clu) +{ + do + { + // get address of the next cluster + const uint16_t clu2 = read_fat(fat, clu); + + // mark cluster as unused + write_fat(fat, clu, 0x0000); + + // advance + clu = clu2; + } + while (clu != 0xFFFF); +} + + +/** + * Check if there is already a file of given RAW name + * Raw name - name as found on disk, not "display name". + */ +bool dir_contains_file_raw(FAT16_FILE* dir, char* fname) +{ + do + { + bool diff = false; + for (uint8_t i = 0; i < 11; i++) + { + if (dir->name[i] != fname[i]) + { + diff = true; + break; + } + } + + if (!diff) return true; + + } + while (fat16_next(dir)); + + return false; +} + + +/** + * Read a file entry + * + * dir_cluster ... directory start cluster + * num ... entry number in the directory + */ +void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num) +{ + // Resolve starting address + uint32_t addr; + if (dir_cluster == 0) + { + addr = clu_addr(fat, dir_cluster) + num * 32; // root directory, max 512 entries. + } + else + { + addr = clu_offs(fat, dir_cluster, num * 32); // cluster + N (wrapping to next cluster if needed) + } + + fat->dev->seek(addr); + fat->dev->load(file, 12); // name, ext, attribs + fat->dev->rseek(14); // skip 14 bytes + fat->dev->load(((void*)file) + 12, 6); // read remaining bytes + + file->clu = dir_cluster; + file->num = num; + + // Resolve filename & type + + file->type = FT_FILE; + + const uint8_t c = file->name[0]; + switch (c) + { + case 0x00: + file->type = FT_NONE; + return; + + case 0xE5: + file->type = FT_DELETED; + return; + + case 0x05: // Starting with 0xE5 + file->type = FT_FILE; + file->name[0] = 0xE5; // convert to the real character + break; + + case 0x2E: + if (file->name[1] == 0x2E) + { + // ".." directory + file->type = FT_PARENT; + } + else + { + // "." directory + file->type = FT_SELF; + } + break; + + default: + if (c < 32) + { + file->type = FT_INVALID; // File is corrupt, treat it as invalid + } + else + { + file->type = FT_FILE; + } + } + + // handle subdir, label + if (file->attribs & FA_DIR && file->type == FT_FILE) + { + file->type = FT_SUBDIR; + } + else if (file->attribs == FA_LABEL) + { + file->type = FT_LABEL; // volume label special file + } + else if (file->attribs == 0x0F) + { + file->type = FT_LFN; // long name special file, can be ignored + } + + // add a FAT pointer + file->fat = fat; + + // Init cursors + fat16_fseek(file, 0); +} + + +void delete_file_do(FAT16_FILE* file) +{ + const FAT16* fat = file->fat; + + // seek to file record + fat->dev->seek(clu_offs(fat, file->clu, file->num * 32)); + + // mark as deleted + fat->dev->write(0xE5); // "deleted" mark + + // free allocated clusters + free_cluster_chain(fat, file->clu_start); + + file->type = FT_DELETED; +} + + + +/** + * Write information into a file header. + * "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) +{ + const BLOCKDEV* dev = file->fat->dev; + + const uint32_t entrystart = clu_offs(file->fat, file->clu, file->num * 32); + + // store the file name + dev->seek(entrystart); + dev->store(fname_raw, 11); + + // attributes + dev->write(attribs); + + // 10 reserved, 2+2 date & time + // (could just skip, but better to fill with zeros) + for (uint8_t i = 0; i < 14; i++) + { + dev->write(0); + } + + // addr of the first file cluster + write16(dev, clu_start); + + // file size (uint32_t) + write16(dev, 0); + write16(dev, 0); + + // reopen file - load & parse the information just written + open_file(file->fat, file, file->clu, file->num); +} + + +/** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */ +bool find_empty_file_slot(FAT16_FILE* file) +{ + const uint16_t clu = file->clu; + const FAT16* fat = file->fat; + + // Find free directory entry that can be used + for (uint16_t num = 0; num < 0xFFFF; num++) + { + // root directory has fewer entries, error if trying + // to add one more. + if (file->clu == 0 && num >= fat->bs.root_entries) + return false; + + // Resolve addres of next file entry + uint32_t addr; + do + { + addr = clu_offs(fat, file->clu, num * 32); + + if (addr == 0xFFFF) + { + // end of chain of allocated clusters for the directory + // append new cluster, return false on failure + if (!append_cluster(fat, file->clu)) return false; + } + + // if new cluster was just added, repeat. + } + while (addr == 0xFFFF); + + // Open the file entry + open_file(fat, file, clu, num); + + // Check if can be overwritten + if (file->type == FT_DELETED || file->type == FT_NONE) + { + return true; + } + } + + return false; // not found. +} + + +// =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= + +/** Initialize a FAT16 handle */ +void fat16_init(const BLOCKDEV* dev, FAT16* fat) +{ + const uint32_t bs_a = find_bs(dev); + fat->dev = dev; + read_bs(dev, &(fat->bs), bs_a); + fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512); + fat->rd_addr = bs_a + (fat->bs.reserved_sectors + fat->bs.fat_size_sectors * fat->bs.num_fats) * 512; + fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long + + fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512); +} + + +/** + * Move file cursor to a position relative to file start + * Allows seek past end of file, will allocate new cluster if needed. + */ +bool fat16_fseek(FAT16_FILE* file, uint32_t addr) +{ + const FAT16* fat = file->fat; + + // Store as rel + file->cur_rel = addr; + + // Rewind and resolve abs, clu, ofs + file->cur_clu = file->clu_start; + + while (addr >= fat->bs.bytes_per_cluster) + { + uint32_t next; + + // Go to next cluster, allocate if needed + do + { + next = next_clu(fat, file->cur_clu); + if (next == 0xFFFF) + { + // reached end of allocated space + // add one more cluster + if (!append_cluster(fat, file->cur_clu)) + { + return false; + } + } + } + while (next == 0xFFFF); + + file->cur_clu = next; + addr -= fat->bs.bytes_per_cluster; + } + + file->cur_abs = clu_addr(fat, file->cur_clu) + addr; + file->cur_ofs = addr; + + // Physically seek to that location + fat->dev->seek(file->cur_abs); + + return true; +} + + +/** + * Check if file is a valid entry (to be shown) + */ +bool fat16_is_file_valid(const FAT16_FILE* file) +{ + switch (file->type) + { + case FT_FILE: + case FT_SUBDIR: + case FT_SELF: + case FT_PARENT: + return true; + + default: + return false; + } +} + + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len) +{ + if (file->cur_abs == 0xFFFF) + return false; // file at the end already + + if (file->cur_rel + len > file->size) + return false; // Attempt to read more than what is available + + const FAT16* fat = file->fat; + const BLOCKDEV* dev = fat->dev; + + while (len > 0 && file->cur_rel < file->size) + { + // How much can be read from the cluster + uint16_t chunk = MIN(file->size - file->cur_rel, MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len)); + + // read the chunk + dev->seek(file->cur_abs); + dev->load(target, chunk); + + // move the cursors + file->cur_abs += chunk; + file->cur_rel += chunk; + file->cur_ofs += chunk; + + // move target pointer + target += chunk; + + // reached end of cluster? + if (file->cur_ofs >= fat->bs.bytes_per_cluster) + { + file->cur_clu = next_clu(fat, file->cur_clu); + file->cur_abs = clu_addr(fat, file->cur_clu); + file->cur_ofs = 0; + } + + // subtract read length + len -= chunk; + } + + return true; +} + + +bool fat16_fwrite(FAT16_FILE* file, void* source, uint32_t len) +{ + const FAT16* fat = file->fat; + const BLOCKDEV* dev = fat->dev; + + + if (file->cur_abs == 0xFFFF) + return false; // file at the end already + + // Attempt to write past end of file + if (file->cur_rel + len >= file->size) + { + const uint32_t pos_start = file->cur_rel; + + // Seek to the last position + // -> fseek will allocate clusters + if (!fat16_fseek(file, pos_start + len)) + return false; // error in seek + + // Write starts beyond EOF - creating a zero-filled "hole" + if (file->cur_rel > file->size) + { + // Seek to the end of valid data + fat16_fseek(file, file->size); + + // fill space between EOF and start-of-write with zeros + uint32_t fill = pos_start - file->size; + + // repeat until all "fill" zeros are stored + while (fill > 0) + { + // How much will fit into this cluster + const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, fill); + + // write the zeros + dev->seek(file->cur_abs); + for (uint16_t i = 0; i < chunk; i++) + { + dev->write(0); + } + + // subtract from "needed" what was just placed + fill -= chunk; + + // advance cursors to the next cluster + file->cur_clu = next_clu(fat, file->cur_clu); + file->cur_abs = clu_addr(fat, file->cur_clu); + file->cur_ofs = 0; + } + } + + // Save new size + fat16_resize(file, pos_start + len); + + // Seek back to where it was before + fat16_fseek(file, pos_start); + } // (end zerofill) + + + // write the data + 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->store(source, chunk); + + // advance cursors + file->cur_abs += chunk; + file->cur_rel += chunk; + file->cur_ofs += chunk; + + // Pointer arith! + source += chunk; // advance the source pointer + + // detect cluster overflow + if (file->cur_ofs >= fat->bs.bytes_per_cluster) + { + // advance to following cluster + file->cur_clu = next_clu(fat, file->cur_clu); + file->cur_abs = clu_addr(fat, file->cur_clu); + file->cur_ofs = 0; + } + + // subtract written length + len -= chunk; + } + + return true; +} + + + +/** Open next file in the directory */ +bool fat16_next(FAT16_FILE* file) +{ + const FAT16* fat = file->fat; + const BLOCKDEV* dev = fat->dev; + + if (file->clu == 0 && file->num >= fat->bs.root_entries) + return false; // attempt to read outside root directory. + + const uint32_t addr = clu_offs(fat, file->clu, (file->num + 1) * 32); + if (addr == 0xFFFF) + return false; // next file is out of the directory cluster + + // read first byte of the file entry + dev->seek(addr); + if (dev->read() == 0) + return false; // can't read (file is NONE) + + open_file(fat, file, file->clu, file->num + 1); + + return true; +} + + +/** Open previous file in the directory */ +bool fat16_prev(FAT16_FILE* file) +{ + if (file->num == 0) + return false; // first file already + + open_file(file->fat, file, file->clu, file->num - 1); + + return true; +} + + +/** Rewind to first file in directory */ +void fat16_first(FAT16_FILE* file) +{ + open_file(file->fat, file, file->clu, 0); +} + + +/** Open a directory denoted by the file. */ +bool fat16_opendir(FAT16_FILE* file) +{ + // Don't open non-dirs and "." directory. + if (!(file->attribs & FA_DIR) || file->type == FT_SELF) + return false; + + open_file(file->fat, file, file->clu_start, 0); + return true; +} + + +void fat16_root(const FAT16* fat, FAT16_FILE* file) +{ + open_file(fat, file, 0, 0); +} + + +/** + * Find a file with given "display name" in this directory. + * 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) +{ + char fname[11]; + fat16_rawname(name, fname); + return dir_contains_file_raw(dir, fname); +} + +bool fat16_mkfile(FAT16_FILE* file, const char* name) +{ + // Convert filename to zero padded raw string + char fname[11]; + fat16_rawname(name, fname); + + // Abort if file already exists + bool exists = dir_contains_file_raw(file, fname); + fat16_first(file); // rewind dir + if (exists) + return false; // file already exists in the dir. + + + if (!find_empty_file_slot(file)) + return false; // error finding a slot + + // Write into the new slot + const uint16_t newclu = alloc_cluster(file->fat); + write_file_header(file, fname, 0, newclu); + + return true; +} + + +/** + * Create a sub-directory of given name. + * Directory is allocated and populated with entries "." and ".." + */ +bool fat16_mkdir(FAT16_FILE* file, const char* name) +{ + // Convert filename to zero padded raw string + char fname[11]; + fat16_rawname(name, fname); + + // Abort if file already exists + bool exists = dir_contains_file_raw(file, fname); + fat16_first(file); // rewind dir + if (exists) + return false; // file already exusts in the dir. + + if (!find_empty_file_slot(file)) + return false; // error finding a slot + + + // Write into the new slot + const uint16_t newclu = alloc_cluster(file->fat); + write_file_header(file, fname, FA_DIR, newclu); + + const uint32_t parent_clu = file->clu; + open_file(file->fat, file, file->clu_start, 0); + + write_file_header(file, ". ", FA_DIR, newclu); + + // Advance to next file slot + find_empty_file_slot(file); + + write_file_header(file, ".. ", FA_DIR, parent_clu); + + // rewind. + fat16_first(file); + + return true; +} + + +char* fat16_disk_label(const FAT16* fat, char* label_out) +{ + FAT16_FILE first; + fat16_root(fat, &first); + + if (first.type == FT_LABEL) + { + return fat16_dispname(&first, label_out); + } + + // find where spaces end + int8_t j = 10; + for (; j >= 0; j--) + { + if (fat->bs.volume_label[j] != ' ') break; + } + + // copy all until spaces + uint8_t i; + for (i = 0; i <= j; i++) + { + label_out[i] = fat->bs.volume_label[i]; + } + + label_out[i] = 0; // ender + + return label_out; +} + + +char* fat16_dispname(const FAT16_FILE* file, char* disp_out) +{ + // Cannot get name for special files + if (file->type == FT_NONE || // not-yet-used directory location + file->type == FT_DELETED || // deleted file entry + file->attribs == 0x0F) // long name special entry (system, hidden) + return NULL; + + // find first non-space + int8_t j = 7; + for (; j >= 0; j--) + { + if (file->name[j] != ' ') break; + } + + // j ... last no-space char + + uint8_t i; + for (i = 0; i <= j; i++) + { + disp_out[i] = file->name[i]; + } + + + // directory entry, no extension + if (file->type == FT_SUBDIR || file->type == FT_SELF || file->type == FT_PARENT) + { + disp_out[i] = 0; // end of string + return disp_out; + } + + + // add a dot + if (file->type != FT_LABEL) // volume label has no dot! + disp_out[i++] = '.'; + + // Add extension chars + for (j = 8; j < 11; j++, i++) + { + const char c = file->name[j]; + if (c == ' ') break; + disp_out[i] = c; + } + + disp_out[i] = 0; // end of string + + return disp_out; +} + + +char* fat16_rawname(const char* disp_in, char* raw_out) +{ + uint8_t name_c = 0, wr_c = 0; + bool filling = false; + bool at_ext = false; + for (; wr_c < 11; wr_c++) + { + // start filling with spaces if end of filename reached + uint8_t c = disp_in[name_c]; + // handle special rule for 0xE5 + if (name_c == 0 && c == 0xE5) + { + c = 0x05; + } + + if (c == '.' || c == 0) + { + if (!filling) + { + filling = true; + + if (c == '.') + { + name_c++; // skip the dot + c = disp_in[name_c]; + at_ext = true; + } + } + } + + // if at the start of ext + if (wr_c == 8) + { + if (!at_ext) + { + // try to advance past dot (if any) + while (true) + { + c = disp_in[name_c++]; + if (c == 0) break; + if (c == '.') + { + // read char PAST the dot + c = disp_in[name_c]; + at_ext = true; + break; + } + } + } + + // if c has valid char for extension + if (c != 0 && c != '.') + { + // start copying again. + filling = false; + } + } + + if (!filling) + { + // copy char of filename + raw_out[wr_c] = disp_in[name_c++]; + } + else + { + // add a filler space + raw_out[wr_c] = ' '; + } + } + + return raw_out; +} + + +/** Write new file size (also to the disk). Does not allocate clusters. */ +void fat16_resize(FAT16_FILE* file, uint32_t size) +{ + const FAT16* fat = file->fat; + const BLOCKDEV* dev = file->fat->dev; + + // Find address for storing the size + const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28); + file->size = size; + + dev->seek(addr); + dev->store(&size, 4); + + // Seek to the end of the file, to make sure clusters are allocated + fat16_fseek(file, size - 1); + + const uint16_t next = next_clu(fat, file->cur_clu); + if (next != 0xFFFF) + { + free_cluster_chain(fat, next); + + // Mark that there's no further clusters + write_fat(fat, file->cur_clu, 0xFFFF); + } +} + +/** Delete a simple file */ +bool fat16_rmfile(FAT16_FILE* file) +{ + if (file->type != FT_FILE) + return false; // not a simple file + + delete_file_do(file); + return true; +} + + +/** Delete an empty directory */ +bool fat16_rmdir(FAT16_FILE* file) +{ + if (file->type != FT_SUBDIR) + return false; // not a subdirectory entry + + const FAT16* fat = file->fat; + + const uint16_t dir_clu = file->clu; + const uint16_t dir_num = file->num; + + // Look for valid files and subdirs in the directory + if (!fat16_opendir(file)) + return false; // could not open + + uint8_t cnt = 0; + do + { + // Stop on apparent corrupt structure (missing "." or "..") + // Can safely delete the folder. + if (cnt == 0 && file->type != FT_SELF) break; + if (cnt == 1 && file->type != FT_PARENT) break; + + // Found valid file + if (file->type == FT_SUBDIR || file->type == FT_FILE) + { + // Valid child file was found, aborting. + // reopen original file + open_file(fat, file, dir_clu, dir_num); + return false; + } + + if (cnt < 2) cnt++; + } + while (fat16_next(file)); + + // reopen original file + open_file(fat, file, dir_clu, dir_num); + + // and delete as ordinary file + delete_file_do(file); + + return true; +} + + +bool fat16_parent(FAT16_FILE* file) +{ + const uint16_t clu = file->clu; + const uint16_t num = file->num; + + // open second entry of the directory + open_file(file->fat, file, file->clu, 1); + + // if it's a valid PARENT link, follow it. + if (file->type == FT_PARENT) + { + open_file(file->fat, file, file->clu_start, 0); + return true; + } + else + { + // maybe in root already? + + // reopen original file + open_file(file->fat, file, clu, num); + return false; + } +} diff --git a/devel/xxx/fat16.h b/devel/xxx/fat16.h new file mode 100644 index 0000000..ff34d92 --- /dev/null +++ b/devel/xxx/fat16.h @@ -0,0 +1,260 @@ +#pragma once + +/** Abstract block device interface */ +typedef struct +{ + // Sequential read + void (*load)(void* dest, const uint16_t len); + // Sequential write + void (*store)(const void* src, const uint16_t len); + // Sequential byte write + void (*write)(const uint8_t b); + // Sequential byte read + uint8_t (*read)(void); + // Absolute seek + void (*seek)(const uint32_t); + // Relative seek + void (*rseek)(const int16_t); +} BLOCKDEV; + + +// ------------------------------- + +/** file types (values don't matter) */ +typedef enum +{ + FT_NONE = '-', + FT_DELETED = 'x', + FT_SUBDIR = 'D', + FT_PARENT = 'P', + FT_LABEL = 'L', + FT_LFN = '~', + FT_INVALID = 'i', // not recognized weird file + FT_SELF = '.', + FT_FILE = 'F' +} FAT16_FT; + + +// File Attributes (bit flags) +#define FA_READONLY 0x01 // read only file +#define FA_HIDDEN 0x02 // hidden file +#define FA_SYSTEM 0x04 // system file +#define FA_LABEL 0x08 // volume label entry, found only in root directory. +#define FA_DIR 0x10 // subdirectory +#define FA_ARCHIVE 0x20 // archive flag + + +/** Boot Sector structure - INTERNAL! */ +typedef struct __attribute__((packed)) +{ + + // Fields loaded directly from disk: + + // 13 bytes skipped + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t num_fats; + uint16_t root_entries; + // 3 bytes skipped + uint16_t fat_size_sectors; + // 8 bytes skipped + uint32_t total_sectors; // if "short size sectors" is used, it's copied here too + // 7 bytes skipped + char volume_label[11]; // space padded, no terminator + + // Added fields: + + uint32_t bytes_per_cluster; + +} +Fat16BootSector; + + +/** FAT filesystem handle - private fields! */ +typedef struct __attribute__((packed)) +{ + // Backing block device + const BLOCKDEV* dev; + + // Root directory sector start + uint32_t rd_addr; + + // Start of first cluster (number "2") + uint32_t data_addr; + + // Start of fat table + uint32_t fat_addr; + + // Boot sector data struct + Fat16BootSector bs; +} +FAT16; + + +/** File handle struct */ +typedef struct __attribute__((packed)) +{ + // Fields loaded directly from disk: + + uint8_t name[11]; // Starting 0x05 converted to 0xE5, other "magic chars" left intact + uint8_t attribs; // composed of FA_* constants + // 14 bytes skipped + uint16_t clu_start; + uint32_t size; + + // Added fields: + + FAT16_FT type; + + // --- Private fields --- + + // Cursor + uint32_t cur_abs; // absolute position in device + uint32_t cur_rel; // relative position in file + uint16_t cur_clu; // cluster where the cursor is + uint16_t cur_ofs; // offset within the active cluster + + // File position in the directory + uint16_t clu; // first cluster of directory + uint16_t num; // fiel entry number + + // pointer to FAT + const FAT16* fat; +} +FAT16_FILE; + + +/** Initialize a filesystem */ +void fat16_init(const BLOCKDEV* dev, FAT16* fat); + + +/** + * Open the first file of the root directory. + * The file may be invalid (eg. a volume label, deleted etc), + * or blank (type FT_NONE) if the filesystem is empty. + * + * Either way, the prev and next functions will work as expected. + */ +void fat16_root(const FAT16* fat, FAT16_FILE* file); + + +/** + * Resolve the disk label. + */ +char* fat16_disk_label(const FAT16* fat, char* label_out); + + +// ----------- FILE I/O ------------- + + +/** + * Move file cursor to a position relative to file start + * Returns false on I/O error (bad file, out of range...) + */ +bool fat16_fseek(FAT16_FILE* file, uint32_t addr); + + +/** + * Read bytes from file into memory + * Returns false on I/O error (bad file, out of range...) + */ +bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len); + + +/** + * Write into file at a "seek" position. + * "seek" cursor must be within (0..filesize) + */ +bool fat16_fwrite(FAT16_FILE* file, void* source, uint32_t len); + + +/** + * Create a new file in given folder + * + * file ... open directory; new file is opened into this handle. + * name ... name of the new file, including extension + */ +bool fat16_mkfile(FAT16_FILE* file, const char* name); + + +/** + * Create a sub-directory of given name. + * Directory is allocated and populated with entries "." and ".." + */ +bool fat16_mkdir(FAT16_FILE* file, const char* name); + + +/** + * Write new file size (also to the disk). + * Allocates / frees needed clusters, does not erase them. + */ +void fat16_resize(FAT16_FILE* file, uint32_t size); + + +/** + * Delete a file entry and free clusters. + * Does NOT work on folders. + */ +bool fat16_rmfile(FAT16_FILE* file); + + +/** + * Delete an empty directory. + * Calling with non-subfolder entry or non-empty directory will cause error. + */ +bool fat16_rmdir(FAT16_FILE* file); + +// --------- NAVIGATION ------------ + + +/** Go to previous file in the directory (false = no prev file) */ +bool fat16_prev(FAT16_FILE* file); + + +/** Go to next file in directory (false = no next file) */ +bool fat16_next(FAT16_FILE* file); + + +/** + * Open a subdirectory denoted by the file. + * Provided handle changes to first entry of the directory. + */ +bool fat16_opendir(FAT16_FILE* file); + +/** + * Open a parent directory. Fails in root. + */ +bool fat16_parent(FAT16_FILE* file); + + +/** Rewind to first file in directory */ +void fat16_first(FAT16_FILE* file); + + +/** + * Find a file with given "display name" in this directory. + * 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); + + +// -------- FILE INSPECTION ----------- + +/** Check if file is a valid entry, or long-name/label/deleted */ +bool fat16_is_file_valid(const FAT16_FILE* file); + + +/** + * Resolve a file name, trim spaces and add null terminator. + * Returns the passed char*, or NULL on error. + */ +char* fat16_dispname(const FAT16_FILE* file, char* disp_out); + + +/** + * Convert filename to zero-padded fixed length one + * Returns the passed char*. + */ +char* fat16_rawname(const char* disp_in, char* raw_out); + diff --git a/devel/xxx/lib b/devel/xxx/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/xxx/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/xxx/main.c b/devel/xxx/main.c new file mode 100644 index 0000000..ac387f3 --- /dev/null +++ b/devel/xxx/main.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "fat16.h" + +BLOCKDEV test; + +void test_seek(const uint32_t pos) +{ + asm volatile (""); +} + +void test_rseek(const int16_t pos) +{ + asm volatile (""); +} + +void test_load(void* dest, const uint16_t len) +{ + asm volatile (""); +} + +void test_store(const void* source, const uint16_t len) +{ + asm volatile (""); +} + +void test_write(const uint8_t b) +{ + asm volatile (""); +} + +uint8_t test_read() +{ + return 0; +} + +void test_open() +{ + test.read = &test_read; + test.write = &test_write; + + test.load = &test_load; + test.store = &test_store; + + test.seek = &test_seek; + test.rseek = &test_rseek; +} + + +void main() +{ + test_open(); + + // Initialize the FS + FAT16 fat; + fat16_init(&test, &fat); + + FAT16_FILE file; + fat16_root(&fat, &file); + + char str[10]; + +fat16_disk_label(&fat, str); + + +// ----------- FILE I/O ------------- + + +/** + * Move file cursor to a position relative to file start + * Returns false on I/O error (bad file, out of range...) + */ +fat16_fseek(&file, 1234); + + +/** + * Read bytes from file into memory + * Returns false on I/O error (bad file, out of range...) + */ +fat16_fread(&file, str, 10); + + +/** + * Write into file at a "seek" position. + * "seek" cursor must be within (0..filesize) + */ +fat16_fwrite(&file, str, 10); + + +/** Go to next file in directory (false = no next file) */ +fat16_next(&file); + + + while(1) { + //uart_puts_P(PSTR("TEST")); + } +}