aboutsummaryrefslogtreecommitdiff
path: root/hw/thefreeman/lin16dac
diff options
context:
space:
mode:
Diffstat (limited to 'hw/thefreeman/lin16dac')
-rw-r--r--hw/thefreeman/lin16dac/cfg.h61
-rw-r--r--hw/thefreeman/lin16dac/hwdef.c92
-rw-r--r--hw/thefreeman/lin16dac/hwdef.h137
3 files changed, 290 insertions, 0 deletions
diff --git a/hw/thefreeman/lin16dac/cfg.h b/hw/thefreeman/lin16dac/cfg.h
new file mode 100644
index 0000000..20d2bf5
--- /dev/null
+++ b/hw/thefreeman/lin16dac/cfg.h
@@ -0,0 +1,61 @@
+// thefreeman's Linear 16 driver using DAC control
+// Copyright (C) 2021-2023 (FIXME)
+// SPDX-License-Identifier: GPL-3.0-or-later
+#pragma once
+
+#define MODEL_NUMBER "1630"
+#include "hwdef-thefreeman-lin16dac.h"
+// ATTINY: 1616
+
+// the button lights up
+#define USE_INDICATOR_LED
+// the button is visible while main LEDs are on
+#define USE_INDICATOR_LED_WHILE_RAMPING
+// off mode: low (1)
+// lockout: blinking (3)
+#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1)
+
+// level_calc.py ninth 2 150 7135 1 0.03 6.4 7135 1 6.3 1600
+#define RAMP_SIZE 150
+
+// 4 ramp segments:
+// - low 0.55V
+// - low 2.5V
+// - high 0.55V
+// - high 2.5V
+// PWM1: DAC Data
+// FIXME: ramp stalls with 8 duplicate levels in a row
+// (maybe use 1.1V Vref during that part of the ramp?)
+#define PWM1_LEVELS 25, 25, 33, 41, 41, 50, 58, 66, 75, 83, 92,108,117,133,150,167,192,209,234, \
+ 58, 64, 71, 80, 90, 99,110,121,134,149,163,180,198,218,241, \
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 39, 41, 44, 47, 50, 53, 56, 59, 63, 67, 71, 75, 79, 84, 89, 94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246, \
+ 57, 60, 63, 66, 69, 73, 76, 80, 84, 88, 93, 97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255
+// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20)
+#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18
+
+#define MAX_1x7135 34
+#define HDR_ENABLE_LEVEL_MIN 35 // bottom level of top half of the ramp
+#define HALFSPEED_LEVEL 255 // always run at 1/4th speed
+#define QUARTERSPEED_LEVEL 255 // because DAC doesn't use PWM
+
+#define RAMP_SMOOTH_FLOOR 1
+#define RAMP_SMOOTH_CEIL 120
+// 10, 28, 46, [65], 83, 101, 120
+#define RAMP_DISCRETE_FLOOR 10
+#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL
+#define RAMP_DISCRETE_STEPS 7
+
+// stop panicking at ~30% power
+#define THERM_FASTER_LEVEL 123
+
+// enable 2 click turbo
+#define DEFAULT_2C_STYLE 1
+
+// don't blink mid-ramp
+#ifdef BLINK_AT_RAMP_MIDDLE
+#undef BLINK_AT_RAMP_MIDDLE
+#endif
+
diff --git a/hw/thefreeman/lin16dac/hwdef.c b/hw/thefreeman/lin16dac/hwdef.c
new file mode 100644
index 0000000..07c7f9e
--- /dev/null
+++ b/hw/thefreeman/lin16dac/hwdef.c
@@ -0,0 +1,92 @@
+// thefreeman linear t1616 DAC driver helper functions
+// Copyright (C) 2023 Selene ToyKeeper
+// SPDX-License-Identifier: GPL-3.0-or-later
+#pragma once
+
+#include "chan-aux.c"
+
+void set_level_zero();
+
+void set_level_main(uint8_t level);
+bool gradual_tick_main(uint8_t gt);
+
+
+Channel channels[] = {
+ { // main LEDs
+ .set_level = set_level_main,
+ .gradual_tick = gradual_tick_main
+ },
+ AUX_CHANNELS
+};
+
+
+void set_level_zero() {
+ DAC_LVL = 0; // DAC off
+ DAC_VREF = V055; // low Vref
+ HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off
+
+ // prevent post-off flash
+ //IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN);
+ //delay_4ms(IN_NFET_DELAY_TIME/4);
+ //IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN);
+
+ // turn off opamp last
+ OPAMP_ENABLE_PORT &= ~(1 << OPAMP_ENABLE_PIN); // Opamp off
+}
+
+// single set of LEDs with 1 regulated power channel
+// and low/high HDR plus low/high Vref as different "gears"
+void set_level_main(uint8_t level) {
+ #if 0 // unsure if this helps anything
+ uint8_t noflash = 0;
+
+ // when turning on from off, try to prevent a flash
+ if ((! actual_level) && (level < HDR_ENABLE_LEVEL_MIN)) {
+ noflash = 1;
+ }
+ #endif
+
+ // Opamp on first, to give it a few extra microseconds to spin up
+ OPAMP_ENABLE_PORT |= (1 << OPAMP_ENABLE_PIN);
+
+ // pre-load ramp data so it can be assigned faster later
+ PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level);
+ PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level);
+
+ // enable HDR on top half of ramp
+ if (level >= (HDR_ENABLE_LEVEL_MIN-1))
+ HDR_ENABLE_PORT |= (1 << HDR_ENABLE_PIN);
+ else
+ HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN);
+
+ #if 0
+ if (noflash) {
+ // wait for flash prevention to finish
+ delay_4ms(OPAMP_ON_DELAY/4);
+ }
+ #endif
+
+ // set these in successive clock cycles to avoid getting out of sync
+ // (minimizes ramp bumps when changing gears)
+ DAC_LVL = dac_lvl;
+ DAC_VREF = dac_vref;
+}
+
+bool gradual_tick_main(uint8_t gt) {
+ // if HDR and Vref "engine gear" is the same, do a small adjustment...
+ // otherwise, simply jump to the next ramp level
+ // and let set_level() handle any gear changes
+
+ PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt);
+ PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt);
+
+ // different gear = full adjustment
+ if (vref_next != DAC_VREF) return true; // let parent set_level() for us
+
+ // same gear = small adjustment
+ GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL);
+ if (dac_next == DAC_LVL) return true; // done
+
+ return false; // not done yet
+}
+
diff --git a/hw/thefreeman/lin16dac/hwdef.h b/hw/thefreeman/lin16dac/hwdef.h
new file mode 100644
index 0000000..c0d0638
--- /dev/null
+++ b/hw/thefreeman/lin16dac/hwdef.h
@@ -0,0 +1,137 @@
+// thefreeman's Linear 16 driver using DAC control
+// Copyright (C) 2021-2023 thefreeman, Selene ToyKeeper
+// SPDX-License-Identifier: GPL-3.0-or-later
+#pragma once
+
+/*
+ * PA6 - DAC for LED brightness control
+ * PA7 - Op-amp enable pin
+ * PB5 - Aux LED
+ * PB4 - Switch pin, internal pullup
+ * PB3 - HDR control, set High to enable the high power channel, set Low for low power
+ * Read voltage from VCC pin, has PFET so no drop
+ */
+
+#define ATTINY 1616
+#include <avr/io.h>
+
+#define HWDEF_C_FILE hwdef-thefreeman-lin16dac.c
+
+// allow using aux LEDs as extra channel modes
+#include "chan-aux.h"
+
+// channel modes:
+// * 0. main LEDs
+// * 1+. aux RGB
+#define NUM_CHANNEL_MODES 2
+enum CHANNEL_MODES {
+ CM_MAIN = 0,
+ CM_AUX
+};
+
+#define DEFAULT_CHANNEL_MODE CM_MAIN
+
+// right-most bit first, modes are in fedcba9876543210 order
+#define CHANNEL_MODES_ENABLED 0b0000000000000001
+
+
+#define PWM_CHANNELS 1 // old, remove this
+
+#define PWM_BITS 8 // 8-bit DAC
+#define PWM_GET PWM_GET8
+#define PWM_DATATYPE uint8_t
+#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255
+#define PWM1_DATATYPE uint8_t // main LED ramp
+
+// main LED outputs
+#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref
+#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V
+#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?)
+// Vref values
+#define V055 16
+#define V11 17
+#define V25 18
+#define V43 19
+#define V15 20
+
+// Opamp enable
+// For turning on and off the op-amp
+#define OPAMP_ENABLE_PIN PIN7_bp
+#define OPAMP_ENABLE_PORT PORTA_OUT
+// how many ms to delay turning on the lights after enabling the channel
+// (FIXME: 80 is long enough it's likely to cause bugs elsewhere,
+// as events stack up unhandled for 5 consecutive WDT ticks)
+#define OPAMP_ON_DELAY 80
+
+// HDR
+// turns on HDR FET for the high current range
+#define HDR_ENABLE_PIN PIN3_bp
+#define HDR_ENABLE_PORT PORTB_OUT
+
+// e-switch
+#define SWITCH_PIN PIN4_bp
+#define SWITCH_PORT VPORTB.IN
+#define SWITCH_ISC_REG PORTB.PIN2CTRL
+#define SWITCH_VECT PORTB_PORT_vect
+#define SWITCH_INTFLG VPORTB.INTFLAGS
+
+// average drop across diode on this hardware
+#ifndef VOLTAGE_FUDGE_FACTOR
+#define VOLTAGE_FUDGE_FACTOR 0 // using a PFET so no appreciable drop
+#endif
+
+// lighted button
+#define AUXLED_PIN PIN5_bp
+#define AUXLED_PORT PORTB
+
+
+inline void hwdef_setup() {
+
+ // set up the system clock to run at 10 MHz instead of the default 3.33 MHz
+ // (it'll get underclocked to 2.5 MHz later)
+ // TODO: maybe run even slower?
+ _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB,
+ CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm );
+
+ VPORTA.DIR = PIN6_bm // DAC
+ | PIN7_bm; // Opamp
+ VPORTB.DIR = PIN3_bm; // HDR
+ //VPORTC.DIR = 0b00000000;
+
+ // enable pullups on the input pins to reduce power
+ PORTA.PIN0CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN1CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN2CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN3CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN4CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN5CTRL = PORT_PULLUPEN_bm;
+ //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // DAC ouput
+ //PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // Op-amp enable pin
+
+ PORTB.PIN0CTRL = PORT_PULLUPEN_bm;
+ PORTB.PIN1CTRL = PORT_PULLUPEN_bm;
+ PORTB.PIN2CTRL = PORT_PULLUPEN_bm;
+ //PORTB.PIN3CTRL = PORT_PULLUPEN_bm; // HDR channel selection
+ PORTB.PIN4CTRL = PORT_PULLUPEN_bm
+ | PORT_ISC_BOTHEDGES_gc; // e-switch
+ //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED
+
+ PORTC.PIN0CTRL = PORT_PULLUPEN_bm;
+ PORTC.PIN1CTRL = PORT_PULLUPEN_bm;
+ PORTC.PIN2CTRL = PORT_PULLUPEN_bm;
+ PORTC.PIN3CTRL = PORT_PULLUPEN_bm;
+
+ // set up the DAC
+ // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf
+ // DAC ranges from 0V to (255 * Vref) / 256
+ // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc
+ VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc;
+ VREF.CTRLB |= VREF_DAC0REFEN_bm;
+ DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm;
+ DAC0.DATA = 255; // set the output voltage
+
+}
+
+
+#define LAYOUT_DEFINED
+
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.