commit:1214e3299d5e45e069c5e72ac18624fd7591bad8
author:Chip
committer:Chip
date:Sun Feb 4 19:58:07 2024 -0600
parents:
Working with board v2

Use `make CALIBRATE=1` to enable calibration build, which outputs raw
ADC values.
diff --git a/.gitignore b/.gitignore
line changes: +2/-0
index 0000000..43f0aa8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.bin
+*.elf

diff --git a/Makefile b/Makefile
line changes: +13/-0
index 0000000..811d425
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
+targets = electrobanana.elf electrobanana.bin
+
+ifdef CALIBRATE
+	FLAGS += -DCALIBRATE
+endif
+
+all: $(targets)
+
+%.elf: %.c
+	avr-gcc -Wall -Os $(FLAGS) -mmcu=attiny13a $< -o $@
+
+%.bin: %.elf
+	avr-objcopy -I elf32-avr -O binary $< $@

diff --git a/electrobanana.c b/electrobanana.c
line changes: +134/-0
index 0000000..0eedf21
--- /dev/null
+++ b/electrobanana.c
@@ -0,0 +1,134 @@
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+#include <avr/pgmspace.h>
+#define F_CPU 8000000UL
+#include <util/delay.h>
+
+void read_values();
+void display_values();
+void clear();
+void shift(uint8_t b);
+void latch();
+uint16_t adc_read(uint8_t channel);
+
+const uint8_t PROGMEM charmap[] = {
+  0b11111100, // 0
+  0b01100000, // 1
+  0b11011010, // 2
+  0b11110010, // 3
+  0b01100110, // 4
+  0b10110110, // 5
+  0b10111110, // 6
+  0b11100000, // 7
+  0b11111110, // 8
+  0b11110110, // 9
+  0b11101110, // A
+  0b00111110, // b
+  0b10011100, // C
+  0b01111010, // d
+  0b10011110, // E
+  0b10001110, // F
+};
+
+#define DECIMAL_POINT 0b00000001
+
+uint16_t values[2];
+uint8_t disp_buf[4];
+
+int main() {
+	// Set PB0, 1, 2 to output, others to input
+	DDRB = 0b00000111;
+	// Enable interrupts
+	sei();
+
+	values[0] = 0;
+
+	while (1) {
+		read_values();
+		display_values();
+	}
+}
+
+void read_values() {
+	for (uint8_t chan = 0; chan < 2; chan++) {
+		uint32_t accum = 0;
+		for (uint16_t i = 0; i < 1024; i++) {
+			accum += adc_read(chan);
+		}
+		// divide by 1024
+		values[chan] = accum >> 10;
+	}
+#ifndef CALIBRATE
+	// multiply by scaling ratio
+	// 5V / 1024 steps / 0.1x scaling factor = 0.04883 V/step
+	// Measured: 0.04866 V/step + 0.2199V offset
+	values[0] = (values[0] * 4866) / 1000 + 22;
+	// 5V / 1024 steps / 47x scaling factor = 104 uV/step
+	values[1] = (values[1] * 104) / 1000 + 0;
+#endif
+}
+
+void display_values() {
+	for (uint8_t chan = 1; chan < 2; chan++) {
+		uint16_t n = values[chan];
+		for (uint8_t i = 0; i < 4; i++) {
+			uint8_t d = n % 10;
+			n = n / 10;
+			disp_buf[3 - i] = pgm_read_byte(charmap + d);
+		}
+#ifndef CALIBRATE
+		disp_buf[1] |= DECIMAL_POINT;
+#endif
+		for (uint8_t i = 0; i < 4; i++) {
+			for (uint8_t j = 0; j < 8; j++) {
+				shift(disp_buf[i] >> j);
+			}
+		}
+	}
+	latch();
+}
+
+void clear() {
+	// 8 bits per digit, 4 digits, two displays
+	for (uint8_t i = 0; i < 8 * 4 * 2; i++) {
+		shift(0);
+	}
+	latch();
+}
+
+void shift(uint8_t b) {
+	PORTB = (PORTB & 0b11111110) | (b & 1);
+	PORTB |= _BV(PB1);
+	PORTB &= ~(_BV(PB1));
+}
+
+void latch() {
+	PORTB |= _BV(PB2);
+	PORTB &= ~(_BV(PB2));
+}
+
+uint16_t adc_read(uint8_t channel) {
+	if (channel == 0) {
+		// ADC: VCC reference, Right Adjust, select PB4
+		ADMUX = 0b00000010;
+	} else {
+		// ADC: VCC reference, Right Adjust, select PB3
+		ADMUX = 0b00000011;
+	}
+
+	// Enable ADC, completion interrupt, Prescaler divisor 32
+	ADCSRA = _BV(ADEN) | _BV(ADIE) | 0b101;
+
+	// Enter ADC Noise Reduction mode
+	set_sleep_mode(SLEEP_MODE_ADC);
+	sleep_mode();
+
+	// read registers in two separate statements to preserve ordering. ADCL
+	// must be read before ADCH.
+	uint8_t tmp = ADCL;
+
+	return tmp | (ADCH << 8);
+}
+
+EMPTY_INTERRUPT(ADC_vect);

diff --git a/flags b/flags
line changes: +3/-0
index 0000000..aa71be4
--- /dev/null
+++ b/flags
@@ -0,0 +1,3 @@
+lfuse = 0x7a
+hfuse = 0xff
+lock = 0xff