~gabe/flashlight-firmware/anduril2

« back to all changes in this revision

Viewing changes to Werner/STAR_improvements/starfirmwarecapmemory.c

  • Committer: Selene Scriven
  • Date: 2016-11-29 22:51:09 UTC
  • mto: This revision was merged to the branch mainline in revision 176.
  • Revision ID: ubuntu@toykeeper.net-20161129225109-oab58sah3mb7mk1j
Copied biscotti.c to gchart/babka/babka.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * NANJG 105C Diagram
 
3
 *           ---
 
4
 *         -|   |- VCC
 
5
 *  Star 4 -|   |- Voltage ADC
 
6
 *  Star 3 -|   |- PWM
 
7
 *     GND -|   |- Star 2
 
8
 *           ---
 
9
 
 
10
 * CPU speed is 4.8Mhz without the 8x divider when low fuse is 0x75
 
11
 *
 
12
 * define F_CPU 4800000  CPU: 4.8MHz  PWM: 9.4kHz       ####### use low fuse: 0x75  #######
 
13
 *                             /8     PWM: 1.176kHz     ####### use low fuse: 0x65  #######
 
14
 * define F_CPU 9600000  CPU: 9.6MHz  PWM: 19kHz        ####### use low fuse: 0x7a  #######
 
15
 *                             /8     PWM: 2.4kHz       ####### use low fuse: 0x6a  #######
 
16
 * 
 
17
 * !!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
 
18
 *
 
19
 * FUSES
 
20
 *              I use these fuse settings
 
21
 *              Low:  0x75
 
22
 *              High: 0xff
 
23
 *
 
24
 * STARS
 
25
 *              Star 2 = Moon if connected              //changed moon is now standard if not soldered
 
26
 *              Star 3 = H-L if connected, L-H if not //changed H-L is now standard...more POWER!!!
 
27
 *              Star 4 = Capacitor for off-time  PB3 is leg #2
 
28
 *
 
29
 * VOLTAGE
 
30
 *              Resistor values for voltage divider (reference BLF-VLD README for more info)
 
31
 *              Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
 
32
 *
 
33
 *           VCC
 
34
 *            |
 
35
 *           Vd (~.25 v drop from protection diode)
 
36
 *            |
 
37
 *          1912 (R1 19,100 ohms)
 
38
 *            |
 
39
 *            |---- PB2 from MCU
 
40
 *            |
 
41
 *          4701 (R2 4,700 ohms)
 
42
 *            |
 
43
 *           GND
 
44
 *
 
45
 *              ADC = ((V_bat - V_diode) * R2   * 255) / ((R1    + R2  ) * V_ref)
 
46
 *              125 = ((3.0   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
 
47
 *              121 = ((2.9   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
 
48
 *
 
49
 *              Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
 
50
 *              130 and 120
 
51
 *
 
52
 *              To find out what value to use, plug in the target voltage (V) to this equation
 
53
 *                      value = (V * 4700 * 255) / (23800 * 1.1)
 
54
 *      
 
55
 */
 
56
 
 
57
 
 
58
 
 
59
 
 
60
 
 
61
 
 
62
 
 
63
#define F_CPU 4800000UL
 
64
 
 
65
//#define F_CPU 9600000
 
66
 
 
67
 
 
68
 
 
69
/*
 
70
 * =========================================================================
 
71
 * Settings to modify per driver
 
72
 */
 
73
 
 
74
#define VOLTAGE_MON                     // Comment out to disable
 
75
 
 
76
#define MEMORY                          // Comment out to disable
 
77
 
 
78
// Levels should start around 10 with Fast PWM
 
79
 
 
80
#define MODE_MOON                       10      // Can comment out to remove mode, but should be set through soldering stars
 
81
#define MODE_LOW                        65//35  // Can comment out to remove mode
 
82
//#define MODE_MED                      130     // Can comment out to remove mode
 
83
#define MODE_HIGH_W_TURBO       150     // MODE_HIGH value when turbo is enabled
 
84
#define MODE_HIGH                       255     // Can comment out to remove mode
 
85
#define MODE_TURBO                      255     // Can comment out to remove mode
 
86
#define TURBO_TIMEOUT           180 // How many WTD ticks before before dropping down (.5 sec each)
 
87
 
 
88
#define ADC_LOW                         130     // When do we start ramping
 
89
#define ADC_CRIT                        124 // When do we shut the light off
 
90
 
 
91
#define CAP_THRESHOLD           200  // Value between 1 and 255 corresponding with cap voltage (0 - 1.1v) where we consider it a short press to move to the next mode
 
92
                                                                 // Not sure the lowest you can go before getting bad readings, but with a value of 70 and a 1uF cap, it seemed to switch sometimes
 
93
                                                                 // even when waiting 10 seconds between presses.
 
94
 
 
95
/*
 
96
 * =========================================================================
 
97
 */
 
98
 
 
99
#ifdef MODE_TURBO
 
100
#undef  MODE_HIGH
 
101
#define MODE_HIGH       MODE_HIGH_W_TURBO
 
102
#endif
 
103
 
 
104
//#include <avr/pgmspace.h>
 
105
#include <avr/io.h>
 
106
#include <util/delay.h>
 
107
#include <avr/interrupt.h>
 
108
#include <avr/wdt.h>    
 
109
#include <avr/eeprom.h>
 
110
#include <avr/sleep.h>
 
111
//#include <avr/power.h>
 
112
 
 
113
#define STAR2_PIN   PB0
 
114
#define STAR3_PIN   PB4
 
115
#define CAP_PIN     PB3
 
116
#define CAP_CHANNEL 0x03        // MUX 03 corresponds with PB3 (Star 4)
 
117
#define CAP_DIDR    ADC3D       // Digital input disable bit corresponding with PB3
 
118
#define PWM_PIN     PB1
 
119
#define VOLTAGE_PIN PB2
 
120
#define ADC_CHANNEL 0x01        // MUX 01 corresponds with PB2
 
121
#define ADC_DIDR        ADC1D   // Digital input disable bit corresponding with PB2
 
122
#define ADC_PRSCL   0x06        // clk/64
 
123
 
 
124
#define PWM_LVL         OCR0B   // OCR0B is the output compare register for PB1
 
125
 
 
126
/*
 
127
 * global variables
 
128
 */
 
129
 
 
130
// Mode storage
 
131
uint8_t eepos = 0;
 
132
uint8_t eep[32];
 
133
uint8_t memory = 0;
 
134
 
 
135
// Modes (gets set when the light starts up based on stars)
 
136
static uint8_t modes[10];  // Don't need 10, but keeping it high enough to handle all
 
137
volatile uint8_t mode_idx = 0;
 
138
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.
 
139
uint8_t mode_cnt = 0;
 
140
 
 
141
uint8_t lowbatt_cnt = 0;
 
142
 
 
143
void store_mode_idx(uint8_t lvl) {  //central method for writing (with wear leveling)
 
144
        uint8_t oldpos=eepos;
 
145
        eepos=(eepos+1)&31;  //wear leveling, use next cell
 
146
        // Write the current mode
 
147
        EEARL=eepos;  EEDR=lvl; EECR=32+4; EECR=32+4+2;  //WRITE  //32:write only (no erase)  4:enable  2:go
 
148
        while(EECR & 2); //wait for completion
 
149
        // Erase the last mode
 
150
        EEARL=oldpos;           EECR=16+4; EECR=16+4+2;  //ERASE  //16:erase only (no write)  4:enable  2:go
 
151
}
 
152
inline void read_mode_idx() {
 
153
        eeprom_read_block(&eep, 0, 32);
 
154
        while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
 
155
        if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
 
156
        else eepos=0;
 
157
}
 
158
 
 
159
inline void next_mode() {
 
160
        if (mode_idx == 0 && mode_dir == -1) {
 
161
                // Wrap around
 
162
                mode_idx = mode_cnt - 1;
 
163
        } else {
 
164
                mode_idx += mode_dir;
 
165
                if (mode_idx > (mode_cnt - 1)) {
 
166
                        // Wrap around
 
167
                        mode_idx = 0;
 
168
                }
 
169
        }
 
170
}
 
171
 
 
172
inline void check_stars() {
 
173
        // Load up the modes based on stars
 
174
        // Always load up the modes array in order of lowest to highest mode
 
175
        // 0 being low for soldered, 1 for pulled-up for not soldered
 
176
        // Moon
 
177
#ifdef MODE_MOON
 
178
        if ((PINB & (1 << STAR2_PIN)) == 1) {           //changed MOON is standard
 
179
                modes[mode_cnt++] = MODE_MOON;
 
180
        }
 
181
#endif
 
182
#ifdef MODE_LOW
 
183
        modes[mode_cnt++] = MODE_LOW;
 
184
#endif
 
185
#ifdef MODE_MED
 
186
        modes[mode_cnt++] = MODE_MED;
 
187
#endif
 
188
#ifdef MODE_HIGH
 
189
        modes[mode_cnt++] = MODE_HIGH;
 
190
#endif
 
191
#ifdef MODE_TURBO
 
192
        modes[mode_cnt++] = MODE_TURBO;
 
193
#endif
 
194
        if ((PINB & (1 << STAR3_PIN)) == 0) {
 
195
                // High to Low
 
196
                mode_dir = 1;                   //changed
 
197
        } else {
 
198
                mode_dir = -1;                  //changed H_L is standard now
 
199
        }
 
200
}
 
201
 
 
202
inline void WDT_on() {
 
203
        // Setup watchdog timer to only interrupt, not reset, every 500ms.
 
204
        cli();                                                  // Disable interrupts
 
205
        wdt_reset();                                    // Reset the WDT
 
206
        WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
 
207
        WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
 
208
        sei();                                                  // Enable interrupts
 
209
}
 
210
 
 
211
inline void WDT_off()
 
212
{
 
213
        cli();                                                  // Disable interrupts
 
214
        wdt_reset();                                    // Reset the WDT
 
215
        MCUSR &= ~(1<<WDRF);                    // Clear Watchdog reset flag
 
216
        WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
 
217
        WDTCR = 0x00;                                   // Disable WDT
 
218
        sei();                                                  // Enable interrupts
 
219
}
 
220
 
 
221
inline void ADC_on() {
 
222
        DIDR0 |= (1 << ADC_DIDR);                                                       // disable digital input on ADC pin to reduce power consumption
 
223
        ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
 
224
        ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
 
225
}
 
226
 
 
227
inline void ADC_off() {
 
228
        ADCSRA &= ~(1<<7); //ADC off
 
229
}
 
230
 
 
231
#ifdef VOLTAGE_MON
 
232
uint8_t low_voltage(uint8_t voltage_val) {
 
233
        // Start conversion
 
234
        ADCSRA |= (1 << ADSC);
 
235
        // Wait for completion
 
236
        while (ADCSRA & (1 << ADSC));
 
237
        // See if voltage is lower than what we were looking for
 
238
        if (ADCH < voltage_val) {
 
239
                // See if it's been low for a while
 
240
                if (++lowbatt_cnt > 8) {
 
241
                        lowbatt_cnt = 0;
 
242
                        return 1;
 
243
                }
 
244
        } else {
 
245
                lowbatt_cnt = 0;
 
246
        }
 
247
        return 0;
 
248
}
 
249
#endif
 
250
 
 
251
ISR(WDT_vect) {
 
252
        static uint8_t ticks = 0;
 
253
        if (ticks < 255) ticks++;
 
254
        
 
255
#ifdef MODE_TURBO       
 
256
        //if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
 
257
        if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
 
258
                // Turbo mode is always at end
 
259
                PWM_LVL = modes[--mode_idx];
 
260
                store_mode_idx(mode_idx);
 
261
        }
 
262
#endif
 
263
 
 
264
}
 
265
 
 
266
int main(void)
 
267
{       
 
268
        // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input!  Made that mistake already)
 
269
        PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN);
 
270
        
 
271
        // Determine what mode we should fire up
 
272
        // Read the last mode that was saved
 
273
        read_mode_idx();
 
274
        
 
275
        check_stars(); // Moving down here as it might take a bit for the pull-up to turn on?
 
276
        
 
277
        // Start up ADC for capacitor pin
 
278
        DIDR0 |= (1 << CAP_DIDR);                                                       // disable digital input on ADC pin to reduce power consumption
 
279
        ADMUX  = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
 
280
        ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
 
281
        
 
282
        // Wait for completion
 
283
        while (ADCSRA & (1 << ADSC));
 
284
        // Start again as datasheet says first result is unreliable
 
285
        ADCSRA |= (1 << ADSC);
 
286
        // Wait for completion
 
287
        while (ADCSRA & (1 << ADSC));
 
288
        if (ADCH > CAP_THRESHOLD) {
 
289
                // Indicates they did a short press, go to the next mode
 
290
                next_mode(); // Will handle wrap arounds
 
291
                store_mode_idx(mode_idx);
 
292
        } else {
 
293
                // Didn't have a short press, keep the same mode
 
294
        #ifndef MEMORY
 
295
                // Reset to the first mode
 
296
                mode_idx = ((mode_dir == 1) ? 0 : (mode_cnt - 1));
 
297
                store_mode_idx(mode_idx);
 
298
        #endif
 
299
        }
 
300
        // Turn off ADC
 
301
        ADC_off();
 
302
        
 
303
        // Charge up the capacitor by setting CAP_PIN to output
 
304
        DDRB  |= (1 << CAP_PIN);        // Output
 
305
    PORTB |= (1 << CAP_PIN);    // High
 
306
        
 
307
    // Set PWM pin to output
 
308
    DDRB |= (1 << PWM_PIN);
 
309
 
 
310
    // Set timer to do PWM for correct output pin and set prescaler timing
 
311
    TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
 
312
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
 
313
        
 
314
        // Turn features on or off as needed
 
315
        #ifdef VOLTAGE_MON
 
316
        ADC_on();
 
317
        #else
 
318
        ADC_off();
 
319
        #endif
 
320
        ACSR   |=  (1<<7); //AC off
 
321
        
 
322
        // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
 
323
        // Will allow us to go idle between WDT interrupts
 
324
        set_sleep_mode(SLEEP_MODE_IDLE);
 
325
        
 
326
        uint8_t prev_mode_idx = mode_idx;
 
327
        
 
328
        WDT_on();
 
329
        
 
330
        // Now just fire up the mode
 
331
        PWM_LVL = modes[mode_idx];
 
332
        
 
333
        uint8_t i = 0;
 
334
        uint8_t hold_pwm;
 
335
        while(1) 
 
336
        {                                                               //main loop
 
337
          #ifdef VOLTAGE_MON                                                            ///VOLTAGE MONITOR!!!
 
338
                if (low_voltage(ADC_LOW)) 
 
339
              {
 
340
                        // We need to go to a lower level
 
341
                        if (mode_idx == 0 && PWM_LVL <= modes[mode_idx]) 
 
342
                          {
 
343
                                // Can't go any lower than the lowest mode
 
344
                                // Wait until we hit the critical level before flashing 10 times and turning off
 
345
                                while (!low_voltage(ADC_CRIT));                 //low_voltage(x) 1 if longer low zero is normal
 
346
                                i = 0;
 
347
                                while (i++<10) {
 
348
                                        PWM_LVL = 0;
 
349
                                        _delay_ms(250);
 
350
                                        PWM_LVL = modes[0];
 
351
                                        _delay_ms(500);
 
352
                                                                }
 
353
                                // Turn off the light
 
354
                                PWM_LVL = 0;
 
355
                                // Disable WDT so it doesn't wake us up
 
356
                                WDT_off();
 
357
                                ADC_off();
 
358
                                // Power down as many components as possible
 
359
                                set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
360
                                sleep_mode();
 
361
                           }
 
362
                         else 
 
363
                          {
 
364
                                // Flash 2 times before lowering
 
365
                                hold_pwm = PWM_LVL;
 
366
                                i = 0;
 
367
                                while (i++<2) 
 
368
                                  { 
 
369
                                        PWM_LVL = 0;
 
370
                                        _delay_ms(250);
 
371
                                        PWM_LVL = hold_pwm;
 
372
                                        _delay_ms(500);
 
373
                              }
 
374
                                // Lower the mode by half, but don't go below lowest level
 
375
                                if ((PWM_LVL >> 1) < modes[0]) 
 
376
                                 {
 
377
                                        PWM_LVL = modes[0];
 
378
                                        mode_idx = 0;
 
379
                                 } 
 
380
                                 else 
 
381
                                        {                                       
 
382
                                          PWM_LVL = (PWM_LVL >> 1);
 
383
                                     }                                  
 
384
                                // See if we should change the current mode level if we've gone under the current mode.
 
385
                                if (PWM_LVL < modes[mode_idx])
 
386
                                 {
 
387
                                        // Lower our recorded mode
 
388
                                        mode_idx--;
 
389
                                  }
 
390
                        }
 
391
                        // Wait 3 seconds before lowering the level again
 
392
                        _delay_ms(3000);
 
393
                }//endiflowvoltagemon
 
394
        #endif
 
395
                sleep_mode();
 
396
        }
 
397
 
 
398
    return 0; // Standard Return Code
 
399
}