fixed_it

STAR_dual_switch firmware adapted for PD68 TripleDown

Mar 24th, 2016
24
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* STAR_dual_switch version 1.0
  2.  *
  3.  * Changelog
  4.  *
  5.  * 1.0 Initial version
  6.  * 1.1 Changed modes to static and no longer access through progmem. Also changed mode levels to more closely match STAR_momentary
  7.  *
  8.  */
  9.  
  10. /*
  11.  * NANJG 105C Diagram
  12.  *           ---
  13.  *         -|   |- VCC
  14.  *  Star 4 -|   |- Voltage ADC
  15.  *  Star 3 -|   |- PWM
  16.  *     GND -|   |- Star 2
  17.  *           ---
  18.  *
  19.  * FUSES
  20.  *      I use these fuse settings
  21.  *      Low:  0x75  (4.8MHz CPU without 8x divider, 9.4kHz phase-correct PWM or 18.75kHz fast-PWM)
  22.  *      High: 0xff
  23.  *
  24.  *      For more details on these settings, visit http://github.com/JCapSolutions/blf-firmware/wiki/PWM-Frequency
  25.  *
  26.  * STARS
  27.  *      Star 2 = H-L if connected, L-H if not
  28.  *      Star 3 = Memory if not connected
  29.  *      Star 4 = Input for switch
  30.  *
  31.  * VOLTAGE
  32.  *      Resistor values for voltage divider (reference BLF-VLD README for more info)
  33.  *      Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
  34.  *
  35.  *           VCC
  36.  *            |
  37.  *           Vd (~.25 v drop from protection diode)
  38.  *            |
  39.  *          1912 (R1 19,100 ohms)
  40.  *            |
  41.  *            |---- PB2 from MCU
  42.  *            |
  43.  *          4701 (R2 4,700 ohms)
  44.  *            |
  45.  *           GND
  46.  *
  47.  *      ADC = ((V_bat - V_diode) * R2   * 255) / ((R1    + R2  ) * V_ref)
  48.  *      125 = ((3.0   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
  49.  *      121 = ((2.9   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
  50.  *
  51.  *      Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
  52.  *      130 and 120
  53.  *
  54.  *      To find out what value to use, plug in the target voltage (V) to this equation
  55.  *          value = (V * 4700 * 255) / (23800 * 1.1)
  56.  *      
  57.  */
  58. #define F_CPU 4800000UL
  59.  
  60. // PWM Mode
  61. #define PHASE 0b00000001
  62. #define FAST  0b00000011
  63.  
  64. /*
  65.  * =========================================================================
  66.  * Settings to modify per driver
  67.  */
  68.  
  69. #define VOLTAGE_MON         // Comment out to disable - ramp down and eventual shutoff when battery is low
  70. #define MODES           8,14,39,125,255,TURBO   // Must be low to high.
  71. #define ALT_MODES       8,14,39,125,255,0       // Must be low to high. Defines the level for the secondary output. Comment out if no secondary output
  72. #define MODE_PWM        PHASE,FAST,FAST,FAST,PHASE,PHASE        // Define one per mode above.
  73. #define TURBO           254 // Convenient define for the turbo level in MODES above.
  74.                             // full output with a step down after n number of seconds if TURBO_TIMEOUT is defined.
  75.                             // This is not defined to 255 so that value remains a valid PWM choice in MODES.
  76. #define TURBO_TIMEOUT   5625 // How many WTD ticks before before dropping down (.016 sec each)
  77.                             // 90  = 5625
  78.                             // 120 = 7500
  79.                            
  80. #define ADC_LOW         130 // When do we start ramping
  81. #define ADC_CRIT        120 // When do we shut the light off
  82. #define ADC_DELAY       188 // Delay in ticks between low-bat rampdowns (188 ~= 3s)
  83.  
  84. #define LOW_TO_HIGH 1       // If 1, will cycle L-H. If 0, H-L
  85. #define MEMORY 1            // If 1, mode memory enabled. If 0, disabled.
  86.  
  87. /*
  88.  * =========================================================================
  89.  */
  90.  
  91. //#include <avr/pgmspace.h>
  92. #include <avr/io.h>
  93. #include <util/delay.h>
  94. #include <avr/interrupt.h>
  95. #include <avr/wdt.h>   
  96. #include <avr/eeprom.h>
  97. #include <avr/sleep.h>
  98. //#include <avr/power.h>
  99.  
  100. #define FET_PIN     PB4
  101. #define SWITCH_PIN  PB3     // what pin the switch is connected to, which is Star 4
  102. #define PWM_PIN     PB1
  103. #define ALT_PWM_PIN PB0
  104. #define VOLTAGE_PIN PB2
  105. #define ADC_CHANNEL 0x01    // MUX 01 corresponds with PB2
  106. #define ADC_DIDR    ADC1D   // Digital input disable bit corresponding with PB2
  107. #define ADC_PRSCL   0x06    // clk/64
  108.  
  109. #define PWM_LVL     OCR0B   // OCR0B is the output compare register for PB1
  110. #define ALT_PWM_LVL OCR0A   // OCR0A is the output compare register for PB0
  111.  
  112. #define DB_REL_DUR  0b00001111 // time before we consider the switch released
  113.                                // each bit of 1 from the right equals 16ms, so 0x0f = 64ms
  114.  
  115. // Switch handling
  116. #define LONG_PRESS_DUR   32 // How many WDT ticks until we consider a press a long press
  117.                             // 32 is roughly .5 s
  118.  
  119. /*
  120.  * The actual program
  121.  * =========================================================================
  122.  */
  123.  
  124. /*
  125.  * global variables
  126.  */
  127. const uint8_t modes[] = { MODES };
  128. #ifdef ALT_MODES
  129. const uint8_t alt_modes[] = { ALT_MODES };
  130. #endif
  131. const uint8_t mode_pwm[] = { MODE_PWM };
  132. volatile uint8_t mode_idx = 0;
  133. volatile uint8_t press_duration = 0;
  134.  
  135. // Mode storage
  136. uint8_t eepos = 0;
  137. uint8_t eep[32];
  138.  
  139. void store_mode_idx(uint8_t lvl) {  //central method for writing (with wear leveling)
  140.     uint8_t oldpos=eepos;
  141.     eepos=(eepos+1)&31;  //wear leveling, use next cell
  142.     // Write the current mode
  143.     EEARL=eepos;  EEDR=lvl; EECR=32+4; EECR=32+4+2;  //WRITE  //32:write only (no erase)  4:enable  2:go
  144.     while(EECR & 2); //wait for completion
  145.     // Erase the last mode
  146.     EEARL=oldpos;           EECR=16+4; EECR=16+4+2;  //ERASE  //16:erase only (no write)  4:enable  2:go
  147. }
  148. inline void read_mode_idx() {
  149.     eeprom_read_block(&eep, 0, 32);
  150.     while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
  151.     if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
  152.     else eepos=0;
  153. }
  154.  
  155. // Debounced switch press value
  156. int is_pressed()
  157. {
  158.     // Keep track of last switch values polled
  159.     static uint8_t buffer = 0x00;
  160.     // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
  161.     buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
  162.     return (buffer & DB_REL_DUR);
  163. }
  164.  
  165. void next_mode(uint8_t save) {
  166.     if (++mode_idx >= sizeof(modes)) {
  167.         // Wrap around
  168.         mode_idx = 0;
  169.     }
  170.     if (MEMORY && save) {
  171.         store_mode_idx(mode_idx);
  172.     }
  173. }
  174.  
  175. void prev_mode(uint8_t save) {
  176.     if (mode_idx == 0) {
  177.         // Wrap around
  178.         mode_idx = sizeof(modes) - 1;
  179.     } else {
  180.         --mode_idx;
  181.     }
  182.     if (MEMORY && save) {
  183.         store_mode_idx(mode_idx);
  184.     }
  185. }
  186. /*
  187. inline void PCINT_on() {
  188.     // Enable pin change interrupts
  189.     GIMSK |= (1 << PCIE);
  190. }
  191.  
  192. inline void PCINT_off() {
  193.     // Disable pin change interrupts
  194.     GIMSK &= ~(1 << PCIE);
  195. }
  196. */
  197.  
  198. // Need an interrupt for when pin change is enabled to ONLY wake us from sleep.
  199. // All logic of what to do when we wake up will be handled in the main loop.
  200. EMPTY_INTERRUPT(PCINT0_vect);
  201.  
  202. inline void WDT_on() {
  203.     // Setup watchdog timer to only interrupt, not reset, every 16ms.
  204.     cli();                          // Disable interrupts
  205.     wdt_reset();                    // Reset the WDT
  206.     WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
  207.     WDTCR = (1<<WDTIE);             // Enable interrupt every 16ms
  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.  
  222. inline void ADC_on() {
  223.     ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
  224.     DIDR0 |= (1 << ADC_DIDR);                           // disable digital input on ADC pin to reduce power consumption
  225.     ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
  226. }
  227.  
  228. inline void ADC_off() {
  229.     ADCSRA &= ~(1<<7); //ADC off
  230. }
  231.  
  232. /*
  233. void sleep_until_switch_press()
  234. {
  235.     // This routine takes up a lot of program memory :(
  236.     // Turn the WDT off so it doesn't wake us from sleep
  237.     // Will also ensure interrupts are on or we will never wake up
  238.     WDT_off();
  239.     // Need to reset press duration since a button release wasn't recorded
  240.     press_duration = 0;
  241.     // Enable a pin change interrupt to wake us up
  242.     // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch
  243.     while (is_pressed()) {
  244.         _delay_ms(16);
  245.     }
  246.     PCINT_on();
  247.     // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
  248.     //set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  249.     // Now go to sleep
  250.     sleep_mode();
  251.     // Hey, someone must have pressed the switch!!
  252.     // Disable pin change interrupt because it's only used to wake us up
  253.     PCINT_off();
  254.     // Turn the WDT back on to check for switch presses
  255.     WDT_on();
  256.     // Go back to main program
  257. }
  258. */
  259.  
  260. // The watchdog timer is called every 16ms
  261. ISR(WDT_vect) {
  262.  
  263.     //static uint8_t  press_duration = 0;  // Pressed or not pressed
  264.     static uint16_t turbo_ticks = 0;
  265.     static uint8_t  adc_ticks = ADC_DELAY;
  266.     static uint8_t  lowbatt_cnt = 0;
  267.  
  268.     if (is_pressed()) {
  269.         if (press_duration < 255) {
  270.             press_duration++;
  271.         }
  272.        
  273.         if (press_duration == LONG_PRESS_DUR) {
  274.             // Long press
  275.             if (LOW_TO_HIGH) {
  276.                 prev_mode(1);
  277.             } else {
  278.                 next_mode(1);
  279.             }          
  280.         }
  281.         // Just always reset turbo timer whenever the button is pressed
  282.         turbo_ticks = 0;
  283.         // Same with the ramp down delay
  284.         adc_ticks = ADC_DELAY;
  285.     } else {
  286.         // Not pressed
  287.         if (press_duration > 0 && press_duration < LONG_PRESS_DUR) {
  288.             // Short press
  289.             if (LOW_TO_HIGH) {
  290.                 next_mode(1);
  291.             } else {
  292.                 prev_mode(1);
  293.             }  
  294.         } else {
  295.             // Only do turbo check when switch isn't pressed
  296.         #ifdef TURBO_TIMEOUT
  297.             if (modes[mode_idx] == TURBO) {
  298.                 turbo_ticks++;
  299.                 if (turbo_ticks > TURBO_TIMEOUT) {
  300.                     // Go to the previous mode
  301.                     prev_mode(0);
  302.                 }
  303.             }
  304.         #endif
  305.             // Only do voltage monitoring when the switch isn't pressed and we aren't at the lowest level
  306.         #ifdef VOLTAGE_MON
  307.             if (mode_idx > 0) {
  308.                 if (adc_ticks > 0) {
  309.                     --adc_ticks;
  310.                 }
  311.                 if (adc_ticks == 0) {
  312.                     // See if conversion is done
  313.                     if (ADCSRA & (1 << ADIF)) {
  314.                         // See if voltage is lower than what we were looking for
  315.                         if (ADCH < ((mode_idx == 1) ? ADC_CRIT : ADC_LOW)) {
  316.                             ++lowbatt_cnt;
  317.                         } else {
  318.                             lowbatt_cnt = 0;
  319.                         }
  320.                     }
  321.                
  322.                     // See if it's been low for a while
  323.                     if (lowbatt_cnt >= 4) {
  324.                         prev_mode(0);
  325.                         lowbatt_cnt = 0;
  326.                         // Restart the counter to when we step down again
  327.                         adc_ticks = ADC_DELAY;
  328.                     }
  329.                
  330.                     // Make sure conversion is running for next time through
  331.                     ADCSRA |= (1 << ADSC);
  332.                 }
  333.             }          
  334.         #endif
  335.         }
  336.         press_duration = 0;
  337.     }
  338. }
  339.  
  340. int main(void)
  341. {  
  342.     // Set all ports to input, and turn pull-up resistors on for the inputs we are using
  343.     DDRB = 0x00;
  344.     PORTB = (1 << SWITCH_PIN);
  345.  
  346.     // Set the switch as an interrupt for when we turn pin change interrupts on
  347.     PCMSK = (1 << SWITCH_PIN);
  348.    
  349.     // Set FET and PWM pin to output
  350.     #ifdef ALT_MODES
  351.     DDRB = (1 << FET_PIN) | (1 << PWM_PIN) | (1 << ALT_PWM_PIN);
  352.     #else
  353.     DDRB = (1 << FET_PIN) | (1 << PWM_PIN);
  354.     #endif
  355.  
  356.     // Set timer to do PWM for correct output pin and set prescaler timing
  357.     //TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
  358.     TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  359.    
  360.     // Turn features on or off as needed
  361.     #ifdef VOLTAGE_MON
  362.     ADC_on();
  363.     #else
  364.     ADC_off();
  365.     #endif
  366.     ACSR   |=  (1<<7); //AC off
  367.    
  368.     // Don't think we want to ever go to sleep
  369.     // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
  370.     //set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  371.     //sleep_until_switch_press();
  372.    
  373.     WDT_on();
  374.    
  375.     // Determine what mode we should fire up
  376.     // Read the last mode that was saved
  377.     if (MEMORY) {
  378.         read_mode_idx();
  379.     } else {
  380.         if (LOW_TO_HIGH) {
  381.             mode_idx = 0;
  382.         } else {
  383.             mode_idx = sizeof(modes);
  384.         }      
  385.     }
  386.    
  387.     uint8_t last_mode_idx = 255;
  388.    
  389.     while(1) {
  390.         // We will never leave this loop.  The WDT will interrupt to check for switch presses and
  391.         // will change the mode if needed.  If this loop detects that the mode has changed, run the
  392.         // logic for that mode while continuing to check for a mode change.
  393.         if (mode_idx != last_mode_idx) {
  394.             // The WDT changed the mode.
  395.             #ifdef ALT_MODES
  396.             TCCR0A = mode_pwm[mode_idx] | 0b10100000;  // Use both outputs
  397.             #else
  398.             TCCR0A = mode_pwm[mode_idx] | 0b00100000;  // Only use the normal output
  399.             #endif
  400.             if (modes[mode_idx] == TURBO)
  401.             {
  402.                 // Turn on FET instead of main PWM.
  403.                 PORTB |= (1 << FET_PIN);
  404.                 PWM_LVL = 0;
  405.             }
  406.             else
  407.             {
  408.                 // Turn off FET, use requested main PWM.
  409.                 PORTB &= ~(1 << FET_PIN);
  410.                 PWM_LVL     = modes[mode_idx];
  411.             }
  412.             #ifdef ALT_MODES
  413.             ALT_PWM_LVL = alt_modes[mode_idx];
  414.             #endif
  415.             last_mode_idx = mode_idx;
  416.         }
  417.     }
  418.  
  419.     return 0; // Standard Return Code
  420. }
RAW Paste Data