; ; ANY-LICENSE V1.0 ; ---------------- ; ; You can use these files under any license approved by the ; Open Source Initiative, preferrably one of the popular licenses, ; as long as the license you choose is compatible to the ; dependencies of these files. ; ; See http://www.opensource.org/licenses/ for a list of ; approved licenses. ; ; Author: Martin Furter ; Project: Tins AVR Lib ; Repository: http://repos.borg.ch/projects/tins_avr_lib/trunk ; Copyright: 2007,2009,2013,2014,2015 ; ; ; ANY-LICENSE V1.0 ; ---------------- ; ; You can use these files under any license approved by the ; Open Source Initiative, preferrably one of the popular licenses, ; as long as the license you choose is compatible to the ; dependencies of these files. ; ; See http://www.opensource.org/licenses/ for a list of ; approved licenses. ; ; Author: Martin Furter ; Project: ; Modified: 2016 ; ; ; ANY-LICENSE V1.0 ; ---------------- ; ; You can use these files under any license approved by the ; Open Source Initiative, preferrably one of the popular licenses, ; as long as the license you choose is compatible to the ; dependencies of these files. ; ; See http://www.opensource.org/licenses/ for a list of ; approved licenses. ; ; Author: Martin Furter ; Project: ; Modified: 2015 ; ; ; Initialize and synchronize timers. ; ; The OCR values should be initialized before calling init_timers(). ; The DDR are not initialized by this function. ; ; AVR model: atmega 48/88/168 ; prescaler: 64 ; mode: pwm ; output compare: clear on compare match, set at bottom ; ; PWM Frequency: ; 18.432MHz -> 1125Hz ; 14.7456MHz -> 900Hz ; ; In C make following function prototype: ; void init_timers( uint8_t enable, uint8_t invert ); ; enable -> r24 ; invert -> r22 ; #include .section .text .global init_timers .type init_timers, @function ; r24 paramter 1: uint8_t inv_pwm 0=normal, >0=inverted PWM init_timers: ; save registers push r16 push r17 push r18 push r19 ; stop timer 0 and 1, reset prescaler ldi r16, 0x81 out _SFR_IO_ADDR(GTCCR), r16 ; initialize zero register, used later clr r19 ; clear invert bit if enable bit is cleared and r22, r24 ; init timer 0 ; set WGM0x values ldi r16, 0x03 ; get COM0xx values rcall .SHIFT_COM_VALUES ; store into TCCR0A sts _SFR_MEM_ADDR(TCCR0A), r16 ; initialize TCCR0B ldi r16, 0x03 sts _SFR_MEM_ADDR(TCCR0B), r16 ; init timer 1 ; set WGM1x values ldi r16, 0x01 ; get COM1xx values rcall .SHIFT_COM_VALUES ; store into TCCR1A sts _SFR_MEM_ADDR(TCCR1A), r16 ; initialize TCCR1B ldi r16, 0x0B sts _SFR_MEM_ADDR(TCCR1B), r16 ; init timer 2 ; set WGM2x values ldi r16, 0x03 ; get COM2xx values rcall .SHIFT_COM_VALUES ; store into TCCR2A sts _SFR_MEM_ADDR(TCCR2A), r16 ; initialize TCCR2B ldi r16, 0x04 sts _SFR_MEM_ADDR(TCCR2B), r16 ; find a change of TCNT2, we'll be a few cycles off lds r16, _SFR_MEM_ADDR(TCNT2) .TCNT2LOOP1: lds r17, _SFR_MEM_ADDR(TCNT2) cp r16, r17 breq .TCNT2LOOP1 ; now find the exact cycle when TCNT2 changed ; total cycles for the loop must be prescaler-1 = 63 .TCNT2LOOP2: mov r16, r17 ; cycles: 1 ldi r18, 14 ; cycles: 1 .TCNT2LOOP2A: nop ; cycles: 1 dec r18 ; cycles: 1 brne .TCNT2LOOP2A ; cycles: 1/2 ; total: 14*4-1 = 55 nop ; cycles: 1 lds r17, _SFR_MEM_ADDR(TCNT2) ; cycles: 2 cp r16, r17 ; cycles: 1 brne .TCNT2LOOP2 ; cycles: 1/2 ; offset is now 1 cycles ; delay until next increase of timer 2 ldi r18, 16 ; cycles: 1 .TCNT2LOOP3: nop ; cycles: 1 dec r18 ; cycles: 1 brne .TCNT2LOOP3 ; cycles: 1/2 ; total: 15*4-1 = 59 ; start timer 0 and 1 out _SFR_IO_ADDR(GTCCR), r19 ; reset all timer counters sts _SFR_MEM_ADDR(TCNT0), r19 sts _SFR_MEM_ADDR(TCNT1H), r19 sts _SFR_MEM_ADDR(TCNT1L), r19 sts _SFR_MEM_ADDR(TCNT2), r19 ; restore registers pop r19 pop r18 pop r17 pop r16 ret .SHIFT_COM_VALUES: ; start with zero ; clr r16 ; shift enable flag for COMxA1 asr r24 rol r16 ; shift invert flag for COMxA0 asr r22 rol r16 ; shift enable flag for COMxB1 asr r24 rol r16 ; shift invert flag for COMxB0 asr r22 rol r16 ; move bits into upper nibble swap r16 ; done. ret