Ondřej Hruška 3 years ago
commit
ac0bc06e29
17 changed files with 1611 additions and 0 deletions
  1. 45 0
      .gitignore
  2. 21 0
      LICENSE
  3. 139 0
      Makefile
  4. 11 0
      README.md
  5. 154 0
      lib/calc.h
  6. 59 0
      lib/debounce.c
  7. 64 0
      lib/debounce.h
  8. 277 0
      lib/iopins.c
  9. 213 0
      lib/iopins.h
  10. 21 0
      lib/nsdelay.h
  11. 62 0
      lib/spi.c
  12. 69 0
      lib/spi.h
  13. 83 0
      lib/usart.c
  14. 86 0
      lib/usart.h
  15. 241 0
      main.c
  16. 14 0
      style.astylerc
  17. 52 0
      us_rgb.pro

+ 45 - 0
.gitignore View File

@@ -0,0 +1,45 @@
1
+# Object files
2
+*.o
3
+*.ko
4
+*.obj
5
+*.elf
6
+*.axf
7
+
8
+# Precompiled Headers
9
+*.gch
10
+*.pch
11
+
12
+# Libraries
13
+*.lib
14
+*.a
15
+*.la
16
+*.lo
17
+
18
+# Shared objects (inc. Windows DLLs)
19
+*.dll
20
+*.so
21
+*.so.*
22
+*.dylib
23
+
24
+# Executables
25
+*.exe
26
+*.out
27
+*.app
28
+*.i*86
29
+*.x86_64
30
+*.hex
31
+
32
+# Debug files
33
+*.dSYM/
34
+
35
+# AVR specific stuff
36
+*.lst
37
+*.dis
38
+*.disasm
39
+*.list
40
+*.eeprom
41
+*.pre
42
+
43
+# QtCreator user-specific
44
+*.pro.user
45
+

+ 21 - 0
LICENSE View File

@@ -0,0 +1,21 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2016 Ondřej Hruška
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.

+ 139 - 0
Makefile View File

@@ -0,0 +1,139 @@
1
+#############################################
2
+
3
+# CPU type
4
+MCU   = atmega328p
5
+
6
+# CPU frequency [Hz]
7
+F_CPU = 16000000
8
+
9
+# Fuses (refer to datasheet)
10
+LFUSE = 0xFF
11
+HFUSE = 0xDE
12
+EFUSE = 0x05
13
+
14
+# AVRDUDE settings
15
+PROG_BAUD = 57600
16
+PROG_DEV  = /dev/ttyUSB0
17
+PROG_TYPE = arduino
18
+
19
+# Build the final AVRDUDE arguments
20
+PROG_ARGS = -c $(PROG_TYPE) -p $(MCU) -b $(PROG_BAUD) -P $(PROG_DEV)
21
+
22
+#############################################
23
+
24
+# Main file
25
+BINARY = main
26
+
27
+# Obj files to be built <- add .o for any .c files you add!
28
+OBJS  = $(BINARY).o
29
+OBJS += lib/usart.o
30
+OBJS += lib/iopins.o
31
+OBJS += lib/spi.o
32
+OBJS += lib/debounce.o
33
+
34
+# Dirs with header files
35
+INCL_DIRS = . lib/
36
+
37
+# Pre-defined macros
38
+DEFS = -DF_CPU=$(F_CPU)UL
39
+
40
+#############################################
41
+
42
+# C flags
43
+CFLAGS = -std=gnu99 -mmcu=$(MCU) $(DEFS) $(INCL_DIRS:%=-I%)
44
+CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffreestanding
45
+CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
46
+CFLAGS += -g2 -Wextra -Wfatal-errors -Wno-unused-but-set-variable
47
+CFLAGS += -ffunction-sections -fdata-sections -Os
48
+
49
+LDFLAGS = -Wl,--gc-sections -Wl,--relax -lm
50
+
51
+#LD_FLAGS += -Wl,-u,vfprintf -lprintf_flt -lm  ## for floating-point printf
52
+#LD_FLAGS += -Wl,-u,vfprintf -lprintf_min      ## for smaller printf
53
+
54
+#############################################
55
+
56
+## Defined programs / locations
57
+CC = avr-gcc
58
+OBJCOPY = avr-objcopy
59
+OBJDUMP = avr-objdump
60
+AVRSIZE = avr-size
61
+AVRDUDE = avrdude
62
+
63
+JUNK = *.o *.d *.elf *.bin *.hex *.srec *.list *.lst *.map *.dis *.disasm *.eep *.eeprom *.lss
64
+
65
+.SUFFIXES: .elf .bin .hex .lst .map .eeprom .pre
66
+.SECONDEXPANSION:
67
+.SECONDARY:
68
+
69
+.PHONY: all elf bin hex lst pre ee eeprom dis size clean flash flashe shell fuses show_fuses set_default_fuses
70
+
71
+all: hex size
72
+
73
+elf: $(BINARY).elf
74
+bin: $(BINARY).bin
75
+hex: $(BINARY).hex
76
+lst: $(BINARY).lst
77
+pre: $(BINARY).pre
78
+ee: $(BINARY).eeprom
79
+eeprom: $(BINARY).eeprom
80
+dis: lst
81
+
82
+# Show how big the resulting program is
83
+size: elf
84
+	$(AVRSIZE) -C --mcu=$(MCU) $(BINARY).elf
85
+
86
+
87
+
88
+# --- Magic build targets ----------------
89
+
90
+%.hex: %.elf
91
+	$(OBJCOPY) -R .eeprom -O ihex $< $@
92
+
93
+%.elf %.map: $(OBJS)
94
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(*).elf
95
+
96
+%.pre: %.c
97
+	$(CC) $(CFLAGS) -E $(*).c --output $@
98
+
99
+%.eeprom: %.elf
100
+	$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
101
+
102
+%.lst: %.elf
103
+	$(Q)$(OBJDUMP) -S $(*).elf > $(*).lst
104
+
105
+%.o: %.c
106
+	$(CC) $(CFLAGS) -o $(*).o -c $(*).c
107
+
108
+%.o: %.s
109
+	$(CC) $(CFLAGS) -o $(*).o -c $(*).s
110
+
111
+
112
+# Clean all produced trash
113
+clean:
114
+	rm -f $(JUNK)
115
+	cd lib && rm -f $(JUNK)
116
+
117
+
118
+## === avrdude ===
119
+
120
+flash: $(BINARY).hex
121
+	$(AVRDUDE) $(PROG_ARGS) -U flash:w:$<
122
+
123
+flashe: $(BINARY).eeprom
124
+	$(AVRDUDE) $(PROG_ARGS) -U eeprom:w:$<
125
+
126
+shell:
127
+	$(AVRDUDE) $(PROG_ARGS) -nt
128
+
129
+# === fuses ===
130
+
131
+# this may not work with the arduino programmer, I haven't tried.
132
+
133
+FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
134
+
135
+fuses:
136
+	$(AVRDUDE) $(PROG_ARGS) $(FUSE_STRING)
137
+
138
+show_fuses:
139
+	$(AVRDUDE) $(PROG_ARGS) -nv

+ 11 - 0
README.md View File

@@ -0,0 +1,11 @@
1
+# arduino-gamepad
2
+super simple gamepad project where Pro Mini is in a gamepad and sends keys over USART
3
+
4
+LED connected to D9 (on-board one at D13).
5
+
6
+Buttons connected from pins to ground with internal pull-up.
7
+
8
+Keys are sent as A - pressed, a - released (different letters), over UART at 115200 baud.
9
+
10
+Key press is indicated by LED at D9.
11
+

+ 154 - 0
lib/calc.h View File

@@ -0,0 +1,154 @@
1
+#pragma once
2
+
3
+//
4
+// Bit and byte manipulation utilities
5
+//
6
+
7
+#include <stdint.h>
8
+
9
+
10
+// --- Increment in range ---
11
+// when overflown, wraps within range. Lower bound < upper bound.
12
+// ..., upper bound excluded
13
+#define inc_wrap(var, min, max) \
14
+    do {                             \
15
+        if ((var) >= ((max) - 1)) {  \
16
+            (var) = (min);           \
17
+        } else {                     \
18
+            (var)++;                 \
19
+        }                            \
20
+    } while(0)
21
+
22
+// ..., upper bound included
23
+#define inc_wrapi(var, min, max) inc_wrap((var), (min), (max) + 1)
24
+
25
+
26
+// --- Decrement in range ---
27
+// when underflown, wraps within range. Lower bound < upper bound.
28
+// ..., upper bound excluded
29
+#define dec_wrap(var, min, max) \
30
+    do {                             \
31
+        if ((var) <= (min)) {        \
32
+            (var) = (max) - 1;       \
33
+        } else {                     \
34
+            (var)--;                 \
35
+        }                            \
36
+    } while(0)
37
+
38
+
39
+// ..., upper bound included
40
+#define dec_wrapi(var, min, max) dec_wrap((var), (min), (max) + 1)
41
+
42
+
43
+// --- Bit manipulation --
44
+
45
+// Set bit
46
+#define sbi(reg, n)  do { (reg) |=  (1 << (uint8_t)(n)); } while(0)
47
+
48
+// Clear bit
49
+#define cbi(reg, n)  do { (reg) &= ~(1 << (uint8_t)(n)); } while(0)
50
+
51
+// Get n-th bit
52
+#define get_bit(reg, n) (((reg) >> (uint8_t)(n)) & 1)
53
+
54
+
55
+// Test n-th bit (Can't use bit_is_set, as it's defined in sfr_def.h)
56
+#define bit_is_high(reg, n) get_bit((reg), (n))
57
+#define bit_is_low(reg, n)  (!get_bit((reg), (n)))
58
+
59
+// Write value to n-th bit
60
+#define set_bit(reg, n, val) \
61
+    do {                                          \
62
+        (reg) = ((reg) & ~(1 << (uint8_t)(n)))    \
63
+              | (((val) & 1) << (uint8_t)(n));    \
64
+    } while(0)
65
+
66
+// Invert n-th bit
67
+#define toggle_bit(reg, n) do { (reg) ^= (1 << (uint8_t)(n)); } while(0)
68
+
69
+
70
+// --- Bit manipulation with pointer to variable ---
71
+
72
+// Set n-th bit in pointee
73
+#define sbi_p(reg_p, n) do { (*(reg_p)) |=  (1 << (uint8_t)(n)); } while(0)
74
+// Clear n-th bit in pointee
75
+#define cbi_p(reg_p, n) do { (*(reg_p)) &= ~(1 << (uint8_t)(n)); } while(0)
76
+
77
+// Get n-th bit in pointee
78
+#define get_bit_p(reg_p, n) ((*(reg_p) >> (uint8_t)(n)) & 1)
79
+
80
+// Test n-th bit in pointee (Can't use bit_is_set, as it's redefined in sfr_def.h)
81
+#define bit_is_high_p(reg_p, bit) get_bit_p(reg_p, bit)
82
+#define bit_is_low_p(reg_p, bit) (!get_bit_p(reg_p, bit))
83
+
84
+
85
+// Write value to a bit in pointee
86
+#define set_bit_p(reg_p, n, value) \
87
+    do {                                             \
88
+        *(reg_p) = (*(reg_p) & ~(1 << (uint8_t)(n))) \
89
+                 | (((value) & 1) << (uint8_t)(n));  \
90
+    } while(0)
91
+
92
+
93
+#define toggle_bit_p(reg_p, n) do { *(reg_p) ^= (1 << (uint8_t)(n)); } while(0)
94
+
95
+
96
+// --- Nibble manipulation ---
97
+
98
+// Replace nibble in a byte
99
+#define set_low_nibble(reg, value) \
100
+    do {                                    \
101
+        (reg) = ((reg) & 0xF0)              \
102
+              | ((uint8_t)(value) & 0xF);   \
103
+    } while(0)
104
+
105
+
106
+#define set_high_nibble(reg, value) \
107
+    do {                                            \
108
+        (reg) = ((reg) & 0x0F)                      \
109
+              | (((uint8_t)(value) & 0xF) << 4);    \
110
+    } while(0)
111
+
112
+
113
+#define set_low_nibble_p(reg_p, value) \
114
+    do {                                            \
115
+        *(reg_p) = (*(reg_p) & 0xF0)                \
116
+                 | ((uint8_t)(value) & 0xF);        \
117
+    } while(0)
118
+
119
+
120
+#define set_high_nibble_p(reg_p, value) \
121
+    do {                                            \
122
+        *(reg_p) = (*(reg_p) & 0x0F)                \
123
+                 | (((uint8_t)(value) & 0xF) << 4); \
124
+    } while(0)
125
+
126
+
127
+#define low_nibble(x)   ((uint8_t)(x) & 0x0F)
128
+#define high_nibble(x) (((uint8_t)(x) & 0xF0) >> 4)
129
+
130
+
131
+// --- Range tests ---
132
+
133
+// Test if X is within low..high, regardless of bounds order
134
+#define in_range(x, low, high) \
135
+    ((low) < (high) ? ((x) >= (low) && (x) < (high))  \
136
+                    : ((x) >= (high) && (x) < (low)))  \
137
+
138
+
139
+// ..., include greater bound
140
+#define in_rangei(x, low, high) \
141
+    ((low) < (high) ? ((x) >= (low) && (x) <= (high))  \
142
+                    : ((x) >= (high) && (x) <= (low)))  \
143
+
144
+
145
+// Test if X in low..high, wrap around ends if needed.
146
+#define in_range_wrap(x, low, high) \
147
+    (((low) < (high)) ? ((x) >= (low) && (x) < (high))  \
148
+                      : ((x) >= (low) || (x) < (high)))
149
+
150
+
151
+// ..., include upper bound
152
+#define in_range_wrapi(x, low, high) \
153
+    (((low) <= (high)) ? ((x) >= (low) && (x) <= (high))  \
154
+                       : ((x) >= (low) || (x) <= (high)))

+ 59 - 0
lib/debounce.c View File

@@ -0,0 +1,59 @@
1
+#include <avr/io.h>
2
+#include <avr/pgmspace.h>
3
+#include <stdbool.h>
4
+#include <stdlib.h>
5
+
6
+
7
+#include "debounce.h"
8
+#include "calc.h"
9
+#include "iopins.h"
10
+
11
+#include "lib/usart.h"
12
+
13
+DeboSlot debo_slots[DEBO_CHANNELS];
14
+
15
+/** Debounce data array */
16
+static uint8_t debo_next_slot = 0;
17
+
18
+uint8_t debo_add_do(PORT_P pin_ptr, uint8_t bit, bool invert, void (*handler)(uint8_t, bool))
19
+{
20
+	DeboSlot *slot = &debo_slots[debo_next_slot];
21
+
22
+	slot->reg = pin_ptr;
23
+	slot->mask = (uint8_t)(1 << bit);
24
+	slot->invert = invert;
25
+	slot->count = 0;
26
+	slot->state = (*slot->reg & slot->mask);
27
+	slot->handler = handler;
28
+
29
+	return debo_next_slot++;
30
+}
31
+
32
+
33
+/** Check debounced pins, should be called periodically. */
34
+void debo_tick(void)
35
+{
36
+	for (uint8_t i = 0; i < debo_next_slot; i++) {
37
+		DeboSlot *slot = &debo_slots[i];
38
+
39
+		// current pin value (right 3 bits, xored with inverse bit)
40
+		bool state = (*slot->reg & slot->mask);
41
+
42
+		if (state != slot->state) {
43
+			// different pin state than last recorded state
44
+			if (slot->count < DEBO_TICKS) {
45
+				slot->count++;
46
+			} else {
47
+				// overflown -> latch value
48
+				slot->state = state; // set state bit
49
+				slot->count = 0;
50
+
51
+				if (slot->handler != NULL) {
52
+					slot->handler(i, slot->invert ^ state);
53
+				}
54
+			}
55
+		} else {
56
+			slot->count = 0;; // reset the counter
57
+		}
58
+	}
59
+}

+ 64 - 0
lib/debounce.h View File

@@ -0,0 +1,64 @@
1
+#pragma once
2
+
3
+//
4
+//  An implementation of button debouncer.
5
+//
6
+//  ----
7
+//
8
+//  You must provide a config file debo_config.h (next to your main.c)
9
+//
10
+//  A pin is registered like this:
11
+//
12
+//    #define BTN1 12 // pin D12
13
+//    #define BTN2 13
14
+//
15
+//    debo_add(BTN0);  // The function returns number assigned to the pin (0, 1, ...)
16
+//    debo_add_rev(BTN1);  // active low
17
+//    debo_register(&PINB, PB2, 0);  // direct access - register, pin & invert
18
+//
19
+//  Then periodically call the tick function (perhaps in a timer interrupt):
20
+//
21
+//    debo_tick();
22
+//
23
+//  To check if input is active, use
24
+//
25
+//    debo_get_pin(0); // state of input #0 (registered first)
26
+//    debo_get_pin(1); // state of input #1 (registered second)
27
+//
28
+
29
+
30
+#include <avr/io.h>
31
+#include <stdbool.h>
32
+#include <stdint.h>
33
+
34
+#include "calc.h"
35
+#include "iopins.h"
36
+
37
+#define DEBO_CHANNELS 11
38
+#define DEBO_TICKS 20
39
+
40
+
41
+/* Internal deboucer entry */
42
+typedef struct
43
+{
44
+	PORT_P reg;    // pin ptr
45
+	uint8_t mask;
46
+	uint8_t count; // number of ticks this was in the new state
47
+	bool invert;
48
+	bool state;
49
+	void (*handler)(uint8_t pin_n, bool state);
50
+} DeboSlot;
51
+
52
+extern DeboSlot debo_slots[DEBO_CHANNELS];
53
+
54
+/** Add a pin for debouncing (must be used with constant args) */
55
+#define debo_add(pin, reverse, hdlr) debo_add_do(&_pin(pin), _pn(pin), reverse, hdlr)
56
+
57
+/** Add a pin for debouncing (low level function) */
58
+uint8_t debo_add_do(PORT_P pin_reg_pointer, uint8_t bit, bool invert, void (*handler)(uint8_t, bool));
59
+
60
+/** Check debounced pins, should be called periodically. */
61
+void debo_tick(void);
62
+
63
+/** Get a value of debounced pin */
64
+#define debo_get_pin(i) (debo_slots[i].state ^ debo_slots[i].invert)

+ 277 - 0
lib/iopins.c View File

@@ -0,0 +1,277 @@
1
+#include <avr/io.h>
2
+#include <stdbool.h>
3
+#include <stdint.h>
4
+
5
+#include "calc.h"
6
+#include "iopins.h"
7
+
8
+
9
+void set_dir_n(uint8_t pin, uint8_t d)
10
+{
11
+	switch(pin) {
12
+		case 0: set_dir(0, d); return;
13
+		case 1: set_dir(1, d); return;
14
+		case 2: set_dir(2, d); return;
15
+		case 3: set_dir(3, d); return;
16
+		case 4: set_dir(4, d); return;
17
+		case 5: set_dir(5, d); return;
18
+		case 6: set_dir(6, d); return;
19
+		case 7: set_dir(7, d); return;
20
+		case 8: set_dir(8, d); return;
21
+		case 9: set_dir(9, d); return;
22
+		case 10: set_dir(10, d); return;
23
+		case 11: set_dir(11, d); return;
24
+		case 12: set_dir(12, d); return;
25
+		case 13: set_dir(13, d); return;
26
+		case 14: set_dir(14, d); return;
27
+		case 15: set_dir(15, d); return;
28
+		case 16: set_dir(16, d); return;
29
+		case 17: set_dir(17, d); return;
30
+		case 18: set_dir(18, d); return;
31
+		case 19: set_dir(19, d); return;
32
+		case 20: set_dir(20, d); return;
33
+		case 21: set_dir(21, d); return;
34
+	}
35
+}
36
+
37
+
38
+void as_input_n(uint8_t pin)
39
+{
40
+	switch(pin) {
41
+		case 0: as_input(0); return;
42
+		case 1: as_input(1); return;
43
+		case 2: as_input(2); return;
44
+		case 3: as_input(3); return;
45
+		case 4: as_input(4); return;
46
+		case 5: as_input(5); return;
47
+		case 6: as_input(6); return;
48
+		case 7: as_input(7); return;
49
+		case 8: as_input(8); return;
50
+		case 9: as_input(9); return;
51
+		case 10: as_input(10); return;
52
+		case 11: as_input(11); return;
53
+		case 12: as_input(12); return;
54
+		case 13: as_input(13); return;
55
+		case 14: as_input(14); return;
56
+		case 15: as_input(15); return;
57
+		case 16: as_input(16); return;
58
+		case 17: as_input(17); return;
59
+		case 18: as_input(18); return;
60
+		case 19: as_input(19); return;
61
+		case 20: as_input(20); return;
62
+		case 21: as_input(21); return;
63
+	}
64
+}
65
+
66
+
67
+void as_input_pu_n(uint8_t pin)
68
+{
69
+	switch(pin) {
70
+		case 0: as_input_pu(0); return;
71
+		case 1: as_input_pu(1); return;
72
+		case 2: as_input_pu(2); return;
73
+		case 3: as_input_pu(3); return;
74
+		case 4: as_input_pu(4); return;
75
+		case 5: as_input_pu(5); return;
76
+		case 6: as_input_pu(6); return;
77
+		case 7: as_input_pu(7); return;
78
+		case 8: as_input_pu(8); return;
79
+		case 9: as_input_pu(9); return;
80
+		case 10: as_input_pu(10); return;
81
+		case 11: as_input_pu(11); return;
82
+		case 12: as_input_pu(12); return;
83
+		case 13: as_input_pu(13); return;
84
+		case 14: as_input_pu(14); return;
85
+		case 15: as_input_pu(15); return;
86
+		case 16: as_input_pu(16); return;
87
+		case 17: as_input_pu(17); return;
88
+		case 18: as_input_pu(18); return;
89
+		case 19: as_input_pu(19); return;
90
+		case 20: as_input_pu(20); return;
91
+		case 21: as_input_pu(21); return;
92
+	}
93
+}
94
+
95
+
96
+void as_output_n(uint8_t pin)
97
+{
98
+	switch(pin) {
99
+		case 0: as_output(0); return;
100
+		case 1: as_output(1); return;
101
+		case 2: as_output(2); return;
102
+		case 3: as_output(3); return;
103
+		case 4: as_output(4); return;
104
+		case 5: as_output(5); return;
105
+		case 6: as_output(6); return;
106
+		case 7: as_output(7); return;
107
+		case 8: as_output(8); return;
108
+		case 9: as_output(9); return;
109
+		case 10: as_output(10); return;
110
+		case 11: as_output(11); return;
111
+		case 12: as_output(12); return;
112
+		case 13: as_output(13); return;
113
+		case 14: as_output(14); return;
114
+		case 15: as_output(15); return;
115
+		case 16: as_output(16); return;
116
+		case 17: as_output(17); return;
117
+		case 18: as_output(18); return;
118
+		case 19: as_output(19); return;
119
+		case 20: as_output(20); return;
120
+		case 21: as_output(21); return;
121
+	}
122
+}
123
+
124
+void pin_set_n(uint8_t pin, uint8_t v)
125
+{
126
+	switch(pin) {
127
+		case 0: pin_set(0, v); return;
128
+		case 1: pin_set(1, v); return;
129
+		case 2: pin_set(2, v); return;
130
+		case 3: pin_set(3, v); return;
131
+		case 4: pin_set(4, v); return;
132
+		case 5: pin_set(5, v); return;
133
+		case 6: pin_set(6, v); return;
134
+		case 7: pin_set(7, v); return;
135
+		case 8: pin_set(8, v); return;
136
+		case 9: pin_set(9, v); return;
137
+		case 10: pin_set(10, v); return;
138
+		case 11: pin_set(11, v); return;
139
+		case 12: pin_set(12, v); return;
140
+		case 13: pin_set(13, v); return;
141
+		case 14: pin_set(14, v); return;
142
+		case 15: pin_set(15, v); return;
143
+		case 16: pin_set(16, v); return;
144
+		case 17: pin_set(17, v); return;
145
+		case 18: pin_set(18, v); return;
146
+		case 19: pin_set(19, v); return;
147
+		case 20: pin_set(20, v); return;
148
+		case 21: pin_set(21, v); return;
149
+	}
150
+}
151
+
152
+void pin_down_n(uint8_t pin)
153
+{
154
+	switch(pin) {
155
+		case 0: pin_down(0); return;
156
+		case 1: pin_down(1); return;
157
+		case 2: pin_down(2); return;
158
+		case 3: pin_down(3); return;
159
+		case 4: pin_down(4); return;
160
+		case 5: pin_down(5); return;
161
+		case 6: pin_down(6); return;
162
+		case 7: pin_down(7); return;
163
+		case 8: pin_down(8); return;
164
+		case 9: pin_down(9); return;
165
+		case 10: pin_down(10); return;
166
+		case 11: pin_down(11); return;
167
+		case 12: pin_down(12); return;
168
+		case 13: pin_down(13); return;
169
+		case 14: pin_down(14); return;
170
+		case 15: pin_down(15); return;
171
+		case 16: pin_down(16); return;
172
+		case 17: pin_down(17); return;
173
+		case 18: pin_down(18); return;
174
+		case 19: pin_down(19); return;
175
+		case 20: pin_down(20); return;
176
+		case 21: pin_down(21); return;
177
+	}
178
+}
179
+
180
+void pin_up_n(uint8_t pin)
181
+{
182
+	switch(pin) {
183
+		case 0: pin_up(0); return;
184
+		case 1: pin_up(1); return;
185
+		case 2: pin_up(2); return;
186
+		case 3: pin_up(3); return;
187
+		case 4: pin_up(4); return;
188
+		case 5: pin_up(5); return;
189
+		case 6: pin_up(6); return;
190
+		case 7: pin_up(7); return;
191
+		case 8: pin_up(8); return;
192
+		case 9: pin_up(9); return;
193
+		case 10: pin_up(10); return;
194
+		case 11: pin_up(11); return;
195
+		case 12: pin_up(12); return;
196
+		case 13: pin_up(13); return;
197
+		case 14: pin_up(14); return;
198
+		case 15: pin_up(15); return;
199
+		case 16: pin_up(16); return;
200
+		case 17: pin_up(17); return;
201
+		case 18: pin_up(18); return;
202
+		case 19: pin_up(19); return;
203
+		case 20: pin_up(20); return;
204
+		case 21: pin_up(21); return;
205
+	}
206
+}
207
+
208
+
209
+void pin_toggle_n(uint8_t pin)
210
+{
211
+	switch(pin) {
212
+		case 0: pin_toggle(0); return;
213
+		case 1: pin_toggle(1); return;
214
+		case 2: pin_toggle(2); return;
215
+		case 3: pin_toggle(3); return;
216
+		case 4: pin_toggle(4); return;
217
+		case 5: pin_toggle(5); return;
218
+		case 6: pin_toggle(6); return;
219
+		case 7: pin_toggle(7); return;
220
+		case 8: pin_toggle(8); return;
221
+		case 9: pin_toggle(9); return;
222
+		case 10: pin_toggle(10); return;
223
+		case 11: pin_toggle(11); return;
224
+		case 12: pin_toggle(12); return;
225
+		case 13: pin_toggle(13); return;
226
+		case 14: pin_toggle(14); return;
227
+		case 15: pin_toggle(15); return;
228
+		case 16: pin_toggle(16); return;
229
+		case 17: pin_toggle(17); return;
230
+		case 18: pin_toggle(18); return;
231
+		case 19: pin_toggle(19); return;
232
+		case 20: pin_toggle(20); return;
233
+		case 21: pin_toggle(21); return;
234
+	}
235
+}
236
+
237
+
238
+bool pin_read_n(uint8_t pin)
239
+{
240
+	switch(pin) {
241
+		case 0: return pin_read(0);
242
+		case 1: return pin_read(1);
243
+		case 2: return pin_read(2);
244
+		case 3: return pin_read(3);
245
+		case 4: return pin_read(4);
246
+		case 5: return pin_read(5);
247
+		case 6: return pin_read(6);
248
+		case 7: return pin_read(7);
249
+		case 8: return pin_read(8);
250
+		case 9: return pin_read(9);
251
+		case 10: return pin_read(10);
252
+		case 11: return pin_read(11);
253
+		case 12: return pin_read(12);
254
+		case 13: return pin_read(13);
255
+		case 14: return pin_read(14);
256
+		case 15: return pin_read(15);
257
+		case 16: return pin_read(16);
258
+		case 17: return pin_read(17);
259
+		case 18: return pin_read(18);
260
+		case 19: return pin_read(19);
261
+		case 20: return pin_read(20);
262
+		case 21: return pin_read(21);
263
+	}
264
+	return false;
265
+}
266
+
267
+
268
+bool pin_is_low_n(uint8_t pin)
269
+{
270
+	return !pin_read_n(pin);
271
+}
272
+
273
+
274
+bool pin_is_high_n(uint8_t pin)
275
+{
276
+	return pin_read_n(pin);
277
+}

+ 213 - 0
lib/iopins.h View File

@@ -0,0 +1,213 @@
1
+#pragma once
2
+
3
+//
4
+// * Utilities for pin aliasing / numbering. *
5
+//
6
+// Designed for Arduino.
7
+//
8
+// If you know the pin number beforehand, you can use the macros.
9
+//
10
+// If you need to use a variable for pin number, use the `_n` functions.
11
+// They are much slower, so always check if you really need them
12
+// - and they aren't fit for things where precise timing is required.
13
+//
14
+
15
+#include <avr/io.h>
16
+#include <stdbool.h>
17
+#include <stdint.h>
18
+
19
+#include "calc.h"
20
+
21
+
22
+// type: pointer to port
23
+typedef volatile uint8_t* PORT_P;
24
+
25
+
26
+/** Pin numbering reference */
27
+#define D0 0
28
+#define D1 1
29
+#define D2 2
30
+#define D3 3
31
+#define D4 4
32
+#define D5 5
33
+#define D6 6
34
+#define D7 7
35
+#define D8 8
36
+#define D9 9
37
+#define D10 10
38
+#define D11 11
39
+#define D12 12
40
+#define D13 13
41
+#define D14 14
42
+#define D15 15
43
+#define D16 16
44
+#define D17 17
45
+#define D18 18
46
+#define D19 19
47
+#define D20 20
48
+#define D21 21
49
+#define A0 14
50
+#define A1 15
51
+#define A2 16
52
+#define A3 17
53
+#define A4 18
54
+#define A5 19
55
+#define A6 20
56
+#define A7 21
57
+
58
+
59
+#define _ddr(pin)  _DDR_##pin
60
+#define _pin(pin)  _PIN_##pin
61
+#define _pn(pin)   _PN_##pin
62
+#define _port(pin) _PORT_##pin
63
+
64
+
65
+/** Set pin direction */
66
+#define set_dir(pin, d)  set_bit( _ddr(pin), _pn(pin), d )
67
+void    set_dir_n(const uint8_t pin, const uint8_t d);
68
+
69
+
70
+/** Configure pin as input */
71
+#define as_input(pin)    cbi( _ddr(pin), _pn(pin) )
72
+void    as_input_n(const uint8_t pin);
73
+
74
+
75
+/** Configure pin as input, with pull-up enabled */
76
+#define as_input_pu(pin) { as_input(pin); pin_up(pin); }
77
+void    as_input_pu_n(const uint8_t pin);
78
+
79
+
80
+/** Configure pin as output */
81
+#define as_output(pin)   sbi( _ddr(pin), _pn(pin) )
82
+void    as_output_n(const uint8_t pin);
83
+
84
+
85
+/** Write value to a pin */
86
+#define pin_set(pin, v) set_bit( _port(pin), _pn(pin), v )
87
+void    pin_set_n(const uint8_t pin, const uint8_t v);
88
+
89
+
90
+/** Write 0 to a pin */
91
+#define pin_down(pin)    cbi( _port(pin), _pn(pin) )
92
+void    pin_down_n(const uint8_t pin);
93
+
94
+
95
+/** Write 1 to a pin */
96
+#define pin_up(pin)   sbi( _port(pin), _pn(pin) )
97
+void    pin_up_n(uint8_t pin);
98
+
99
+
100
+/** Toggle a pin state */
101
+#define pin_toggle(pin)   sbi( _pin(pin), _pn(pin) )
102
+void    pin_toggle_n(uint8_t pin);
103
+
104
+
105
+/** Read a pin value */
106
+#define pin_read(pin)  get_bit( _pin(pin), _pn(pin) )
107
+bool    pin_read_n(uint8_t pin);
108
+
109
+
110
+/** CHeck if pin is low */
111
+#define pin_is_low(pin)   (pin_read(pin) == 0)
112
+bool    pin_is_low_n(uint8_t pin);
113
+
114
+
115
+/** CHeck if pin is high */
116
+#define pin_is_high(pin)  (pin_read(pin) != 0)
117
+bool    pin_is_high_n(uint8_t pin);
118
+
119
+
120
+
121
+// Helper macros
122
+
123
+#define _PORT_0  PORTD
124
+#define _PORT_1  PORTD
125
+#define _PORT_2  PORTD
126
+#define _PORT_3  PORTD
127
+#define _PORT_4  PORTD
128
+#define _PORT_5  PORTD
129
+#define _PORT_6  PORTD
130
+#define _PORT_7  PORTD
131
+#define _PORT_8  PORTB
132
+#define _PORT_9  PORTB
133
+#define _PORT_10 PORTB
134
+#define _PORT_11 PORTB
135
+#define _PORT_12 PORTB
136
+#define _PORT_13 PORTB
137
+#define _PORT_14 PORTC
138
+#define _PORT_15 PORTC
139
+#define _PORT_16 PORTC
140
+#define _PORT_17 PORTC
141
+#define _PORT_18 PORTC
142
+#define _PORT_19 PORTC
143
+#define _PORT_20 PORTC
144
+#define _PORT_21 PORTC
145
+
146
+#define _PIN_0  PIND
147
+#define _PIN_1  PIND
148
+#define _PIN_2  PIND
149
+#define _PIN_3  PIND
150
+#define _PIN_4  PIND
151
+#define _PIN_5  PIND
152
+#define _PIN_6  PIND
153
+#define _PIN_7  PIND
154
+#define _PIN_8  PINB
155
+#define _PIN_9  PINB
156
+#define _PIN_10 PINB
157
+#define _PIN_11 PINB
158
+#define _PIN_12 PINB
159
+#define _PIN_13 PINB
160
+#define _PIN_14 PINC
161
+#define _PIN_15 PINC
162
+#define _PIN_16 PINC
163
+#define _PIN_17 PINC
164
+#define _PIN_18 PINC
165
+#define _PIN_19 PINC
166
+#define _PIN_20 PINC
167
+#define _PIN_21 PINC
168
+
169
+#define _DDR_0  DDRD
170
+#define _DDR_1  DDRD
171
+#define _DDR_2  DDRD
172
+#define _DDR_3  DDRD
173
+#define _DDR_4  DDRD
174
+#define _DDR_5  DDRD
175
+#define _DDR_6  DDRD
176
+#define _DDR_7  DDRD
177
+#define _DDR_8  DDRB
178
+#define _DDR_9  DDRB
179
+#define _DDR_10 DDRB
180
+#define _DDR_11 DDRB
181
+#define _DDR_12 DDRB
182
+#define _DDR_13 DDRB
183
+#define _DDR_14 DDRC
184
+#define _DDR_15 DDRC
185
+#define _DDR_16 DDRC
186
+#define _DDR_17 DDRC
187
+#define _DDR_18 DDRC
188
+#define _DDR_19 DDRC
189
+#define _DDR_20 DDRC
190
+#define _DDR_21 DDRC
191
+
192
+#define _PN_0  0
193
+#define _PN_1  1
194
+#define _PN_2  2
195
+#define _PN_3  3
196
+#define _PN_4  4
197
+#define _PN_5  5
198
+#define _PN_6  6
199
+#define _PN_7  7
200
+#define _PN_8  0
201
+#define _PN_9  1
202
+#define _PN_10 2
203
+#define _PN_11 3
204
+#define _PN_12 4
205
+#define _PN_13 5
206
+#define _PN_14 0
207
+#define _PN_15 1
208
+#define _PN_16 2
209
+#define _PN_17 3
210
+#define _PN_18 4
211
+#define _PN_19 5
212
+#define _PN_20 6
213
+#define _PN_21 7

+ 21 - 0
lib/nsdelay.h View File

@@ -0,0 +1,21 @@
1
+#pragma once
2
+
3
+//
4
+// Functions for precise delays (nanoseconds / cycles)
5
+//
6
+
7
+#include <avr/io.h>
8
+#include <util/delay_basic.h>
9
+#include <stdint.h>
10
+
11
+/* Convert nanoseconds to cycle count */
12
+#define ns2cycles(ns)  ( (ns) / (1000000000L / (signed long) F_CPU) )
13
+
14
+/** Wait c cycles */
15
+#define delay_c(c)  (((c) > 0) ? __builtin_avr_delay_cycles(c) :  __builtin_avr_delay_cycles(0))
16
+
17
+/** Wait n nanoseconds, plus c cycles  */
18
+#define delay_ns_c(ns, c)  delay_c(ns2cycles(ns) + (c))
19
+
20
+/** Wait n nanoseconds  */
21
+#define delay_ns(ns)  delay_c(ns2cycles(ns))

+ 62 - 0
lib/spi.c View File

@@ -0,0 +1,62 @@
1
+#include <avr/io.h>
2
+#include <stdint.h>
3
+#include <stdbool.h>
4
+
5
+#include "iopins.h"
6
+#include "spi.h"
7
+
8
+
9
+/** Init SPI (for SD card communication) */
10
+void spi_init_master(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha, enum SPI_clk_div clkdiv)
11
+{
12
+	as_output(PIN_SS); // SS output - we control slave
13
+	as_output(PIN_MOSI); // MOSI output - we talk to slave
14
+	as_output(PIN_SCK); // SCK output - we're generating clock
15
+	// MISO is configured automatically as input
16
+
17
+	SPCR = 0;
18
+	SPCR |= (1 << MSTR);
19
+	SPCR |= (order << DORD);
20
+	SPCR |= (cpol << CPOL);
21
+	SPCR |= (cpha << CPHA);
22
+
23
+	// speed
24
+	SPCR |= (clkdiv & 0b11);
25
+	SPSR = (bool)(clkdiv & 0b100); // write SPI2X flag
26
+
27
+	// enable SPI
28
+	SPCR |= (1 << SPE);
29
+}
30
+
31
+
32
+/** Init SPI (for SD card communication) */
33
+void spi_init_slave(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha)
34
+{
35
+	as_output(PIN_MISO); // we're listening to master
36
+	// MOSI, SS, SCK are configured automatically
37
+
38
+	SPCR = 0;
39
+	SPCR |= (order << DORD);
40
+	SPCR |= (cpol << CPOL);
41
+	SPCR |= (cpha << CPHA);
42
+
43
+	// enable SPI
44
+	SPCR |= (1 << SPE);
45
+}
46
+
47
+/** Write a byte to SPI. Returns received byte. */
48
+uint8_t spi_send(uint8_t byte)
49
+{
50
+	SPDR = byte;
51
+	while (bit_is_low(SPSR, SPIF));
52
+
53
+	return SPDR;
54
+}
55
+
56
+/** Receive (as slave). Blocking. */
57
+uint8_t spi_receive(uint8_t reply)
58
+{
59
+	SPDR = reply;
60
+	while (bit_is_low(SPSR, SPIF));
61
+	return SPDR;
62
+}

+ 69 - 0
lib/spi.h View File

@@ -0,0 +1,69 @@
1
+#pragma once
2
+
3
+#include <avr/io.h>
4
+#include <stdint.h>
5
+
6
+#include "calc.h"
7
+#include "iopins.h"
8
+
9
+#define PIN_MISO 12
10
+#define PIN_MOSI 11
11
+#define PIN_SCK 13
12
+#define PIN_SS 10
13
+
14
+/** Bit order */
15
+enum SPI_order {
16
+	SPI_LSB_FIRST = 0,
17
+	SPI_MSB_FIRST = 1
18
+};
19
+
20
+/** Clock polarity */
21
+enum SPI_cpol {
22
+	CPOL_0 = 0,
23
+	CPOL_1 = 1
24
+};
25
+
26
+/** Clock phase */
27
+enum SPI_cpha {
28
+	CPHA_0 = 0,
29
+	CPHA_1 = 1
30
+};
31
+
32
+/** Clock prescaller <SPI2X><SPR1><SPR0> */
33
+enum SPI_clk_div {
34
+	SPI_DIV_2   = 0b100, // 2x (master only, can't receive at this speed)
35
+	SPI_DIV_4   = 0b000,
36
+	SPI_DIV_8   = 0b101, // 2x
37
+	SPI_DIV_16  = 0b001,
38
+	SPI_DIV_32  = 0b110, // 2x
39
+	SPI_DIV_64  = 0b010,
40
+	SPI_DIV_128 = 0b011
41
+};
42
+
43
+
44
+/** Set SS to active state (LOW) */
45
+#define spi_ss_enable()  pin_down(PIN_SS)
46
+
47
+
48
+/** Set SS to disabled state (HIGH) */
49
+#define spi_ss_disable() pin_up(PIN_SS)
50
+
51
+
52
+/** Enable SPI ISR */
53
+#define spi_isr_enable(yes) set_bit(SPCR, SPIE, yes)
54
+
55
+
56
+/** Init SPI (for SD card communication) */
57
+void spi_init_master(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha, enum SPI_clk_div clkdiv);
58
+
59
+
60
+/** Init SPI (for SD card communication) */
61
+void spi_init_slave(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha);
62
+
63
+
64
+/** Write a byte to SPI. Returns received byte. */
65
+uint8_t spi_send(uint8_t byte);
66
+
67
+
68
+/** Receive (as slave). Blocking. */
69
+uint8_t spi_receive(uint8_t reply);

+ 83 - 0
lib/usart.c View File

@@ -0,0 +1,83 @@
1
+#include <avr/io.h>
2
+#include <avr/pgmspace.h>
3
+#include <util/delay.h>
4
+
5
+#include <stdbool.h>
6
+#include <stdint.h>
7
+#include <stdlib.h>
8
+
9
+#include "calc.h"
10
+#include "usart.h"
11
+
12
+
13
+void usart_init(uint16_t ubrr)
14
+{
15
+	/*Set baud rate */
16
+	UBRR0H = (uint8_t)(ubrr >> 8);
17
+	UBRR0L = (uint8_t) ubrr;
18
+
19
+	// Enable Rx and Tx
20
+	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
21
+
22
+	// Clear U2X0
23
+	cbi(UCSR0A, U2X0);
24
+
25
+	// 8-bit data, 1 stop bit
26
+	UCSR0C = (0b11 << UCSZ00);
27
+}
28
+
29
+
30
+/** Set Double Speed Asynchronous mode */
31
+void usart_set_2x(bool set)
32
+{
33
+	set_bit(UCSR0A, U2X0, set);
34
+}
35
+
36
+
37
+/** Send byte over USART */
38
+void usart_tx(uint8_t data)
39
+{
40
+	// Wait for transmit buffer
41
+	while (!usart_tx_ready());
42
+	// send it
43
+	UDR0 = data;
44
+}
45
+
46
+
47
+/** Receive one byte over USART */
48
+uint8_t usart_rx(void)
49
+{
50
+	// Wait for data to be received
51
+	while (!usart_rx_ready());
52
+	// Get and return received data from buffer
53
+	return UDR0;
54
+}
55
+
56
+
57
+/** Send string over USART */
58
+void usart_puts(const char* str)
59
+{
60
+	while (*str) {
61
+		usart_tx(*str++);
62
+	}
63
+}
64
+
65
+
66
+/** Send progmem string over USART */
67
+void usart_puts_P(const char* str)
68
+{
69
+	char c;
70
+	while ((c = pgm_read_byte(str++))) {
71
+		usart_tx(c);
72
+	}
73
+}
74
+
75
+
76
+/** Clear receive buffer */
77
+void usart_flush_rx(void)
78
+{
79
+	uint8_t dummy;
80
+	while (bit_is_high(UCSR0A, RXC0)) {
81
+		dummy = UDR0;
82
+	}
83
+}

+ 86 - 0
lib/usart.h View File

@@ -0,0 +1,86 @@
1
+#pragma once
2
+
3
+//
4
+// Utilities for UART communication.
5
+//
6
+// First, init uart with usart_init().
7
+// Then enable interrupts you want with usart_XXX_isr_enable().
8
+//
9
+
10
+#include <avr/io.h>
11
+#include <avr/pgmspace.h>
12
+#include <util/delay.h>
13
+
14
+#include <stdbool.h>
15
+#include <stdint.h>
16
+
17
+#include "calc.h"
18
+
19
+
20
+/* USART BAUD RATE REGISTER values at 16 MHz */
21
+enum {
22
+	BAUD_9600 = 103,
23
+	BAUD_14400 = 68,
24
+	BAUD_19200 = 51,
25
+	BAUD_28800 = 34,
26
+	BAUD_38400 = 25,
27
+	BAUD_57600 = 16,
28
+	BAUD_76800 = 12,
29
+	BAUD_115200 = 8,
30
+	BAUD_250k = 3,
31
+	BAUD_500k = 1,
32
+	BAUD_1M = 0,
33
+};
34
+
35
+/** Init UART with a UBRR value - can use the BAUD_* constants for 16 MHz */
36
+void usart_init(uint16_t ubrr);
37
+
38
+
39
+/** Set Double Speed Asynchronous mode on or off */
40
+void usart_set_2x(bool set);
41
+
42
+
43
+/** Check if there's a byte in the RX register */
44
+#define usart_rx_ready() bit_is_high(UCSR0A, RXC0)
45
+
46
+
47
+/** Check if USART is ready to accept new byte to send */
48
+#define usart_tx_ready() bit_is_high(UCSR0A, UDRE0)
49
+
50
+
51
+// ---- Enable UART interrupts ------------
52
+
53
+/** Enable or disable RX ISR */
54
+#define usart_isr_rx_enable(yes) set_bit(UCSR0B, RXCIE0, (yes))
55
+
56
+
57
+/** Enable or disable TX ISR (all data sent) */
58
+#define usart_isr_tx_enable(yes) set_bit(UCSR0B, TXCIE0, (yes))
59
+
60
+
61
+/** Enable or disable DRE ISR (data register empty) */
62
+#define usart_isr_dre_enable(yes) set_bit(UCSR0B, UDRIE0, (yes))
63
+
64
+
65
+// ---- Basic IO --------------------------
66
+
67
+/** Send byte over USART */
68
+void usart_tx(uint8_t data);
69
+
70
+
71
+/** Receive one byte over USART */
72
+uint8_t usart_rx(void);
73
+
74
+
75
+/** Clear receive buffer */
76
+void usart_flush_rx(void);
77
+
78
+
79
+// ---- Strings ---------------------------
80
+
81
+/** Send string over UART */
82
+void usart_puts(const char* str);
83
+
84
+
85
+/** Send progmem string `PSTR("foobar")` over UART  */
86
+void usart_puts_P(const char* str);

+ 241 - 0
main.c View File

@@ -0,0 +1,241 @@
1
+#include <avr/io.h>          // register definitions
2
+#include <avr/pgmspace.h>    // storing data in program memory
3
+#include <avr/interrupt.h>   // interrupt vectors
4
+#include <util/delay.h>      // delay functions
5
+
6
+#include <stdint.h>
7
+#include <stdbool.h>
8
+#include <stdlib.h>
9
+
10
+// Include stuff from the library
11
+#include "lib/iopins.h"
12
+#include "lib/usart.h"
13
+#include "lib/nsdelay.h"
14
+
15
+static void sonar_start(void);
16
+
17
+#define WS_PIN 5
18
+
19
+#define TRIG_PIN 2
20
+#define ECHO1_PIN 3
21
+#define ECHO2_PIN 4
22
+
23
+
24
+/** Wait long enough for the colors to show */
25
+static void ws_show(void)
26
+{
27
+	_delay_us(10);
28
+}
29
+
30
+static inline __attribute__((always_inline))
31
+void delay_cyc(uint8_t __count)
32
+{
33
+	__asm__ volatile (
34
+		"1: dec %0" "\n\t"
35
+		"brne 1b"
36
+		: "=r" (__count)
37
+		: "0" (__count)
38
+	);
39
+}
40
+
41
+
42
+/** Send one byte to the RGB strip */
43
+static inline  __attribute__((always_inline))
44
+void ws_send_byte(uint8_t bb)
45
+{
46
+	for (int8_t i = 8; i > 0; i--) {
47
+		pin_up(WS_PIN);
48
+		if (bb & 0x80) {
49
+			delay_cyc(4);
50
+			pin_down(WS_PIN);
51
+			delay_cyc(1);
52
+		} else {
53
+			delay_cyc(1);
54
+			pin_down(WS_PIN);
55
+			delay_cyc(4);
56
+		}
57
+
58
+		bb = (uint8_t)(bb << 1);
59
+	}
60
+}
61
+
62
+
63
+static void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b)
64
+{
65
+	ws_send_byte(g);
66
+	ws_send_byte(r);
67
+	ws_send_byte(b);
68
+}
69
+
70
+
71
+static void hw_init(void)
72
+{
73
+	usart_init(BAUD_115200);
74
+
75
+	as_output(2);
76
+	as_input_pu(3);
77
+	as_input_pu(4);
78
+	as_output(5); // WS
79
+}
80
+
81
+typedef enum {
82
+	MEAS_WAIT_1,
83
+	MEAS_WAIT_0,
84
+	MEAS_DONE
85
+} MeasPhase;
86
+
87
+
88
+#define PULSE_LEN 9
89
+const uint8_t pulse[PULSE_LEN] = {79, 150, 206, 243, 255, 243, 206, 150, 79};
90
+
91
+
92
+#define MBUF_LEN 64
93
+typedef struct {
94
+	float data[MBUF_LEN];
95
+} MBuf;
96
+
97
+float mbuf_add(MBuf *buf, float value)
98
+{
99
+	float aggr = value;
100
+	for (int i = 1; i < MBUF_LEN; i++) {
101
+		aggr += buf->data[i];
102
+		buf->data[i] = buf->data[i-1];
103
+	}
104
+	buf->data[0] = value;
105
+
106
+	return aggr / (float)MBUF_LEN;
107
+}
108
+
109
+MBuf mb_offs1;
110
+MBuf mb_offs2;
111
+
112
+
113
+static void sonar_measure(void)
114
+{
115
+	usart_puts("MEASURE!\n");
116
+
117
+	pin_up(TRIG_PIN);
118
+	_delay_ms(10);
119
+	pin_down(TRIG_PIN);
120
+
121
+	MeasPhase e1_ph = MEAS_WAIT_1;
122
+	MeasPhase e2_ph = MEAS_WAIT_1;
123
+
124
+	uint32_t echo1 = 0;
125
+	uint32_t echo2 = 0;
126
+
127
+	TCNT1 = 0;
128
+	TCCR1B = (0b010 << CS10);
129
+	while (true) {
130
+		switch (e1_ph) {
131
+			case MEAS_WAIT_1:
132
+				if (pin_is_high(ECHO1_PIN)) {
133
+					echo1 = TCNT1;
134
+					e1_ph = MEAS_WAIT_0;
135
+				}
136
+				break;
137
+
138
+			case MEAS_WAIT_0:
139
+				if (pin_is_low(ECHO1_PIN)) {
140
+					echo1 = TCNT1 - echo1;
141
+					e1_ph = MEAS_DONE;
142
+				}
143
+				break;
144
+		}
145
+
146
+		switch (e2_ph) {
147
+			case MEAS_WAIT_1:
148
+				if (pin_is_high(ECHO2_PIN)) {
149
+					echo2 = TCNT1;
150
+					e2_ph = MEAS_WAIT_0;
151
+				}
152
+				break;
153
+
154
+			case MEAS_WAIT_0:
155
+				if (pin_is_low(ECHO2_PIN)) {
156
+					echo2 = TCNT1 - echo2;
157
+					e2_ph = MEAS_DONE;
158
+				}
159
+				break;
160
+		}
161
+
162
+		if (e1_ph == MEAS_DONE && e2_ph == MEAS_DONE) {
163
+			break; // done
164
+		}
165
+	}
166
+
167
+	TCCR1B = 0; // stop
168
+
169
+	// Both pulses measured with 0.5us accuracy
170
+
171
+	// Convert to mm
172
+
173
+	echo1 *= 8000;
174
+	echo1 /= 10000;
175
+
176
+	echo2 *= 8000;
177
+	echo2 /= 10000;
178
+
179
+	char buf[10];
180
+
181
+	ltoa(echo1, buf, 10);
182
+	usart_puts("echo1: ");
183
+	usart_puts(buf);
184
+	usart_puts(" -> ");
185
+
186
+	float offset1 = echo1 / 100.0f;
187
+	float offset2 = echo2 / 100.0f;
188
+
189
+	offset1 = mbuf_add(&mb_offs1, offset1);
190
+	offset2 = mbuf_add(&mb_offs2, offset2);
191
+
192
+	int of1i = (int) roundf(offset1);
193
+	int of2i = (int) roundf(offset2);
194
+
195
+	of1i = 15 - of1i;
196
+	of2i = 15 - of2i;
197
+
198
+	int gi = -15 + PULSE_LEN/2 - of1i - 15;
199
+	int bi = -15 + PULSE_LEN/2 + of2i + 15;
200
+	int ri = -15 + PULSE_LEN/2 + 0;
201
+
202
+	uint8_t r, g, b;
203
+	for (int i = 0; i < 32; i++) {
204
+		if (ri >= 0 && ri < PULSE_LEN) {
205
+			r = pulse[ri];
206
+		} else {
207
+			r = 0;
208
+		}
209
+
210
+		if (gi >= 0 && gi < PULSE_LEN) {
211
+			g = pulse[gi];
212
+		} else {
213
+			g = 0;
214
+		}
215
+
216
+		if (bi >= 0 && bi < PULSE_LEN) {
217
+			b = pulse[bi];
218
+		} else {
219
+			b = 0;
220
+		}
221
+
222
+		ws_send_rgb(r,g,b);
223
+
224
+		ri++;
225
+		gi++;
226
+		bi++;
227
+	}
228
+
229
+	ws_show();
230
+}
231
+
232
+
233
+int main(void)
234
+{
235
+	hw_init();
236
+
237
+	while (1) {
238
+		sonar_measure();
239
+		_delay_ms(20);
240
+	}
241
+}

+ 14 - 0
style.astylerc View File

@@ -0,0 +1,14 @@
1
+style=kr
2
+indent=tab
3
+max-instatement-indent=60
4
+
5
+convert-tabs
6
+
7
+indent-switches
8
+keep-one-line-statements
9
+
10
+pad-oper
11
+unpad-paren
12
+pad-header
13
+
14
+verbose

+ 52 - 0
us_rgb.pro View File

@@ -0,0 +1,52 @@
1
+TEMPLATE = app
2
+CONFIG += console
3
+CONFIG -= app_bundle
4
+CONFIG -= qt
5
+
6
+INCLUDEPATH += \
7
+	lib \
8
+	/usr/avr/include
9
+
10
+DEFINES += __AVR_ATmega328P__ F_CPU=16000000UL
11
+
12
+DISTFILES += \
13
+	style.astylerc \
14
+	Makefile \
15
+	README.md \
16
+	LICENSE
17
+
18
+HEADERS += \
19
+	lib/calc.h \
20
+	lib/iopins.h \
21
+	lib/usart.h \
22
+	lib/nsdelay.h \
23
+	lib/spi.h \
24
+    lib/debounce.h
25
+
26
+SOURCES += \
27
+	lib/iopins.c \
28
+	main.c \
29
+	lib/usart.c \
30
+	lib/spi.c \
31
+    lib/debounce.c
32
+
33
+# === Flags for the Clang code model===
34
+#
35
+#-Weverything
36
+#-Wno-c++98-compat
37
+#-Wno-c++98-compat-pedantic
38
+#-Wno-unused-macros
39
+#-Wno-newline-eof
40
+#-Wno-exit-time-destructors
41
+#-Wno-global-constructors
42
+#-Wno-gnu-zero-variadic-macro-arguments
43
+#-Wno-documentation
44
+#-Wno-missing-prototypes
45
+#-std=gnu99
46
+#-Wno-gnu
47
+#-Wno-format-nonliteral
48
+#-Wno-conversion
49
+#-Wno-pointer-sign
50
+#-Wno-unknown-attributes
51
+#-Wno-main-return-type
52
+#-Wno-missing-noreturn