SHARE
TWEET

SolarLight AVR Assembler

a guest Mar 13th, 2011 146 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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 *****
RAW Paste Data
Top