Advertisement
Guest User

SolarLight AVR Assembler

a guest
Mar 13th, 2011
318
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.87 KB | None | 0 0
  1. /***************************************************************************
  2. * Title : SolarLight (http://bitsnbikes.blogspot.com/search/label/Solarlight)
  3. * Version : rev. 1.0
  4. * Last updated : 2011-02-23
  5. * Target : ATTiny15L @ 1.6MHz (internal osc)
  6. * DESCRIPTION : Assembly code for SolarLight, controls the voltage output
  7. * of a SEPIC converter driving a LUXEON STAR K2 White LED.
  8. * controls the time of solar charging of 3 AAA NiMH batteries.
  9. * NiMH are not recomended for trickle charge, but we have to
  10. * live with it...
  11. ***************************************************************************
  12. * TODO:
  13. * DONE: 2011-02-26
  14. * - corrections to the Voltage values for 3 batteries
  15. * - charge counter is reset from power up to zero (start after programming)
  16. * DONE: 2011-02-23
  17. * - remove 4 battery section (not needed and conflicts with charging)
  18. * - remove BAT4 define
  19. * DONE: 2011-02-09
  20. * - change battery values to 4x AAA instead of 3x AAA to maximize solar panel
  21. * - create define BAT4 for activation - disables external power detection
  22. * DONE: 2011-02-08
  23. * - charge charge counter to 8 bits
  24. * DONE: 2011-02-07
  25. * - divide number of status outputs to once/twice a minute.
  26. * - reduce Ton on status output (save power)
  27. * - use wdr to present status (power down mode)
  28. * - detect external power and turn on (if there's no sun)
  29. * DONE: 2011-01-28
  30. * - improve charging counter and accounting of charge time
  31. * - output status of charge/discharge the LED
  32. * DONE: 2011-01-15
  33. * - gracefull degradation, reduce target voltage on the LED (and power
  34. * as battery voltage decreases.
  35. * - sleep processor between ADC conversions
  36. * - convert software to avrgcc/gas linux and create makefile
  37. ****************************************************************************/
  38.  
  39. /*
  40. * Code Control
  41. */
  42. #define __SFR_OFFSET 0
  43. #include <avr/io.h>
  44.  
  45. /*
  46. * add linker option -nostartfiles -nodefaultlibs
  47. */
  48. .global __do_clear_bss
  49. __do_clear_bss:
  50. .global __do_copy_data
  51. __do_copy_data:
  52.  
  53. /*
  54. * DEBUG CONTROL VARIABLES
  55. */
  56. /*
  57. * Uncoment the following definitions to enable debugging, these output
  58. * a variable (or more than one) at the LED pin when function dbug is called
  59. * beware of register use if debug is enabled !!
  60. */
  61. /*
  62. #define DEBUG R29 ; debug control variable
  63. #define DB_CNT R28 ; debug help variable
  64. */
  65. /*
  66. * Equates
  67. */
  68. /* --- Pinout ---
  69. * ATTiny15L PinNb Prototype
  70. * RESET/ADC0 - 1 - RST
  71. * PortB4/ADC3(*) - 2 - Vsun
  72. * PortB3/ADC2(*) - 3 - Vled
  73. * - 4 - GND
  74. * PortB0/AIN0/AREF - 5 - Status LED
  75. * PortB1/AIN1/OC1A - 6 - MOSFET output
  76. * PortB2/ADC1/T0/INT0 - 7 - Vbat
  77. * - 8 - VCC
  78. *(*) change in ATTiny25/45/85
  79. */
  80.  
  81. /*
  82. * FCLK WATCHDOG = 350kHz @ Vcc=3V /2048K = 6.01s
  83. * FCLK WATCHDOG = 500kHz @ Vcc=3.5V /2048K = 4.21s
  84. * FCLK WATCHDOG = 700kHz @ Vcc=4V /2048K = 3.00s
  85. * FCLK WATCHDOG = 1MHz @ Vcc=5V /2048K = 2.10s
  86. */
  87. /* number of elapsed watchdog periods before taking decisions - saves power */
  88. WD_REP= 30/6 /* about 30 seconds divided by minimum WD timeout */
  89.  
  90. /* CNT_CHRG counts the number of cycles (as divided by WD_REP) where Vdiode>100mV */
  91. CNT_CHRG= 30 /* about 1 hour of charging (number of cycles as divided above)*/
  92.  
  93. /* ADC LSB = 20mV therefore divide volts by 20 to get bits */
  94. VCHRG = 100/20 /* 100mV if (Vf(diode)> 100mV) => charging, about 5mA */
  95.  
  96. /* defines number of elements of the battery NiCad or NiMH */
  97. /* defines for voltage values */
  98. VBATMIN = 2800/20 /* < 2800mV, stop driving, minimum NiMH/LiPo voltage */
  99. VBATOPR = 3000/20 /* > 3000mV minimum value to start light, 50% */
  100. VBATFUL = 3600/20 /* >= 3600mV means that batt is fully charged 75% */
  101. VINEXT = 4000/20 /* >= 4000mV => external power */
  102.  
  103. VSUNMIN = 1000/20 /* 1000mV - dark threshold */
  104.  
  105. VLEDMAX = 4000/20 /* 4000mV i.e. no LED! open circuit */
  106.  
  107. /* these are calculated values */
  108. /* VLED100 = 3700/20 */ /* Vf=3700mV@950mA P=3.52W */
  109. /* VLED75 = 3600/20 */ /* Vf=3600mV@700mA P=2.52W */
  110. /* VLED50 = 3500/20 */ /* Vf=3500mV@500mA P=1.75W */
  111. /* VLED25 = 3350/20 */ /* Vf=3350mV@200mA P=0.75W */
  112. /* these are more practical values related to operating time */
  113. VLED75 = 3400/20 /* Vf=3400@600mA P=2.04W */
  114. VLED50 = 3200/20 /* Vf=3200@400mA P=1.28W */
  115. VLED25 = 3100/20 /* Vf=3100@200mA P=0.62W */
  116.  
  117. PWMMAX = 166 /* maximum allowable duty cycle = 0.75 */
  118. PWMREF = 145 /* reference duty cycle = 0.57 */
  119. PWMMIN = 115 /* minimum allowable duty cycle = 0.45 */
  120.  
  121. /*
  122. * Status output definitions
  123. */
  124. ST_EXT = 7 /* external power */
  125. ST_CHRG1= 6 /* Charging battery for more than 1 hour */
  126. ST_CHRG = 5 /* Charging battery */
  127. ST_LOWB = 4 /* Low Bat, No Charging */
  128. ST_SUN = 3 /* No Charging, Bat OK, Sun is still high */
  129. ST_NCHRG= 2 /* not enough charge time */
  130. ST_OPR = 1 /* lamp should be operating - for information */
  131.  
  132. /*
  133. * Register Definitions
  134. */
  135. #define zero R0 /* register holding zero (after oscillator calibration!)*/
  136. #define mcusr_sv R1 /* save MCUSR for later testing */
  137. #define wdt_cnt R2 /* counter of WDT resets */
  138. #define chrg_cnt R3 /* charging time counter */
  139.  
  140. #define accl R16 /* accumulator low/temporary holding variable */
  141. #define acch R17 /* accumulator high/temporary holding variable */
  142.  
  143. #define vsun R18 /* result of conversion Vsolarpanel */
  144. #define vbat R19 /* result of conversion Vbattery */
  145. #define vled R20 /* result of conversion VLED */
  146. #define vref R21 /* reference LED voltage (adjustable) */
  147.  
  148. #define pwm R22 /* next pwm value */
  149.  
  150. #define status R23 /* info status */
  151.  
  152. #define wdr_cnt R24 /* counter of wdr cycles for longer sleep time */
  153.  
  154. /*
  155. * Code
  156. */
  157. .section .text
  158. .org 0
  159. rjmp RESET ; RESET handle
  160. reti ; INT0
  161. reti ; PCI0
  162. reti ; OC1
  163. reti ; OVF1
  164. reti ; OVF0
  165. reti ; ERDY
  166. reti ; ACI
  167. reti ; ADCC
  168. /*
  169. * Main
  170. */
  171. RESET:
  172. in mcusr_sv,MCUSR ; save MCUSR for test of watchdog timer reset
  173. sbrc mcusr_sv,WDRF ; skip if not wdt reset (power up first time)
  174. rjmp INIT ; jump if watchdog reset (wake up from sleep)
  175. clr chrg_cnt ; clear counter of charging times (start next cycle)
  176. ; rcall chrg_ld ; load charge counter with initial value
  177. clr status ; clear status indication
  178. clr wdr_cnt ; clear wdr status
  179. INIT:
  180. ldi ZH,hi8(pm(FLASHEND))
  181. ldi ZL,lo8(pm(FLASHEND)); get OSCCAL calibration value
  182. lpm ; read from ROM(Z)->R0
  183. out OSCCAL,zero ; set oscillator calibration
  184. clr zero ; setup zero register (lpm destroys zero reg!!)
  185. out MCUSR,zero ; clear MCUSR
  186.  
  187. out PORTB,zero ; clear output port
  188. ldi accl,0b00000010 ; Bit 0 as input (check if LED is tied to VCC => allways on)
  189. out DDRB,accl ; set LED as input, MOSFET GATE as output.
  190.  
  191. sbic PINB,PORTB0 ; skip if not connected to VCC
  192. rjmp LIGHT_SETUP ; jump directly to light if link 2-4 in ISP
  193.  
  194. ldi accl,0b00000011
  195. out DDRB,accl ; set status LED/MOSFET GATE as outputs
  196. TSLEEP:
  197. ldi accl,0b00110000 ; Sleep enable, power down mode
  198. out MCUCR,accl
  199. tst status ; first display status indication
  200. breq TSLEEP100 ; status display is over
  201. brpl TSLEEP010 ; branch if status.7 is cleared
  202. cbr status,0x80 ; clear status.7
  203. tst status ; is status >0
  204. breq TSLEEP001 ; if not end
  205. dec status ; else decrement status
  206. TSLEEP001:
  207. ldi accl,0b00001011 ; WDT EN, div by 128K - 200ms @ 3.6
  208. out WDTCR,accl ; start watchdog timer and wait about 4 seconds
  209. wdr
  210. sleep
  211. nop
  212. TSLEEP010:
  213. sbi PORTB,PORTB0 ; set LED on
  214. sbr status,0x80 ; set status.7
  215. ldi accl,0b00001011 ; WDT EN, div by 128K - 200ms @ 3.6
  216. out WDTCR,accl ; start watchdog timer and wait about 4 seconds
  217. wdr
  218. sleep
  219. nop
  220. TSLEEP100:
  221. tst wdr_cnt ; check if must go back to sleep
  222. breq BEGIN ; sleep time is over
  223. dec wdr_cnt ; decrement watchdog cycle counter
  224. ldi accl,0b00001111 ; WDT EN, div by 2048K
  225. out WDTCR,accl ; start watchdog timer and wait about 4 seconds
  226. wdr
  227. sleep
  228. nop ; never reached!
  229. BEGIN:
  230. sei ; enable interrupts (ADCC is used for wakeup)
  231. clr status ; if forced on status is zero (also is reset here)
  232. rcall sample ; sample light values
  233. ; ***** Conditional Assembly *****
  234. ; with 4 batteries max voltage would be 6 V, this would fry the CPU disable external power
  235. #ifndef BAT4
  236. cpi vbat,VINEXT ; test if Vbat is over battery limits (external charger)
  237. brlo BEGIN_001 ; vbat is lower, continue in normal mode
  238. ldi status,ST_EXT ; set status as external power
  239. cpi vsun,VSUNMIN ; compare with minimum sun
  240. brsh deep_sleep ; sun is high, don't turn on
  241. rjmp LIGHT_SETUP ; turn on the light
  242. #endif
  243. ; ***** Conditional Assembly *****
  244. ;
  245. BEGIN_001:
  246. cp vsun,vbat ; test vsun-vbat
  247. brlo LIGHT ; if vsun is lower than vbat -> not charging
  248. mov accl,vsun
  249. sub accl,vbat ; accl = vsun-vbat
  250. cpi accl,VCHRG ; accl-VCHRG
  251. brlo LIGHT ; branch if lower check Light
  252. ldi status,ST_CHRG ; set status to charge
  253. rcall chrg_dec ; decrement counter
  254. brne BEGIN_000 ; skip if conter is not zero
  255. ldi status,ST_CHRG1 ; status is charge more than one hour
  256. BEGIN_000:
  257. rjmp deep_sleep ; if charging Vsun is too high
  258. LIGHT:
  259. cpi vbat,VBATOPR ; check if enough battery to start a discharge
  260. brsh LIGHT_000 ; jump if >=
  261. ldi status,ST_LOWB ; set LOWBAT status
  262. rjmp deep_sleep ; wait another counter period
  263. LIGHT_000:
  264. cpi vsun,VSUNMIN ; check if Vsun below 1V
  265. brlo LIGHT_001 ; light on if lower
  266. ldi status,ST_SUN ; Sun is high
  267. rjmp deep_sleep ; else deep sleep
  268. LIGHT_001:
  269. ldi status,ST_OPR ; status is operating (but could stop on failure)
  270. tst chrg_cnt ; test for zero
  271. breq LIGHT_SETUP ; enough charge time
  272. ldi status,ST_NCHRG ; set status not enough charge time
  273. rjmp deep_sleep ; if != 0 deep_sleep
  274. LIGHT_SETUP:
  275. rcall chrg_ld ; reload counter
  276. ldi accl,0b01100010 ; PWM mode, non inverted PWM,PCK/2
  277. out TCCR1,accl
  278. ser accl
  279. out OCR1B,accl ; set OCR1B=0hFF, PWM frequency 50KHz
  280. ldi accl,PWMREF
  281. out OCR1A,accl ; reference duty cycle
  282. mov pwm,accl ; set pwm
  283. LIGHT_ON:
  284. rcall sample ; sample analog values
  285. rcall set_ref ; set led vref function of battery voltage
  286.  
  287. cpi vbat,VBATMIN ; if vbatt < vbatt min
  288. brlo deep_sleep
  289. cpi vsun,VSUNMIN ; if Vsun > vsun min , sun shinning
  290. brsh deep_sleep
  291. cpi vled,VLEDMAX ; if Vled > vled max
  292. brsh deep_sleep ; emergency shutdown - LED is open !!
  293. ; adjusting pwm
  294. cp vled,vref
  295. breq LIGHT_ON ; branch if vled == vref ...stable just continue...
  296. brsh LIGHT_ON_000 ; branch if vled >= VLEDREF
  297.  
  298. cpi pwm,PWMMAX
  299. brsh LIGHT_ON_001 ; branch if pwm >= PWMMAX
  300. inc pwm
  301. rjmp LIGHT_ON_001
  302.  
  303. LIGHT_ON_000:
  304. cpi pwm,PWMMIN
  305. brlo LIGHT_ON_001 ; branch if pwm < PWMMIN
  306. dec pwm
  307. LIGHT_ON_001:
  308. out OCR1A,pwm ; update pwm register
  309. rjmp LIGHT_ON ; loop
  310.  
  311. ;***************************************************************************
  312. ;* Functions
  313. ;***************************************************************************
  314. ;* Function : Deep Sleep
  315. ;* Description : shuts down all systems and displays last status at LED PB0.
  316. ;* Code Size : Words
  317. ;* Low Reg Used : R0
  318. ;* High Reg Used: R16 (accl),R17 (acch), R23 (status)
  319. ;* Interrupts : Timer0_overflow
  320. deep_sleep:
  321. cli ; disable interrupts... forever...
  322. out TCCR1,zero ; stop timer
  323. out PORTB,zero ; clear all outputs
  324. out ADCSR,zero ; power off ADC
  325. ldi wdr_cnt,WD_REP ; about a minute
  326. ldi accl,0b00110000 ; Sleep enable, Power Down Mode
  327. out MCUCR,accl
  328. ldi accl,0b00001111 ; WDT EN, div by 2048K
  329. out WDTCR,accl ; start watchdog timer and wait about 4 seconds
  330. wdr
  331. deep_sleep_200:
  332. sleep ; code should never continue from here
  333. rjmp deep_sleep_200 ; once you're here should be the watchdog to wake me up
  334. ;***************************************************************************
  335. ;* Function : Sample
  336. ;* Description : sample 3 analog inputs, store MSB of conversion in registers
  337. ;* : use only 8 bits of the conversion for reduced complexity
  338. ;* : Value = Vin*(10/(10+10))/(2.56/256)
  339. ;* : 1LSB = 20mV
  340. ;* Code Size : 22 Words
  341. ;* Cycles : 108 + conversion time!
  342. ;* Low Reg Used : R4,R5,R6 (results of conversion)
  343. ;* High Reg Used: R16 (acc)
  344. ;* Interrupts : None
  345. ;* Notes: - all conversions are extended (change of channel) according to datasheet pg 45
  346. ;* sample and hold is 13.5 cy, total conversion in 25 cy. currently ADC clock is CK/128,
  347. ;* could be changed for system stability to CK/2,CK/4|8|16|32|64|128 in ADCSR
  348. ;* (0bxxxx_x000,010,011,100,101,110,111) current setting CK/128 ADCSR =0bxxxx_x111.
  349. ;* - in order to smooth out measurements of the battery and output voltage and
  350. ;* average is made V(n) = (V(n) + V(n-1))/2
  351. ;* Changes Sleep Mode to Enabled and noise reduction mode selected
  352. ;*
  353. sample:
  354. ldi accl,0b00101000 ; Sleep enable, ADC Noise Reduction Mode
  355. out MCUCR,accl
  356. ldi accl,0b10100001 ; select PB2/Vbat, ADLAR=1 (Left justified), Vref=2.56V
  357. out ADMUX,accl
  358. ldi accl,0b10001111 ; Enable, Int Enable, CK/128 *
  359. out ADCSR,accl
  360. sleep ; wait quietly for end of conversion
  361.  
  362. in accl,ADCH
  363. add vbat,accl ; V(n) + V(n-1)
  364. ror vbat ; /2 and store conversion result
  365.  
  366. ldi accl,0b10100010 ; select PB3/Vled, ADLAR=1 (Left justified), Vref=2.56V
  367. out ADMUX,accl
  368. ldi accl,0b10001111 ; Enable, Int Enable, CK/128 *
  369. out ADCSR,accl
  370. sleep ; wait quietly for end of conversion
  371.  
  372. in accl,ADCH
  373. add vled,accl ; V(n) + V(n-1)
  374. ror vled ; /2 and store conversion result
  375.  
  376. ldi accl,0b10100011 ; select PB4/Vsun, ADLAR=1 (Left justified), Vref=2.56V
  377. out ADMUX,accl
  378. ldi accl,0b10001111 ; Enable, Int Enable, CK/128 *
  379. out ADCSR,accl
  380. sleep ; wait quietly for end of conversion
  381.  
  382. in accl,ADCH
  383. add vsun,accl ; V(n) + V(n-1)
  384. ror vsun ; /2 and store conversion result
  385. ret
  386. ;***************************************************************************
  387. ;* Function : Set Reference Output Voltage
  388. ;* Description : dependent on battery voltage select output voltage -> and power
  389. ;* Code Size : Words
  390. ;* Low Reg Used : R19(vbat),R21(vtrg)
  391. ;* High Reg Used: R16 (accl)
  392. ;* Interrupts : None
  393. ;* Notes: due to inductor limitation we can never go to full power on a charged
  394. ;* battery (it would also mean 1A input!), we start at 75% and then go down in
  395. ;* steps of 25%
  396. set_ref:
  397. cpi vbat,VBATFUL ; if vbatt < vbatt full
  398. brlo set_ref_000 ; jump to next test
  399. ldi vref,VLED75 ; else set for 75% power
  400. ret
  401. set_ref_000:
  402. cpi vbat,VBATOPR ; if vbatt < vbatt Operating
  403. brlo set_ref_001 ; jump to next test
  404. ldi vref,VLED50 ; else set for 50% power
  405. ret
  406. set_ref_001:
  407. ldi vref,VLED25 ; set to 25% power
  408. ret
  409. ;* Function : Charge Counter Load
  410. ;* Description : Load counter with reload value
  411. ;* Code Size : 3 Words
  412. ;* Low Reg Used : R7 (Charge counter)
  413. ;* High Reg Used: R16 (accl)
  414. ;* Interrupts : None
  415. chrg_ld:
  416. ldi accl,CNT_CHRG ; if power on reset or end of light on cycle
  417. mov chrg_cnt,accl
  418. ret
  419. ;* Function : 8 bit decrement / Zero?
  420. ;* Description : decrement counter (if > 0), Z set if Zero
  421. ;* Code Size : 12 Words
  422. ;* Low Reg Used : R7 (Charge counter)
  423. ;* High Reg Used: R16
  424. ;* Interrupts : None
  425. chrg_dec:
  426. tst chrg_cnt ; test for zero, return with Z set
  427. brne chrg_dec_000 ; skip return if non zero
  428. ret ; return with Z set
  429. chrg_dec_000:
  430. dec chrg_cnt ; decrement number of cycles
  431. ret
  432.  
  433. ;***** DEBUG *****
  434. .IFDEF DEBUG
  435. ;* Function : DEBUG OUTPUT
  436. ;* Description : outputs in the LED pin 1 byte coded as FM clock+data(0,1) MSB first
  437. ;* Code Size : 25 Words
  438. ;* Low Reg Used : None
  439. ;* High Reg Used: R29,R28
  440. ;* Interrupts : None
  441. dbug:
  442. ldi DB_CNT,8 ; output 8 bits [1]
  443. sbi DDRB,PORTB0 ; always do it [2]
  444. sbi PORTB,PORTB0 ; start bit longer than normal 1 [2]
  445. nop
  446. nop
  447. nop
  448. nop
  449. cbi PORTB,PORTB0 ; short break, begin of data [2]
  450. dbug_000:
  451. rol DEBUG ; bit7 -> C [1]
  452. brcc dbug_001 ; branch if C=0 [2] non taken [1]
  453. sbi PORTB,PORTB0 ; send a one [2]
  454. cbi PORTB,PORTB0
  455. sbi PORTB,PORTB0 ; send a one [2]
  456. cbi PORTB,PORTB0
  457. rjmp dbug_002 ; [2]
  458. dbug_001:
  459. sbi PORTB,PORTB0 ; send a one [2]
  460. cbi PORTB,PORTB0
  461. nop
  462. nop
  463. nop
  464. nop
  465. nop
  466. dbug_002:
  467. dec DB_CNT ; [1]
  468. brne dbug_000 ; [1] false, [2] taken
  469. ret
  470. .ENDIF
  471. ;***** DEBUG *****
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement