Guest User

buzzing

a guest
Jan 19th, 2015
214
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #define F_CPU 4800000UL
  2.  
  3. /*
  4. * =========================================================================
  5. * Settings to modify per driver
  6. */
  7.  
  8. #define VOLTAGE_MON // Comment out to disable
  9.  
  10. #define MEMORY // Comment out to disable
  11.  
  12. //#define TICKS_250MS // If enabled, ticks are every 250 ms. If disabled, ticks are every 500 ms
  13. // Affects turbo timeout/rampdown timing
  14.  
  15. #define MODE_MOON 1 // Can comment out to remove mode, but should be set through soldering stars
  16. #define MODE_LOW 39 // Can comment out to remove mode
  17. #define MODE_MED 41 // Can comment out to remove mode
  18. #define MODE_HIGH 125 // Can comment out to remove mode
  19. #define MODE_TURBO 255 // Can comment out to remove mode
  20. #define MODE_TURBO_LOW 140 // Level turbo ramps down to if turbo enabled
  21. #define TURBO_TIMEOUT 60
  22. #define TURBO_RAMP_DOWN
  23.  
  24. #define FAST_PWM_START 30 // Above what output level should we switch from phase correct to fast-PWM?
  25. #define DUAL_PWM_START 40 // Above what output level should we switch from the alternate PWM output to both PWM outputs? Comment out to disable alternate PWM output
  26.  
  27. #define ADC_LOW 130 // When do we start ramping
  28. #define ADC_CRIT 120 // When do we shut the light off
  29.  
  30. #define CAP_THRESHOLD 240
  31.  
  32. //#include <avr/pgmspace.h>
  33. #include <avr/io.h>
  34. #include <util/delay.h>
  35. #include <avr/interrupt.h>
  36. #include <avr/wdt.h>
  37. #include <avr/eeprom.h>
  38. #include <avr/sleep.h>
  39. //#include <avr/power.h>
  40.  
  41. #define STAR2_PIN PB0
  42. #define STAR3_PIN PB4
  43. #define CAP_PIN PB3
  44. #define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4)
  45. #define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3
  46. #define PWM_PIN PB1
  47. #define VOLTAGE_PIN PB2
  48. #define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2
  49. #define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
  50. #define ADC_PRSCL 0x06 // clk/64
  51.  
  52. #define PWM_LVL OCR0B // OCR0B is the output compare register for PB1
  53. #define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0
  54.  
  55. /*
  56. * global variables
  57. */
  58.  
  59. // Mode storage
  60. uint8_t eepos = 0;
  61. uint8_t eep[32];
  62. uint8_t memory = 0;
  63.  
  64. // Modes (gets set when the light starts up based on stars)
  65. static uint8_t modes[10]; // Don't need 10, but keeping it high enough to handle all
  66. volatile uint8_t mode_idx = 0;
  67. 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.
  68. uint8_t mode_cnt = 0;
  69.  
  70. uint8_t lowbatt_cnt = 0;
  71.  
  72. void store_mode_idx(uint8_t lvl) { //central method for writing (with wear leveling)
  73. uint8_t oldpos=eepos;
  74. eepos=(eepos+1)&31; //wear leveling, use next cell
  75. // Write the current mode
  76. EEARL=eepos; EEDR=lvl; EECR=32+4; EECR=32+4+2; //WRITE //32:write only (no erase) 4:enable 2:go
  77. while(EECR & 2); //wait for completion
  78. // Erase the last mode
  79. EEARL=oldpos; EECR=16+4; EECR=16+4+2; //ERASE //16:erase only (no write) 4:enable 2:go
  80. }
  81. inline void read_mode_idx() {
  82. eeprom_read_block(&eep, 0, 32);
  83. while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
  84. if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
  85. else eepos=0;
  86. }
  87.  
  88. inline void next_mode() {
  89. if (mode_idx == 0 && mode_dir == -1) {
  90. // Wrap around
  91. mode_idx = mode_cnt - 1;
  92. } else {
  93. mode_idx += mode_dir;
  94. if (mode_idx > (mode_cnt - 1)) {
  95. // Wrap around
  96. mode_idx = 0;
  97. }
  98. }
  99. }
  100.  
  101. inline void check_stars() {
  102. // Load up the modes based on stars
  103. // Always load up the modes array in order of lowest to highest mode
  104. // 0 being low for soldered, 1 for pulled-up for not soldered
  105. // Moon
  106. #ifdef MODE_MOON
  107. #ifndef DUAL_PWM_START
  108. if (1==1) {
  109. #endif
  110. modes[mode_cnt++] = MODE_MOON;
  111. #ifndef DUAL_PWM_START
  112. }
  113. #endif
  114. #endif
  115. #ifdef MODE_LOW
  116. modes[mode_cnt++] = MODE_LOW;
  117. #endif
  118. #ifdef MODE_MED
  119. modes[mode_cnt++] = MODE_MED;
  120. #endif
  121. #ifdef MODE_HIGH
  122. modes[mode_cnt++] = MODE_HIGH;
  123. #endif
  124. #ifdef MODE_TURBO
  125. modes[mode_cnt++] = MODE_TURBO;
  126. #endif
  127. if ((PINB & (1 << STAR3_PIN)) == 0) {
  128. // High to Low
  129. mode_dir = -1;
  130. } else {
  131. mode_dir = 1;
  132. }
  133. }
  134.  
  135. inline void WDT_on() {
  136. // Setup watchdog timer to only interrupt, not reset
  137. cli(); // Disable interrupts
  138. wdt_reset(); // Reset the WDT
  139. WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
  140. #ifdef TICKS_250MS
  141. WDTCR = (1<<WDTIE) | (1<<WDP2); // Enable interrupt every 250ms
  142. #else
  143. WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
  144. #endif
  145. sei(); // Enable interrupts
  146. }
  147.  
  148. inline void WDT_off()
  149. {
  150. cli(); // Disable interrupts
  151. wdt_reset(); // Reset the WDT
  152. MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
  153. WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
  154. WDTCR = 0x00; // Disable WDT
  155. sei(); // Enable interrupts
  156. }
  157.  
  158. inline void ADC_on() {
  159. DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption
  160. ADMUX = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
  161. ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
  162. }
  163.  
  164. inline void ADC_off() {
  165. ADCSRA &= ~(1<<7); //ADC off
  166. }
  167.  
  168. void set_output(uint8_t pwm_lvl) {
  169. #ifdef DUAL_PWM_START
  170. if (pwm_lvl > DUAL_PWM_START) {
  171. // Using the normal output along with the alternate
  172. PWM_LVL = pwm_lvl;
  173. } else {
  174. PWM_LVL = 0;
  175. }
  176. #else
  177. PWM_LVL = pwm_lvl;
  178. #endif
  179. // Always set alternate PWM value even if not compiled for dual output as we will use this value
  180. // throughout the code when trying to see what the current output level is. Setting this wont affect
  181. // the output when alternate output is disabled.
  182. ALT_PWM_LVL = pwm_lvl;
  183. }
  184.  
  185. #ifdef VOLTAGE_MON
  186. uint8_t low_voltage(uint8_t voltage_val) {
  187. // Start conversion
  188. ADCSRA |= (1 << ADSC);
  189. // Wait for completion
  190. while (ADCSRA & (1 << ADSC));
  191. // See if voltage is lower than what we were looking for
  192. if (ADCH < voltage_val) {
  193. // See if it's been low for a while
  194. if (++lowbatt_cnt > 8) {
  195. lowbatt_cnt = 0;
  196. return 1;
  197. }
  198. } else {
  199. lowbatt_cnt = 0;
  200. }
  201. return 0;
  202. }
  203. #endif
  204.  
  205. ISR(WDT_vect) {
  206. static uint8_t ticks = 0;
  207. if (ticks < 255) ticks++;
  208. // If you want more than 255 for longer turbo timeouts
  209. //static uint16_t ticks = 0;
  210. //if (ticks < 60000) ticks++;
  211.  
  212. #ifdef MODE_TURBO
  213. //if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
  214. if (ticks >= TURBO_TIMEOUT && mode_idx == (mode_cnt - 1) && PWM_LVL > MODE_TURBO_LOW) {
  215. #ifdef TURBO_RAMP_DOWN
  216. set_output(PWM_LVL - 1);
  217. #else
  218. // Turbo mode is always at end
  219. set_output(MODE_TURBO_LOW);
  220. if (MODE_TURBO_LOW <= modes[mode_idx-1]) {
  221. // Dropped at or below the previous mode, so set it to the stored mode
  222. // Kept this as it was the same functionality as before. For the TURBO_RAMP_DOWN feature
  223. // it doesn't do this logic because I don't know what makes the most sense
  224. store_mode_idx(--mode_idx);
  225. }
  226. #endif
  227. }
  228. #endif
  229.  
  230. }
  231.  
  232. int main(void)
  233. {
  234. // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input! Made that mistake already)
  235. #ifdef DUAL_PWM_START
  236. PORTB = (1 << STAR3_PIN);
  237. #else
  238. PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN);
  239. #endif
  240.  
  241. // Determine what mode we should fire up
  242. // Read the last mode that was saved
  243. read_mode_idx();
  244.  
  245. check_stars(); // Moving down here as it might take a bit for the pull-up to turn on?
  246.  
  247. // Start up ADC for capacitor pin
  248. DIDR0 |= (1 << CAP_DIDR); // disable digital input on ADC pin to reduce power consumption
  249. ADMUX = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
  250. ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
  251.  
  252. // Wait for completion
  253. while (ADCSRA & (1 << ADSC));
  254. // Start again as datasheet says first result is unreliable
  255. ADCSRA |= (1 << ADSC);
  256. // Wait for completion
  257. while (ADCSRA & (1 << ADSC));
  258. if (ADCH > CAP_THRESHOLD) {
  259. // Indicates they did a short press, go to the next mode
  260. next_mode(); // Will handle wrap arounds
  261. store_mode_idx(mode_idx);
  262. } else {
  263. // Didn't have a short press, keep the same mode
  264. #ifndef MEMORY
  265. // Reset to the first mode
  266. mode_idx = ((mode_dir == 1) ? 0 : (mode_cnt - 1));
  267. store_mode_idx(mode_idx);
  268. #endif
  269. }
  270. // Turn off ADC
  271. ADC_off();
  272.  
  273. // Charge up the capacitor by setting CAP_PIN to output
  274. DDRB |= (1 << CAP_PIN); // Output
  275. PORTB |= (1 << CAP_PIN); // High
  276.  
  277. // Set PWM pin to output
  278. DDRB |= (1 << PWM_PIN);
  279. #ifdef DUAL_PWM_START
  280. DDRB |= (1 << STAR2_PIN);
  281. #endif
  282.  
  283. // Set timer to do PWM for correct output pin and set prescaler timing
  284. TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
  285. TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  286.  
  287. // Turn features on or off as needed
  288. #ifdef VOLTAGE_MON
  289. ADC_on();
  290. #else
  291. ADC_off();
  292. #endif
  293. ACSR |= (1<<7); //AC off
  294.  
  295. // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
  296. // Will allow us to go idle between WDT interrupts
  297. set_sleep_mode(SLEEP_MODE_IDLE);
  298.  
  299. uint8_t prev_mode_idx = mode_idx;
  300.  
  301. WDT_on();
  302.  
  303. // Now just fire up the mode
  304. // Set timer to do PWM for correct output pin and set prescaler timing
  305. if (modes[mode_idx] > FAST_PWM_START) {
  306. #ifdef DUAL_PWM_START
  307. TCCR0A = 0b10100011; // fast-PWM both outputs
  308. #else
  309. TCCR0A = 0b00100011; // fast-PWM normal output
  310. #endif
  311. } else {
  312. #ifdef DUAL_PWM_START
  313. TCCR0A = 0b10100001; // phase corrected PWM both outputs
  314. #else
  315. TCCR0A = 0b00100001; // phase corrected PWM normal output
  316. #endif
  317. }
  318. TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  319.  
  320. set_output(modes[mode_idx]);
  321.  
  322. uint8_t i = 0;
  323. uint8_t hold_pwm;
  324. while(1) {
  325. #ifdef VOLTAGE_MON
  326. if (low_voltage(ADC_LOW)) {
  327. // We need to go to a lower level
  328. if (mode_idx == 0 && ALT_PWM_LVL <= modes[mode_idx]) {
  329. // Can't go any lower than the lowest mode
  330. // Wait until we hit the critical level before flashing 10 times and turning off
  331. while (!low_voltage(ADC_CRIT));
  332. i = 0;
  333. while (i++<10) {
  334. set_output(0);
  335. _delay_ms(250);
  336. set_output(modes[0]);
  337. _delay_ms(500);
  338. }
  339. // Turn off the light
  340. set_output(0);
  341. // Disable WDT so it doesn't wake us up
  342. WDT_off();
  343. // Power down as many components as possible
  344. set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  345. sleep_mode();
  346. } else {
  347. // Flash 3 times before lowering
  348. hold_pwm = ALT_PWM_LVL;
  349. i = 0;
  350. while (i++<3) {
  351. set_output(0);
  352. _delay_ms(250);
  353. set_output(hold_pwm);
  354. _delay_ms(500);
  355. }
  356. // Lower the mode by half, but don't go below lowest level
  357. if ((ALT_PWM_LVL >> 1) < modes[0]) {
  358. set_output(modes[0]);
  359. mode_idx = 0;
  360. } else {
  361. set_output(ALT_PWM_LVL >> 1);
  362. }
  363. // See if we should change the current mode level if we've gone under the current mode.
  364. if (ALT_PWM_LVL < modes[mode_idx]) {
  365. // Lower our recorded mode
  366. mode_idx--;
  367. }
  368. }
  369. // Wait 3 seconds before lowering the level again
  370. _delay_ms(3000);
  371. }
  372. #endif
  373. sleep_mode();
  374. }
  375.  
  376. return 0; // Standard Return Code
  377. }
RAW Paste Data