3
* ====================================================================
4
* Ramping UI for nanjg105c and a clicky switch by gChart (Gabriel Hart)
6
* This firmware has its roots loosely based on "Biscotti" by ToyKeeper
8
* ====================================================================
10
* 12 or more fast presses > Configuration mode
14
* 2: Stop-at-the-top toggle (without any user interaction, stops itself at turbo)
15
* 3: Turbo Timer Toggle (turbo steps down to 50%)
16
* 4: Reset to default configuration
18
* ====================================================================
20
* "Biscotti" firmware (attiny13a version of "Bistro")
21
* This code runs on a single-channel driver with attiny13a MCU.
22
* It is intended specifically for nanjg 105d drivers from Convoy.
24
* Copyright (C) 2015 Selene Scriven
26
* This program is free software: you can redistribute it and/or modify
27
* it under the terms of the GNU General Public License as published by
28
* the Free Software Foundation, either version 3 of the License, or
29
* (at your option) any later version.
31
* This program is distributed in the hope that it will be useful,
32
* but WITHOUT ANY WARRANTY; without even the implied warranty of
33
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
* GNU General Public License for more details.
36
* You should have received a copy of the GNU General Public License
37
* along with this program. If not, see <http://www.gnu.org/licenses/>.
45
* GND -|4 5|- PWM (Nx7135)
49
* I use these fuse settings on attiny13
55
* To find out what values to use, flash the driver with battcheck.hex
56
* and hook the light up to each voltage you need a value for. This is
57
* much more reliable than attempting to calculate the values from a
58
* theoretical formula.
60
* Same for off-time capacitor values. Measure, don't guess.
62
// Choose your MCU here, or in the build script
64
#define NANJG_LAYOUT // specify an I/O pin layout
65
// Also, assign I/O pins in this file:
66
#include "../tk-attiny.h"
68
#define DEFAULTS 0b00000100 // No memory, doesn't stop at the top, turbo timer is enabled
70
#define FAST 0xA3 // fast PWM both channels
71
#define PHASE 0xA1 // phase-correct PWM both channels
72
#define VOLTAGE_MON // Comment out to disable LVP
74
#define BLINK_BRIGHTNESS 40 // output to use for blinks in config mode
75
#define BLINK_SPEED 750 // ms per normal-speed blink
77
#define USE_BATTCHECK // Enable battery check mode
78
#define BATTCHECK_8bars // up to 8 blinks
80
#define TURBO_MINUTES 5 // when turbo timer is enabled, how long before stepping down
81
#define TICKS_PER_MINUTE 120 // used for Turbo Timer timing
82
#define TURBO_LOWER 128 // the PWM level to use when stepping down
83
#define TURBO_THRESHOLD sizeof(ramp_values)-5 // Min output level that we consider to be turbo?
85
#define RAMP_TIME 5 // number of seconds to go from min brightness to max brightness
87
#define RAMP_SIZE sizeof(ramp_values)
88
//#define RAMP_VALUES 1,1,1,1,1,2,2,2,2,3,3,4,5,5,6,7,8,9,10,11,13,14,16,18,20,22,24,26,29,32,34,38,41,44,48,51,55,60,64,68,73,78,84,89,95,101,107,113,120,127,134,142,150,158,166,175,184,193,202,212,222,233,244,255
89
#define RAMP_VALUES 5,5,5,5,5,6,6,6,6,7,7,8,8,9,10,11,12,13,14,15,17,18,20,22,23,25,28,30,32,35,38,41,44,47,51,55,59,63,67,71,76,81,86,92,97,103,109,116,122,129,136,144,151,159,167,176,185,194,203,213,223,233,244,255
91
// Calibrate voltage and OTC in this file:
92
#include "../tk-calibration.h"
95
* =========================================================================
98
// Ignore a spurious warning, we did the cast on purpose
99
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
101
#include <avr/pgmspace.h>
102
#include <avr/interrupt.h>
103
#include <avr/eeprom.h>
104
#include <avr/sleep.h>
107
#define OWN_DELAY // Don't use stock delay functions.
108
#define USE_DELAY_S // Also use _delay_s(), not just _delay_ms()
109
#include "../tk-delay.h"
111
#include "../tk-voltage.h"
113
register uint8_t options asm("r6");
114
register uint8_t eepos asm("r7");
116
#define NUM_FP_BYTES 3
117
uint8_t fast_presses[NUM_FP_BYTES] __attribute__ ((section (".noinit")));
120
#define RAMPING_DOWN 1
121
uint8_t ramp_direction __attribute__ ((section (".noinit")));
122
uint8_t ramp_stopped __attribute__ ((section (".noinit")));
123
uint8_t output __attribute__ ((section (".noinit")));
124
uint8_t output_in_eeprom;
126
PROGMEM const uint8_t ramp_values[] = { RAMP_VALUES };
128
inline uint8_t memory_is_enabled() { return (options ) & 0b00000001; }
129
inline uint8_t stop_at_the_top() { return (options >> 1) & 0b00000001; }
130
inline uint8_t ttimer_is_enabled() { return (options >> 2) & 0b00000001; }
132
void save_output() { // save the current output level (with wear leveling)
133
uint8_t oldpos=eepos;
134
eepos = (eepos+1) & ((EEPSIZE/2)-1); // wear leveling, use next cell
135
eeprom_write_byte((uint8_t *)(eepos), output); // save current state
136
eeprom_write_byte((uint8_t *)(oldpos), 0xff); // erase old state
139
#define OPT_options (EEPSIZE-1)
140
void save_state() { // central method for writing complete state
142
eeprom_write_byte((uint8_t *)OPT_options, options);
145
inline void reset_state() {
146
output_in_eeprom = 1;
147
options = DEFAULTS; // 3 brightness levels with memory
151
inline void restore_state() {
155
// find the output level data
156
for(i=0; i<(EEPSIZE-6); i++) {
157
eep = eeprom_read_byte((const uint8_t *)i);
160
output_in_eeprom = eep;
165
// if no output level was found, assume this is the first boot
171
// load other config values
172
options = eeprom_read_byte((uint8_t *)OPT_options);
175
void set_pwm(uint8_t pwm) {
181
void set_level(uint8_t level) {
182
if (level == 0) { set_pwm(0); }
183
else { set_pwm( pgm_read_byte(ramp_values + level - 1) ); }
186
void blink(uint8_t val, uint16_t speed)
190
set_pwm(BLINK_BRIGHTNESS);
198
void toggle_options(uint8_t value, uint8_t num) {
199
blink(num, BLINK_SPEED/4); // indicate which option number this is
200
uint8_t temp = options;
203
blink(32, 500/32); // "buzz" for a while to indicate the active toggle window
205
// if the user didn't click, reset the value and return
211
inline uint8_t we_did_a_fast_press() {
212
uint8_t i = NUM_FP_BYTES-1;
213
while (i && (fast_presses[i] == fast_presses[i-1] )){ --i; }
216
inline void increment_fast_presses() {
218
for(i=0; i<NUM_FP_BYTES; i++) { fast_presses[i]++; }
221
void reset_fast_presses() {
223
for(i=0; i<NUM_FP_BYTES; i++) { fast_presses[i] = 0; }
229
DDRB |= (1 << PWM_PIN); // Set PWM pin to output, enable main channel
231
restore_state(); // Read config values and saved state
233
if ( we_did_a_fast_press() ) {
234
increment_fast_presses();
235
ramp_stopped = !ramp_stopped;
237
if(fast_presses[0] == 2) { // jump to turbo on a double-tap from anywhere
242
if(ramp_stopped) { save_output(); }
244
} else { // Long press
245
reset_fast_presses();
246
ramp_direction = RAMPING_UP;
247
if( memory_is_enabled() ) {
248
output = output_in_eeprom;
266
uint8_t lowbatt_cnt = 0;
268
ADCSRA |= (1 << ADSC); // Make sure voltage reading is running for later
272
if (fast_presses[0] >= 12) { // Config mode if 12 or more fast presses
273
_delay_s(); // wait for user to stop fast-pressing button
274
reset_fast_presses(); // exit this mode after one use
276
toggle_options((options ^ 0b00000001), 1); // memory
277
toggle_options((options ^ 0b00000010), 2); // stop at the top
278
toggle_options((options ^ 0b00000100), 3); // turbo timer
279
toggle_options(DEFAULTS, 4); // reset to defaults
281
else if (fast_presses[0] == 3) {
282
//else if (output == BATT_CHECK) {
283
blink(battcheck(), BLINK_SPEED/4);
284
_delay_s(); _delay_s();
285
// shouldn't need to worry about resetting fast_presses here, but may need to later
287
else if ( !ramp_stopped ) {
289
if(output == 1 || output == RAMP_SIZE) { _delay_s(); } // pause for a second at the lowest & highest levels
291
if( (ramp_direction == RAMPING_DOWN && output == 1) || (ramp_direction == RAMPING_UP && output == RAMP_SIZE) ) {
292
ramp_direction = !ramp_direction;
295
if( output == RAMP_SIZE && stop_at_the_top() ) {
299
if(ramp_direction == RAMPING_UP) { output++; }
302
_delay_ms(RAMP_TIME*1000/RAMP_SIZE);
304
// if we've been ramping around for more than half a second, reset the fast_presses
305
ticks = ticks + (RAMP_TIME*1000/RAMP_SIZE);
308
reset_fast_presses();
313
if ((output >= TURBO_THRESHOLD) && ( ttimer_is_enabled() ) && (ticks > (TURBO_MINUTES * TICKS_PER_MINUTE))) {
314
set_pwm(TURBO_LOWER);
317
ticks ++; // count ticks for turbo timer
321
_delay_ms(500); // Otherwise, just sleep.
322
reset_fast_presses();
325
if (ADCSRA & (1 << ADIF)) { // if a voltage reading is ready
326
voltage = ADCH; // get the waiting value
328
if (voltage < ADC_LOW) { // See if voltage is lower than what we were looking for
334
if (lowbatt_cnt >= 8) { // See if it's been low for a while, and maybe step down
335
if (output > 1) { // not yet at the lowest level
336
output = (output>>1); // divide output in half using bitwise operators
337
} else { // Can't go any lower
338
set_pwm(0); // Turn off the light
339
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Power down as many components as possible
344
_delay_s(); // Wait before lowering the level again
347
ADCSRA |= (1 << ADSC); // Make sure conversion is running for next time through
349
#endif // ifdef VOLTAGE_MON