diff --git a/lib/arduino_pins.h b/lib/arduino_pins.h new file mode 100644 index 0000000..6f90221 --- /dev/null +++ b/lib/arduino_pins.h @@ -0,0 +1,28 @@ +#pragma once + +/** + Pin definitions for Arduino (Pro Mini with ATmega328P) +*/ + +#include "pins.h" + +#define D0 D,0 +#define D1 D,1 +#define D2 D,2 +#define D3 D,3 +#define D4 D,4 +#define D5 D,5 +#define D6 D,6 +#define D7 D,7 +#define D8 B,0 +#define D9 B,1 +#define D10 B,2 +#define D11 B,3 +#define D12 B,4 +#define D13 B,5 +#define A0 C,0 +#define A1 C,1 +#define A2 C,2 +#define A3 C,3 +#define A4 C,4 +#define A5 C,5 diff --git a/lib/calc.h b/lib/calc.h new file mode 100644 index 0000000..15f0be2 --- /dev/null +++ b/lib/calc.h @@ -0,0 +1,37 @@ +#pragma once + +/** + General purpose calculation and bit manipulation utilities. +*/ + +// if max, go to zero. Else increment. +#define inc_wrap(var, max) do { if ((var) >= (max)) { (var)=0; } else { (var)++; } } while(0) + +// If zero, go to max. Else decrement, +#define dec_wrap(var, max) do { if ((var) > 0) { (var)--; } else { (var)=(max); } } while(0) + +// Check if value is in range A..B or B..A +#define in_range(x, low, high) (((low) < (high)) && ((x) > (low) && (x) < (high))) || (((low) > (high)) && ((x) < (low) || (x) > (high))) + +// Check if value is in range A..B. If B < A, matches all outside B..A +#define in_range_wrap(x, low, high) (((low) < (high)) && ((x) > (low) && (x) < (high))) || (((low) > (high)) && ((x) > (low) || (x) < (high))) + +// === general bit manipulation with register === +#define set_bit(reg, bit) do { (reg) |= (1 << bit); } while(0) +#define clear_bit(reg, bit) do { (reg) &= ~(1 << bit); } while(0) +#define toggle_bit(reg, bit) do { (reg) ^= (1 << bit); } while(0) + +#define sbi(reg, bit) set_bit(reg, bit) +#define cbi(reg, bit) clear_bit(reg, bit) + +#define read_bit(reg, bit) ((((uint8_t)(reg)) >> ((uint8_t)(bit))) & 0x1) +#define write_bit(reg, bit, value) do { (reg) = (((reg) & ~(1 << bit)) | ((value & 0x1) << (bit))); } while(0) + + +// general pin manipulation - with pointer to register +#define set_bit_p(reg_p, bit) do { (*reg_p) |= (1 << bit); } while(0) +#define clear_bit_p(reg_p, bit) do { (*reg_p) &= ~(1 << bit); } while(0) +#define sbi_p(reg_p, bit) set_bit_p(reg_p, bit) +#define cbi_p(reg_p, bit) clear_bit_p(reg_p, bit) +#define read_bit_p(reg_p, bit) ((((uint8_t)(*reg_p)) >> ((uint8_t)(bit))) & 0x1) +#define write_bit_p(reg_p, bit, value) do { (*reg_p) = (((*reg_p) & ~(1 << bit)) | ((value & 0x1) << (bit))); } while(0) diff --git a/lib/colors.h b/lib/colors.h new file mode 100644 index 0000000..454923b --- /dev/null +++ b/lib/colors.h @@ -0,0 +1,57 @@ +#pragma once + +/* + Some useful utilities for RGB color manipulation +*/ + +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} xrgb_t; + +typedef uint32_t rgb24_t; +typedef uint16_t rgb16_t; +typedef uint16_t rgb12_t; +typedef uint8_t rgb6_t; + + +#define xrgb(rr, gg, bb) { .r = ((uint8_t)(rr)), .g = ((uint8_t)(gg)), .b = ((uint8_t)(bb)) } +#define xrgb_r(c) ((uint8_t)(c.r)) +#define xrgb_g(c) ((uint8_t)(c.g)) +#define xrgb_b(c) ((uint8_t)(c.b)) +#define xrgb_rgb24(c) ((((rgb24_t)c.r) << 16) | (((rgb24_t)c.g) << 8) | (((rgb24_t)c.b))) +#define xrgb_rgb15(c) (((((rgb15_t)c.r) & 0xF8) << 7) | ((((rgb15_t)c.g) & 0xF8) << 2) | ((((rgb15_t)c.b) & 0xF8) >> 3)) +#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4)) +#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6)) + + +#define rgb24(r,g,b) ((rgb24_t) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))) +#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF) +#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF) +#define rgb24_b(c) ((((rgb24_t) (c)) >> 0) & 0xFF) +#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c)) + + +#define rgb15(r,g,b) ((rgb16_t) (((r & 0x1F) << 10) | ((g & 0x1F) << 5) | (b & 0x1F))) +#define rgb15_r(c) ((((rgb15_t) (c)) & 0x7C00) >> 7) +#define rgb15_g(c) ((((rgb15_t) (c)) & 0x3E0) >> 2) +#define rgb15_b(c) ((((rgb15_t) (c)) & 0x1F) << 3) +#define rgb15_xrgb(c) xrgb(rgb15_r(c), rgb15_g(c), rgb15_b(c)) +#define rgb15_rgb24(c) rgb24(rgb15_r(c), rgb15_g(c), rgb15_b(c)) + + +#define rgb12(r,g,b) ((rgb12_t) (((r & 0xF) << 8) | ((g & 0xF) << 4) | (b & 0xF))) +#define rgb12_r(c) ((((rgb12_t) (c)) & 0xF00) >> 4) +#define rgb12_g(c) (((rgb12_t) (c)) & 0xF0) +#define rgb12_b(c) (((r(rgb12_t) (c)gb) & 0x0F) << 4) +#define rgb12_xrgb(c) xrgb(rgb12_r(c), rgb12_g(c), rgb12_b(c)) +#define rgb12_rgb24(c) rgb24(rgb12_r(c), rgb12_g(c), rgb12_b(c)) + + +#define rgb6(r,g,b) ((rgb6_t) (((r & 3) << 4) | ((g & 3) << 2) | (b & 3))) +#define rgb6_r(c) ((((rgb6_t) (c)) & 0x30) << 2) +#define rgb6_g(c) ((((rgb6_t) (c)) & 0xC) << 4) +#define rgb6_b(c) ((((rgb6_t) (c)) & 0x3) << 6) +#define rgb6_xrgb(c) xrgb(rgb6_r(c), rgb6_g(c), rgb6_b(c)) +#define rgb6_rgb24(c) rgb24(rgb6_r(c), rgb6_g(c), rgb6_b(c)) diff --git a/lib/debounce.h b/lib/debounce.h new file mode 100644 index 0000000..5301020 --- /dev/null +++ b/lib/debounce.h @@ -0,0 +1,116 @@ +#pragma once + +/** + An implementation of button debouncer. + + First, the system must be initialized: + + debounce_init(); + + A pin is registered for debouncing by calling + + #define BTN0 B,0 + #define BTN1 B,1 + + debounce_register(0, BTN0); + debounce_register(1, BTN1); + + Then periodically the tick function must be called: + + debounce_tick(); + + To check if pin is high, use + + debounce_get_pin(0); // registered as #0 + debounce_get_pin(1); // registered as #1 +*/ + +#include "pins.h" +#include "calc.h" +#include "avr/io.h" + +/** Number of ticks the pin must be in given state */ +#ifndef DEBOUNCE_TICKS +# define DEBOUNCE_TICKS 5 +#endif + +/** Max number of pins observed */ +#ifndef DEBOUNCE_SLOT_COUNT +#define DEBOUNCE_SLOT_COUNT 16 +#endif + + +/* Internal deboucer entry */ +typedef struct { + PORT_P port; + PIN_N bit; + uint8_t count; + bool state; +} debounce_slot_t; + + +/** Debounce data array */ +debounce_slot_t debounce_slots[DEBOUNCE_SLOT_COUNT]; + + +/** Init the debounce slots table */ +void debounce_init() +{ + for (uint8_t i = 0; i < DEBOUNCE_SLOT_COUNT; i++) { + debounce_slots[i] = { + .port = (PORT_P)0; + .bit = 0; + .state = 0; + .count = 0; + }; + } +} + + +/** Define a debounced pin (must be IO!) */ +inline void debounce_register_real(uint8_t number, PORT_P port, PIN_N bit) +{ + debounce_slots[number] = { + .port = port; + .bit = bit; + .count = 0; + .state = 0; + }; +} + +#define debounce_register(number, io) debounce_register_real((number), &io2port(io), io2n(io)) + + +/** Check debounced pins, should be called periodically. */ +void debounce_tick() +{ + for (uint8_t i = 0; i < DEBOUNCE_SLOT_COUNT; i++) { + + if (debounce_slots[i].port == 0) continue; // slot is unused + + // current pin value + bool value = read_bit_p(debounce_slots[i].port, debounce_slots[i].bit); + + if (value != debounce_slots[i].state) { + + // different pin state than last recorded state + if (debounce_slots[i].count < DEBOUNCE_TICKS) { + // increment + if (++debounce_slots[i].count == DEBOUNCE_TICKS) { + // overflown -> latch value + debounce_slots[i].state = value; + } + } + + } else { + debounce_slots[i].count = 0; // reset the counter + } + } +} + + +/** Get a value of debounced pin */ +inline bool debounce_get_pin(uint8_t number) +{ + return debounce_slots[number].state; +} diff --git a/lib/meta.h b/lib/meta.h new file mode 100644 index 0000000..ec16799 --- /dev/null +++ b/lib/meta.h @@ -0,0 +1,6 @@ +#pragma once + +/** Weird constructs for the compiler */ + +// general macros +#define SECTION(pos) __attribute__((naked, used, section(pos))) diff --git a/lib/nsdelay.h b/lib/nsdelay.h new file mode 100644 index 0000000..0a1e843 --- /dev/null +++ b/lib/nsdelay.h @@ -0,0 +1,18 @@ +#pragma once + +/** + Functions for precise delays (nanoseconds / cycles) +*/ + +#include +#include +#include + +/* Convert nanoseconds to cycle count */ +#define ns2cycles(ns) ( (ns) / (1000000000L / (signed long) F_CPU) ) + +/** Wait c cycles */ +#define delay_c(c) (((c) > 0) ? __builtin_avr_delay_cycles(c) : __builtin_avr_delay_cycles(0)) + +/** Wait n nanoseconds, plus c cycles */ +#define delay_ns_c(ns, c) delay_c(ns2cycles(ns) + (c)) diff --git a/lib/pins.h b/lib/pins.h new file mode 100644 index 0000000..37ed335 --- /dev/null +++ b/lib/pins.h @@ -0,0 +1,109 @@ +#pragma once + +/** + This file provides macros for pin manipulation. + + You can define your application pins like so: + + // Led at PORTB, pin 1 + #define LED B,1 + + // Switch at PORTD, pin 7 + #define SW1 D,7 + + Now you can use macros from this file to wirh with the pins, eg: + + as_output(LED); + as_input(SW1); + pullup_on(SW1); + + toggle_pin(LED); + while (pin_is_low(SW1)); + + - The macros io2XXX() can be used to get literal name of register associated with the pin. + io2n() provides pin number. + - The XXX_aux() macros are internal and should not be used elsewhere. + - The io_pack() macro is used to pass pin (io) to other macro without expanding it. + + Additionaly, there's general-purpose bit-manipulation macros (set_bit, clear_bit etc.). + Those work with register name and pin number, not the "io" format (#define LED2 D,3). + +*/ + +#include +#include "calc.h" + + +// Get particular register associated with the name X (eg. D -> PORTD) +#define reg_ddr(X) DDR ## X +#define reg_port(X) PORT ## X +#define reg_pin(X) PIN ## X + +#define io2ddr_aux(reg, bit) reg_ddr(reg) +#define io2ddr(io) io2ddr_aux(io) +#define io2port_aux(reg, bit) reg_port(reg) +#define io2port(io) io2port_aux(io) +#define io2pin_aux(reg, bit) reg_pin(reg) +#define io2pin(io) io2pin_aux(io) +#define io2n_aux(reg, bit) bit +#define io2n(io) io2n_aux(io) + +#define io_pack(port, bit) port, bit + + +// pointer to port +typedef volatile uint8_t* PORT_P; +// number of bit in port +typedef uint8_t BIT_N; + + +// === pin manipulation === +#define set_pin_aux(port, bit) set_bit(reg_port(port), bit) +#define clear_pin_aux(port, bit) clear_bit(reg_port(port), bit) +#define read_pin_aux(port, bit) read_bit(reg_pin(port), bit) +#define write_pin_aux(port, bit, value) write_bit(reg_port(port), bit, value) +#define toggle_pin_aux(port, bit) set_bit(reg_pin(port), bit) + + +#define set_pin(io) set_pin_aux(io) +#define pin_high(io) set_pin_aux(io) + +#define clear_pin(io) clear_pin_aux(io) +#define pin_low(io) clear_pin_aux(io) + +#define read_pin(io) read_pin_aux(io) + +#define pin_is_low(io) !read_pin_aux(io) +#define pin_is_high(io) read_pin_aux(io) + +#define write_pin(io, value) write_pin_aux(io, value) + +#define toggle_pin(io) toggle_pin_aux(io) + + + +// setting pin direction +#define as_input_aux(port, bit) clear_bit(reg_ddr(port), bit) +#define as_output_aux(port, bit) set_bit(reg_ddr(port), bit) +#define set_dir_aux(port, bit, dir) write_bit(reg_ddr(port), bit, dir) + + +#define as_input(io) as_input_aux(io) +#define as_output(io) as_output_aux(io) +#define set_dir(io, dir) set_dir_aux(io, dir) + + + +// setting pullup +#define pullup_enable_aux(port, bit) set_bit(reg_port(port), bit) +#define pullup_disable_aux(port, bit) clear_bit(reg_port(port), bit) +#define set_pullup_aux(port, bit, on) write_bit(reg_port(port), bit, on) + + +#define pullup_enable(io) pullup_enable_aux(io) +#define pullup_on(io) pullup_enable_aux(io) + +#define pullup_disable(io) pullup_disable_aux(io) +#define pullup_off(io) pullup_disable_aux(io) + +#define set_pullup(io, on) set_pullup_aux(io, on) diff --git a/lib/ws2812.h b/lib/ws2812.h new file mode 100644 index 0000000..b988aa7 --- /dev/null +++ b/lib/ws2812.h @@ -0,0 +1,77 @@ +#pragma once + +/** + Utils for driving a WS2812 (WS2812B) RGB LED strips. + + It's implemented as macros to avoid overhead when passing values, and to + enable driving multiple strips at once. There is over 1us of free time between + the colors, which can be used for some processing or color computation. + + To avoid bloating your code, try to reduce the nuĂ˝mber of invocations - + compute color and then send it. +*/ + +#include + +#include "pins.h" +#include "nsdelay.h" +#include "colors.h" + +/* Driver code for WS2812B */ + +// --- timing constraints (NS) --- + +#ifndef WS_T_1H +#define WS_T_1H 700 +#endif + +#ifndef WS_T_1L +#define WS_T_1L 150 +#endif + +#ifndef WS_T_0H +#define WS_T_0H 150 +#endif + +#ifndef WS_T_0L +#define WS_T_0L 700 +#endif + +#ifndef WS_T_LATCH +#define WS_T_LATCH 6000 +#endif + + +/** Wait long enough for the colors to show */ +#define ws_show() do { delay_ns_c(WS_T_LATCH, 0); } while(0) + + +/** Send one byte to the RGB strip */ +#define ws_send_byte(io, bb) do { \ + for (volatile int8_t __wsba_i = 7; __wsba_i >= 0; --__wsba_i) { \ + if ((bb) & (1 << __wsba_i)) { \ + pin_high(io_pack(io)); delay_ns_c(WS_T_1H, -2); \ + pin_low(io_pack(io)); delay_ns_c(WS_T_1L, -10); \ + } else { \ + pin_high(io_pack(io)); delay_ns_c(WS_T_0H, -2); \ + pin_low(io_pack(io)); delay_ns_c(WS_T_0L, -10); \ + } \ + } \ +} while(0) + + +/** Send R,G,B color to the strip */ +#define ws_send_rgb(io, r, g, b) do { \ + ws_send_byte(io_pack(io), g); \ + ws_send_byte(io_pack(io), r); \ + ws_send_byte(io_pack(io), b); \ +} while(0) + +/** Send a RGB struct */ +#define ws_send_xrgb(io, xrgb) ws_send_rgb(io_pack(io), (xrgb).r, (xrgb).g, (xrgb).b) + +/** Send color hex */ +#define ws_send_rgb24(io, rgb) ws_send_rgb(io_pack(io), rgb24_r(rgb), rgb24_g(rgb), rgb24_b(rgb)) +#define ws_send_rgb15(io, rgb) ws_send_rgb(io_pack(io), rgb15_r(rgb), rgb15_g(rgb), rgb15_b(rgb)) +#define ws_send_rgb12(io, rgb) ws_send_rgb(io_pack(io), rgb12_r(rgb), rgb12_g(rgb), rgb12_b(rgb)) +#define ws_send_rgb6(io, rgb) ws_send_rgb(io_pack(io), rgb6_r(rgb), rgb6_g(rgb), rgb6_b(rgb)) diff --git a/new-pins-test/Makefile b/new-pins-test/Makefile new file mode 100644 index 0000000..9f4c5f1 --- /dev/null +++ b/new-pins-test/Makefile @@ -0,0 +1,153 @@ + +MCU = attiny13 + +F_CPU = 9600000 + +LFUSE = 0x72 +HFUSE = 0xFF + +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.) ########## +##########------------------------------------------------------########## + +PROGRAMMER_TYPE = dragon_isp +PROGRAMMER_ARGS = + + +##########------------------------------------------------------########## +########## 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 -Os -I. -I$(EXTRA_SOURCE_DIR) +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -Wall -Wno-main +CFLAGS += -g2 -ggdb +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += -std=gnu99 +# 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))) +SRC = $(TARGET).c +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 + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS) $(SRC) --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 + +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_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 + +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 +set_default_fuses: fuses diff --git a/new-pins-test/README.md b/new-pins-test/README.md new file mode 100644 index 0000000..11be5f1 --- /dev/null +++ b/new-pins-test/README.md @@ -0,0 +1,31 @@ +Keyboard Lamp +============= + +This is a keyboard lamp with adjustable brightness, that remembers last brightnbess level even when powered off. + +I've made it as a replacement for my broken ThinkLight. + +It uses ATtiny13, and the schematic is something like this: + + Vcc + | + ,---------------+ + | | + | +----u----+ | + '--| |--' + | ATMEL | Buttons + ,--[180R]-|<|---| |--BRT----o/ o---, + | LED2 | ATtiny | | + | -| 13 |--DIM----o/ o---+--- GND + GND | | + ,--| |----, + | +---------+ | LED1 + | | ,-|<|--[47R]-- Vcc + GND | | + '-[10k]-|< Transistor NPN + | + GND + +LED1 is the bright white LED, LED2 is an indicator that the brightness has been saved. You can leave LED2 out if you want. + +**Fuses** and other settings can be found in the Makefile. diff --git a/new-pins-test/lib b/new-pins-test/lib new file mode 120000 index 0000000..da7aca1 --- /dev/null +++ b/new-pins-test/lib @@ -0,0 +1 @@ +/home/ondra/devel/avr/avr-projects/lib \ No newline at end of file diff --git a/new-pins-test/main.c b/new-pins-test/main.c new file mode 100644 index 0000000..3c8e632 --- /dev/null +++ b/new-pins-test/main.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/pins.h" + +/** + * +--u--+ + * RST --| |-- Vcc + * SAVE LED : PB3 --| t13 |-- PB2 : BTN: HIGH + * N.C. : PB4 --| |-- PB1 : BTN: LOW + * GND --| |-- PB0 : LED + * +-----+ + */ + + +// pins config +#define LED B,0 +#define BTN_DOWN B,1 +#define BTN_UP B,2 +#define INDICATOR B,3 + +#define btn_on() pin_is_low(BTN_UP) + + +/** Initialize IO ports. */ +void SECTION(".init8") init_io(void) +{ + as_output(LED); + as_output(INDICATOR); + + as_input(BTN_DOWN); + as_input(BTN_UP); + + pullup_on(BTN_DOWN); + pullup_on(BTN_UP); + + // initialize the timer + + // Fast PWM mode, Output to OC0A + OCR0A = 32; + TCCR0A = _BV(WGM00) | _BV(WGM01) | _BV(COM0A1); + TCCR0B = _BV(CS00); +} + + +#define BRIGHTNESS_LEN 121 + +const uint8_t BRIGHTNESS[] PROGMEM = { + 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, + 6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14, 14, + 15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34, + 35, 36, 38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 54, + 56, 58, 59, 61, 63, 65, 67, 69, 71, 72, 74, 76, 78, 80, 82, + 85, 88, 90, 92, 95, 98, 100, 103, 106, 109, 112, 116, 119, + 122, 125, 129, 134, 138, 142, 147, 151, 156, 160, 165, 170, + 175, 180, 185, 190, 195, 200, 207, 214, 221, 228, 234, 241, + 248, 255 +}; + +#define apply_brightness(level) OCR0A = pgm_read_byte( & BRIGHTNESS[level] ) + + +/** + * Main function + */ +void main() +{ + bool changed = 0; + bool changed_since_last_save = 0; + + uint8_t savetimer = 0; + + uint8_t level = eeprom_read_byte((uint8_t *) 0); + + if (level >= BRIGHTNESS_LEN) + level = BRIGHTNESS_LEN - 1; + else if (level == 0) + level = BRIGHTNESS_LEN / 2; + + apply_brightness(level); + + while (1) { + if (btn_on() && level < BRIGHTNESS_LEN - 1) { + level++; + changed = 1; + } + + if (!btn_on() && level > 1) { + level--; + changed = 1; + } + + if (changed) { + changed = 0; + savetimer = 0; + changed_since_last_save = 1; + apply_brightness(level); + } + + _delay_ms(20); + savetimer++; + + if (savetimer >= 50 && changed_since_last_save) { + changed_since_last_save = 0; + savetimer = 0; + + pin_high(INDICATOR); + eeprom_update_byte((uint8_t*) 0, level); + _delay_ms(10); + pin_low(INDICATOR); + } + } +} diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/utils.h b/new-pins-test/utils.h similarity index 95% rename from rgb-led-strip/arduino-ws-anim-rainbow/utils.h rename to new-pins-test/utils.h index 82805bd..4ab82a1 100644 --- a/rgb-led-strip/arduino-ws-anim-rainbow/utils.h +++ b/new-pins-test/utils.h @@ -1,10 +1,9 @@ #pragma once -#include - // general macros #define SECTION(pos) __attribute__((naked, used, section(pos))) + // pin manipulation #define sbi(port, bit) (port) |= _BV(bit) #define cbi(port, bit) (port) &= ~ _BV(bit) diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/Makefile b/rgb-led-strip/arduino-ws-anim-rainbow/Makefile index 3c9bb65..3382e13 100644 --- a/rgb-led-strip/arduino-ws-anim-rainbow/Makefile +++ b/rgb-led-strip/arduino-ws-anim-rainbow/Makefile @@ -12,7 +12,7 @@ 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 = ws_driver.c +LOCAL_SOURCE = ## Here you can link to one more directory (and multiple .c files) # EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ @@ -48,19 +48,22 @@ 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 -Os -I. -I$(EXTRA_SOURCE_DIR) +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 -Wstrict-prototypes -Wno-main -Wno-strict-prototypes -Wno-comment -CFLAGS += -g2 -ggdb +CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment +CFLAGS += -g2 -Wextra -pedantic CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax -CFLAGS += -std=gnu99 + +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))) -SRC = $(TARGET).c +SRC1 = $(TARGET).c +SRC = $(SRC1) EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) SRC += $(EXTRA_SOURCE) SRC += $(LOCAL_SOURCE) @@ -73,12 +76,16 @@ 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) $(SRC) --output $@ + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ %.eeprom: %.elf $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/arduino_pins.h b/rgb-led-strip/arduino-ws-anim-rainbow/arduino_pins.h deleted file mode 100644 index efe67d4..0000000 --- a/rgb-led-strip/arduino-ws-anim-rainbow/arduino_pins.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include - -#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 0 -#define D9 1 -#define D10 2 -#define D11 3 -#define D12 4 -#define D13 5 -#define A0 0 -#define A1 1 -#define A2 2 -#define A3 3 -#define A4 4 -#define A5 5 - -// port definitions -#define PORT_D0 PORTD -#define PORT_D1 PORTD -#define PORT_D2 PORTD -#define PORT_D3 PORTD -#define PORT_D4 PORTD -#define PORT_D5 PORTD -#define PORT_D6 PORTD -#define PORT_D7 PORTD -#define PORT_D8 PORTB -#define PORT_D9 PORTB -#define PORT_D10 PORTB -#define PORT_D11 PORTB -#define PORT_D12 PORTB -#define PORT_D13 PORTB -#define PORT_A0 PORTC -#define PORT_A1 PORTC -#define PORT_A2 PORTC -#define PORT_A3 PORTC -#define PORT_A4 PORTC -#define PORT_A5 PORTC - -#define PIN_D0 PIND -#define PIN_D1 PIND -#define PIN_D2 PIND -#define PIN_D3 PIND -#define PIN_D4 PIND -#define PIN_D5 PIND -#define PIN_D6 PIND -#define PIN_D7 PIND -#define PIN_D8 PINB -#define PIN_D9 PINB -#define PIN_D10 PINB -#define PIN_D11 PINB -#define PIN_D12 PINB -#define PIN_D13 PINB -#define PIN_A0 PINC -#define PIN_A1 PINC -#define PIN_A2 PINC -#define PIN_A3 PINC -#define PIN_A4 PINC -#define PIN_A5 PINC - -#define DDR_D0 DDRD -#define DDR_D1 DDRD -#define DDR_D2 DDRD -#define DDR_D3 DDRD -#define DDR_D4 DDRD -#define DDR_D5 DDRD -#define DDR_D6 DDRD -#define DDR_D7 DDRD -#define DDR_D8 DDRB -#define DDR_D9 DDRB -#define DDR_D10 DDRB -#define DDR_D11 DDRB -#define DDR_D12 DDRB -#define DDR_D13 DDRB -#define DDR_A0 DDRC -#define DDR_A1 DDRC -#define DDR_A2 DDRC -#define DDR_A3 DDRC -#define DDR_A4 DDRC -#define DDR_A5 DDRC - -#define OUT 1 -#define IN 0 diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/config.h b/rgb-led-strip/arduino-ws-anim-rainbow/config.h deleted file mode 100644 index 42cb8f4..0000000 --- a/rgb-led-strip/arduino-ws-anim-rainbow/config.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "arduino_pins.h" - -#define WS_PORT PORT_D8 -#define WS_BIT D8 -#define WS_DDR DDR_D8 - -#define WS_T_1H 700 -#define WS_T_1L 150 -#define WS_T_0H 150 -#define WS_T_0L 700 -#define WS_T_LATCH 6000 diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/lib b/rgb-led-strip/arduino-ws-anim-rainbow/lib new file mode 120000 index 0000000..da7aca1 --- /dev/null +++ b/rgb-led-strip/arduino-ws-anim-rainbow/lib @@ -0,0 +1 @@ +/home/ondra/devel/avr/avr-projects/lib \ No newline at end of file diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/main.c b/rgb-led-strip/arduino-ws-anim-rainbow/main.c index 1586d5d..df86abd 100644 --- a/rgb-led-strip/arduino-ws-anim-rainbow/main.c +++ b/rgb-led-strip/arduino-ws-anim-rainbow/main.c @@ -1,135 +1,78 @@ #include -#include -#include -#include - #include -#include - #include #include -#include -#include "arduino_pins.h" -#include "utils.h" -#include "config.h" -#include "ws_driver.h" +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" +#include "lib/colors.h" +#include "lib/ws2812.h" +#define WS1 D8 +#define WS2 D9 -void init_io(void) SECTION(".init8"); -void init_io() +void SECTION(".init8") init_io() { - set_bit(WS_DDR, WS_BIT, OUT); + as_output(WS1); + as_output(WS2); } - void main() { - const uint8_t anim_step = 5; - const uint8_t anim_max = 255; - - uint8_t r = 0; - uint8_t g = 0; - uint8_t b = 0; + const uint8_t anim_step = 10; + const uint8_t anim_max = 250; + const uint8_t pixel_count = 30; + xrgb_t color = xrgb(anim_max, 0, 0); uint8_t step = 0; - uint8_t r2 = anim_max; - uint8_t g2 = 0; - uint8_t b2 = 0; - + xrgb_t color2 = xrgb(anim_max, 0, 0); uint8_t step2 = 0; - while (1) { - r = r2; - g = g2; - b = b2; + + color = color2; step = step2; - for (uint8_t i = 0; i < 72; i++) { - ws_send_rgb(r, g, b); + for (uint8_t i = 0; i < pixel_count; i++) { + ws_send_xrgb(WS1, color); if (i == 1) { - r2 = r; - g2 = g; - b2 = b; + color2 = color; step2 = step; } switch (step) { case 0: - g += anim_step; - if (g == anim_max) step++; + color.g += anim_step; + if (color.g >= anim_max) step++; break; - case 1: - r -= anim_step; - if (r == 0) step++; + color.r -= anim_step; + if (color.r == 0) step++; break; - case 2: - b += anim_step; - if (b == anim_max) step++; + color.b += anim_step; + if (color.b >= anim_max) step++; break; - case 3: - g -= anim_step; - if (g == 0) step++; + color.g -= anim_step; + if (color.g == 0) step++; break; - case 4: - r += anim_step; - if (r == anim_max) step++; + color.r += anim_step; + if (color.r >= anim_max) step++; break; - default: - b -= anim_step; - if (b == 0) step = 0; + color.b -= anim_step; + if (color.b == 0) step = 0; break; } } ws_show(); - _delay_ms(30); + + _delay_ms(20); } } - - - -// void main() -// { -// while (1) { -// uint8_t r = 250; -// uint8_t g = 0; -// uint8_t b = 0; - -// uint8_t step = 0; - -// for (uint8_t i = 0; i < 30; i++) { -// ws_send_rgb(r, g, b); - -// switch (step) { -// case 0: -// r -= 50; -// g += 50; -// if (g == 250) step++; -// break; -// case 1: -// g -= 50; -// b += 50; -// if (b == 250) step++; -// break; -// case 2: -// b -= 50; -// r += 50; -// if (r == 250) step=0; -// break; -// } -// } - -// ws_show(); -// _delay_ms(100); -// } -// } - diff --git a/rgb-led-strip/arduino-ws-gamepad/Makefile b/rgb-led-strip/arduino-ws-gamepad/Makefile new file mode 100644 index 0000000..385f3eb --- /dev/null +++ b/rgb-led-strip/arduino-ws-gamepad/Makefile @@ -0,0 +1,158 @@ + +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 = lib/ws_driver.c + +## 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 -Os -I. -I$(EXTRA_SOURCE_DIR) +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -Wall -Wstrict-prototypes -Wno-main -Wno-strict-prototypes -Wno-comment +CFLAGS += -g2 -ggdb +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += -std=gnu99 +# 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))) +SRC = $(TARGET).c +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 + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS) $(SRC) --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 + +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/rgb-led-strip/arduino-ws-gamepad/README.md b/rgb-led-strip/arduino-ws-gamepad/README.md new file mode 100644 index 0000000..836bc8f --- /dev/null +++ b/rgb-led-strip/arduino-ws-gamepad/README.md @@ -0,0 +1,13 @@ +WS2812B RGB LED strip driving code +================================== + +This code is meant for 16MHz Arduino, but should work on any 16MHz AVR. It is in plain C, not the Arduino language. + +All you need is `ws_driver.c` and `ws_driver.h`, and `config.c` where you define the port / pin information. + +Connection +---------- + +Digital pin 8 on Arduino (PB0) is connected via a 200-500 R to WS2812B data input. In parallel to the LED strip is a 500-1000 uF capacitor that takes care of smoothening the power supply. Without the cap, the LEDs will flicker. + +It is recommended to use stronger power supply for the LED strip, a 30-led one takes around to 1A when fully powered. diff --git a/rgb-led-strip/arduino-ws-gamepad/config.h b/rgb-led-strip/arduino-ws-gamepad/config.h new file mode 100644 index 0000000..1b46c1d --- /dev/null +++ b/rgb-led-strip/arduino-ws-gamepad/config.h @@ -0,0 +1,16 @@ +#pragma once + +#include "lib/arduino_pins2.h" + +#define WSDATA_in D8_in +#define WSDATA_out D8_out +#define WSDATA_dir D8_dir + +#define WS_T_1H 700 +#define WS_T_1L 150 +#define WS_T_0H 150 +#define WS_T_0L 700 +#define WS_T_LATCH 6000 + +# define DEBOUNCE_COUNT 63 +#define DEBOUNCE_SLOT_COUNT 4 diff --git a/rgb-led-strip/arduino-ws-gamepad/gamepad_pins.h b/rgb-led-strip/arduino-ws-gamepad/gamepad_pins.h new file mode 100644 index 0000000..6f8aaa8 --- /dev/null +++ b/rgb-led-strip/arduino-ws-gamepad/gamepad_pins.h @@ -0,0 +1,22 @@ +#pragma once +#include "lib/arduino_pins.h" + +#define PIN_LEFT PIN_D2 +#define DDR_LEFT DDR_D2 +#define PORT_LEFT PORT_D2 +#define LEFT D2 + +#define PIN_RIGHT PIN_D3 +#define DDR_RIGHT DDR_D3 +#define PORT_RIGHT PORT_D3 +#define RIGHT D3 + +#define PIN_UP PIN_D4 +#define DDR_UP DDR_D4 +#define PORT_UP PORT_D4 +#define UP D4 + +#define PIN_DOWN PIN_D5 +#define DDR_DOWN DDR_D5 +#define PORT_DOWN PORT_D5 +#define DOWN D5 diff --git a/rgb-led-strip/arduino-ws-gamepad/lib b/rgb-led-strip/arduino-ws-gamepad/lib new file mode 120000 index 0000000..da7aca1 --- /dev/null +++ b/rgb-led-strip/arduino-ws-gamepad/lib @@ -0,0 +1 @@ +/home/ondra/devel/avr/avr-projects/lib \ No newline at end of file diff --git a/rgb-led-strip/arduino-ws-gamepad/main.c b/rgb-led-strip/arduino-ws-gamepad/main.c new file mode 100644 index 0000000..a80d6ff --- /dev/null +++ b/rgb-led-strip/arduino-ws-gamepad/main.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "lib/arduino_pins2.h" +#include "lib/utils.h" +#include "lib/ws_driver.h" +#include "lib/debounce.h" + +#include "config.h" +#include "gamepad_pins.h" + + +void init_io() SECTION(".init8") +{ + // WS2182B data pin as output + set_bit(WS_dir, OUT); + + // enable pullups on input pins + set_bit(LEFT_out); + sbi(PORT_RIGHT, RIGHT); + sbi(PORT_UP, UP); + sbi(PORT_DOWN, DOWN); + + // init timer + TCCR0A = _BV(WGM01); // CTC mode + TCCR0B = _BV(CS02) | _BV(CS00); // prescaler 1024 + OCR0A = 250; // interrupt every 16 ms + sbi(TIMSK0, OCIE0A); // enable interrupt from timer + + // set up debouncer + debounce_register(0, &PIN) +} + + +/** timer 0 interrupt vector */ +ISR(TIM0_COMPA_vect) +{ + debounce_tick(); +} + + + +typedef struct +{ + uint8_t r, + uint8_t g, + uint8_t b, +} color_t; + +#define RED {.r=0xFF, .g=0x00, .b=0x00} +#define GREEN {.r=0xFF, .g=0x00, .b=0x00} +#define BLUE {.r=0xFF, .g=0x00, .b=0x00} + +#define YELLOW {.r=0xFF, .g=0xFF, .b=0x00} +#define MAGENTA {.r=0xFF, .g=0x00, .b=0xFF} +#define CYAN {.r=0x00, .g=0xFF, .b=0xFF} + +#define BLACK {.r=0x00, .g=0x00, .b=0x00} +#define WHITE {.r=0xFF, .g=0xFF, .b=0xFF} + + +#define BULB_COUNT 4; + +color_t bulbs[BULB_COUNT]; + +void show_lights() +{ + for (uint8_t i = 0; i < BULB_COUNT; i++) { + ws_send_rgb(bulbs[i].r, bulbs[i].g, bulbs[i].b); + } + ws_show(); +} + + +void main() +{ + while (1) { + show_lights(); + } +} diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/ws_driver.c b/rgb-led-strip/ws_driver_legacy/ws_driver.c similarity index 91% rename from rgb-led-strip/arduino-ws-anim-rainbow/ws_driver.c rename to rgb-led-strip/ws_driver_legacy/ws_driver.c index 59b1d67..1b34325 100644 --- a/rgb-led-strip/arduino-ws-anim-rainbow/ws_driver.c +++ b/rgb-led-strip/ws_driver_legacy/ws_driver.c @@ -19,6 +19,7 @@ #define delay_ns_c(ns, c) delay_c(ns2cycles(ns) + (c)) +/** Latch and display the RGB values */ void ws_show() { ws_low(); @@ -26,6 +27,7 @@ void ws_show() } +/** Send one byte to the RGB strip */ void ws_send_byte(uint8_t bb) { for (int8_t i = 7; i >= 0; --i) { @@ -46,9 +48,13 @@ void ws_send_byte(uint8_t bb) } +/** Send RGB color to the strip */ void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b) { int8_t i; + + // manualy inlined, because `inline` doesn't work with delays. + // GREEN for (i = 7; i >= 0; --i) { if (g & (1 << i)) { diff --git a/rgb-led-strip/arduino-ws-anim-rainbow/ws_driver.h b/rgb-led-strip/ws_driver_legacy/ws_driver.h similarity index 90% rename from rgb-led-strip/arduino-ws-anim-rainbow/ws_driver.h rename to rgb-led-strip/ws_driver_legacy/ws_driver.h index 0b70f7d..efa0859 100644 --- a/rgb-led-strip/arduino-ws-anim-rainbow/ws_driver.h +++ b/rgb-led-strip/ws_driver_legacy/ws_driver.h @@ -2,7 +2,7 @@ // -- AVR GCC utility for driving WS2812B and similar RGB LED stripes -- -// You must define the foillowing in config file or here: +// You must define the following in config file or here: // * WS_PORT // * WS_BIT @@ -34,7 +34,7 @@ #endif -// More accurate timing +// More precise timing // #define WS_T_1H 800 // #define WS_T_1L 450 // #define WS_T_0H 200 @@ -45,8 +45,10 @@ /** Latch and display the RGB values */ void ws_show(void); + /** Send one byte to the RGB strip */ void ws_send_byte(uint8_t b); + /** Send RGB color to the strip */ void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b); diff --git a/rgb-led-strip/ws_driver_legacy/ws_driver2.c b/rgb-led-strip/ws_driver_legacy/ws_driver2.c new file mode 100644 index 0000000..ff17299 --- /dev/null +++ b/rgb-led-strip/ws_driver_legacy/ws_driver2.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#include "extra_delays.h" +#include "pins.h" +#include "ws_driver2.h" + + + +/** Latch and display the RGB values */ +void ws_show_real(PORT_P portp, BIT_N pin) +{ + cbi_p(portp, pin); + delay_ns_c(WS_T_LATCH, 0); +} + + +/** Send one byte to the RGB strip */ +void ws_send_byte_real(PORT_P portp, BIT_N pin, uint8_t bb) +{ + for (int8_t i = 7; i >= 0; --i) { + if (bb & (1 << i)) { + // send ONE + sbi_p(portp, pin); + delay_ns_c(WS_T_1H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_1L, -10); // compensation for overhead + } else { + // send ZERO + sbi_p(portp, pin); + delay_ns_c(WS_T_0H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_0L, -10); + } + } +} + + +/** Send RGB color to the strip */ +void ws_send_rgb_real(PORT_P portp, BIT_N pin, uint8_t r, uint8_t g, uint8_t b) +{ + int8_t i; + + // manualy inlined, because `inline` doesn't work with delays. + + // GREEN + for (i = 7; i >= 0; --i) { + if (g & (1 << i)) { + // send ONE + sbi_p(portp, pin); + delay_ns_c(WS_T_1H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_1L, -10); + } else { + // send ZERO + sbi_p(portp, pin); + delay_ns_c(WS_T_0H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_0L, -10); + } + } + + // RED + for (i = 7; i >= 0; --i) { + if (r & (1 << i)) { + // send ONE + sbi_p(portp, pin); + delay_ns_c(WS_T_1H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_1L, -10); + } else { + // send ZERO + sbi_p(portp, pin); + delay_ns_c(WS_T_0H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_0L, -10); + } + } + + // BLUE + for (i = 7; i >= 0; --i) { + if (b & (1 << i)) { + // send ONE + sbi_p(portp, pin); + delay_ns_c(WS_T_1H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_1L, -10); + } else { + // send ZERO + sbi_p(portp, pin); + delay_ns_c(WS_T_0H, -2); + cbi_p(portp, pin); + delay_ns_c(WS_T_0L, -10); + } + } +} diff --git a/rgb-led-strip/ws_driver_legacy/ws_driver2.h b/rgb-led-strip/ws_driver_legacy/ws_driver2.h new file mode 100644 index 0000000..ae621a2 --- /dev/null +++ b/rgb-led-strip/ws_driver_legacy/ws_driver2.h @@ -0,0 +1,56 @@ +#pragma once + +#include "pins.h" + +// -- Utility for driving WS2812B and similar RGB LED stripes -- + +// --- timing constraints (NS) --- + +#ifndef WS_T_1H +#define WS_T_1H 700 +#endif + +#ifndef WS_T_1L +#define WS_T_1L 150 +#endif + +#ifndef WS_T_0H +#define WS_T_0H 150 +#endif + +#ifndef WS_T_0L +#define WS_T_0L 700 +#endif + +#ifndef WS_T_LATCH +#define WS_T_LATCH 6000 +#endif + + +// More precise timing +// #define WS_T_1H 800 +// #define WS_T_1L 450 +// #define WS_T_0H 200 +// #define WS_T_0L 650 +// #define WS_T_LATCH 50000 + + +// Only ws_show / ws_send_byte / ws_send_rgb should be used, with port alias macros +// See pins.h for reference + +/** Latch and display the RGB values */ +void ws_show_real(PORT_P port, BIT_N pin); +#define ws_show_aux(port, pin) ws_show_real(®_port(port), pin) +#define ws_show(io) ws_show_aux(io) + + +/** Send one byte to the RGB strip */ +void ws_send_byte_real(PORT_P port, BIT_N pin, uint8_t b); +#define ws_send_byte_aux(port, pin, b) ws_send_byte_real(®_port(port), pin, b) +#define ws_send_byte(io, b) ws_send_byte_aux(io, b) + + +/** Send RGB color to the strip */ +void ws_send_rgb_real(PORT_P port, BIT_N pin, uint8_t r, uint8_t g, uint8_t b); +#define ws_send_rgb_aux(port, pin, r, g, b) ws_send_rgb_real(®_port(port), pin, r, g, b) +#define ws_send_rgb(io, r, g, b) ws_send_rgb_aux(io, r, g, b) diff --git a/rgb-led-strip/ws_driver_legacy/ws_driver3.c b/rgb-led-strip/ws_driver_legacy/ws_driver3.c new file mode 100644 index 0000000..6c301ff --- /dev/null +++ b/rgb-led-strip/ws_driver_legacy/ws_driver3.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +#include "ws_driver3.h" + +#define WS_PORT PORTB +#define WS_BIT 0 + +uint16_t ws_port = _SFR_ADDR(PORTB); +uint8_t ws_bit; + +/** Raise the bus line *///_SFR_MEM8(ws_port) +#define ws_high() do { _SFR_MEM8(ws_port) |= (1 << 0); } while(0) +//#define ws_high() (_SFR_MEM8(_SFR_ADDR(PORTB))) |= (1 << WS_BIT) + +/** Drop the bus line */ +#define ws_low() do { _SFR_MEM8(ws_port) &= ~(1 << 0); } while(0) +//#define ws_low() (_SFR_MEM8(_SFR_ADDR(PORTB))) &= ~(1 << WS_BIT) + +/* Convert nanoseconds to cycle count */ +#define ns2cycles(ns) ( (ns) / (1000000000L / (signed long) F_CPU) ) + +/** Wait c cycles */ +#define delay_c(c) (((c) > 0) ? __builtin_avr_delay_cycles(c) : __builtin_avr_delay_cycles(0)) + +/** Wait n nanoseconds, plus c cycles */ +#define delay_ns_c(ns, c) delay_c(ns2cycles(ns) + (c)) + + +void ws_bind(uint8_t port_addr, uint8_t bit) +{ + // ws_port = port_addr; + // ws_bit = bit; +} + + + +/** Latch and display the RGB values */ +void ws_show() +{ + ws_low(); + delay_ns_c(WS_T_LATCH, 0); +} + +#define _do_ws_send_byte(x) do { \ + for (int8_t i = 7; i >= 0; --i) { \ + if (x & (1 << i)) { \ + ws_high(); \ + delay_ns_c(WS_T_1H, -2); \ + ws_low(); \ + delay_ns_c(WS_T_1L, -10); \ + } else { \ + ws_high(); \ + delay_ns_c(WS_T_0H, -2); \ + ws_low(); \ + delay_ns_c(WS_T_0L, -10); \ + } \ + } \ +} while(0) + +void ws_send_byte(uint8_t b) +{ + _do_ws_send_byte(b); +} + + +/** Send RGB color to the strip */ +void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b) +{ + _do_ws_send_byte(g); + _do_ws_send_byte(r); + _do_ws_send_byte(b); +} diff --git a/rgb-led-strip/ws_driver_legacy/ws_driver3.h b/rgb-led-strip/ws_driver_legacy/ws_driver3.h new file mode 100644 index 0000000..49462b8 --- /dev/null +++ b/rgb-led-strip/ws_driver_legacy/ws_driver3.h @@ -0,0 +1,54 @@ +#pragma once + +// -- AVR GCC utility for driving WS2812B and similar RGB LED stripes -- + +// You must define the following in config file or here: + +// The pin must be set to OUTPUT before using the output functions + + +// --- timing constraints (NS) --- + +#ifndef WS_T_1H +#define WS_T_1H 700 +#endif + +#ifndef WS_T_1L +#define WS_T_1L 150 +#endif + +#ifndef WS_T_0H +#define WS_T_0H 150 +#endif + +#ifndef WS_T_0L +#define WS_T_0L 700 +#endif + +#ifndef WS_T_LATCH +#define WS_T_LATCH 7000 +#endif + + +// More precise timing +// #define WS_T_1H 800 +// #define WS_T_1L 450 +// #define WS_T_0H 200 +// #define WS_T_0L 650 +// #define WS_T_LATCH 50000 + + + +void ws_bind(uint8_t port_addr, uint8_t bit); + + +/** Latch and display the RGB values */ +void ws_show(void); + + +/** Send one byte to the RGB strip */ +void ws_send_byte(uint8_t b); + + +/** Send RGB color to the strip */ +void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b); diff --git a/test-passportbyref/Makefile b/test-passportbyref/Makefile new file mode 100644 index 0000000..9f4c5f1 --- /dev/null +++ b/test-passportbyref/Makefile @@ -0,0 +1,153 @@ + +MCU = attiny13 + +F_CPU = 9600000 + +LFUSE = 0x72 +HFUSE = 0xFF + +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.) ########## +##########------------------------------------------------------########## + +PROGRAMMER_TYPE = dragon_isp +PROGRAMMER_ARGS = + + +##########------------------------------------------------------########## +########## 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 -Os -I. -I$(EXTRA_SOURCE_DIR) +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -Wall -Wno-main +CFLAGS += -g2 -ggdb +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += -std=gnu99 +# 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))) +SRC = $(TARGET).c +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 + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS) $(SRC) --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 + +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_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 + +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 +set_default_fuses: fuses diff --git a/test-passportbyref/README.md b/test-passportbyref/README.md new file mode 100644 index 0000000..11be5f1 --- /dev/null +++ b/test-passportbyref/README.md @@ -0,0 +1,31 @@ +Keyboard Lamp +============= + +This is a keyboard lamp with adjustable brightness, that remembers last brightnbess level even when powered off. + +I've made it as a replacement for my broken ThinkLight. + +It uses ATtiny13, and the schematic is something like this: + + Vcc + | + ,---------------+ + | | + | +----u----+ | + '--| |--' + | ATMEL | Buttons + ,--[180R]-|<|---| |--BRT----o/ o---, + | LED2 | ATtiny | | + | -| 13 |--DIM----o/ o---+--- GND + GND | | + ,--| |----, + | +---------+ | LED1 + | | ,-|<|--[47R]-- Vcc + GND | | + '-[10k]-|< Transistor NPN + | + GND + +LED1 is the bright white LED, LED2 is an indicator that the brightness has been saved. You can leave LED2 out if you want. + +**Fuses** and other settings can be found in the Makefile. diff --git a/test-passportbyref/lib b/test-passportbyref/lib new file mode 120000 index 0000000..da7aca1 --- /dev/null +++ b/test-passportbyref/lib @@ -0,0 +1 @@ +/home/ondra/devel/avr/avr-projects/lib \ No newline at end of file diff --git a/test-passportbyref/main.c b/test-passportbyref/main.c new file mode 100644 index 0000000..acd5225 --- /dev/null +++ b/test-passportbyref/main.c @@ -0,0 +1,16 @@ +#include + +void led_on(volatile uint8_t* portp, uint8_t pinn) { + *portp |= _BV(pinn); +} + +void led_off(volatile uint8_t* portp, uint8_t pinn) { + *portp &= ~ _BV(pinn); +} + +void main() +{ + led_on(&PORTB, 3); + led_off(&PORTB, 5); + led_on(&DDRB, 3); +}