2
* This is a copy of JonnyC/STAR_on-time_memory/STAR_1.1.c , modified only
3
* slightly to shave off a few bytes. It has moon mode hard-coded as
4
* "enabled" and turbo step-down disabled. This is because the original
5
* firmware was compiling to a file bigger than 1024 bytes, and I wanted to
6
* have something I could flash as a test. This provided my first working
7
* self-flashed firmware, and is intended to help others to test their
8
* toolchain and general flashing setup. Treat it like "hello world".
10
* Original author: JonnyC
11
* Size reduced by: ToyKeeper / Selene Scriven
16
* Star 4 -| |- Voltage ADC
21
* CPU speed is 4.8Mhz without the 8x divider when low fuse is 0x75
23
* define F_CPU 4800000 CPU: 4.8MHz PWM: 9.4kHz ####### use low fuse: 0x75 #######
24
* /8 PWM: 1.176kHz ####### use low fuse: 0x65 #######
25
* define F_CPU 9600000 CPU: 9.6MHz PWM: 19kHz ####### use low fuse: 0x7a #######
26
* /8 PWM: 2.4kHz ####### use low fuse: 0x6a #######
28
* Above PWM speeds are for phase-correct PWM. This program uses Fast-PWM, which when the CPU is 4.8MHz will be 18.75 kHz
31
* I use these fuse settings
36
* Star 2 = Moon if connected
37
* Star 3 = H-L if connected, L-H if not
38
* Star 4 = Memory if not connected
41
* Resistor values for voltage divider (reference BLF-VLD README for more info)
42
* Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
46
* Vd (~.25 v drop from protection diode)
48
* 1912 (R1 19,100 ohms)
52
* 4701 (R2 4,700 ohms)
56
* ADC = ((V_bat - V_diode) * R2 * 255) / ((R1 + R2 ) * V_ref)
57
* 125 = ((3.0 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
58
* 121 = ((2.9 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
60
* Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
63
* To find out what value to use, plug in the target voltage (V) to this equation
64
* value = (V * 4700 * 255) / (23800 * 1.1)
67
#define F_CPU 4800000UL
70
* =========================================================================
71
* Settings to modify per driver
74
#define VOLTAGE_MON // Comment out to disable
76
#define MODE_MOON 8 // Can comment out to remove mode, but should be set through soldering stars
77
#define MODE_LOW 14 // Can comment out to remove mode
78
#define MODE_MED 39 // Can comment out to remove mode
79
#define MODE_HIGH_W_TURBO 110 // MODE_HIGH value when turbo is enabled
80
#define MODE_HIGH 120 // Can comment out to remove mode
81
//#define MODE_TURBO 255 // Can comment out to remove mode
82
#define TURBO_TIMEOUT 240 // How many WTD ticks before before dropping down (.5 sec each)
84
#define WDT_TIMEOUT 2 // Number of WTD ticks before mode is saved (.5 sec each)
86
#define ADC_LOW 130 // When do we start ramping
87
#define ADC_CRIT 120 // When do we shut the light off
90
* =========================================================================
95
#define MODE_HIGH MODE_HIGH_W_TURBO
98
//#include <avr/pgmspace.h>
100
#include <util/delay.h>
101
#include <avr/interrupt.h>
103
#include <avr/eeprom.h>
104
#include <avr/sleep.h>
105
//#include <avr/power.h>
107
#define STAR2_PIN PB0
108
#define STAR3_PIN PB4
109
#define STAR4_PIN PB3
111
#define VOLTAGE_PIN PB2
112
#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2
113
#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
114
#define ADC_PRSCL 0x06 // clk/64
116
#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1
127
// Modes (gets set when the light starts up based on stars)
128
static uint8_t modes[10]; // Don't need 10, but keeping it high enough to handle all
129
volatile uint8_t mode_idx = 0;
130
int mode_dir = 0; // 1 or -1. Determined when checking stars. Do we increase or decrease the idx when moving up to a higher mode.
131
uint8_t mode_cnt = 0;
133
uint8_t lowbatt_cnt = 0;
135
void store_mode_idx(uint8_t lvl) { //central method for writing (with wear leveling)
136
uint8_t oldpos=eepos;
137
eepos=(eepos+1)&31; //wear leveling, use next cell
138
// Write the current mode
139
EEARL=eepos; EEDR=lvl; EECR=32+4; EECR=32+4+2; //WRITE //32:write only (no erase) 4:enable 2:go
140
while(EECR & 2); //wait for completion
141
// Erase the last mode
142
EEARL=oldpos; EECR=16+4; EECR=16+4+2; //ERASE //16:erase only (no write) 4:enable 2:go
144
inline void read_mode_idx() {
145
eeprom_read_block(&eep, 0, 32);
146
while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
147
if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
151
inline void next_mode() {
152
if (mode_idx == 0 && mode_dir == -1) {
154
mode_idx = mode_cnt - 1;
156
mode_idx += mode_dir;
157
if (mode_idx > (mode_cnt - 1)) {
164
inline void WDT_on() {
165
// Setup watchdog timer to only interrupt, not reset, every 500ms.
166
cli(); // Disable interrupts
167
wdt_reset(); // Reset the WDT
168
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
169
WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
170
sei(); // Enable interrupts
173
inline void WDT_off()
175
cli(); // Disable interrupts
176
wdt_reset(); // Reset the WDT
177
MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
178
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
179
WDTCR = 0x00; // Disable WDT
180
sei(); // Enable interrupts
183
inline void ADC_on() {
184
ADMUX = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
185
DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption
186
ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
189
inline void ADC_off() {
190
ADCSRA &= ~(1<<7); //ADC off
194
uint8_t low_voltage(uint8_t voltage_val) {
196
ADCSRA |= (1 << ADSC);
197
// Wait for completion
198
while (ADCSRA & (1 << ADSC));
199
// See if voltage is lower than what we were looking for
200
if (ADCH < voltage_val) {
201
// See if it's been low for a while
202
if (++lowbatt_cnt > 8) {
214
static uint8_t ticks = 0;
215
if (ticks < 255) ticks++;
217
if (ticks == WDT_TIMEOUT) {
219
store_mode_idx(mode_idx);
221
// Reset the mode to the start for next time
222
store_mode_idx((mode_dir == 1) ? 0 : (mode_cnt - 1));
225
//} else if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
226
} else if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
227
// Turbo mode is always at end
228
PWM_LVL = modes[--mode_idx];
236
// All ports default to input, but turn pull-up resistors on for the stars (not the ADC input! Made that mistake already)
237
PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN) | (1 << STAR4_PIN);
239
// Set PWM pin to output
240
DDRB = (1 << PWM_PIN);
242
// Set timer to do PWM for correct output pin and set prescaler timing
243
TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
244
TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
246
// Turn features on or off as needed
252
ACSR |= (1<<7); //AC off
254
// Load up the modes based on stars
255
// Always load up the modes array in order of lowest to highest mode
256
// 0 being low for soldered, 1 for pulled-up for not soldered
259
/* if ((PINB & (1 << STAR2_PIN)) == 0) { */
260
modes[mode_cnt++] = MODE_MOON;
264
modes[mode_cnt++] = MODE_LOW;
267
modes[mode_cnt++] = MODE_MED;
270
modes[mode_cnt++] = MODE_HIGH;
273
modes[mode_cnt++] = MODE_TURBO;
276
if ((PINB & (1 << STAR3_PIN)) == 0) {
285
// Not soldered (1) should enable memory
286
//memory = ((PINB & (1 << STAR4_PIN)) > 0) ? 1 : 0;
289
// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
290
// Will allow us to go idle between WDT interrupts
291
set_sleep_mode(SLEEP_MODE_IDLE);
293
// Determine what mode we should fire up
294
// Read the last mode that was saved
297
// Indicates we did a short press last time, go to the next mode
298
// Remove short press indicator first
300
next_mode(); // Will handle wrap arounds
302
// Didn't have a short press, keep the same mode
304
// Store mode with short press indicator
305
store_mode_idx(mode_idx|0x10);
309
// Now just fire up the mode
310
PWM_LVL = modes[mode_idx];
316
if (low_voltage(ADC_LOW)) {
317
// We need to go to a lower level
318
if (mode_idx == 0 && PWM_LVL <= modes[mode_idx]) {
319
// Can't go any lower than the lowest mode
320
// Wait until we hit the critical level before flashing 10 times and turning off
321
while (!low_voltage(ADC_CRIT));
329
// Turn off the light
331
// Disable WDT so it doesn't wake us up
333
// Power down as many components as possible
334
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
337
// Flash 3 times before lowering
346
// Lower the mode by half, but don't go below lowest level
347
if ((PWM_LVL >> 1) < modes[0]) {
351
PWM_LVL = (PWM_LVL >> 1);
353
// See if we should change the current mode level if we've gone under the current mode.
354
if (PWM_LVL < modes[mode_idx]) {
355
// Lower our recorded mode
359
// Wait 3 seconds before lowering the level again
366
return 0; // Standard Return Code