Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Name: main.S
- Project: Monster B Gone
- $Author$
- Creation Date: 2016-10-02
- Tabsize: 4
- Copyright: License: GNU GPL v2 (see License.txt)
- This Revision: $Id$
- $Log$
- */
- /*
- The code reads the calibration byte from the first eeprom address,
- put there by the Makefile during programming.
- Program first calls the random number generator, gets the number of
- pixel rolls to do in blue (minimum 3 tours).
- Frame pause should be bigger than 50ms, better between 100ms and
- 200ms.
- After all the rolls, stays green for 3 seconds, then shutsdown and
- sleeps until new reset.
- Driving the neopixel:
- Timer T1 works in PWM mode for driving a neopixel each clock
- with Timer 1 clock at 156.25ns. The rotine is tightly timed, disable
- ints and do nothing else.
- for latching and waiting uses T0 to sleep for 200ms.
- */
- #define __SFR_OFFSET 0
- #include <avr/io.h>
- #include <avr/eeprom.h>
- /*
- EEPROM
- */
- /*
- IO Definitions
- */
- #define NEOPIXEL PB1 /* output to neopixel data */
- #define ENABLE_5 PB0 /* enable 5V supply */
- /*
- Constants
- */
- #define ZERO 0
- #define num_leds 12 /* number of leds in the ring (up to 16) */
- /* Time system constants */
- /*
- Register definition, use only C-style comments (avr-as is stupid)
- */
- ; from R0-R15 only direct addressing
- #define zero R0 /* this register is always zero */
- #define rnd_a R1 /* random number generator register A */
- #define rnd_b R2 /* random number generator register B */
- #define rnd_c R3 /* random number generator register C */
- #define rnd_d R4 /* random number generator register D */
- #define rnd_xor R5 /* random number generator auxiliary register */
- #define G0 R6 /* working shift for green for ring */
- #define G1 R7
- #define R0 R8 /* working shift for red for ring */
- #define R1 R9
- #define B0 R10 /* working shift for blue for ring */
- #define B1 R11
- #define SEND0 R12 /* values to reload counters */
- #define SEND1 R13 /* values to reload counters */
- #define sw_prss R14 /* number of times reset pressed */
- ; from R16-R31 ldi possible
- #define wreg R16 /* working register */
- /* shifting colours in this order GRB, msb first */
- #define GREEN0 R17 /* intensity color for green 8 bits */
- #define GREEN1 R18
- #define RED0 R19 /* intensity for colour red */
- #define RED1 R20
- #define BLUE0 R21 /* intensity for colour blue */
- #define BLUE1 R22
- #define led_cnt R23 /* led counter */
- #define count R24 /* counter for number of rounds */
- #define count_t R25 /* counter for timing loop */
- /*
- Interrupt Routines
- */
- ;* Addresses of interrupt routines is defined in io.h (for this processor)
- ;.global INT0_vect
- ;.global IO_PINS_vect
- ;.global TIMER1_COMP_vect
- ;.global TIMER1_OVF_vect
- ;.global TIMER0_OVF_vect
- ;.global EE_RDY_vect
- ;.global ANA_COMP_vect
- ;.global ADC_vect
- .text
- ;*
- ;* Interrupt 0
- ;*
- .global INT0_vect
- INT0_vect:
- reti
- ;*
- ;* Pin change interrupt
- ;*
- .global IO_PINS_vect
- IO_PINS_vect:
- reti
- ;*
- ;* Interrupt Timer 1 Overflow
- ;*
- .global TIMER1_OVF_vect
- TIMER1_OVF_vect:
- reti
- ;*
- ;* Interrupt Timer 1 Compare
- ;*
- .global TIMER1_COMP_vect
- TIMER1_COMP_vect:
- reti
- ;*
- ;* Interrupt Timer 0 Overflow
- ;*
- .global TIMER0_OVF_vect
- TIMER0_OVF_vect:
- reti
- ;*
- ;* EEPROM ready interrupt
- ;*
- .global EE_RDY_vect
- EE_RDY_vect:
- reti
- ;.global ANA_COMP_vect
- ;*
- ;* Analog Comparator Interrupt
- ;*
- .global ANA_COMP_vect
- ANA_COMP_vect:
- reti
- ;*
- ;* ADC Converter, End of Convertion
- ;*
- .global ADC_vect
- ADC_vect:
- reti
- ;*
- ;* Main routine
- ;*
- .global main
- main:
- clr zero ; register zero is always zero
- start:
- rcall rnd_init ; check and correct locking value
- rcall random ; get a new random number
- rcall init_io ; initialize IO system and unmutable variables
- inc sw_prss ; increment number of pressed switches
- rcall wr_latch
- rcall wr_latch
- rcall wr_latch
- rcall wr_latch ; wait 800ms for a second reset
- mov wreg,sw_prss
- cpi wreg,0x3 ; if sw_press > 0x02
- brcc white_lgt ; jump white light
- seeking:
- mov count, rnd_a ; load lsb
- andi count, 0x0F ; max is 16
- inc count ; minimum 3 turns
- inc count
- inc count
- sk_bg_loop:
- ldi BLUE0,0x01 ; set one blue light on
- clr BLUE1
- clr GREEN0 ; clear all green
- clr GREEN1
- clr RED0 ; clear all red
- clr RED1
- sk_loop: ; seeking for monsters loop
- rcall wr_frame ; update
- rcall wr_latch
- mv_light: ;move the blue LED
- lsl BLUE0
- rol BLUE1
- mov wreg,BLUE1
- andi wreg,0xf0 ; test if at end of light loop
- brne mv_lg_nx ; if so start again
- rjmp sk_loop
- mv_lg_nx:
- dec count
- breq no_monster
- rjmp sk_bg_loop
- no_monster: ; everthing goes green
- clr sw_prss
- clr BLUE0
- clr BLUE1
- ldi wreg,0xff
- mov GREEN0,wreg
- mov GREEN1,wreg
- rcall wr_frame ; update
- rcall wr_latch
- ldi count_t,50 ; 5 * 10 * 200ms = 10s
- no_monst_10:
- rcall wr_latch
- dec count_t
- brne no_monst_10
- mov GREEN0,zero ; clear string
- mov GREEN1,zero
- rcall wr_frame ; update
- rcall wr_latch
- out PORTB,zero ; shut down converter
- ldi wreg,0x30
- out MCUCR,wreg ; sleep mode power-down
- sleep ; only leaves with reset
- nop
- ;*********************************************************************************************
- ;* white_lgt
- ;*********************************************************************************************
- white_lgt:
- clr sw_prss
- ldi wreg,0xff
- mov BLUE0,wreg ; all blue
- mov BLUE1,wreg
- mov GREEN0,wreg ; all green
- mov GREEN1,wreg
- mov RED0,wreg ; all red
- mov RED1,wreg
- rcall wr_frame ; update
- rcall wr_latch
- rcall wr_frame ; update
- rcall wr_latch
- ldi count_t,100 ; 100 * 200ms = 20s
- white_lgt_lp:
- rcall wr_latch
- dec count_t
- brne white_lgt_lp
- clr BLUE0 ; set one blue light on
- clr BLUE1
- clr GREEN0 ; clear all green
- clr GREEN1
- clr RED0 ; clear all red
- clr RED1
- rcall wr_frame ; update
- rcall wr_latch
- rcall wr_frame ; update
- rcall wr_latch
- out PORTB,zero ; shutdown converter
- ldi wreg,0x30
- out MCUCR,wreg ; sleep mode power-down
- sleep ; only leaves with reset
- nop
- ;*********************************************************************************************
- ;* init_io
- ;*********************************************************************************************
- ; Initialize all the IO system, write IO values and unmutable variables.
- ; uses wreg,SEND0,SEND1
- ;*********************************************************************************************
- init_io:
- out EEAR,zero ; get calibration byte from eeprom(0)
- sbi EECR,EERE ; strobe a read
- in wreg,EEDR ; get value from eeprom(0)
- out OSCCAL,wreg ; set calibration byte @ 1.6MHz +/- 1%
- ldi wreg,0x03 ; PB1 must be programmed as output to work
- out DDRB,wreg ; PB0 controls the power supply
- ldi wreg,0x01
- out PORTB,wreg ; enable Power Supply
- out OCR1A,zero ; clear output (keep PB1=0)
- ; maximum frequency OCR1B=0;
- ; period is OCR1B+1 * tclk
- ldi wreg, 8 ; maximum length of PWM (for this clock) was 8
- out OCR1B,wreg ; this is arround 1us ~2 clocks per pixel
- ldi wreg, 0x63 ; PWM1,COM1A1,CS11,CS10 CK*4->T1
- out TCCR1,wreg ; PCK = 156.3ns, start timer
- ldi wreg, 0x20 ; Sleep Enable
- out MCUCR,wreg
- ldi wreg,0x02 ; Enable TOIE0
- out TIMSK,wreg
- ;unmutable variables
- ldi wreg,0x04 ; ~650ns
- mov SEND1,wreg
- ldi wreg,0x01 ; ~300ns
- mov SEND0,wreg
- ret
- ;*********************************************************************************************
- ;* wr_frame
- ;*********************************************************************************************
- ; write a frame of neopixels (up to 16)
- ; copies data from GREEN1 to G1 ... RED0 to R0;
- ; uses G1,G0,B1,B0,R1,R0
- wr_frame:
- cli ; disable interrupts here
- mov G1,GREEN1 ; copy the current to the working regs
- mov G0,GREEN0
- mov R1,RED1
- mov R0,RED0
- mov B1,BLUE1
- mov B0,BLUE0 ; copy current frame to temp locations
- ldi led_cnt,num_leds ; number of LEDs (max 16)
- gr_pix:
- lsr G1 ; [1] + 9
- ror G0 ; [1] rotate 16 bits, CY has bit
- brcs gr_pix_s ; [1/2]
- mov wreg,SEND0 ; [1]
- rjmp gr_wait ; [2]
- gr_pix_s:
- mov wreg,SEND1 ; [1] send a 1 for green
- nop ; [1]
- gr_wait:
- nop ; [1] 16
- nop ; [1] 17
- out OCR1A,wreg ; [1] set bit to send
- rd_pix:
- lsr R1 ; [1]
- ror R0 ; [1] rotate 16 bits, CY has bit
- brcs rd_pix_s ; [1/2]
- mov wreg,SEND0 ; [1]
- rjmp rd_wait ; [2]
- rd_pix_s:
- mov wreg,SEND1 ; [1] send a 1 for red
- nop ; [1]
- rd_wait:
- nop ; [1] 7 clocks
- nop ; [1] 8 clocks
- nop ; [1] 9 clocks
- nop ; [1] 10 clocks
- nop ; [1] 11 clocks
- nop ; [1] 12 clocks
- nop ; [1] 13 clocks
- nop ; [1] 14 clocks
- nop ; [1] 15 clocks
- nop ; [1] 16 clocks
- nop ; [1] 17 clocks
- out OCR1A,wreg ; [1] update
- bl_pix:
- lsr B1 ; [1]
- ror B0 ; [1] rotate 16 bits, CY has bit
- brcs bl_pix_s ; [1/2]
- mov wreg,SEND0 ; [1]
- rjmp bl_wait ; [2]
- bl_pix_s:
- mov wreg,SEND1 ; [1] send a 1 for blue
- nop ; [1]
- bl_wait:
- nop ; [1] 7 clocks
- nop ; [1] 8 clocks
- nop ; [1] 9 clocks
- nop ; [1] 10 clocks
- nop ; [1] 11 clocks
- nop ; [1] 12 clocks
- nop ; [1] 13 clocks
- nop ; [1] 14 clocks
- nop ; [1] 15 clocks
- nop ; [1] 16 clocks
- nop ; [1] 17 clocks
- out OCR1A,wreg ; [1] update
- dec led_cnt ; [1]
- breq last ; [1/2]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- rjmp gr_pix ; [2]
- last:
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1]
- nop ; [1] - 16 counts from last update
- out OCR1A,zero ; clear output
- ret
- ;*********************************************************************************************
- ;* wr_latch
- ;*********************************************************************************************
- ; make a break of 100-200ms (200 load T0 with 100)
- ; use timer 0 to count 200ms and sleep until interrup.
- wr_latch:
- sei ; enable interrupts
- ldi wreg,100
- out TCNT0,wreg ; reset timer0 (change for other timeout)
- ldi wreg,0x01 ; reset prescaller T0
- out SFIOR,wreg
- ldi wreg,0x05 ; start T0, /1024
- out TCCR0,wreg
- sleep ; wait for timeout
- nop
- out TCCR0,zero ; stop timer
- cli ; disable interrupts
- ret
- ;*********************************************************************************************
- ;* Random Number Generator
- ;*********************************************************************************************
- ; Pseudo Random Number generator, uses 32 bits (4 bytes) generator.
- ; if 32 bits (xor 32,22,2,1)
- ; 32,30,26,25
- ; if 16 bits (xor 16,15,13,4)
- ; Bit 1 in the taps is bit 1 of rnd_a (convention in lfsr).
- ; if operation is xor, all zeros blocks the lfsr, run randinit first
- ; if operation is xnor, all ones blocks the lfsr, adapt randinit then run it first.
- ; CY returns a pseudo-random bit sequence; rnd_a to rnd_d hold a pseudo random sequence
- ; of values
- ;*********************************************************************************************
- #define MASK_A 0b00000000 /* constants to separate the bits, anded with rnd_a */
- #define MASK_B 0b00000000 /* constants to separate the bits, anded with rnd_b */
- #define MASK_C 0b00000000 /* constants to separate the bits, anded with rnd_c */
- #define MASK_D 0b10100011 /* constants to separate the bits, anded with rnd_d */
- random:
- clr rnd_xor ;clear xor accumulative register
- ldi wreg,MASK_D
- and wreg,rnd_d
- eor rnd_xor,wreg
- ldi wreg,MASK_C
- and wreg,rnd_c
- eor rnd_xor,wreg
- ldi wreg,MASK_B
- and wreg,rnd_b
- eor rnd_xor,wreg
- ldi wreg,MASK_A
- and wreg,rnd_a ; load mask and extract bits from register
- eor rnd_xor,wreg ; xor with accumaltive
- clr wreg ; counter of ones
- rand_lp:
- lsr rnd_xor ; Rotate to bit to carry
- brcc rand_nx ; carry clear skip
- inc wreg
- rand_nx:
- tst rnd_xor ; stop when no more ones to count
- ; it is a bound operation, zeros are shift in so max is 8 shifts (bit7=1)
- brne rand_lp ; repeat if !=
- ; CY holds a bit of a pseudo random sequence
- lsr wreg ; if odd number of bits, wreg()==1 => XOR operation
- rol rnd_a ; feed CY in shift register
- rol rnd_b
- rol rnd_c
- rol rnd_d
- mov wreg,rnd_a ;copy shifted bit to CY and return
- lsr wreg
- ret
- ;*********************************************************************************************
- ; Because a XOR (XNOR) is made of selected bits, one value of the random value can block it.
- ; tests for a (FFFF) and changes the value to the opposite.
- rnd_init:
- clr wreg
- or wreg,rnd_a
- or wreg,rnd_b
- or wreg,rnd_c
- or wreg,rnd_d
- breq rnd_init0
- ret
- rnd_init0:
- ldi wreg,0x55
- mov rnd_a,wreg
- mov rnd_b,wreg
- mov rnd_c,wreg
- mov rnd_d,wreg
- ret
- ;*********************************************************************************************
- .section .eeprom
- .org 0x00
- .ds 1 ; holds calibration byte
- .end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement