diff options
| author | Selene ToyKeeper | 2021-04-02 14:34:10 -0600 |
|---|---|---|
| committer | Selene ToyKeeper | 2021-04-02 14:34:10 -0600 |
| commit | 7713133fedd51212eee10c8ed855e512820ff5fb (patch) | |
| tree | aca9e6bf2fb078aa50ad71800afeace32be61daa | |
| parent | updated MODELS file with missing K9.3-nofet build target (diff) | |
| parent | re-numbered t1616 builds to reflect manufacturer better (diff) | |
| download | anduril-7713133fedd51212eee10c8ed855e512820ff5fb.tar.gz anduril-7713133fedd51212eee10c8ed855e512820ff5fb.tar.bz2 anduril-7713133fedd51212eee10c8ed855e512820ff5fb.zip | |
merged gchart's Tiny1 series branch for t1616 support
| -rw-r--r-- | README | 54 | ||||
| -rwxr-xr-x | bin/build.sh | 10 | ||||
| -rwxr-xr-x | bin/flash-tiny1616.sh | 14 | ||||
| -rw-r--r-- | hwdef-BLF_Q8-T1616.h | 101 | ||||
| -rw-r--r-- | hwdef-Sofirn_SP10S.h | 124 | ||||
| -rw-r--r-- | hwdef-gchart-fet1-t1616.h | 103 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/BRANDS | 1 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/MODELS | 5 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/cfg-blf-lantern-t1616.h | 90 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/cfg-blf-q8-t1616.h | 43 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h | 39 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/cfg-sofirn-sp10s.h | 28 | ||||
| -rw-r--r-- | spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h | 33 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-adc.c | 57 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-main.c | 9 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-misc.c | 78 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-pcint.c | 27 | ||||
| -rw-r--r-- | spaghetti-monster/fsm-wdt.c | 20 | ||||
| -rw-r--r-- | tk-attiny.h | 29 |
19 files changed, 849 insertions, 16 deletions
@@ -115,3 +115,57 @@ build Crescendo for an attiny25-based driver and then flash it: ../../bin/flash-tiny25.sh crescendo.hex Other useful tools are in bin/ too, so they might be worth a look. + + +ATtiny Series 1 (tiny1616) Support +================================== + +As of early 2021, the Debian packages for gcc-avr and avrdude do not include +support for the Tiny1 series chips. Extra steps are required to get these +working. + + - Download the Atmel ATtiny Series Device Support pack: + http://packs.download.atmel.com/ + + - Unzip the pack somewhere on your build computer + + - Set ATTINY_DFP=/path/to/where/you/unzipped/the/pack + (either in your shell, or in this repo's bin/build.sh script) + + export ATTINY_DFP=$HOME/src/torches/atmel/attiny-dfp + + - Make sure you're using gcc-avr 1:5.4.0+Atmel3.6.2 or newer. + 3.6.1 will not work. It gives errors like: + /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: address 0x80381e of anduril.elf section `.data' is not within region `data' + This requires debian/bullseye or newer; buster has 3.6.1. + +This should at least allow the code to compile. + +Some extra steps are also needed to make flashing (avrdude) work: + + - Get an AVR jtag2 device. + The one I'm using is: "HWAYEH AVR JTAG ICE Version 2.0" + Connect the cables: + - GND = - + - Vtref = + + - nSRST = R (reset/UPDI) + + - Flash the jtag2 device with the relevant firmware: + https://github.com/ElTangas/jtag2updi/tree/master/tools/avrjtagicev2 + + - Get an avrdude.conf which supports jtag2updi: + + - Download avrdude.conf from https://github.com/ElTangas/jtag2updi + and put it in /etc + + - Or grab the source and set an environment variable: + + cd ~/src/torches/avrdude + git clone https://github.com/ElTangas/jtag2updi + export AVRDUDE_CONF="-C$HOME/src/torches/avrdude/jtag2updi/avrdude.conf" + + - Maybe configure which USB serial port to use too: + export AVRDUDE_TTYUSB="/dev/ttyUSB2" + +Afterward, flashing should work. You may need to unplug and replug the jtag2 +USB device between uses though, since it may stop responding after each use. diff --git a/bin/build.sh b/bin/build.sh index 3992c38..c733320 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -11,11 +11,17 @@ fi export ATTINY=$1 ; shift export PROGRAM=$1 ; shift + +# path to the Atmel ATtiny device family pack: (for attiny1616 support) +# http://packs.download.atmel.com/ +if [ -z "$ATTINY_DFP" ]; then export ATTINY_DFP=~/avr/attiny_dfp ; fi + export MCU=attiny$ATTINY export CC=avr-gcc export OBJCOPY=avr-objcopy -export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -fgnu89-inline -fwhole-program -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums" -export OFLAGS="-Wall -g -Os -mmcu=$MCU" +export DFPFLAGS="-B $ATTINY_DFP/gcc/dev/$MCU/ -I $ATTINY_DFP/include/" +export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -fgnu89-inline -fwhole-program -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums $DFPFLAGS" +export OFLAGS="-Wall -g -Os -mmcu=$MCU $DFPFLAGS" export LDFLAGS="-fgnu89-inline" export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex' export OBJS=$PROGRAM.o diff --git a/bin/flash-tiny1616.sh b/bin/flash-tiny1616.sh new file mode 100755 index 0000000..44d716c --- /dev/null +++ b/bin/flash-tiny1616.sh @@ -0,0 +1,14 @@ +#/bin/sh +FIRMWARE=$1 +if [ -z "$AVRDUDE_TTYUSB" ]; then AVRDUDE_TTYUSB=/dev/ttyUSB0 ; fi + +# In your shell config: +# from https://github.com/ElTangas/jtag2updi ... +# export AVRDUDE_CONF="-C$HOME/path/to/jtag2updi/avrdude.conf" +# export AVRDUDE_TTYUSB="/dev/ttyUSB2" + +avrdude $AVRDUDE_CONF \ + -c jtag2updi \ + -P $AVRDUDE_TTYUSB \ + -p t1616 \ + -u -Uflash:w:$FIRMWARE diff --git a/hwdef-BLF_Q8-T1616.h b/hwdef-BLF_Q8-T1616.h new file mode 100644 index 0000000..2a0e6ff --- /dev/null +++ b/hwdef-BLF_Q8-T1616.h @@ -0,0 +1,101 @@ +#ifndef HWDEF_BLF_Q8_T1616_H +#define HWDEF_BLF_Q8_T1616_H + +/* BLF Q8 driver layout using the Attiny1616 + +Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * PWM FET: PB0 (TCA0 WO0) + * PWM 1x7135: PB1 (TCA0 WO1) + * Voltage: VCC + +*/ + + +#define LAYOUT_DEFINED + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1616 +#include <avr/io.h> + +#define PWM_CHANNELS 2 + +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +#endif + + +// 7135 channel +#ifndef PWM1_PIN +#define PWM1_PIN PB1 // +#define PWM1_LVL TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 +#endif + +// FET channel +#ifndef PWM2_PIN +#define PWM2_PIN PB0 // +#define PWM2_LVL TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 +#endif + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + + +// lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB +#endif + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + + // set up the system clock to run at 5 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + VPORTB.DIR = PIN0_bm | PIN1_bm | PIN5_bm; // Outputs: Aux LED and PWMs + //VPORTC.DIR = ...; + + // enable pullups on the unused 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 | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //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 PWM + // TODO: add references to MCU documentation + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + TCA0.SINGLE.PER = 255; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + + +#endif diff --git a/hwdef-Sofirn_SP10S.h b/hwdef-Sofirn_SP10S.h new file mode 100644 index 0000000..0ee3332 --- /dev/null +++ b/hwdef-Sofirn_SP10S.h @@ -0,0 +1,124 @@ +#ifndef HWDEF_SOFIRN_SP10S_H +#define HWDEF_SOFIRN_SP10S_H + +// TODO: rename to sofirn-sp10s-gchart? + +/* gChart's PIC12 to ATTINY1616 v1 adapter for the SP10S +https://oshpark.com/shared_projects/b4IZEGSy + +PIC12 Pinout: +1 - VDD +2 - No Connect +3 - Low Channel FET (series 4.7K Ohms) +4 - Switch +5 - High Channel FET (main PWM) +6 - Voltage Divider (300K:100K Ohms) +7 - Boost chip enable +8 - GND + +ATTINY1616 Mapping: +2 - PA5 : (no connect) +3 - PB5 : TCA0 - WO2 Alternate MUX +4 - PB3 : (switch) +5 - PB0 : TCA0 - WO0 +6 - PB4 : ADC0 - AIN9 +7 - PA1 : (boost enable) + +*/ + + +#define LAYOUT_DEFINED + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1616 +#include <avr/io.h> + +#ifndef SWITCH_PIN +#define SWITCH_PIN 3 +#define SWITCH_PORT VPORTB.IN +#define SWITCH_ISC_REG PORTB.PIN3CTRL +#define SWITCH_VECT PORTB_PORT_vect +#define SWITCH_INTFLG VPORTB.INTFLAGS +#endif + +#define PWM_CHANNELS 2 + +// Small channel +#ifndef PWM1_PIN +#define PWM1_PIN PB5 +#define PWM1_LVL TCA0.SINGLE.CMP2 // PB5 is Alternate MUX for TCA Compare 2 +#endif + +// Big channel +#ifndef PWM2_PIN +#define PWM2_PIN PB0 +#define PWM2_LVL TCA0.SINGLE.CMP0 // PB0 is TCA Compare 0 +#endif + +#define LED_ENABLE_PIN PIN1_bp +#define LED_ENABLE_PORT PORTA_OUT + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define DUAL_VOLTAGE_FLOOR 20 // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_LOW_LOW 07 // the lower voltage range's danger zone 0.7 volts +#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN9_gc // which ADC channel to read + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// Resistors are 300,000 and 100,000 +#ifndef ADC_44 +#define ADC_44 1023 // raw value at 4.40V +#endif +#ifndef ADC_22 +#define ADC_22 512 // raw value at 2.20V +#endif + + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + + // set up the system clock to run at 5 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm ); + + VPORTA.DIR = PIN1_bm; // Boost enable pin + VPORTB.DIR = PIN0_bm | PIN5_bm; // PWM pins as output + //VPORTC.DIR = ...; + + // enable pullups on the input pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // Boost enable pin + 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; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // Big PWM channel + PORTB.PIN1CTRL = PORT_PULLUPEN_bm; + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // Switch + //PORTB.PIN4CTRL = PORT_PULLUPEN_bm; // Voltage divider + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Small PWM channel + + //PORTC.PIN0CTRL = PORT_PULLUPEN_bm; connected to the ADC via airwire + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // TODO: add references to MCU documentation + PORTMUX.CTRLC = PORTMUX_TCA02_ALTERNATE_gc; // Use alternate pin for TCA0:WO2 + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP2EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + TCA0.SINGLE.PER = 255; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + + +#endif diff --git a/hwdef-gchart-fet1-t1616.h b/hwdef-gchart-fet1-t1616.h new file mode 100644 index 0000000..365ecd7 --- /dev/null +++ b/hwdef-gchart-fet1-t1616.h @@ -0,0 +1,103 @@ +#ifndef HWDEF_GCH_FET1_T1616_H +#define HWDEF_GCH_FET1_T1616_H + +/* gChart's custom FET+1 driver layout + +PB0 - PWM for FET (TCA - WO0) +PB1 - PWM for 7135 (TCA - WO1) +PB2 - Switch pin, internal pullup +PB3 - Aux LED with 4700 Ohm series resistor +Read voltage from VCC pin, has diode with ~0.4v drop + +*/ + + +#define LAYOUT_DEFINED + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1616 +#include <avr/io.h> + +#define PWM_CHANNELS 2 + +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN2_bp +#define SWITCH_PORT VPORTB.IN +#define SWITCH_ISC_REG PORTB.PIN2CTRL +#define SWITCH_VECT PORTB_PORT_vect +#define SWITCH_INTFLG VPORTB.INTFLAGS +#endif + + +// 7135 channel +#ifndef PWM1_PIN +#define PWM1_PIN PB1 // +#define PWM1_LVL TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 +#endif + +// FET channel +#ifndef PWM2_PIN +#define PWM2_PIN PB0 // +#define PWM2_LVL TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 +#endif + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 8 // 4 = add 0.20V +#endif + + +// lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PIN3_bp +#define AUXLED_PORT PORTB +#endif + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + + // set up the system clock to run at 5 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = 0b00000010; + VPORTB.DIR = PIN0_bm | PIN1_bm | PIN3_bm; + //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; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // switch + //PORTB.PIN3CTRL = PORT_PULLUPEN_bm; // Aux LED + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + PORTB.PIN5CTRL = PORT_PULLUPEN_bm; + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // TODO: add references to MCU documentation + // TODO: measure 5 MHz fast PWM vs 10 MHz phase-correct, to see if it + // still has issues at 0/255 and 255/255 like older models did + // (and maybe switch to phase-correct@10MHz) + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + TCA0.SINGLE.PER = 255; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + + +#endif diff --git a/spaghetti-monster/anduril/BRANDS b/spaghetti-monster/anduril/BRANDS index b74ddab..4e73002 100644 --- a/spaghetti-monster/anduril/BRANDS +++ b/spaghetti-monster/anduril/BRANDS @@ -7,3 +7,4 @@ Lumintop 0300 - 0399 Fireflies 0400 - 0499 Mateminco 0500 - 0599 Sofirn 0600 - 0699 +gChart 1600 - 1699 diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS index 52fa200..13ce2e4 100644 --- a/spaghetti-monster/anduril/MODELS +++ b/spaghetti-monster/anduril/MODELS @@ -37,6 +37,11 @@ Model numbers: 0521 mateminco-mf01-mini 0611 blf-q8 0612 sofirn-sp36 +0613 blf-q8-t1616 +0614 sofirn-sp36-t1616 0621 blf-lantern +0622 blf-lantern-t1616 +0631 sofirn-sp10s +1618 gchart-fet1-t1616 Duplicates: Missing: diff --git a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h new file mode 100644 index 0000000..d602641 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h @@ -0,0 +1,90 @@ +// BLF Lantern config options for Anduril using the Attiny1616 +#define MODEL_NUMBER "0622" +/* BLF Lantern pinout + * PB0 is 5000K channel + * PB1 is 3000K channel + */ + +// basically the same as a Q8... sort of +#include "hwdef-BLF_Q8-T1616.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 +// enable blinking indicator LED while off +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s +#define USE_FANCIER_BLINKING_INDICATOR +// off mode: high (2) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) + +// the lantern has two PWM channels, but they drive different sets of emitters +// (one channel for warm emitters, one channel for cold) +// so enable a special ramping mode which changes tint instead of brightness +#define USE_TINT_RAMPING +// how much to increase total brightness at middle tint +// (0 = 100% brightness, 64 = 200% brightness) +//#define TINT_RAMPING_CORRECTION 26 // prototype, 140% +#define TINT_RAMPING_CORRECTION 10 // production model, 115% + +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif + +// level_calc.py 1 150 7135 1 30 800 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 + +// the default of 26 looks a bit flat, so increase it +#define CANDLE_AMPLITUDE 40 + +// override default ramp style +#undef RAMP_STYLE +#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped +// set floor and ceiling as far apart as possible +// because this lantern isn't overpowered +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 5 + +// LT1 can handle heat well, so don't limit simple mode +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL +#define SIMPLE_UI_STEPS RAMP_DISCRETE_STEPS + +#define USE_SOS_MODE +#define USE_SOS_MODE_IN_BLINKY_GROUP + +// the sensor (attiny85) is nowhere near the emitters +// so thermal regulation can't work +#ifdef USE_THERMAL_REGULATION +#undef USE_THERMAL_REGULATION +#endif + +// also, the set_level_gradually() thing isn't compatible with tint ramping +// (but unsetting it here doesn't actually do anything, because the thermal +// regulation define enables it later... so this is mostly just a note to +// make this compatibility issue explicit) +#ifdef USE_SET_LEVEL_GRADUALLY +#undef USE_SET_LEVEL_GRADUALLY +#endif + +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_FLOOR +#undef BLINK_AT_RAMP_FLOOR +#endif +// except the top... blink at the top +#ifndef BLINK_AT_RAMP_CEIL +#define BLINK_AT_RAMP_CEIL +#endif diff --git a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h new file mode 100644 index 0000000..73702a9 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h @@ -0,0 +1,43 @@ +// BLF Q8 config options for Anduril using the Attiny1616 +#define MODEL_NUMBER "0613" +#include "hwdef-BLF_Q8-T1616.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 +// enable blinking indicator LED while off +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s +#define USE_FANCIER_BLINKING_INDICATOR +// off mode: high (2) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) + +// copied from Emisar D4 ramp +// ../../bin/level_calc.py 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 + +#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 + +// safe limit ~50% power +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL +#define SIMPLE_UI_STEPS 5 + +// stop panicking at ~75% power or ~3000 lm, this light has high thermal mass +#define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high + diff --git a/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h b/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h new file mode 100644 index 0000000..101f25a --- /dev/null +++ b/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h @@ -0,0 +1,39 @@ +// gChart's custom FET+1 driver config options for Anduril +#define MODEL_NUMBER "1618" // Golden Ratio... because I can +#include "hwdef-gchart-fet1-t1616.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 +// enable blinking indicator LED while off +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s +#define USE_FANCIER_BLINKING_INDICATOR +// off mode: low (1) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) + +#undef BLINK_AT_RAMP_MIDDLE + +// Mostly borrowed from the D4 for now +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 6 + +#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 105 + +// enable 2 click turbo +#define USE_2C_MAX_TURBO diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp10s.h b/spaghetti-monster/anduril/cfg-sofirn-sp10s.h new file mode 100644 index 0000000..99ed17d --- /dev/null +++ b/spaghetti-monster/anduril/cfg-sofirn-sp10s.h @@ -0,0 +1,28 @@ +// gChart's custom SP10S driver config options for Anduril +#define MODEL_NUMBER "0631" +#include "hwdef-Sofirn_SP10S.h" +// ATTINY: 1616 + +#undef BLINK_AT_RAMP_MIDDLE + +#define USE_DYNAMIC_UNDERCLOCKING + +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 20,30,41,54,69,87,106,128,152,179,209,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,10,10,11,12,12,13,14,14,15,16,17,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,38,39,41,42,43,45,46,48,50,51,53,55,56,58,60,62,64,66,68,70,72,74,76,78,80,83,85,87,90,92,94,97,99,102,105,107,110,113,116,119,121,124,127,130,133,137,140,143,146,150,153,156,160,164,167,171,174,178,182,186,190,194,198,202,206,210,214,219,223,227,232,236,241,246,250,255 + +#define MAX_1x7135 13 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 6 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 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 105 + +// enable 2 click turbo +#define USE_2C_MAX_TURBO diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h b/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h new file mode 100644 index 0000000..ce1c04a --- /dev/null +++ b/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h @@ -0,0 +1,33 @@ +// Sofirn SP36 (small Q8) config options for Anduril using the Attiny1616 +// same as the BLF Q8, mostly +#include "cfg-blf-q8-t1616.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0614" +// ATTINY: 1616 + +// voltage readings were a little high with the Q8 value +#undef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V, not 0.35V + +// the high button LED mode on this light uses too much power +// off mode: low (1) +// lockout: blinking (3) +#ifdef INDICATOR_LED_DEFAULT_MODE +#undef INDICATOR_LED_DEFAULT_MODE +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) +#endif + +// don't blink during the ramp; the button LED brightness is sufficient +// to indicate which power channel(s) are being used +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#endif + +// stop panicking at ~60% power or ~3000 lm +#ifdef THERM_FASTER_LEVEL +#undef THERM_FASTER_LEVEL +#endif +#define THERM_FASTER_LEVEL 130 diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 71ecf65..975d12e 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -37,6 +37,9 @@ static inline void set_admux_therm() { #elif (ATTINY == 841) // FIXME: not tested ADMUXA = ADMUXA_THERM; ADMUXB = ADMUXB_THERM; + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature + ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Internal ADC reference #else #error Unrecognized MCU type #endif @@ -66,6 +69,15 @@ inline void set_admux_voltage() { ADMUXA = ADMUXA_VCC; ADMUXB = ADMUXB_VCC; #endif + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + #ifdef USE_VOLTAGE_DIVIDER // 1.1V / ADC input pin + // verify that this is correct!!! untested + ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin + ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Use internal ADC reference + #else // VCC / 1.1V reference + ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference + ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference + #endif #else #error Unrecognized MCU type #endif @@ -77,6 +89,9 @@ inline void set_admux_voltage() { inline void ADC_start_measurement() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 841) || (ATTINY == 1634) ADCSRA |= (1 << ADSC) | (1 << ADIE); + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt + ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions #else #error unrecognized MCU type #endif @@ -108,13 +123,22 @@ inline void ADC_on() // enable, start, auto-retrigger, prescale ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; //ADCSRA |= (1 << ADSC); // start measuring + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + set_admux_voltage(); + VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V + ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm; // Enabled, free-running (aka, auto-retrigger) + ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions #else #error Unrecognized MCU type #endif } inline void ADC_off() { - ADCSRA &= ~(1<<ADEN); //ADC off + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC + #else + ADCSRA &= ~(1<<ADEN); //ADC off + #endif } #ifdef USE_VOLTAGE_DIVIDER @@ -140,9 +164,16 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { #define ADC_CYCLES_PER_SECOND 2 #endif +#ifdef AVRXMEGA3 // ATTINY816, 817, etc +#define ADC_vect ADC0_RESRDY_vect +#endif // happens every time the ADC sampler finishes a measurement ISR(ADC_vect) { + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt + #endif + if (adc_sample_count) { uint16_t m; // latest measurement @@ -150,7 +181,23 @@ ISR(ADC_vect) { uint8_t channel = adc_channel; // update the latest value + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // Use the factory calibrated values in SIGROW.TEMPSENSE0 and SIGROW.TEMPSENSE1 + // to calculate a temperature reading in Kelvin, then left-align it. + if (channel == 1) { // thermal, convert ADC reading to left-aligned Kelvin + int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed value from signature row + uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // Read unsigned value from signature row + uint32_t temp = ADC0.RES - sigrow_offset; + temp *= sigrow_gain; // Result might overflow 16 bit variable (10bit+8bit) + temp += 0x80; // Add 1/2 to get correct rounding on division below + temp >>= 8; // Divide result to get Kelvin + m = (temp << 6); // left align it + } + else { m = (ADC0.RES << 6); } // voltage, force left-alignment + + #else m = ADC; + #endif adc_raw[channel] = m; // lowpass the value @@ -181,8 +228,12 @@ void adc_deferred() { // real-world entropy makes this a true random, not pseudo // Why here instead of the ISR? Because it makes the time-critical ISR // code a few cycles faster and we don't need crypto-grade randomness. + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + pseudo_rand_seed += ADC0.RESL; // right aligned, not left... so should be equivalent? + #else pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2); #endif + #endif // the ADC triggers repeatedly when it's on, but we only need to run the // voltage and temperature regulation stuff once in a while...so disable @@ -290,7 +341,11 @@ static inline void ADC_voltage_handler() { if (lvp_timer) { lvp_timer --; } else { // it has been long enough since the last warning + #ifdef DUAL_VOLTAGE_FLOOR + if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { + #else if (voltage < VOLTAGE_LOW) { + #endif // send out a warning emit(EV_voltage_low, 0); // reset rate-limit counter diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index b96bce8..f3c319c 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -23,6 +23,9 @@ #include "fsm-main.h" #if PWM_CHANNELS == 4 +#ifdef AVRXMEGA3 // ATTINY816, 817, etc +#error 4-channel PWM not currently set up for the AVR 1-Series +#endif // 4th PWM channel requires manually turning the pin on/off via interrupt :( ISR(TIMER1_OVF_vect) { //bitClear(PORTB, 3); @@ -68,7 +71,7 @@ static inline void hw_setup() { PORTB = (1 << SWITCH_PIN); // e-switch is the only input PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin } -#elif (ATTINY == 1634) +#elif (ATTINY == 1634) || defined(AVRXMEGA3) // ATTINY816, 817, etc static inline void hw_setup() { // this gets tricky with so many pins... // ... so punt it to the hwdef file @@ -82,7 +85,11 @@ static inline void hw_setup() { //#ifdef USE_REBOOT static inline void prevent_reboot_loop() { // prevent WDT from rebooting MCU again + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset status flag + #else MCUSR &= ~(1<<WDRF); // reset status flag + #endif wdt_disable(); } //#endif diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 15cb659..c2c1afe 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -110,6 +110,37 @@ uint8_t blink_num(uint8_t num) { #ifdef USE_INDICATOR_LED void indicator_led(uint8_t lvl) { switch (lvl) { + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + + case 0: // indicator off + AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output + AUXLED_PORT.OUTCLR = (1 << AUXLED_PIN); // set output low + #ifdef AUXLED2_PIN // second LED mirrors the first + AUXLED2_PORT.DIRSET = (1 << AUXLED2_PIN); // set as output + AUXLED2_PORT.OUTCLR = (1 << AUXLED2_PIN); // set output low + #endif + break; + case 1: // indicator low + AUXLED_PORT.DIRCLR = (1 << AUXLED_PIN); // set as input + // this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm; + *((uint8_t *)&AUXLED_PORT + 0x10 + AUXLED_PIN) = PORT_PULLUPEN_bm; // enable internal pull-up + #ifdef AUXLED2_PIN // second LED mirrors the first + AUXLED2_PORT.DIRCLR = (1 << AUXLED2_PIN); // set as input + // this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm; + *((uint8_t *)&AUXLED2_PORT + 0x10 + AUXLED2_PIN) = PORT_PULLUPEN_bm; // enable internal pull-up + #endif + break; + default: // indicator high + AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output + AUXLED_PORT.OUTSET = (1 << AUXLED_PIN); // set as high + #ifdef AUXLED2_PIN // second LED mirrors the first + AUXLED2_PORT.DIRSET = (1 << AUXLED2_PIN); // set as output + AUXLED2_PORT.OUTSET = (1 << AUXLED2_PIN); // set as high + #endif + break; + + #else + case 0: // indicator off DDRB &= 0xff ^ (1 << AUXLED_PIN); PORTB &= 0xff ^ (1 << AUXLED_PIN); @@ -134,6 +165,8 @@ void indicator_led(uint8_t lvl) { PORTB |= (1 << AUXLED2_PIN); #endif break; + + #endif // MCU type } } @@ -150,6 +183,25 @@ void indicator_led_auto() { // TODO: Refactor this and RGB LED function to merge code and save space void button_led_set(uint8_t lvl) { switch (lvl) { + + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + + case 0: // LED off + BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output + BUTTON_LED_PORT.OUTCLR = (1 << BUTTON_LED_PIN); // set output low + break; + case 1: // LED low + BUTTON_LED_PORT.DIRCLR = (1 << BUTTON_LED_PIN); // set as input + // this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm; + *((uint8_t *)&BUTTON_LED_PORT + 0x10 + BUTTON_LED_PIN) = PORT_PULLUPEN_bm; // enable internal pull-up + break; + default: // LED high + BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output + BUTTON_LED_PORT.OUTSET = (1 << BUTTON_LED_PIN); // set as high + break; + + #else + case 0: // LED off BUTTON_LED_DDR &= 0xff ^ (1 << BUTTON_LED_PIN); BUTTON_LED_PUE &= 0xff ^ (1 << BUTTON_LED_PIN); @@ -165,6 +217,8 @@ void button_led_set(uint8_t lvl) { BUTTON_LED_PUE |= (1 << BUTTON_LED_PIN); BUTTON_LED_PORT |= (1 << BUTTON_LED_PIN); break; + + #endif // MCU type } } #endif @@ -177,6 +231,25 @@ void rgb_led_set(uint8_t value) { uint8_t lvl = (value >> (i<<1)) & 0x03; uint8_t pin = pins[i]; switch (lvl) { + + #ifdef AVRXMEGA3 // ATTINY816, 817, etc + + case 0: // LED off + AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output + AUXLED_RGB_PORT.OUTCLR = (1 << pin); // set output low + break; + case 1: // LED low + AUXLED_RGB_PORT.DIRCLR = (1 << pin); // set as input + // this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm; + *((uint8_t *)&AUXLED_RGB_PORT + 0x10 + pin) = PORT_PULLUPEN_bm; // enable internal pull-up + break; + default: // LED high + AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output + AUXLED_RGB_PORT.OUTSET = (1 << pin); // set as high + break; + + #else + case 0: // LED off AUXLED_RGB_DDR &= 0xff ^ (1 << pin); AUXLED_RGB_PUE &= 0xff ^ (1 << pin); @@ -192,6 +265,8 @@ void rgb_led_set(uint8_t value) { AUXLED_RGB_PUE |= (1 << pin); AUXLED_RGB_PORT |= (1 << pin); break; + + #endif // MCU type } } } @@ -217,6 +292,9 @@ void reboot() { // reset (WDIF + WDE), no WDIE, fastest (16ms) timing (0000) // (DS section 8.5.2 and table 8-4) WDTCSR = 0b10001000; + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + CCP = CCP_IOREG_gc; // temporarily disable change protection + WDT.CTRLA = WDT_PERIOD_8CLK_gc; // Enable, timeout 8ms #endif sei(); wdt_reset(); diff --git a/spaghetti-monster/fsm-pcint.c b/spaghetti-monster/fsm-pcint.c index 24cc82c..4ada5b8 100644 --- a/spaghetti-monster/fsm-pcint.c +++ b/spaghetti-monster/fsm-pcint.c @@ -46,6 +46,8 @@ inline void PCINT_on() { #else GIMSK |= (1 << SWITCH_PCIE); #endif + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc) + SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc; #else #error Unrecognized MCU type #endif @@ -58,6 +60,8 @@ inline void PCINT_off() { #elif (ATTINY == 1634) // disable all pin-change interrupts GIMSK &= ~(1 << SWITCH_PCIE); + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc) + SWITCH_ISC_REG &= ~(PORT_ISC_gm); #else #error Unrecognized MCU type #endif @@ -65,19 +69,20 @@ inline void PCINT_off() { //void button_change_interrupt() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) -//EMPTY_INTERRUPT(PCINT0_vect); -#ifdef PCINT_vect -ISR(PCINT_vect) { -#else -ISR(PCINT0_vect) { -#endif - irq_pcint = 1; -} + #ifdef PCINT_vect + ISR(PCINT_vect) { + #else + ISR(PCINT0_vect) { + #endif +#elif defined(AVRXMEGA3) // ATTINY816, 817, etc) + ISR(SWITCH_VECT) { + // Write a '1' to clear the interrupt flag + SWITCH_INTFLG |= (1 << SWITCH_PIN); #else #error Unrecognized MCU type #endif -/* -ISR(PCINT0_vect) { + + irq_pcint = 1; // let deferred code know an interrupt happened //DEBUG_FLASH; @@ -86,9 +91,7 @@ ISR(PCINT0_vect) { // noisy / bouncy switch (so the content of this function has been // moved to a separate function, called from WDT only) // PCINT_inner(button_is_pressed()); - } -*/ // should only be called from PCINT and/or WDT // (is a separate function to reduce code duplication) diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 9e8d9af..ea2efac 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -23,6 +23,10 @@ #include <avr/interrupt.h> #include <avr/wdt.h> +// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT +// is not used for time-based interrupts. A new peripheral, the +// Periodic Interrupt Timer ("PIT") is used for this purpose. + void WDT_on() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) @@ -35,6 +39,10 @@ void WDT_on() #elif (ATTINY == 1634) wdt_reset(); // Reset the WDT WDTCSR = (1<<WDIE); // Enable interrupt every 16ms + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; // Period = 16ms, enable the PI Timer #else #error Unrecognized MCU type #endif @@ -53,6 +61,10 @@ inline void WDT_slow() #elif (ATTINY == 1634) wdt_reset(); // Reset the WDT WDTCSR = (1<<WDIE) | STANDBY_TICK_SPEED; + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; // Set period, enable the PI Timer #else #error Unrecognized MCU type #endif @@ -75,13 +87,21 @@ inline void WDT_off() CCP = 0xD8; // enable config changes WDTCSR = 0; // disable and clear all WDT settings sei(); + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = 0; // Disable the PI Timer #else #error Unrecognized MCU type #endif } // clock tick -- this runs every 16ms (62.5 fps) +#ifdef AVRXMEGA3 // ATTINY816, 817, etc +ISR(RTC_PIT_vect) { + RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag +#else ISR(WDT_vect) { +#endif irq_wdt = 1; // WDT event happened } diff --git a/tk-attiny.h b/tk-attiny.h index 49f1195..ae70afd 100644 --- a/tk-attiny.h +++ b/tk-attiny.h @@ -71,6 +71,12 @@ #define DELAY_ZERO_TIME 1020 //#define SWITCH_PORT PINA // set this in hwdef //#define VOLTAGE_ADC_DIDR DIDR0 // set this in hwdef +#elif (ATTINY == 412) || (ATTINY == 416) || (ATTINY == 417) || (ATTINY == 816) || (ATTINY == 817) || (ATTINY == 1616) || (ATTINY == 1617) || (ATTINY == 3216) || (ATTINY == 3217) + #define AVRXMEGA3 + #define F_CPU 5000000UL + #define BOGOMIPS (F_CPU/4000) + #define EEPSIZE 128 + #define DELAY_ZERO_TIME 1020 #else #error Hey, you need to define ATTINY. #endif @@ -138,6 +144,29 @@ clock_div_256 = 8 } clock_div_t; +#elif defined(AVRXMEGA3) // ATTINY816, 817, etc + // this should work, but needs further validation + inline void clock_prescale_set(uint8_t n) { + cli(); + CCP = CCP_IOREG_gc; // temporarily disable clock change protection + CLKCTRL.MCLKCTRLB = n; // Set the prescaler + while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {} // wait for clock change to finish + sei(); + } + typedef enum + { + // Actual clock is 20 MHz, but assume that 5 MHz is the top speed and work from there + // TODO: measure PWM speed and power use at 1.25/2.5/5/10 MHz, to determine which speeds are optimal + clock_div_1 = (CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm), // 5 MHz + clock_div_2 = (CLKCTRL_PDIV_8X_gc | CLKCTRL_PEN_bm), // 2.5 MHz + clock_div_4 = (CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm), // 1.25 MHz + clock_div_8 = (CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm), // 625 kHz + clock_div_16 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz, max without changing to the 32 kHz ULP + clock_div_32 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_64 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_128 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_256 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm) // 312 kHz + } clock_div_t; #else #error Unable to define MCU macros. #endif |
