Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;-------------------------------------------------------------------------------
- ; Throbber.S - ATtiny85 PWM throbber for an illuminated dildo
- ;-------------------------------------------------------------------------------
- ;
- ; Author: Daniel Neville (creamygoat@gmail.com)
- ; Date: 1 April 2017
- ; Licence: Public domain
- ; Version: 1.0.0
- ;
- ; PIN ASSIGNMENT
- ; ____
- ; ~RESET 1| AT |8 Vcc
- ; NC 2|tiny|7 NC
- ; NC 3| 85 |6 PWMOUT
- ; GND 4|____|5 NC
- ;
- ;-------------------------------------------------------------------------------
- ; Notes
- ;-------------------------------------------------------------------------------
- ;
- ; Fuses:
- ; Low fuse: 0x62 (7:CKDIV8, 4:SUT0, 3-0:CKSEL=8MHz RC, 1MHz system clock)
- ; High fuse: 0xdf (5:SPIEN) 0xd7 (6:SPIEN, 3:EESAVE)
- ; Extended fuse: 0xff
- ;
- ; Fuse programming
- ; avrdude -p t85 -c usbasp -U lfuse:w:0x62:m
- ; avrdude -p t85 -c usbasp -U hfuse:w:0xdf:m
- ; avrdude -p t85 -c usbasp -U efuse:w:0xff:m
- ;
- ; Compiling, inspecting and programming:
- ;
- ; avr-gcc -mmcu=attiny85 -o Throbber.o Throbber.S
- ; avr-objdump -C -d Throbber.o
- ; avr-ld -o Throbber.elf Throbber.o
- ; avr-objcopy -O ihex Throbber.elf Throbber.hex
- ; avrdude -p t85 -c usbasp -U flash:w:Throbber.hex:i
- ;
- ;-------------------------------------------------------------------------------
- ;-------------------------------------------------------------------------------
- ; Index
- ;-------------------------------------------------------------------------------
- ; Imports
- ; Exports
- ; Constants
- ; Structures
- ; Macros
- ;
- ; Interrupt handlers
- ; __vector_default
- ; TIM1_OVF_vect
- ;
- ; Initialisation
- ; InitialiseRegisterConstants
- ; InitialiseHardware
- ; ClearGlobals
- ;
- ; main
- ;
- ; Data in program memory
- ;
- ; PM_ThrobTable
- ;
- ; Globals in SRAM
- ;-------------------------------------------------------------------------------
- ; Imports
- ;-------------------------------------------------------------------------------
- #include <avr/common.h>
- #include <avr/io.h>
- ;-------------------------------------------------------------------------------
- ; Exports
- ;-------------------------------------------------------------------------------
- .global main
- .global __vector_default
- .global TIM1_OVF_vect
- ;-------------------------------------------------------------------------------
- ; Constants
- ;-------------------------------------------------------------------------------
- ; Inputs and outputs
- OUTPUT_BIT_PWM_OUT = 0 ; Fixed at 5:OC1A
- THROB_INDEX_BITS = 8
- THROB_INDEX_RANGE = 1 << THROB_INDEX_BITS
- THROB_INDEX_MASK = THROB_INDEX_RANGE - 1
- ; The Timer 1 output compare register C sets the throbbing rate.
- ; Sensible values range from about 12 (0.21s) to 255 (4.2s).
- ; Nice defaults include 91 (1.5s, 40bpm) and 182 (3.0s, 20bpm).
- THROB_INTERRUPT_PERIOD_MINUS_ONE = 91
- ;-------------------------------------------------------------------------------
- ; Structures
- ;-------------------------------------------------------------------------------
- G_ThrobIndex = 0
- GSize = G_ThrobIndex + 1
- ;-------------------------------------------------------------------------------
- ; Macros
- ;-------------------------------------------------------------------------------
- ; Conditional execution of the following one-word instruction
- .macro ifcc
- brcs . + 2
- .endm
- .macro ifcs
- brcc . + 2
- .endm
- .macro ifne
- breq . + 2
- .endm
- .macro ifeq
- brne . + 2
- .endm
- .macro ifpl
- brmi . + 2
- .endm
- .macro ifmi
- brpl . + 2
- .endm
- .macro ifvc
- brvs . + 2
- .endm
- .macro ifvs
- brvc . + 2
- .endm
- .macro iflt
- brge . + 2
- .endm
- .macro ifge
- brlt . + 2
- .endm
- .macro ifhc
- brhs . + 2
- .endm
- .macro ifhs
- brhc . + 2
- .endm
- .macro iftc
- brts . + 2
- .endm
- .macro ifts
- brtc . + 2
- .endm
- .macro ifid
- brie . + 2
- .endm
- .macro ifie
- brid . + 2
- .endm
- .macro iflo
- brsh . + 2
- .endm
- .macro ifsh
- brlo . + 2
- .endm
- .macro ifbs
- brbc . + 2
- .endm
- .macro ifbc
- brbs . + 2
- .endm
- ;-------------------------------------------------------------------------------
- ; Positive-sense register and I/O bit tests
- .macro ifbrc a:req, b:req
- sbrs \a, \b
- .endm
- .macro ifbrs a:req, b:req
- sbrc \a, \b
- .endm
- .macro ifbic a:req, b:req
- sbis \a, \b
- .endm
- .macro ifbis a:req, b:req
- sbic \a, \b
- .endm
- ;-------------------------------------------------------------------------------
- ; Load high & low 8-bit registers with one 16-bit word
- .macro ldhl a:req, b:req, c:req
- ldi \b, lo8(\c)
- ldi \a, hi8(\c)
- .endm
- ;-------------------------------------------------------------------------------
- ; Load immediate word
- .macro ldiw a:req, b:req
- .ifc \a, r17:r16
- ldhl r17, r16, \b
- .else
- .ifc \a, r19:r18
- ldhl r19, r18, \b
- .else
- .ifc \a, r21:r20
- ldhl r21, r20, \b
- .else
- .ifc \a, r23:r22
- ldhl r23, r22, \b
- .else
- .ifc \a, r25:r24
- ldhl r25, r24, \b
- .else
- .ifc \a, r27:r26
- ldhl XH, XL, \b
- .else
- .ifc \a, r29:r28
- ldhl YH, YL, \b
- .else
- .ifc \a, r31:r30
- ldhl ZH, ZL, \b
- .else
- .ifc \a, X
- ldhl XH, XL, \b
- .else
- .ifc \a, Y
- ldhl YH, YL, \b
- .else
- .ifc \a, Z
- ldhl ZH, ZL, \b
- .else
- .error "Expected LDIW R, x where R is X, Y, Z or a register pair."
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endm
- ;-------------------------------------------------------------------------------
- .macro scmd a:req, b
- .ifnb \b
- .ifc \a, rest
- .byte WSCMD_REST, (\b) & 255, (\b) >> 8
- .else
- .ifc \a, duration
- .byte WSCMD_DURATION, (\b) & 255, (\b) >> 8
- .else
- .ifc \a, waveix
- .byte WSCMD_WAVEIX, \b
- .else
- .ifc \a, volume
- .byte WSCMD_VOLUME, \b
- .else
- .ifc \a, frequency
- .byte WSCMD_FREQUENCY, (\b) & 255, (\b) >> 8
- .else
- .ifc \a, sweeprate
- .byte WSCMD_SWEEPRATE, (\b) & 255, ((\b) >> 8) & 255
- .else
- .ifc \a, phase
- .byte WSCMD_PHASE, \b
- .else
- .error "Invalid track command name."
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .endif
- .else
- .ifc \a, end
- .byte WSCMD_END
- .else
- .error "Parameter required for this track command."
- .endif
- .endif
- .endm
- ;-------------------------------------------------------------------------------
- .section .text
- ;-------------------------------------------------------------------------------
- ;-------------------------------------------------------------------------------
- ; Interrupt handlers
- ;-------------------------------------------------------------------------------
- __vector_default:
- reti
- ;-------------------------------------------------------------------------------
- TIM1_OVF_vect:
- ; Timber 1 overflow nterrupt handler
- ;
- ; Fetches a new PWM value from the Throb Table through an index and increments
- ; that index by one, wrapping around when the end is reached.
- push r1
- push r16
- push ZL
- push ZH
- in r16, _SFR_IO_ADDR(SREG)
- push r16
- clr r1
- lds ZH, Globals + G_ThrobIndex
- andi ZH, THROB_INDEX_MASK
- mov r16, ZH
- inc ZH
- andi ZH, THROB_INDEX_MASK
- sts Globals + G_ThrobIndex, ZH
- ldiw Z, PM_ThrobTable
- add ZL, r16
- adc ZH, r1
- lpm r16, Z
- out _SFR_IO_ADDR(OCR0A), r16
- pop r16
- out _SFR_IO_ADDR(SREG), r16
- pop ZH
- pop ZL
- pop r16
- pop r1
- reti
- ; 49 cycles, including entry
- ;-------------------------------------------------------------------------------
- ; Initialisation
- ;-------------------------------------------------------------------------------
- InitialiseRegisterConstants:
- ; Out: r1 = 0
- ; r2 = 1
- ; r3 = 255
- ; Y = Globals
- ; r1 = 0
- clr r1
- ; r2 = 1, handy for carry-changing inc/dec via add/sub.
- clr r2
- inc r2
- ; r3 = 255 for sign extension.
- clr r3
- dec r3
- ldiw Y, Globals
- ret
- ;-------------------------------------------------------------------------------
- InitialiseHardware:
- ; No interrupts!
- cli
- ; Clear the watchdog reset flag so that it doesn't
- ; disable the watchdog timer.
- in r16, _SFR_IO_ADDR(MCUSR)
- andi r16, ~(1 << WDRF)
- out _SFR_IO_ADDR(MCUSR), r16
- ; Start the watchdog timer and have it force a reset of the CPU if
- ; the timer isn't reset at least once every 0.25 seconds.
- in r16, _SFR_IO_ADDR(WDTCR)
- ori r16, (1 << WDCE) | (1 << WDE)
- mov r17, r16
- andi r17, ~((1 << WDCE) | (1 << WDP3) | (0b111 << WDP0))
- ori r17, (1 << WDE) | (0 << WDP3) | (0b100 << WDP0)
- out _SFR_IO_ADDR(WDTCR), r16
- out _SFR_IO_ADDR(WDTCR), r17
- ; Halt and configure Timer/Counter 0 to run at 125kHz,
- ; producing 488.3Hz PWM on Pin 5:OC0A
- ;
- ; TCCR0A.COM0A[1:0] = 0b10 => Output high, then low for PWM
- ; TCCR0A.WGM0[1:0] = 0b11 (WGM0 = 0b011 => Fast PWM)
- ; TCCR0B.CS0[2:0] = 0x010 => Clk_IO/8 (125kHz)
- ; TCNT0 = 0
- ; OCR0A = 0
- ; OCR0C is not used, as CTC0 is left disabled.
- ldi r18, (1 << TSM) | (1 << PSR0)
- out _SFR_IO_ADDR(GTCCR), r18
- ldi r18, (0b10 << COM0A0) | (0b11 << WGM00)
- out _SFR_IO_ADDR(TCCR0A), r18
- ldi r18, (0 << WGM02) | (0b010 << CS00)
- out _SFR_IO_ADDR(TCCR0B), r18
- out _SFR_IO_ADDR(TCNT0), r1
- ; Start the counting.
- out _SFR_IO_ADDR(GTCCR), r1
- ; Configure Timer/Counter 1 to run at 15.625kHz,
- ; producing f = 61.035Hz when C is set to 255
- ; where f = Timer_frequency / (C + 1).
- ; For a 256 byte throb table, C = 255 implies a throb rate of 0.2384Hz.
- ;
- ; OCR1C = 255
- ; OCR1A = 255
- ; TCCR1.CTC = 1 => C modifies frequency
- ; TCCR1.PWM1A = 1 => PWM enabled (else interrupt won't work)
- ; TCCR1.COM1A[1:0] = 0b00 => No output
- ; TCCR1.CS1[3:0] = 0b0111 => Clk_IO/64 (15.625kHz)
- ; TCNT1 = 0
- out _SFR_IO_ADDR(OCR1A), r3
- ldi r18, THROB_INTERRUPT_PERIOD_MINUS_ONE
- out _SFR_IO_ADDR(OCR1C), r18
- ldi r18, (1 << CTC1) | (1 << PWM1A) | (0b0111 << CS10)
- out _SFR_IO_ADDR(TCCR1), r18
- out _SFR_IO_ADDR(TCNT1), r1
- ; Enable Timer 1 to generate interrupts on match with C.
- ldi r18, (1 << TOIE1)
- out _SFR_IO_ADDR(TIMSK), r18
- ; Set Data Direction and pull-ups
- ; 2:PB3 is unused, pulled high
- ; 3:PB4 is unused, pulled high
- ; 5:PB1 is output (PWM ouput)
- ; 6:PB0 is unused, pulled high
- ; 7:PB2 is unused, pulled high
- ldi r18, (0b011111 & ~(1 << OUTPUT_BIT_PWM_OUT))
- ldi r19, (1 << OUTPUT_BIT_PWM_OUT)
- out _SFR_IO_ADDR(PORTB), r18
- out _SFR_IO_ADDR(DDRB), r19
- ; Disable digital input buffers to avoid floating inputs
- ; and save power.
- ldi r18, 0b011111
- out _SFR_IO_ADDR(DIDR0), r18
- ; Save power by turning off the ADC module. (It is already disabled.)
- ; The Universal Serial Interface module can be disabled, too.
- ldi r18, (1 << PRADC); | (1 << PRUSI)
- out _SFR_IO_ADDR(PRR), r18
- ret
- ;-------------------------------------------------------------------------------
- ClearGlobals:
- ldi r18, (GlobalsEnd - Globals)
- tst r18
- breq 2f
- movw ZL, YL
- 1: st Z+, r1
- dec r18
- brne 1b
- 2:
- ret
- ;-------------------------------------------------------------------------------
- ; main
- ;-------------------------------------------------------------------------------
- main:
- rcall InitialiseRegisterConstants
- rcall InitialiseHardware
- rcall ClearGlobals
- ; Enable interrupts
- sei
- main_Loop:
- ldi r18, (0 << BODS) | (1 << SE) | (0b00 << SM0) | (0 << BODSE)
- out _SFR_IO_ADDR(MCUCR), r18
- sleep
- ; An interrupt occurred. Keep the watchdog happy, then.
- wdr
- rjmp main_Loop
- ;-------------------------------------------------------------------------------
- ; Data in program memory
- ;-------------------------------------------------------------------------------
- PM_ThrobTable:
- ; y = (0.5 + 0.5 * (0.5 - 0.5 * cos(x))) ^ 2.2
- .byte 55,56,56,56,56,56,56,56
- .byte 57,57,57,58,58,59,59,60
- .byte 60,61,62,62,63,64,65,65
- .byte 66,67,68,69,70,71,73,74
- .byte 75,76,78,79,80,82,83,85
- .byte 86,88,90,91,93,95,97,98
- .byte 100,102,104,106,108,110,112,115
- .byte 117,119,121,124,126,128,131,133
- .byte 135,138,140,143,145,148,150,153
- .byte 156,158,161,163,166,169,171,174
- .byte 176,179,182,184,187,189,192,194
- .byte 197,199,202,204,207,209,211,213
- .byte 216,218,220,222,224,226,228,230
- .byte 232,234,235,237,239,240,242,243
- .byte 244,246,247,248,249,250,251,252
- .byte 252,253,253,254,254,255,255,255
- .byte 255,255,255,255,254,254,253,253
- .byte 252,252,251,250,249,248,247,246
- .byte 244,243,242,240,239,237,235,234
- .byte 232,230,228,226,224,222,220,218
- .byte 216,213,211,209,207,204,202,199
- .byte 197,194,192,189,187,184,182,179
- .byte 176,174,171,169,166,163,161,158
- .byte 156,153,150,148,145,143,140,138
- .byte 135,133,131,128,126,124,121,119
- .byte 117,115,112,110,108,106,104,102
- .byte 100,98,97,95,93,91,90,88
- .byte 86,85,83,82,80,79,78,76
- .byte 75,74,73,71,70,69,68,67
- .byte 66,65,65,64,63,62,62,61
- .byte 60,60,59,59,58,58,57,57
- .byte 57,56,56,56,56,56,56,56
- .if 0
- ; y = (0.4999 * ((0.4 + 0.6 * (0.5 - 0.5 * cos(x)))) ^ 2.2)
- .byte 17,17,17,17,17,17,17,17
- .byte 18,18,18,18,18,18,19,19
- .byte 19,19,20,20,20,21,21,22
- .byte 22,23,23,23,24,25,25,26
- .byte 26,27,28,28,29,30,30,31
- .byte 32,33,34,35,35,36,37,38
- .byte 39,40,41,42,43,45,46,47
- .byte 48,49,50,52,53,54,56,57
- .byte 58,60,61,62,64,65,67,68
- .byte 69,71,72,74,75,77,78,80
- .byte 81,83,84,86,87,89,90,92
- .byte 93,94,96,97,99,100,101,103
- .byte 104,105,107,108,109,110,112,113
- .byte 114,115,116,117,118,119,120,120
- .byte 121,122,123,123,124,124,125,125
- .byte 126,126,127,127,127,127,127,127
- .byte 127,127,127,127,127,127,127,126
- .byte 126,125,125,124,124,123,123,122
- .byte 121,120,120,119,118,117,116,115
- .byte 114,113,112,110,109,108,107,105
- .byte 104,103,101,100,99,97,96,94
- .byte 93,92,90,89,87,86,84,83
- .byte 81,80,78,77,75,74,72,71
- .byte 69,68,67,65,64,62,61,60
- .byte 58,57,56,54,53,52,50,49
- .byte 48,47,46,45,43,42,41,40
- .byte 39,38,37,36,35,35,34,33
- .byte 32,31,30,30,29,28,28,27
- .byte 26,26,25,25,24,23,23,23
- .byte 22,22,21,21,20,20,20,19
- .byte 19,19,19,18,18,18,18,18
- .byte 18,17,17,17,17,17,17,17
- ; y = (0.5 - 0.5 * cos(x)) ^ 2.2
- .byte 0,0,0,0,0,0,0,0
- .byte 0,0,0,0,0,0,0,0
- .byte 0,0,0,0,1,1,1,1
- .byte 1,1,2,2,2,2,3,3
- .byte 4,4,5,5,6,7,8,8
- .byte 9,10,11,12,14,15,16,18
- .byte 19,21,22,24,26,28,30,32
- .byte 34,37,39,42,44,47,50,53
- .byte 55,59,62,65,68,72,75,79
- .byte 82,86,90,93,97,101,105,109
- .byte 113,117,121,126,130,134,138,142
- .byte 147,151,155,159,164,168,172,176
- .byte 180,184,188,192,196,199,203,207
- .byte 210,213,217,220,223,226,229,232
- .byte 234,237,239,241,243,245,247,248
- .byte 250,251,252,253,254,254,255,255
- .byte 255,255,255,254,254,253,252,251
- .byte 250,248,247,245,243,241,239,237
- .byte 234,232,229,226,223,220,217,213
- .byte 210,207,203,199,196,192,188,184
- .byte 180,176,172,168,164,159,155,151
- .byte 147,142,138,134,130,126,121,117
- .byte 113,109,105,101,97,93,90,86
- .byte 82,79,75,72,68,65,62,59
- .byte 55,53,50,47,44,42,39,37
- .byte 34,32,30,28,26,24,22,21
- .byte 19,18,16,15,14,12,11,10
- .byte 9,8,8,7,6,5,5,4
- .byte 4,3,3,2,2,2,2,1
- .byte 1,1,1,1,1,0,0,0
- .byte 0,0,0,0,0,0,0,0
- .byte 0,0,0,0,0,0,0,0
- .endif
- ;-------------------------------------------------------------------------------
- .section .bss
- ;-------------------------------------------------------------------------------
- ;-------------------------------------------------------------------------------
- ; Globals in SRAM
- ;-------------------------------------------------------------------------------
- Globals:
- .fill GSize
- GlobalsEnd:
- ;-------------------------------------------------------------------------------
- .end
- ;-------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement