Attiny804 multiple interrupts not working

Go To Last Post
21 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi forum members Greetings of the day!

I am a newbie and I am facing a problem with interrupts.

Chip – attiny804

Assembler

IDE – Atmel studio 7

Programmer – ch340Ftdi with polarisu updi software.

My friend has  2009 GM Optra with inoperative instrument panel cluster. I planned to help him with a mini IPC which will display engine temperature, fuel tank level & speedometer in 1602LCD. The initial program that was implemented was a loop which reads speed for 20 times and then read fuel and temperature 1 times infinitely. Although this worked while the 3 signals (speed,temperature & fuel level) were continuously available, it would fail to update if the speed signal is missing ,for eg if the ignition key is on but vehicle is not moving. I have used the ADC in single conversion mode to measure the fuel level and engine temperature and change the MUXPOS to the grab the readings sequentially. The speed measurement is done with frequency measure utility of timer counter B (TCB0) by polling for a negative edge which is supplied from the IPC through an opto-coupler. On receiving the edge on PA1 which is routed to TCB0 via EVENT system the TCB0 counter value is copied to the compare register and a flag is raised in the flag register. I have a loop that checks on the flag register after setting up the timerB. The clock source of the TCB0 is taken from TCA0. The speed measurement will be stuck in an infinite loop until a signal is received and the timer counter B interrupt flag is set. I tried to implement a 1)timeout , 2)toggling the speed input pin PA1 PIN_register to simulate a edge which makes the loop to exit but the speed measurement will always show 0kmph. The program fails to read a speed signal and always displays 0 but other ADC readings started to update properly.  

                                                I felt that the issue is with the complex loop and tried to find a solution based on interrupt and found that the display doesn’t get updated. To investigate further whether I am making a fundamental mistake the program was shortened  to include only the timer setup , a 1 second TIMER A overflow ISR , TCB0 ISR for capture compare of the signal. On using the studio7 debugger to step through the program it was found that the ISRs fire properly based on PORTA_PIN values (speed signal) and 1 second TCA0 overflow ISR. The code is pasted below which lights up LED on PA2 when the TCA0 overflow ISR fires 1st time and later switches off the LED when it fires 2nd time. Another LED is connected to PA3 which lights up when the TCB0 capture happens and the TCB0 ISR fires. I have added a delay of 500ms to the TCB0_ISR so that the LED is visible if the ISR fires. When the program is run on the chip it was found that the TCA0_OVF LED on PA2 lights up constantly/latched after 1 second of switching on the chip and the TCB0_ISR LED on PA3 stays off (never lights up). On commenting out TCA0_OVF vector (disabling TCA0_OVF ISR) the TCB0_ISR LED was found flashing when an edge is applied to PA1 (for ease I applied positive edge on the breadboard). Afterwards when the TCB0_ISR vector was commented out and TCA0_OVF vector was enabled, the TCA0_OVF ISR LED on PA2 flashed consistently. If both ISRs are enabled the OVF LED stays on and TCB0 LED stays off. I tried many permutations and combinations but failed to get both ISRs work in the same program. Stepping through the program with studio debugger does not show any issues and the ISRs fire in the simulator when values are written to the counter registers and PIN registers. The chip does not behave the same way as the simulator. Requesting help to identify the bug or lack of understanding on my side on why the chip is in a frozen like state. Please bear with my English and lack of understanding. below is the stripped down code.

; 804TCBinterruptTEST.asm
;
; Created: 3/8/2021 7:00:56 PM
; Author : pappan
;	PB1 SDA = 8
;	PB0 SCL = 9
;	PA1 - FREQUENCY INPUT =11
;	PA2 - ADC FOR TEMPRATURE =12 =AIN2
;	PA3 - ADC FOR FUEL LEVEL =13 =AIN3
;	T = ((1024-V1)/10)+33




.equ fclk = 10000000


.macro micros
ldi temp,@0
rcall delayTx1uS
.endm

.macro millis
ldi YL,low(@0)
ldi YH,high(@0)
rcall delayYx1mS
.endm



.DSEG
PAD: .BYTE 1				
PAD1: .BYTE 1
FUEL_BUFFERH: .BYTE 1
FUEL_BUFFERL: .BYTE 1
TEMP_BUFFERH: .BYTE 1
TEMP_BUFFERL: .BYTE 1
SPEEDL: .BYTE 1
SPEEDH: .BYTE 1
BUFFER: .BYTE 8
SPC: .BYTE 1




.CSEG
.ORG 0X00
rjmp reset

.ORG 0x08
rjmp ISR_OVF

.org 0x0D
rjmp ISR_TCB0






reset:
		lds r16,portA_DIR					;setting port
		andi r16,0b11111101					;setting PA1 as inputs
		sts portA_DIR,r16
		ldi r16,0b00000010					;enable PA1 pullup resistor for speed signal
		sts PORTA_PIN1CTRL,r16
		ldi r16,0b00001011					;enable PA1 as event generator ,BM 0x0B
		sts EVSYS_ASYNCCH0,r16
		ldi r16,0b00000011					;enable event user as TCB0
		sts EVSYS_ASYNCUSER0,r16
		ldi r16,0x0C						;enable PA2 & PA3 as outputs for blinking LED
		sts PORTA_DIR,r16
		ldi r16,0x00						;initially portA is 0 , when need to light led PA2 & PA3 will be made 1
		sts PORTA_OUT,r16
		rcall PROT_WRITE					;subroutine to change MCU clock speed from default 3.3Mhz to 10Mhz
		rcall SPEED_INIT					;initialize TCB0 & TCA0 for frequency measurement
speedo:
		
		
		rjmp speedo						
		
		


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;PROTECTED WRITE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PROT_WRITE:
		ldi r16,0Xd8
		out CPU_CCP,r16
		ldi r16,0x01						; clk prescaler of 2, 20Mhz/2 = 10Mhz
		STS CLKCTRL_MCLKCTRLB,R16
		RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


SPEED_INIT:
	LDI R16,0b00000011					;value for frequency measure 0x03
	STS TCB0_CTRLB,R16					;ENABLE FREQUENCY MEASURE MODE
	LDI R16,0b00000001
	STS TCB0_EVCTRL,R16					;ENABLE positive EDGE AND START INPUT CAPTURE
	LDI R16,0b00000001
	STS TCB0_INTCTRL,R16					;ENABLE INPUT CAPTURE INTERRUPT

	LDI R16,0b00000001
	sts TCA0_SINGLE_INTCTRL,r16				;enable TCA0 overflow interrupt (timer A) (timer B does not have OVF interrupt)
	LDI R16,0b00000101
	STS TCB0_CTRLA,R16   					;CKSEL= 0X2 = USE CLK_TCA ENABLE TIMER B .timer A is used as clock
	ldi r16,low(39062)
	sts TCA0_SINGLE_PER,r16					;load TCA0 period register LOW the period value of 39062 = 10Mhz/256 (prescale)=1 sec
	ldi r16,high(39062)
	sts TCA0_SINGLE_PER + 1,r16				;load TCA0 period register HIGH the period value of 39062 = 10Mhz/256 (prescale)=1 sec
	LDI R16,0b00001101						;enable timer A as we need the clock from this for timer B
	STS TCA0_SINGLE_CTRLA,R16				; CLKSEL =0X6 ENABLE 0X1 , PRESCALER 256,39062 COUNTS IN 1 SEC
	sei							;enable interrupts globally in SREG
	RET






SPEED_STOP:
clr R0								;clear R0 =0x00
;STS TCA0_SINGLE_CTRLA,R0					;store in TCA0 control registerA
;STS TCB0_CTRLA,R0						;store in TCB0 control registerA
;STS TCB0_INTCTRL,R0						;store in TCB interrupt register
STS TCB0_CCMPL,R0						;store in TCB0 capture compare register low
STS TCB0_CCMPH,R0						;store in TCB0 capture compare register high
STS TCB0_CNTL,R0						;store in TCB0 counter low
STS TCB0_CNTH,R0						;store in TCB0 counter high
sts TCA0_SINGLE_CNT,r0
sts TCA0_SINGLE_CNT + 1,r0
;inc r0
;sts TCB0_INTFLAGS,r0
RET 






ISR_OVF:
	push r16							; backup r16
	in r16,cpu_sreg							; copy sreg to r16
	push r16							; copy sreg to stack
	cli								; disable interrupts

	ldi r16,0x04							; value 0x4 to set portA pin2, PA2
	sts PORTA_OUTTGL,r16						; storing 0x04 in PORTA_OUTGL will toggle the pin2 between on & OFF
	ldi r16,0x01							; load value 0x01 in r16 
	sts TCA0_SINGLE_INTFLAGS,r16					; write 0x01 to INTFLAG register of timerA to clear interrupt flag
	pop r16								; copy sreg from stack
	out cpu_sreg,r16						; restore sreg
	pop r16								; restore r16
	reti


ISR_TCB0:
	push r16							; backup r16
	in r16,cpu_sreg							; copy sreg to r16
	push r16							; copy sreg to stack
	cli								; disable interrupts
	ldi r16,0x01							; load value 0x01 in r16
	sts TCB0_INTFLAGS,r16						; write 0x01 in timerB INTFLAG regiter to clear interrupt flag
	ldi r16,0x08							; storing 0x08 in PORTA_OUTGL will toggle the pin3 between on & OFF
	sts PORTA_OUTTGL,r16						; storing 0x08 in PORTA_OUTGL will toggle the pin3 between on & OFF
	rcall SPEED_STOP
	millis 500							; delay 500ms to make sure the LED flashing is visible
	pop r16								; copy sreg from stack
	out cpu_sreg,r16						; restore sreg
	pop r16								; restore r16
	reti






; ============================== Time Delay Subroutines =====================
; Name:     delayYx1mS
; Purpose:  provide a delay of (YH:YL) x 1 mS
; Entry:    (YH:YL) = delay data
; Exit:     no parameters
; Notes:    the 16-bit register provides for a delay of up to 65.535 Seconds
;           requires delay1mS

delayYx1mS:
    rcall    delay1mS                        ; delay for 1 mS
    sbiw    YH:YL, 1                        ; update the the delay counter
    brne    delayYx1mS                      ; counter is not zero

; arrive here when delay counter is zero (total delay period is finished)
    ret
; ---------------------------------------------------------------------------
; Name:     delayTx1mS
; Purpose:  provide a delay of (temp) x 1 mS
; Entry:    (temp) = delay data
; Exit:     no parameters
; Notes:    the 8-bit register provides for a delay of up to 255 mS
;           requires delay1mS

delayTx1mS:
    rcall    delay1mS                        ; delay for 1 mS
    dec     temp                            ; update the delay counter
    brne    delayTx1mS                      ; counter is not zero

; arrive here when delay counter is zero (total delay period is finished)
    ret

; ---------------------------------------------------------------------------
; Name:     delay1mS
; Purpose:  provide a delay of 1 mS
; Entry:    no parameters
; Exit:     no parameters
; Notes:    chews up fclk/1000 clock cycles (including the 'call')

delay1mS:
    push    YL                              ; [2] preserve registers
    push    YH                              ; [2]
    ldi     YL, low(((fclk/1000)-18)/4)     ; [1] delay counter              (((fclk/1000)-18)/4)
    ldi     YH, high(((fclk/1000)-18)/4)    ; [1]                            (((fclk/1000)-18)/4)

delay1mS_01:
    sbiw    YH:YL, 1                        ; [2] update the the delay counter
    brne    delay1mS_01                     ; [2] delay counter is not zero

; arrive here when delay counter is zero
    pop     YH                              ; [2] restore registers
    pop     YL                              ; [2]
    ret                                     ; [4]

; ---------------------------------------------------------------------------
; Name:     delayTx1uS
; Purpose:  provide a delay of (temp) x 1 uS with a 16 MHz clock frequency
; Entry:    (temp) = delay data
; Exit:     no parameters
; Notes:    the 8-bit register provides for a delay of up to 255 uS
;           requires delay1uS

delayTx1uS:
    rcall    delay10uS                        ; delay for 1 uS
    dec     temp                            ; decrement the delay counter
    brne    delayTx1uS                      ; counter is not zero

; arrive here when delay counter is zero (total delay period is finished)
    ret

; ---------------------------------------------------------------------------
; Name:     delay10uS
; Purpose:  provide a delay of 1 uS with a 16 MHz clock frequency ;MODIFIED TO PROVIDE 10us with 1200000cs chip by Sajeev
; Entry:    no parameters
; Exit:     no parameters
; Notes:    add another push/pop for 20 MHz clock frequency

delay10uS:
    ;push    temp                            ; [2] these instructions do nothing except consume clock cycles
    ;pop     temp                            ; [2]
    ;push    temp                            ; [2]
    ;pop     temp                            ; [2]
    ;ret                                     ; [4]
     nop
     nop
     nop
     ret

; ============================== End of Time Delay Subroutines ==============

I have also attached the full version of code where i tried to exit the input capture loop with an OVF ISR. Only the ADC parts updates properly the speed always shows 0 kmph. If i comment out the OVF-ISR and the code portion in the flag loop which forces an exit the input capture also works but will get stuck if no signal.

Regards

Attachment(s): 

This topic has a solution.

darth vader

Last Edited: Tue. Mar 16, 2021 - 10:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wiring diagram for both test and use scenarios 

regards

Attachment(s): 

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

1) You call millis but dont save/restore Y (r28,r29).

2) You don't need cli in an interrupt handler.

that's all I see right now.

Last Edited: Thu. Mar 11, 2021 - 02:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

IIRC, the AVR 0/1 tiny's do not clear the interrupt flags automatically, so you need to do that in each ISR() or once an interrupt triggers, it remains set and will  be constantly called over and over and over and over.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(please ignore - misread above)

Last Edited: Thu. Mar 11, 2021 - 02:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

IIRC, the AVR 0/1 tiny's do not clear the interrupt flags automatically, so you need to do that in each ISR() or once an interrupt triggers, it remains set and will  be constantly called over and over and over and over.

edit- sorry, I didn't read the above right. The above is talking about peripheral flags I assume, where below I'm talking about the cli which is not needed. The peripheral irq flags need to be cleared 'manually' in a number of cases, but like in the code below there are times when its done for you (by reading CCMP in this particular case). See datahseet for that answer.

 

The isr (hardware) does not touch the global interrupt bit, because they also have a high priority interrupt (want to let the high priority irq interrupt). What they do instead is set the LVLnEX bit in CPUINT.STATUS, which then prevents any other irq of the same level while set. To clear any of these LVLnEX bits requires a 'reti' instruction. So no, you need not do 'cli' in an avr0/1 isr (unless I guess if you want to disable the high priority interrupt in a level 0 interrupt- would be odd).

 

There may be reasons to enable interrupts inside an interrupt like could do in older avr's, then you are required to get a reti instruction to run (call a naked function which has a reti is an easy way to do this).

 

 

 

It is hard to read asm so probably do not get much help. I made something in C to count tcb0 frequency on a 3217 board I had running. Probably also hard to read. The idea is to let the irq's do the work so you do not have to poll. The tca timer is a timeout monitor, and when it times out there is something wrong. When the tcb0 irq runs enough times, can consider the signal back online and it uses the freq mode. When the tcb0_value is not 0, then its a good value (or at least the value did not overflow the counter). The tca timeout can be adjusted down from 1 second to some value greater than the highest count that will be seen, but probably not important as its either a good signal or no signal.

 

The tca0_timeout count may be unnecessary, but it just makes sure the tcb0 irq has fired enough times to be considered running ok. Some kind of averaging of the count would be nice, but this is a simple example. This runs and prints on the lcd values from 100.00 down to ~5x.xx, so seems to work ok. Not sure what kind of pulse times you are looking for, but doesn't really matter.

 

 

#include "MyAvr.hpp" //F_CPU is 3333333ul
#include "LcdST7032.hpp"

 

LcdST7032_Twi lcd             { board.twiPins };   //default or alt twi pins
PinFast<A5>   lcdBacklight    { OUTPUT };          //separate backlight control pin
PinFast<B5>   lcdReset        { OUTPUT, LOWISON }; //lcd reset pin (low is reset)

 

volatile u8 tca0_timeout = 8;   //need n good tcb irq's after a timeout
volatile u16 tcb0_value = 0;    //0 = tca timeout

 

void timersInit(){
    //tca0 1 second timeout, ovf irq, clock source for tcb0
    //normal mode, PER=TOP, OVF=TOP
    TCA0.SINGLE.INTFLAGS = 1;       //ovf flag
    TCA0.SINGLE.INTCTRL = 1;        //ovf irq
    TCA0.SINGLE.CNT = 0;
    TCA0.SINGLE.PER= F_CPU/256-1;   //1 second
    TCA0.SINGLE.CTRLA = (6<<1)|1;   //div256, enable

    //tcb0
    TCB0.CTRLB = 3;                 //FRQ frequency
    TCB0.EVCTRL = (1<<4)|1;         //edge=1, captei
    TCB0.INTFLAGS = 1;              //capt flag
    TCB0.INTCTRL = 1;               //captei
    TCB0.CTRLA = (2<<1)|1;          //TCA0 CLK, enable

    //evsys
    EVSYS.SYNCCH0 = 0x0B;           //PC4 (also tcb1 WOalt)
    EVSYS.ASYNCUSER0 = 1;           //TCB0, sync ch0

    //test signal (using same pin as tcb0 input)

    //tcb1, output ~100Hz on WOalt (PC4)
    TCB1.CTRLA = (2<<1)|1;          //TCA0 CLK, enable
    TCB1.CTRLB = (1<<4)|7;          //out enable, pwm mode
    TCB1.CCMP = 0x4182;             //period=L (0x82 = ~100Hz), duty=H
    PinFast<C4>().output();         //pc4 output
    PORTMUX.CTRLD |= 2;             //portmux TCB1 alt WO pin
}

 

int main(){

    board.init();
    rtc.init();

    lcdBacklight.on();
    lcdReset.on(); rtc.waitMS( 100 ); lcdReset.off();

 

    timersInit();

 

    //TCB1.CTRLB = 7; //disable WO output to test no signal (displays 000.00)

 

    MAIN_LOOP_IRQon {
        u16 v;
        { InterruptLock lock; v = tcb0_value; } //protected read
        u32 hz = v ? F_CPU*100/256/v : 0;   //hz * 100
        u8 hz100 = hz%100;                  //decimal .nn
        hz = hz/100;                        //integer
        Print( lcd, "\tfreq: %03lu.%02u", hz, hz100 ); // \t is lcd home
        rtc.waitMS(300); 

        TCB1.CCMP++; //vary the tcb1 period so value changes
        if( TCB1.CCMP >= 0x41FE ) TCB1.CCMP = 0x4182; //up to a point
    }

}

 

#include <avr/interrupt.h>

ISR( TCA0_OVF_vect ){           //1 second timeout with no tcb0 activity
    TCA0.SINGLE.INTFLAGS = 1;   //clear ovf
    tca0_timeout = 8;           //reset to some value
    tcb0_value = 0;             //tcb0 value no good
    board.led.toggle();         //if lights up (blinks), timeout
}

ISR( TCB0_INT_vect ){
    board.led.off();
    TCA0.SINGLE.CNT = 0;        //reset tca0
    if( tca0_timeout ) tca0_timeout--; //dec count if not 0
    u16 ccmp = TCB0.CCMP;       //read also clears flag
    if( tca0_timeout ) return;  //not at 0 yet
    tcb0_value = ccmp;          // >= n good irq's, value is good
}

Last Edited: Fri. Mar 12, 2021 - 12:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir Jim,

Thanks for the comment /advice. The interrupt flag for TCB0 is automatically cleared on reading the result from capture compare register. In the above code I have cleared it with ldi r16,0x01 ; sts TCB0_INTFLAGS,r16. I have also confirmed that the flag clears by stepping through the atmel studio debugger for all interrupts called.

regards

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir Curtvm,

Thanks for the detailed advice. I have removed the cli from the ISR as it is not necessary. I tried to light up one LED for each interrupt and found that they become stuck on or never turn on at all. Sometimes they toggle for 3-10 seconds and latch on permanently. Seems there is a problem when running in interrupt mode.

                I stripped the ADC part of the original code which measures by polling only kept the frequency measurement part. To this I have added result reading by TCB0 compare capture interrupt and removed the compare flag polling. On programming and testing I found that the speed result is always 0 kmph. This means that the interrupt is not firing on an event on PA1. I have an ATTINY13 based RGB LED fader running at 0 - 60Hz PWM and using the signal feed to the RGB LED as a test signal on PA1 of ATtiny804. The RGB fader gives result on the LCD when using polling method. On debugging step by step in atmel studio I don’t find any discrepancy and the ISR fires when the PORTA_PIN1 is toggled for one clock cycle. The new code is pasted below. I have used the same parameter for setup as you have used in your code except I have used ASYNCH for both generator & user while you have SYNCCH for generator & ASYNCH for user. I tried to do the same but didn’t get the code to work. I assume that the ISR is not firing (reason I don’t know) . The event channel should be fine as it was working in the polling method.

          I tried to paste your code into studio7 but it throws many errors and I don’t have a STxxLCD. I am not formally educated in this subject, I don’t understand the syntax and logic of C , I learned the little assembler I understand from YOUTUBE and sites like AVR freaks, avr beginners etc. If it’s not too much to ask can you provide me a working code snippet in C which measures the frequency and stores in some register/SRAM with studio7 header files necessary. I’ll build it in studio and see what asm the compiler has generated in the lss file so that I can find out my mistake.

Is it possible that the chip could be damaged?

PA1 = speed input

PB0 & PB1 = default scl & sda connected to LCD via pull ups ext

regards

 

;
; 804speed.asm
;
; Created: 3/12/2021 8:39:13 PM
; Author : pappan
;;
; 
;PB1 SDA = pin8
;PB0 SCL = pin9
;PA1 - FREQUENCY INPUT =11
; ACK is not considered . checking ack prints garbage on the LCD
; Created: 2/16/2021 6:08:16 PM
; Author : pappan
;

.equ data_command1 = 0b00001001		; data control nibble ,led on P3, EN 0 on P2, R/W 0 (write) in P1 , RS 1 (0 instruction, 1 data) = 1001  =0x09
.equ data_command2 = 0b00001101		; data control nibble , 1101  = 0x0D   - EN goes hi=1
.equ data_command3 = 0b00001001		; data control nibble , 1001  = 0x09   - EN goes low=0
.equ inst_command1 = 0b00001000		;instruction control nibble ,  led on en-lo,Rw-0,rs =0   = 1000   = 0x08
.equ inst_command2 = 0b00001100		;instruction control nibble ,  led on,EN hi , rs/RW 0    = 1100   = 0x0C
.equ inst_command3 = 0b00001000		;instruction control nibble  , led on, EN lo ,rs/rw 0    = 1000   = 0x08
.EQU SLAVE_ADDRESSW = 0X4E   ; OLED = 0X78 ,1602 =4E
.equ fclk = 10000000
.DEF  SLAVE_REG = R17
.DEF  TEMP = R16
.def HundredCounter = r20
.def TenthCounter = r21
.def OneCounter = r22
.def ZEROREG = r23


.macro micros               ;macro for micro second delay
ldi temp,@0
rcall delayTx1uS
.endm

.macro millis               ;macro for milli second delay
ldi YL,low(@0)
ldi YH,high(@0)
rcall delayYx1mS
.endm

.macro pos                  ;macro for LCD cursor positioning
ldi r16,@1
mov r6,r16
ldi r16,@0
rcall posi
.endm

.macro arrayread            ;macro for reading null terminated string
ldi ZL,low(2*@0)
ldi ZH,high(2*@0)
rcall array
.endm

.DSEG
PAD: .BYTE 1		    ; reserve one byte in SRAM with address name PAD for COMMAND_WRITE & DATA_WRITE calculations
PAD1: .BYTE 1
SPEEDL: .BYTE 1
SPEEDH: .BYTE 1
BUFFER: .BYTE 8





.CSEG
.ORG 0X00
	rjmp reset


.org 0x0D
ISR_TCB0:
	push r16			; backup r16
	push r17			; backup r17
	in r16,cpu_sreg			; copy sreg to r16
	push r16			; copy sreg to stack
	lds r16,TCB0_CCMPL		; COPY TCB0 low compare register
	lds r17,TCB0_CCMPH		; COPY TCB0 high compare register
	sts SPEEDH,r17			; store copied value in SRAM
	sts SPEEDL,r16			; store copied value in SRAM
	rcall SPEED_STOP		; call routine to clear capture compare register & TCB0 count register
	pop r16				; copy sreg from stack
	out cpu_sreg,r16		; restore sreg
	pop r17				; restore r17
	pop r16				; restore r16
	reti





reset:
		lds r16,portA_DIR		; setting port
		andi r16,0b11110001		; setting PA1,PA2,PA3 as inputs
		sts portA_DIR,r16
		ldi r16,0b00000010		; enable PA1 pullup resistor for speed signal
		sts PORTA_PIN1CTRL,r16
		ldi r16,0b00001011		; enable PA1 as asynch event generator ,BM 0x0B
		sts EVSYS_ASYNCCH0,r16
		ldi r16,0b00000011		; enable  TCB0 as asynch event user, 0x03
		sts EVSYS_ASYNCUSER0,r16
		rcall i2c_init			; subroutine to initialize and send TWI start
		rcall LCD_INIT			; subroutine to initialize Hitachi LCD
		rcall PROT_WRITE		; subroutine to change MCU clock speed from default 3.3Mhz to 10Mhz
		pos 0,0				; cursor position to Y = 0 , X = 0 (top left corner)
		arrayread string		; reads array "Hello!",0 stored in flash address 'string' (welcome message)
		millis 1000			; 1 second delay after welcome message "hello"
		pos 0,0				; cursor position - 0,0 . top left corner of LCD
		arrayread string3		; "SPEED    KM/H",0 is printed on LCD

		rcall SPEED_INIT		; initialize TCB0  for frequency measurement
		
		
				
speedo:
		rcall SPEED_CALC
		rcall zero_suppress		        ; call routine to suppress leading zeros in the LCD display
		pos 0,6				        ; coordinates to print speed result in blanks space of "SPEED    KM/H"
		mov SLAVE_REG,HundredCounter	        ; copy hundredth position to r17 to begin TWI transmission
		rcall DATA_WRITE		        ; call DATA_WRITE function to do a 4 bit TWI transmit to LCD
		mov SLAVE_REG,TenthCounter	        ; copy tenth position to r17 to begin TWI transmission
		rcall DATA_WRITE		        ; call DATA_WRITE function to do a 4 bit TWI transmit to LCD
		mov SLAVE_REG,OneCounter	        ; copy unit position to r17 to begin TWI transmission
		rcall DATA_WRITE		        ; call DATA_WRITE function to do a 4 bit TWI transmit to LCD
		rjmp speedo			        ; jump back to measure to 

SPEED_INIT:
	LDI R16,0b00000011		; 0x03
	STS TCB0_CTRLB,R16		; ENABLE FREQUENCY MEASURE MODE
	LDI R16,0b00000001
	STS TCB0_EVCTRL,R16		; ENABLE positive EDGE AND START INPUT CAPTURE
	LDI R16,0b00000001
	STS TCB0_INTCTRL,R16		; ENABLE INPUT CAPTURE INTERRUPT
	sts TCB0_INTFLAGS,r16		; clear TCB0 interrupt flags
	LDI R16,0b00000101
	STS TCB0_CTRLA,R16   		; USE TCA as clock for TCB0, ENABLE TIMER B
	rcall SPEED_STOP		; clear TCB counter & capture compare register
	LDI R16,0b00001101		; enable timer A as we need the clock from this for timer B
	STS TCA0_SINGLE_CTRLA,R16	; CLKSEL =0X6 ENABLE 0X1 , PRESCALER 256 for TCA0
	sei				; enable interrupts globally in SREG
	RET



SPEED_READ:
	cli				        ; clear interrupts for atomic access
	lds r16,SPEEDL				; copy contents of SRAM speed value(L) stored earlier with ISR to r16
	lds r17,SPEEDH				; copy contents of SRAM speed value(H) stored earlier with ISR to r17
	sei					; enable interrupts as values were copied to desired registers
	rcall SPEED_CALC			; call procedure to calculate speed/frequency from result
	RET

SPEED_STOP:
	clr R0					; clear R0 =0x00
	STS TCB0_CCMPL,R0			; clear TCB0 capture compare register low
	STS TCB0_CCMPH,R0			; clear TCB0 capture compare register high
	STS TCB0_CNTL,R0			; clear TCB0 counter low
	STS TCB0_CNTH,R0			; clear in TCB0 counter high
	RET 

SPEED_CALC:
	rcall division				; call division routine to divide 39062/input capture/2 = GPS speed ( Hz/2)
	rcall ASCII_CONVERT			; convert the binary to ACSII values to display on LCD
	ret
		
		

;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;ALL ROUTINES BELOW THIS LINE FUNCTIONS PROPERLY AS i GET PROPER LCD DISPLAY THROUGH I2C
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;PROTECTED WRITE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PROT_WRITE:
		ldi r16,0Xd8
		out CPU_CCP,r16
		ldi r16,0x01			; clk prescaler of 2, 20Mhz/2 = 10Mhz
		STS CLKCTRL_MCLKCTRLB,R16
		RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;I2C ROUTINES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TWI_INIT:
		ldi r16,80			    ;load baud rate for I2C , (fclck/2*bitrate)-10 , freq = 10Mhz
		sts TWI0_MBAUD,R16		; store into baud register
		LDI R16,0b00000001		;ENABLE
		STS TWI0_MCTRLA,R16
		LDI R16,0b00001000		;FLUSH ADDR & DATA REGISTERS
		STS TWI0_MCTRLB,R16
		LDI R16,0b00000001		;FORCE IDLE
		STS TWI0_MSTATUS,R16
		ret

TWI_START:
		ldi SLAVE_REG,SLAVE_ADDRESSW
		MOV R16,SLAVE_REG		; SLAVE_REG IS R17, READ OR WRITE ADDRESS SHOULD BE LOADED HERE PRIOR TO CALL INIT
		STS TWI0_MADDR,R16
		RCALL WAIT_WIF
		RET

TWI_WRITE:
		MOV R16,SLAVE_REG		;mov data from SLAVE_REG/r17 to r16
		STS TWI0_MDATA,R16		;copy r16 to MDATA register for I2C transmission
		RCALL WAIT_WIF			;call WAIT_WIF subroutine to check write interrupt flag is set after writing finished
		micros 30
		RET

TWI_STOP:
		LDI R16,0b00000011              ;STOP
		STS TWI0_MCTRLB,R16
		RET


WAIT_WIF:
		LDS R16,TWI0_MSTATUS
		SBRS R16,6			;CHECK WIF IS SET,IF SET SKIP NEXT INSTRUCTION
		RJMP WAIT_WIF
		ret


i2c_init:
		LDI SLAVE_REG,SLAVE_ADDRESSW
 		RCALL TWI_INIT
		rcall TWI_START
		ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;LCD ROUTINES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
COMMAND_WRITE:
		STS PAD,R17		;copy SLAVE_REG to SRAM address PAD for processing
		ANDI R17,0XF0		;preserve upper nibble of SLAVE_REG by anding with 0xF0 ,lower 4 becomes 0
		ORI R17,inst_command1	;add instruction_command1 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,inst_command2	;add instruction_command2 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,inst_command3	;add instruction_command3 to lower nibble of r17 by OR ing it
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20		
		LDS R17,PAD		;copy back data from PAD to r17 for processing the remaining lower nibble
		SWAP R17		;swap the nibbles in R17 so the lower nibble will occupy the upper area of reg
		ANDI R17,0XF0		;preserve upper nibble of SLAVE_REG by anding with 0xF0
		ORI R17,inst_command1	;add instruction_command1 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,inst_command2	;add instruction_command2 to lower nibble of r17 by OR ing it
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,inst_command3	;add instruction_command3 to lower nibble of r17 by OR ing it
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		RET	


DATA_WRITE:
		STS PAD,R17		;copy SLAVE_REG to SRAM address PAD for processing
		ANDI R17,0XF0		;preserve upper nibble of SLAVE_REG by anding with 0xF0,lower 4 becomes 0
		ORI R17,data_command1	;add data_command1 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,data_command2	;add data_command2 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,data_command3	;add data_command3 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		LDS R17,PAD		;copy back data from PAD to r17 for processing the remaining lower nibble
		SWAP R17		;swap the nibbles in R17 so the lower nibble will occupy the upper area of reg
		ANDI R17,0XF0		;preserve upper nibble of SLAVE_REG by anding with 0xF0
		ORI R17,data_command1	;add data_command1 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,data_command2	;add data_command2 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		ORI R17,data_command3	;add data_command3 to lower nibble of r17 by OR ing it 
		RCALL TWI_WRITE		;call TWI_WRITE routine to transmit command data to LCD
		micros 20
		RET	

LCD_INIT:
		millis 50
		LDI R17,0b00111100
		RCALL TWI_WRITE
		micros 20
		LDI R17,0B00111000
		RCALL TWI_WRITE
		millis 50			; value loaded here (20) decides the number of milli seconds in the delay below
 		

		
		LDI R17,0b00111100
		RCALL TWI_WRITE
		micros 20
		LDI R17,0B00111000
		RCALL TWI_WRITE
		millis 50			; value loaded here (20) decides the number of milli seconds in the delay below
 		

		
		LDI R17,0b00111100
		RCALL TWI_WRITE
		micros 20
		LDI R17,0B00111000
		RCALL TWI_WRITE
		millis 50			; value loaded here (20) decides the number of milli seconds in the delay below
 		

		
		LDI R17,0b00101100
		RCALL TWI_WRITE
		micros 20
		LDI r17,0b00101000
		RCALL TWI_WRITE
		millis 50			; value loaded here (20) decides the number of milli seconds in the delay below
 		

		
		LDI R17,0b00101000
		RCALL COMMAND_WRITE
		micros 20

		
		LDI R17,0b00001100
		RCALL COMMAND_WRITE
		micros 20

		
		LDI R17,0b00000110
		RCALL COMMAND_WRITE
		micros 20

		
		LDI R17,0b00000001
		RCALL COMMAND_WRITE
		micros 20
		RET



posi:
		cpi r16,0x00			;check the first parameter of macro is 0 or a higher number
		breq line1			;if zero go to label first line
		ldi r16,0xc0			; if not zero the input is for 2nd line. load 0xC0 in r16 which is address of 2nd line first position DDRAM
		add r6,r16			; add with horizontal position on 2nd line to get the correct DDRAM address
		mov SLAVE_REG,r6		; copy new LCD DDRAM address to SLAVE_REG
		rcall COMMAND_WRITE		; call TWI transmit command
		ret
	line1:
		ldi r16,0x80			; if Y = 0 which means 1st line of LCD load address of 1st line 1st position DDRAM =0x80
		add r6,r16			; add 0x80 to X position saved in r6 to get the start position on 1st line
		mov SLAVE_REG,r6		; copy new LCD DDRAM address to SLAVE_REG
		rcall COMMAND_WRITE		; call TWI transmit command
		ret


array:
		lpm SLAVE_REG,Z+		;load from program memory to r17 data pointed by Z pointer
		cpi SLAVE_REG,0			; check for null terminator in the string
		breq exit		    	; if zero go to exit
		rcall DATA_WRITE		; transmit copied data to LCD via TWI
		rjmp array			; jump back to array until null
	exit: 	ret


; ============================== Time Delay Subroutines =====================
; Name:     delayYx1mS
; Purpose:  provide a delay of (YH:YL) x 1 mS
; Entry:    (YH:YL) = delay data
; Exit:     no parameters
; Notes:    the 16-bit register provides for a delay of up to 65.535 Seconds
;           requires delay1mS

delayYx1mS:
    rcall    delay1mS                        ; delay for 1 mS
    sbiw    YH:YL, 1                        ; update the the delay counter
    brne    delayYx1mS                      ; counter is not zero

; arrive here when delay counter is zero (total delay period is finished)
    ret
; ---------------------------------------------------------------------------
; Name:     delayTx1mS
; Purpose:  provide a delay of (temp) x 1 mS
; Entry:    (temp) = delay data
; Exit:     no parameters
; Notes:    the 8-bit register provides for a delay of up to 255 mS
;           requires delay1mS

delayTx1mS:
    rcall    delay1mS                        ; delay for 1 mS
    dec     temp                            ; update the delay counter
    brne    delayTx1mS                      ; counter is not zero

; arrive here when delay counter is zero (total delay period is finished)
    ret

; ---------------------------------------------------------------------------
; Name:     delay1mS
; Purpose:  provide a delay of 1 mS
; Entry:    no parameters
; Exit:     no parameters
; Notes:    chews up fclk/1000 clock cycles (including the 'call')

delay1mS:
    push    YL                              ; [2] preserve registers
    push    YH                              ; [2]
    ldi     YL, low(((fclk/1000)-18)/4)     ; [1] delay counter              (((fclk/1000)-18)/4)
    ldi     YH, high(((fclk/1000)-18)/4)    ; [1]                            (((fclk/1000)-18)/4)

delay1mS_01:
    sbiw    YH:YL, 1                        ; [2] update the the delay counter
    brne    delay1mS_01                     ; [2] delay counter is not zero

; arrive here when delay counter is zero
    pop     YH                              ; [2] restore registers
    pop     YL                              ; [2]
    ret                                     ; [4]

; ---------------------------------------------------------------------------
; Name:     delayTx1uS
; Purpose:  provide a delay of (temp) x 1 uS with a 16 MHz clock frequency
; Entry:    (temp) = delay data
; Exit:     no parameters
; Notes:    the 8-bit register provides for a delay of up to 255 uS
;           requires delay1uS

delayTx1uS:
    rcall    delay10uS                        ; delay for 1 uS
    dec     temp                            ; decrement the delay counter
    brne    delayTx1uS                      ; counter is not zero

; arrive here when delay counter is zero (total delay period is finished)
    ret

; ---------------------------------------------------------------------------
; Name:     delay10uS
; Purpose:  provide a delay of 1 uS with a 16 MHz clock frequency ;
; Entry:    no parameters
; Exit:     no parameters
; Notes:    add another push/pop for 20 MHz clock frequency

delay10uS:
    ;push    temp                            ; [2] these instructions do nothing except consume clock cycles
    ;pop     temp                            ; [2]
    ;push    temp                            ; [2]
    ;pop     temp                            ; [2]
    ;ret                                     ; [4]
     nop
     nop
     nop
     ret

; ============================== End of Time Delay Subroutines ==============

                                                                                                      
                                       


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;* Integer to ASCII converter subrountine here ,r17:r16 is the input registers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ASCII_CONVERT:
	ldi		HundredCounter,0	; set counters values to zero
	ldi		TenthCounter,0		;	
	ldi		OneCounter,0		;
	ldi		ZEROREG,48		; ASCII = Number + 48; In ASCII table, we can see that '0' is 48 (0x30); therefore, need to add 48 to the single digits
						; which convert integer value to
						; ASCII value
IntToASCII:
	LDI R18,HIGH(100)			;16bit comparison
	CLC					;clear carry
	CPI R16,100				;16bit comparison
	CPC R17,R18				;16bit comparison
	
	brge	DivideBy100			; jump if (intVal>=100) 
	LDI R18,HIGH(10)			;16bit comparison
	CLC					;clear carry
	CPI R16,10				;16bit comparison
	CPC R17,R18				;16bit comparison
	
	brge	DivideBy10			; jump if (intVal>=10)
	mov		OneCounter,r16
	add		HundredCounter,ZEROREG	; here, we got there single digits
	add		TenthCounter,ZEROREG	; from that, we convert them to
	add		OneCounter,ZEROREG	; ASCII values !!!
	ret

DivideBy100:
	
	CLR R19
	CLC
	SUBI R16,100
	SBC R17,R19
	inc		HundredCounter
	rjmp	IntToASCII

DivideBy10:
	
	CLR R19
	CLC
	SUBI R16,10
	SBC R17,R19
	inc		TenthCounter
	rjmp	IntToASCII


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

zero_suppress:					;this routine replaces all leading zeros in the result with blanks
	cpi HundredCounter,0x30
	breq blank
	ret
blank:
	ldi r16,' '
	mov HundredCounter,r16
	cpi TenthCounter,0x30
	brne exit1
	ldi r16,' '
	mov TenthCounter,r16
exit1:
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;






;***************************************************************************
; DIVISION
;***************************************************************************
;*
;* "div16u" - 16/16 Bit Unsigned Division
;*
;* This subroutine divides the two 16-bit numbers
;* "dd8uH:dd8uL" (dividend) and "dv16uH:dv16uL" (divisor).
;* The result is placed in "dres16uH:dres16uL" and the remainder in
;* "drem16uH:drem16uL".
;*
;* Number of words	:19
;* Number of cycles	:235/251 (Min/Max)
;* Low registers used	:2 (drem16uL,drem16uH)
;* High registers used  :5 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dv16uH,
;*			    dcnt16u)
;*
;***************************************************************************

;***** Subroutine Register Variables

;r14 = remainder 
;r15 = remainder
;r16 = result   
;r17 = result   
;r16 = dividend  
;r17 = dividend  
;r18 = divisor  
;r19 = divisor  
;r20 = counter  
division:
	push r14
	push r15
	push r18
	PUSH R19
	PUSH R20
	cpi r16,0		;if result low is 0 exit division to avoid division by 0
	brne start_op		;if result low is 0 exit division to avoid division by 0 = go to label ASCII_CONVERTER
	cpi r17,0		;
	breq no_signal		;even if the high register is valid it will become 0 in strt_op function, ASCII_CONVERTER is also dealing with 8 bits
				;check high register only if 16 bit result is needed to be printed on LCD.our car has max 180kmp which is less than 256.

start_op:
		mov R18,R16
		mov R19,R17
		ldi R16,low(39062)
		ldi R17,high(39062)

;***** Code

div16u:	clr	r14 		        ;clear remainder Low byte
		sub	r15,r15		;clear remainder High byte and carry
		ldi	r20,17		;init loop counter
d16u_1:	rol	r16			;shift left dividend
		rol	r17
		dec	r20		;decrement counter
		brne	d16u_2		;if done
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;any manipulation of division result ,put code here
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		lsr 	r17		;    right shift highregister
		ror 	r16		;    rotate carry to low register ,now result is divided by 2 which is same as GPS speed freq/2
no_signal:
		;LDI ZL,LOW(BUFFER)
		;LDI ZH,HIGH(BUFFER)
		;st Z+, r16
		;st Z,r17
		;MOV R11,R17
		;MOV R10,R16
		pop r20
		pop r19
		pop r18
		pop r15
		pop r14
		ret
					;    return
d16u_2:	rol	r14 		        ;    shift dividend into remainder
		rol	r15
		sub	r14,r18		;    remainder = remainder - divisor
		sbc	r15,r19		;
		brcc	d16u_3	        ;    if result negative
		add	r14 ,r18	;    restore remainder
		adc	r15,r19
		clc			;    clear carry to be shifted into result
		rjmp	d16u_1	        ;    else
d16u_3:	sec				;    set carry to be shifted into result
		rjmp	d16u_1



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;




 string:
.db "Hello!",0 
string3:
.db "SPEED    KM/H",0  

 

Attachment(s): 

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

>I have used ASYNCH for both generator & user while you have SYNCCH for generator & ASYNCH for user.

 

If you look at the Tcb chapter in the datasheet, in the Events sections it shows what type of events you can use and in this case you are limited to a Sync generator.

 

The example code was an example, and was using headers/devices only I would have, so it will not compile for anyone else. The following is the same thing, but stripped down to the essentials. You should be able to create a 804 project, create a main.c file, copy/paste the following in it (replace everything).  You can run with debugger, let it run with whatever signal you have, put a breakpoint on the sei(), view the v or tcb0_value. Disable the breakpoint, repeat. The timers are halted by default when debugger stops, so this just lets things run a little bit between reading values. The v var could also be sent out the uart, or if you translate the lcd/twi code to c, to the lcd. You can also reuse the asm code and call from C, but you are not using the registers the C compiler expects so would need to rewrite the asm to comply.

 

So the main idea is the freq measurement happens in the background, and all you are left to do is read tcb0_value whenever you want. If its 0, then there is no signal.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#define F_CPU 3333333ul //default if fused to OSC20M
#include <util/delay.h>

 

typedef uint8_t  u8;
typedef uint16_t u16;

 

volatile u8 tca0_timeout = 8;   //need n good tcb irq's after a timeout
volatile u16 tcb0_value = 0;    //0 = tca timeout

 

void timersInit(){
    //tca0 1 second timeout, ovf irq, clock source for tcb0
    //normal mode, PER=TOP, OVF=TOP
    TCA0.SINGLE.INTFLAGS = 1;       //ovf flag
    TCA0.SINGLE.INTCTRL = 1;        //ovf irq
    TCA0.SINGLE.CNT = 0;
    TCA0.SINGLE.PER= F_CPU/256-1;   //1 second
    TCA0.SINGLE.CTRLA = (6<<1)|1;   //div256, enable

    //tcb0
    TCB0.CTRLB = 3;                 //FRQ frequency
    TCB0.EVCTRL = (1<<4)|1;         //edge=1, captei
    TCB0.INTFLAGS = 1;              //capt flag
    TCB0.INTCTRL = 1;               //captei
    TCB0.CTRLA = (2<<1)|1;          //TCA0 CLK, enable

    //evsys
    EVSYS.SYNCCH0 = 0x0E;           //PA1 (pin is already input by default)
    EVSYS.ASYNCUSER0 = 1;           //TCB0, sync ch0
}

 

ISR( TCA0_OVF_vect ){               //1 second timeout with no tcb0 activity
    TCA0.SINGLE.INTFLAGS = 1;       //clear ovf
    tca0_timeout = 8;               //reset to some value
    tcb0_value = 0;                 //tcb0 value no good
}

 

ISR( TCB0_INT_vect ){
    TCA0.SINGLE.CNT = 0;            //reset tca0
    if( tca0_timeout ) tca0_timeout--; //dec count if not 0
    u16 ccmp = TCB0.CCMP;           //read also clears flag
    if( tca0_timeout ) return;      //not at 0 yet
    tcb0_value = ccmp;              // >= n good irq's, value is good
}

 

int main(){

    timersInit();

    sei();
    while(1) {

        cli();
        u16 v = tcb0_value; //protected read
        sei();
        
        //if v == 0, no signal
        //do whatever you want with v, which is the raw 16bit capture count

 

        _delay_ms(300); //do other things or kill time

    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir Curtvm,

Thanks for the kindness , nice explanation & code. I'll compile ,study and comeback to present my fault. It may take a while though.

Regards

 

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Welcome to the Forum.

 

You have a great project!

 

Sometimes a Flow Chart can be a helpful design tool, to help structure the program before one starts writing code.

 

I drew a rough flow chart for your project, below.

 

As Version #1 of the project, it doesn't use interrupts to read the Temperature or fuel level, or to update the display.

(There are a lot of ways one could structure this program!)

 

As drawn, it shows that each section is its own little block, and you can write and test them separately.

 

With this in mind you can work on writing your "Read Speed" section of the code so that it does have a time out to force an exit if the speed is 0, (or very slow).

That section might use a timer running in the background and keep checking to see how long it is taking to get a pulse.

The background timer might use a Timer/Counter in CTC mode to generate an interrupt once every 1 mSec, (or whatever you decide), as your "clock" for easily counting time.

 

Also, since your project is in a vehicle, Google "Load Dump" for some articles and App Notes on protecting your circuit from the electrical noise and spikes that are present on vehicle power buses.

Protecting the input signal with an opto-isolator is a great idea!

You also, however, need to protect the power supply for the micro itself, if that is powered from the vehicle's battery.

 

Good luck with your project!

 

Post a photo when you have it working and installed!

 

JC

 

Last Edited: Sat. Mar 13, 2021 - 05:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir DocJC,

Thankyou for the uplifting comments & the nice flowchart ! Implementing a flowchart will help me to decide where to focus . I will also google and study "load dump" which you have suggested. Once completed I will post the picture & code here.

Thanks & Regards

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir Curtvm,

testing done on 804speed code published in comment # 8

I changed the ASYNCH generator I used earlier to SYNCCH generator as you have specified in the C code with values you have given ,but the output was still 0kmph. When I disabled the pullup resistor on PA1 which I had set earlier under RESET function, the code started giving output on the LCD (means ISR firing). I think the fault was enabling the internal pullup resistor on PA1 (speed input).

                                       

 It was like this- 

                                         

                ldi r16,0b00000010		; enable PA1 pullup resistor for speed signal
		sts PORTA_PIN1CTRL,r16

I changed it to-

                ldi r16,0b00000000		; disable PA1 pullup resistor for speed signal
		sts PORTA_PIN1CTRL,r16

Once this is done the LCD started displaying speed signal.

I swapped the event generator & user  with my original setup/code & your example and found both settings displayed the same output/speed on the LCD. [ I have used ASYNCH for both generator & user while you have SYNCCH for generator & ASYNCH for user ]

 

1) What could have happened when the pullup was enabled ? signal short to volt?

2)Kindly correct me whether I understood this correctly. The data sheet shows GPIO PA1 listed under Asynchronous event & Synchronous event generator . TCB0 is listed as ASYNCH user but can be connected to SYNCH0,ASYNCH0,ASYNCH1 generators. If this is the case  the speed signal should be considered as an asynchronous signal (not related to cpu clock if i understood correctly). If I am wrong what would be the qualifier/criteria for synchronous & asynchronous signals in the event system?

 

Thanks again for providing the example code . Looking forward for some comments on the doubts raised above

 

Regards

darth vader

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
ldi r16,0b00000010		; enable PA1 pullup resistor for speed signal

That is a RISING interrupt, not PULLUPEN.

 

You will also have to read the EVSYS chapter in the datasheet. The tcb event table in the TCB chapter indicates it can use a SYNC channel in the mode used, but its not hard to imagine an ASYNC channel also works with the same requirements as SYNC where you need an event long enough to get synced to the clock. Datasheet interpretation is not an exact science, and you go by what you see in action.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Dear Sir Curtvm,

Yes! Now everything is clear . I thought I was enabling the pullup resistor on PA1 by writing 

ldi r16,0b00000010		; enable PA1 pullup resistor for speed signal

By doing above I enabled the wrong bit in the PORTA_PIN1CTRL register because I read the wrong table in the data sheet

 

I read this table for bit position 3 but enabled bit position1

 

 

 

The correct code would be 

ldi r16,0b00001000              ;enable bit3 ,pullup enable bit
sts PORTA_PIN1CTRL,r16          ;store in portA pin 1 control register

I will enable the correct bit and try again

Thanks for the diagnosis

Regards

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

This is the kind of error that happens when you use raw bit numbers like 0b00000010. If you look at the asm header file for tiny804:

C:\Program Files (x86)\Atmel\Studio\7.0\packs\atmel\ATtiny_DFP\1.8.332\avrasm\inc>grep PULLUPEN tn804def.inc
.equ PORT_PULLUPEN_bm = 0x08             ; Pullup enable bit mask
.equ PORT_PULLUPEN_bp = 3                ; Pullup enable bit position

then there are two forms of "PULLUPEN" defined there. So instead of:

ldi r16,0b00001000              ;enable bit3 ,pullup enable bit
sts PORTA_PIN1CTRL,r16          ;store in portA pin 1 control register

you could either write:

ldi r16,(1 << PORT_PULLUPEN_bp) ;enable bit3 ,pullup enable bit
sts PORTA_PIN1CTRL,r16          ;store in portA pin 1 control register

or, for no other reason that it is simply less typing!, it is probably easier to use:

ldi r16,PORT_PULLUPEN_bm        ;enable bit3 ,pullup enable bit
sts PORTA_PIN1CTRL,r16          ;store in portA pin 1 control register

Not only does this prevent the kind of 0b00000010/0b000001000 accident you made but there's a certain argument to say you don't even need the comment. The very fact you are writing something called "PORT_PULLUPEN" is surely a large enough clue to the reader as to what is going on anyway?

 

You will find that almost every control bit mentioned in the Tiny804 datasheet also has a similar definition in that tn804def.inc header file:

C:\Program Files (x86)\Atmel\Studio\7.0\packs\atmel\ATtiny_DFP\1.8.332\avrasm\inc>grep _bm tn804def.inc
.equ AC_ENABLE_bm = 0x01                 ; Enable bit mask
.equ AC_HYSMODE0_bm = (1<<1)             ; Hysteresis Mode bit 0 mask
.equ AC_HYSMODE1_bm = (1<<2)             ; Hysteresis Mode bit 1 mask
.equ AC_INTMODE0_bm = (1<<4)             ; Interrupt Mode bit 0 mask
.equ AC_INTMODE1_bm = (1<<5)             ; Interrupt Mode bit 1 mask
.equ AC_OUTEN_bm = 0x40                  ; Output Buffer Enable bit mask
.equ AC_RUNSTDBY_bm = 0x80               ; Run in Standby Mode bit mask
.equ AC_CMP_bm = 0x01                    ; Analog Comparator 0 Interrupt Enable bit mask
.equ AC_INVERT_bm = 0x80                 ; Invert AC Output bit mask
.equ AC_MUXNEG0_bm = (1<<0)              ; Negative Input MUX Selection bit 0 mask
.equ AC_MUXNEG1_bm = (1<<1)              ; Negative Input MUX Selection bit 1 mask
.equ AC_MUXPOS0_bm = (1<<3)              ; Positive Input MUX Selection bit 0 mask
.equ AC_MUXPOS1_bm = (1<<4)              ; Positive Input MUX Selection bit 1 mask
.equ AC_STATE_bm = 0x10                  ; Analog Comparator State bit mask
.equ ADC_DUTYCYC_bm = 0x01               ; Duty Cycle bit mask
.equ ADC_STCONV_bm = 0x01                ; Start Conversion Operation bit mask
.equ ADC_ENABLE_bm = 0x01                ; ADC Enable bit mask
.equ ADC_FREERUN_bm = 0x02               ; ADC Freerun mode bit mask
.equ ADC_RESSEL_bm = 0x04                ; ADC Resolution bit mask
.equ ADC_RUNSTBY_bm = 0x80               ; Run standby mode bit mask
.equ ADC_SAMPNUM0_bm = (1<<0)            ; Accumulation Samples bit 0 mask
.equ ADC_SAMPNUM1_bm = (1<<1)            ; Accumulation Samples bit 1 mask
.equ ADC_SAMPNUM2_bm = (1<<2)            ; Accumulation Samples bit 2 mask
.equ ADC_PRESC0_bm = (1<<0)              ; Clock Pre-scaler bit 0 mask
.equ ADC_PRESC1_bm = (1<<1)              ; Clock Pre-scaler bit 1 mask
.equ ADC_PRESC2_bm = (1<<2)              ; Clock Pre-scaler bit 2 mask
.equ ADC_REFSEL0_bm = (1<<4)             ; Reference Selection bit 0 mask
.equ ADC_REFSEL1_bm = (1<<5)             ; Reference Selection bit 1 mask
.equ ADC_SAMPCAP_bm = 0x40               ; Sample Capacitance Selection bit mask
.equ ADC_ASDV_bm = 0x10                  ; Automatic Sampling Delay Variation bit mask
.equ ADC_INITDLY0_bm = (1<<5)            ; Initial Delay Selection bit 0 mask
.equ ADC_INITDLY1_bm = (1<<6)            ; Initial Delay Selection bit 1 mask
.equ ADC_INITDLY2_bm = (1<<7)            ; Initial Delay Selection bit 2 mask
.equ ADC_SAMPDLY0_bm = (1<<0)            ; Sampling Delay Selection bit 0 mask
.equ ADC_SAMPDLY1_bm = (1<<1)            ; Sampling Delay Selection bit 1 mask
.equ ADC_SAMPDLY2_bm = (1<<2)            ; Sampling Delay Selection bit 2 mask
.equ ADC_SAMPDLY3_bm = (1<<3)            ; Sampling Delay Selection bit 3 mask
.equ ADC_WINCM0_bm = (1<<0)              ; Window Comparator Mode bit 0 mask
.equ ADC_WINCM1_bm = (1<<1)              ; Window Comparator Mode bit 1 mask
.equ ADC_WINCM2_bm = (1<<2)              ; Window Comparator Mode bit 2 mask
.equ ADC_DBGRUN_bm = 0x01                ; Debug run bit mask
.equ ADC_STARTEI_bm = 0x01               ; Start Event Input Enable bit mask
.equ ADC_RESRDY_bm = 0x01                ; Result Ready Interrupt Enable bit mask
.equ ADC_WCMP_bm = 0x02                  ; Window Comparator Interrupt Enable bit mask
.equ ADC_MUXPOS0_bm = (1<<0)             ; Analog Channel Selection Bits bit 0 mask
.equ ADC_MUXPOS1_bm = (1<<1)             ; Analog Channel Selection Bits bit 1 mask
.equ ADC_MUXPOS2_bm = (1<<2)             ; Analog Channel Selection Bits bit 2 mask
.equ ADC_MUXPOS3_bm = (1<<3)             ; Analog Channel Selection Bits bit 3 mask
.equ ADC_MUXPOS4_bm = (1<<4)             ; Analog Channel Selection Bits bit 4 mask
.equ ADC_SAMPLEN0_bm = (1<<0)            ; Sample lenght bit 0 mask
.equ ADC_SAMPLEN1_bm = (1<<1)            ; Sample lenght bit 1 mask
.equ ADC_SAMPLEN2_bm = (1<<2)            ; Sample lenght bit 2 mask
.equ ADC_SAMPLEN3_bm = (1<<3)            ; Sample lenght bit 3 mask
.equ ADC_SAMPLEN4_bm = (1<<4)            ; Sample lenght bit 4 mask
.equ ADC_TEMP0_bm = (1<<0)               ; Temporary bit 0 mask
.equ ADC_TEMP1_bm = (1<<1)               ; Temporary bit 1 mask
.equ ADC_TEMP2_bm = (1<<2)               ; Temporary bit 2 mask
.equ ADC_TEMP3_bm = (1<<3)               ; Temporary bit 3 mask
.equ ADC_TEMP4_bm = (1<<4)               ; Temporary bit 4 mask
.equ ADC_TEMP5_bm = (1<<5)               ; Temporary bit 5 mask
.equ ADC_TEMP6_bm = (1<<6)               ; Temporary bit 6 mask
.equ ADC_TEMP7_bm = (1<<7)               ; Temporary bit 7 mask
.equ BOD_ACTIVE0_bm = (1<<2)             ; Operation in active mode bit 0 mask
.equ BOD_ACTIVE1_bm = (1<<3)             ; Operation in active mode bit 1 mask
.equ BOD_SAMPFREQ_bm = 0x10              ; Sample frequency bit mask
.equ BOD_SLEEP0_bm = (1<<0)              ; Operation in sleep mode bit 0 mask
.equ BOD_SLEEP1_bm = (1<<1)              ; Operation in sleep mode bit 1 mask
.equ BOD_LVL0_bm = (1<<0)                ; Bod level bit 0 mask
.equ BOD_LVL1_bm = (1<<1)                ; Bod level bit 1 mask
.equ BOD_LVL2_bm = (1<<2)                ; Bod level bit 2 mask
.equ BOD_VLMCFG0_bm = (1<<1)             ; Configuration bit 0 mask
.equ BOD_VLMCFG1_bm = (1<<2)             ; Configuration bit 1 mask
.equ BOD_VLMIE_bm = 0x01                 ; voltage level monitor interrrupt enable bit mask
.equ BOD_VLMIF_bm = 0x01                 ; Voltage level monitor interrupt flag bit mask
.equ BOD_VLMS_bm = 0x01                  ; Voltage level monitor status bit mask
.equ BOD_VLMLVL0_bm = (1<<0)             ; voltage level monitor level bit 0 mask
.equ BOD_VLMLVL1_bm = (1<<1)             ; voltage level monitor level bit 1 mask
.equ CCL_ENABLE_bm = 0x01                ; Enable bit mask
.equ CCL_RUNSTDBY_bm = 0x40              ; Run in Standby bit mask
.equ CCL_CLKSRC_bm = 0x40                ; Clock Source Selection bit mask
.equ CCL_EDGEDET_bm = 0x80               ; Edge Detection Enable bit mask
.equ CCL_FILTSEL0_bm = (1<<4)            ; Filter Selection bit 0 mask
.equ CCL_FILTSEL1_bm = (1<<5)            ; Filter Selection bit 1 mask
.equ CCL_OUTEN_bm = 0x08                 ; Output Enable bit mask
.equ CCL_INSEL00_bm = (1<<0)             ; LUT Input 0 Source Selection bit 0 mask
.equ CCL_INSEL01_bm = (1<<1)             ; LUT Input 0 Source Selection bit 1 mask
.equ CCL_INSEL02_bm = (1<<2)             ; LUT Input 0 Source Selection bit 2 mask
.equ CCL_INSEL03_bm = (1<<3)             ; LUT Input 0 Source Selection bit 3 mask
.equ CCL_INSEL10_bm = (1<<4)             ; LUT Input 1 Source Selection bit 0 mask
.equ CCL_INSEL11_bm = (1<<5)             ; LUT Input 1 Source Selection bit 1 mask
.equ CCL_INSEL12_bm = (1<<6)             ; LUT Input 1 Source Selection bit 2 mask
.equ CCL_INSEL13_bm = (1<<7)             ; LUT Input 1 Source Selection bit 3 mask
.equ CCL_INSEL20_bm = (1<<0)             ; LUT Input 2 Source Selection bit 0 mask
.equ CCL_INSEL21_bm = (1<<1)             ; LUT Input 2 Source Selection bit 1 mask
.equ CCL_INSEL22_bm = (1<<2)             ; LUT Input 2 Source Selection bit 2 mask
.equ CCL_INSEL23_bm = (1<<3)             ; LUT Input 2 Source Selection bit 3 mask
.equ CCL_SEQSEL0_bm = (1<<0)             ; Sequential Selection bit 0 mask
.equ CCL_SEQSEL1_bm = (1<<1)             ; Sequential Selection bit 1 mask
.equ CCL_SEQSEL2_bm = (1<<2)             ; Sequential Selection bit 2 mask
.equ CLKCTRL_CLKOUT_bm = 0x80            ; System clock out bit mask
.equ CLKCTRL_CLKSEL0_bm = (1<<0)         ; clock select bit 0 mask
.equ CLKCTRL_CLKSEL1_bm = (1<<1)         ; clock select bit 1 mask
.equ CLKCTRL_PDIV0_bm = (1<<1)           ; Prescaler division bit 0 mask
.equ CLKCTRL_PDIV1_bm = (1<<2)           ; Prescaler division bit 1 mask
.equ CLKCTRL_PDIV2_bm = (1<<3)           ; Prescaler division bit 2 mask
.equ CLKCTRL_PDIV3_bm = (1<<4)           ; Prescaler division bit 3 mask
.equ CLKCTRL_PEN_bm = 0x01               ; Prescaler enable bit mask
.equ CLKCTRL_LOCKEN_bm = 0x01            ; lock ebable bit mask
.equ CLKCTRL_EXTS_bm = 0x80              ; External Clock status bit mask
.equ CLKCTRL_OSC20MS_bm = 0x10           ; 20MHz oscillator status bit mask
.equ CLKCTRL_OSC32KS_bm = 0x20           ; 32KHz oscillator status bit mask
.equ CLKCTRL_SOSC_bm = 0x01              ; System Oscillator changing bit mask
.equ CLKCTRL_XOSC32KS_bm = 0x40          ; 32.768 kHz Crystal Oscillator status bit mask
.equ CLKCTRL_CAL20M0_bm = (1<<0)         ; Calibration bit 0 mask
.equ CLKCTRL_CAL20M1_bm = (1<<1)         ; Calibration bit 1 mask
.equ CLKCTRL_CAL20M2_bm = (1<<2)         ; Calibration bit 2 mask
.equ CLKCTRL_CAL20M3_bm = (1<<3)         ; Calibration bit 3 mask
.equ CLKCTRL_CAL20M4_bm = (1<<4)         ; Calibration bit 4 mask
.equ CLKCTRL_CAL20M5_bm = (1<<5)         ; Calibration bit 5 mask
.equ CLKCTRL_LOCK_bm = 0x80              ; Lock bit mask
.equ CLKCTRL_TEMPCAL20M0_bm = (1<<0)     ; Oscillator temperature coefficient bit 0 mask
.equ CLKCTRL_TEMPCAL20M1_bm = (1<<1)     ; Oscillator temperature coefficient bit 1 mask
.equ CLKCTRL_TEMPCAL20M2_bm = (1<<2)     ; Oscillator temperature coefficient bit 2 mask
.equ CLKCTRL_TEMPCAL20M3_bm = (1<<3)     ; Oscillator temperature coefficient bit 3 mask
.equ CLKCTRL_RUNSTDBY_bm = 0x02          ; Run standby bit mask
.equ CPU_CCP0_bm = (1<<0)                ; CCP signature bit 0 mask
.equ CPU_CCP1_bm = (1<<1)                ; CCP signature bit 1 mask
.equ CPU_CCP2_bm = (1<<2)                ; CCP signature bit 2 mask
.equ CPU_CCP3_bm = (1<<3)                ; CCP signature bit 3 mask
.equ CPU_CCP4_bm = (1<<4)                ; CCP signature bit 4 mask
.equ CPU_CCP5_bm = (1<<5)                ; CCP signature bit 5 mask
.equ CPU_CCP6_bm = (1<<6)                ; CCP signature bit 6 mask
.equ CPU_CCP7_bm = (1<<7)                ; CCP signature bit 7 mask
.equ CPU_C_bm = 0x01                     ; Carry Flag bit mask
.equ CPU_H_bm = 0x20                     ; Half Carry Flag bit mask
.equ CPU_I_bm = 0x80                     ; Global Interrupt Enable Flag bit mask
.equ CPU_N_bm = 0x04                     ; Negative Flag bit mask
.equ CPU_S_bm = 0x10                     ; N Exclusive Or V Flag bit mask
.equ CPU_T_bm = 0x40                     ; Transfer Bit bit mask
.equ CPU_V_bm = 0x08                     ; Two's Complement Overflow Flag bit mask
.equ CPU_Z_bm = 0x02                     ; Zero Flag bit mask
.equ CPUINT_CVT_bm = 0x20                ; Compact Vector Table bit mask
.equ CPUINT_IVSEL_bm = 0x40              ; Interrupt Vector Select bit mask
.equ CPUINT_LVL0RR_bm = 0x01             ; Round-robin Scheduling Enable bit mask
.equ CPUINT_LVL0PRI0_bm = (1<<0)         ; Interrupt Level Priority bit 0 mask
.equ CPUINT_LVL0PRI1_bm = (1<<1)         ; Interrupt Level Priority bit 1 mask
.equ CPUINT_LVL0PRI2_bm = (1<<2)         ; Interrupt Level Priority bit 2 mask
.equ CPUINT_LVL0PRI3_bm = (1<<3)         ; Interrupt Level Priority bit 3 mask
.equ CPUINT_LVL0PRI4_bm = (1<<4)         ; Interrupt Level Priority bit 4 mask
.equ CPUINT_LVL0PRI5_bm = (1<<5)         ; Interrupt Level Priority bit 5 mask
.equ CPUINT_LVL0PRI6_bm = (1<<6)         ; Interrupt Level Priority bit 6 mask
.equ CPUINT_LVL0PRI7_bm = (1<<7)         ; Interrupt Level Priority bit 7 mask
.equ CPUINT_LVL1VEC0_bm = (1<<0)         ; Interrupt Vector with High Priority bit 0 mask
.equ CPUINT_LVL1VEC1_bm = (1<<1)         ; Interrupt Vector with High Priority bit 1 mask
.equ CPUINT_LVL1VEC2_bm = (1<<2)         ; Interrupt Vector with High Priority bit 2 mask
.equ CPUINT_LVL1VEC3_bm = (1<<3)         ; Interrupt Vector with High Priority bit 3 mask
.equ CPUINT_LVL1VEC4_bm = (1<<4)         ; Interrupt Vector with High Priority bit 4 mask
.equ CPUINT_LVL1VEC5_bm = (1<<5)         ; Interrupt Vector with High Priority bit 5 mask
.equ CPUINT_LVL1VEC6_bm = (1<<6)         ; Interrupt Vector with High Priority bit 6 mask
.equ CPUINT_LVL1VEC7_bm = (1<<7)         ; Interrupt Vector with High Priority bit 7 mask
.equ CPUINT_LVL0EX_bm = 0x01             ; Level 0 Interrupt Executing bit mask
.equ CPUINT_LVL1EX_bm = 0x02             ; Level 1 Interrupt Executing bit mask
.equ CPUINT_NMIEX_bm = 0x80              ; Non-maskable Interrupt Executing bit mask
.equ CRCSCAN_ENABLE_bm = 0x01            ; Enable CRC scan bit mask
.equ CRCSCAN_NMIEN_bm = 0x02             ; Enable NMI Trigger bit mask
.equ CRCSCAN_RESET_bm = 0x80             ; Reset CRC scan bit mask
.equ CRCSCAN_SRC0_bm = (1<<0)            ; CRC Source bit 0 mask
.equ CRCSCAN_SRC1_bm = (1<<1)            ; CRC Source bit 1 mask
.equ CRCSCAN_BUSY_bm = 0x01              ; CRC Busy bit mask
.equ CRCSCAN_OK_bm = 0x02                ; CRC Ok bit mask
.equ EVSYS_ASYNCCH00_bm = (1<<0)         ; Asynchronous Channel 0 Generator Selection bit 0 mask
.equ EVSYS_ASYNCCH01_bm = (1<<1)         ; Asynchronous Channel 0 Generator Selection bit 1 mask
.equ EVSYS_ASYNCCH02_bm = (1<<2)         ; Asynchronous Channel 0 Generator Selection bit 2 mask
.equ EVSYS_ASYNCCH03_bm = (1<<3)         ; Asynchronous Channel 0 Generator Selection bit 3 mask
.equ EVSYS_ASYNCCH04_bm = (1<<4)         ; Asynchronous Channel 0 Generator Selection bit 4 mask
.equ EVSYS_ASYNCCH05_bm = (1<<5)         ; Asynchronous Channel 0 Generator Selection bit 5 mask
.equ EVSYS_ASYNCCH06_bm = (1<<6)         ; Asynchronous Channel 0 Generator Selection bit 6 mask
.equ EVSYS_ASYNCCH07_bm = (1<<7)         ; Asynchronous Channel 0 Generator Selection bit 7 mask
.equ EVSYS_ASYNCCH10_bm = (1<<0)         ; Asynchronous Channel 1 Generator Selection bit 0 mask
.equ EVSYS_ASYNCCH11_bm = (1<<1)         ; Asynchronous Channel 1 Generator Selection bit 1 mask
.equ EVSYS_ASYNCCH12_bm = (1<<2)         ; Asynchronous Channel 1 Generator Selection bit 2 mask
.equ EVSYS_ASYNCCH13_bm = (1<<3)         ; Asynchronous Channel 1 Generator Selection bit 3 mask
.equ EVSYS_ASYNCCH14_bm = (1<<4)         ; Asynchronous Channel 1 Generator Selection bit 4 mask
.equ EVSYS_ASYNCCH15_bm = (1<<5)         ; Asynchronous Channel 1 Generator Selection bit 5 mask
.equ EVSYS_ASYNCCH16_bm = (1<<6)         ; Asynchronous Channel 1 Generator Selection bit 6 mask
.equ EVSYS_ASYNCCH17_bm = (1<<7)         ; Asynchronous Channel 1 Generator Selection bit 7 mask
.equ EVSYS_ASYNCUSER00_bm = (1<<0)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 0 mask
.equ EVSYS_ASYNCUSER01_bm = (1<<1)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 1 mask
.equ EVSYS_ASYNCUSER02_bm = (1<<2)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 2 mask
.equ EVSYS_ASYNCUSER03_bm = (1<<3)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 3 mask
.equ EVSYS_ASYNCUSER04_bm = (1<<4)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 4 mask
.equ EVSYS_ASYNCUSER05_bm = (1<<5)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 5 mask
.equ EVSYS_ASYNCUSER06_bm = (1<<6)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 6 mask
.equ EVSYS_ASYNCUSER07_bm = (1<<7)       ; Asynchronous User Ch 0 Input Selection - TCB0 bit 7 mask
.equ EVSYS_ASYNCUSER10_bm = (1<<0)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 0 mask
.equ EVSYS_ASYNCUSER11_bm = (1<<1)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 1 mask
.equ EVSYS_ASYNCUSER12_bm = (1<<2)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 2 mask
.equ EVSYS_ASYNCUSER13_bm = (1<<3)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 3 mask
.equ EVSYS_ASYNCUSER14_bm = (1<<4)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 4 mask
.equ EVSYS_ASYNCUSER15_bm = (1<<5)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 5 mask
.equ EVSYS_ASYNCUSER16_bm = (1<<6)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 6 mask
.equ EVSYS_ASYNCUSER17_bm = (1<<7)       ; Asynchronous User Ch 1 Input Selection - ADC0 bit 7 mask
.equ EVSYS_ASYNCUSER20_bm = (1<<0)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 0 mask
.equ EVSYS_ASYNCUSER21_bm = (1<<1)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 1 mask
.equ EVSYS_ASYNCUSER22_bm = (1<<2)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 2 mask
.equ EVSYS_ASYNCUSER23_bm = (1<<3)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 3 mask
.equ EVSYS_ASYNCUSER24_bm = (1<<4)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 4 mask
.equ EVSYS_ASYNCUSER25_bm = (1<<5)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 5 mask
.equ EVSYS_ASYNCUSER26_bm = (1<<6)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 6 mask
.equ EVSYS_ASYNCUSER27_bm = (1<<7)       ; Asynchronous User Ch 2 Input Selection - CCL LUT0 Event 0 bit 7 mask
.equ EVSYS_ASYNCUSER30_bm = (1<<0)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 0 mask
.equ EVSYS_ASYNCUSER31_bm = (1<<1)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 1 mask
.equ EVSYS_ASYNCUSER32_bm = (1<<2)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 2 mask
.equ EVSYS_ASYNCUSER33_bm = (1<<3)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 3 mask
.equ EVSYS_ASYNCUSER34_bm = (1<<4)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 4 mask
.equ EVSYS_ASYNCUSER35_bm = (1<<5)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 5 mask
.equ EVSYS_ASYNCUSER36_bm = (1<<6)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 6 mask
.equ EVSYS_ASYNCUSER37_bm = (1<<7)       ; Asynchronous User Ch 3 Input Selection - CCL LUT1 Event 0 bit 7 mask
.equ EVSYS_ASYNCUSER40_bm = (1<<0)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 0 mask
.equ EVSYS_ASYNCUSER41_bm = (1<<1)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 1 mask
.equ EVSYS_ASYNCUSER42_bm = (1<<2)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 2 mask
.equ EVSYS_ASYNCUSER43_bm = (1<<3)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 3 mask
.equ EVSYS_ASYNCUSER44_bm = (1<<4)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 4 mask
.equ EVSYS_ASYNCUSER45_bm = (1<<5)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 5 mask
.equ EVSYS_ASYNCUSER46_bm = (1<<6)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 6 mask
.equ EVSYS_ASYNCUSER47_bm = (1<<7)       ; Asynchronous User Ch 4 Input Selection - CCL LUT0 Event 1 bit 7 mask
.equ EVSYS_ASYNCUSER50_bm = (1<<0)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 0 mask
.equ EVSYS_ASYNCUSER51_bm = (1<<1)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 1 mask
.equ EVSYS_ASYNCUSER52_bm = (1<<2)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 2 mask
.equ EVSYS_ASYNCUSER53_bm = (1<<3)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 3 mask
.equ EVSYS_ASYNCUSER54_bm = (1<<4)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 4 mask
.equ EVSYS_ASYNCUSER55_bm = (1<<5)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 5 mask
.equ EVSYS_ASYNCUSER56_bm = (1<<6)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 6 mask
.equ EVSYS_ASYNCUSER57_bm = (1<<7)       ; Asynchronous User Ch 5 Input Selection - CCL LUT1 Event 1 bit 7 mask
.equ EVSYS_ASYNCUSER60_bm = (1<<0)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 0 mask
.equ EVSYS_ASYNCUSER61_bm = (1<<1)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 1 mask
.equ EVSYS_ASYNCUSER62_bm = (1<<2)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 2 mask
.equ EVSYS_ASYNCUSER63_bm = (1<<3)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 3 mask
.equ EVSYS_ASYNCUSER64_bm = (1<<4)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 4 mask
.equ EVSYS_ASYNCUSER65_bm = (1<<5)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 5 mask
.equ EVSYS_ASYNCUSER66_bm = (1<<6)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 6 mask
.equ EVSYS_ASYNCUSER67_bm = (1<<7)       ; Asynchronous User Ch 6 Input Selection - TCD0 Event 0 bit 7 mask
.equ EVSYS_ASYNCUSER70_bm = (1<<0)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 0 mask
.equ EVSYS_ASYNCUSER71_bm = (1<<1)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 1 mask
.equ EVSYS_ASYNCUSER72_bm = (1<<2)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 2 mask
.equ EVSYS_ASYNCUSER73_bm = (1<<3)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 3 mask
.equ EVSYS_ASYNCUSER74_bm = (1<<4)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 4 mask
.equ EVSYS_ASYNCUSER75_bm = (1<<5)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 5 mask
.equ EVSYS_ASYNCUSER76_bm = (1<<6)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 6 mask
.equ EVSYS_ASYNCUSER77_bm = (1<<7)       ; Asynchronous User Ch 7 Input Selection - TCD0 Event 1 bit 7 mask
.equ EVSYS_ASYNCUSER80_bm = (1<<0)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 0 mask
.equ EVSYS_ASYNCUSER81_bm = (1<<1)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 1 mask
.equ EVSYS_ASYNCUSER82_bm = (1<<2)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 2 mask
.equ EVSYS_ASYNCUSER83_bm = (1<<3)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 3 mask
.equ EVSYS_ASYNCUSER84_bm = (1<<4)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 4 mask
.equ EVSYS_ASYNCUSER85_bm = (1<<5)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 5 mask
.equ EVSYS_ASYNCUSER86_bm = (1<<6)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 6 mask
.equ EVSYS_ASYNCUSER87_bm = (1<<7)       ; Asynchronous User Ch 8 Input Selection - Event Out 0 bit 7 mask
.equ EVSYS_ASYNCUSER90_bm = (1<<0)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 0 mask
.equ EVSYS_ASYNCUSER91_bm = (1<<1)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 1 mask
.equ EVSYS_ASYNCUSER92_bm = (1<<2)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 2 mask
.equ EVSYS_ASYNCUSER93_bm = (1<<3)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 3 mask
.equ EVSYS_ASYNCUSER94_bm = (1<<4)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 4 mask
.equ EVSYS_ASYNCUSER95_bm = (1<<5)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 5 mask
.equ EVSYS_ASYNCUSER96_bm = (1<<6)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 6 mask
.equ EVSYS_ASYNCUSER97_bm = (1<<7)       ; Asynchronous User Ch 9 Input Selection - Event Out 1 bit 7 mask
.equ EVSYS_ASYNCUSER100_bm = (1<<0)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 0 mask
.equ EVSYS_ASYNCUSER101_bm = (1<<1)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 1 mask
.equ EVSYS_ASYNCUSER102_bm = (1<<2)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 2 mask
.equ EVSYS_ASYNCUSER103_bm = (1<<3)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 3 mask
.equ EVSYS_ASYNCUSER104_bm = (1<<4)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 4 mask
.equ EVSYS_ASYNCUSER105_bm = (1<<5)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 5 mask
.equ EVSYS_ASYNCUSER106_bm = (1<<6)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 6 mask
.equ EVSYS_ASYNCUSER107_bm = (1<<7)      ; Asynchronous User Ch 10 Input Selection - Event Out 2 bit 7 mask
.equ EVSYS_ASYNCUSER110_bm = (1<<0)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 0 mask
.equ EVSYS_ASYNCUSER111_bm = (1<<1)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 1 mask
.equ EVSYS_ASYNCUSER112_bm = (1<<2)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 2 mask
.equ EVSYS_ASYNCUSER113_bm = (1<<3)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 3 mask
.equ EVSYS_ASYNCUSER114_bm = (1<<4)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 4 mask
.equ EVSYS_ASYNCUSER115_bm = (1<<5)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 5 mask
.equ EVSYS_ASYNCUSER116_bm = (1<<6)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 6 mask
.equ EVSYS_ASYNCUSER117_bm = (1<<7)      ; Asynchronous User Ch 11 Input Selection - TCB1 bit 7 mask
.equ EVSYS_ASYNCUSER120_bm = (1<<0)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 0 mask
.equ EVSYS_ASYNCUSER121_bm = (1<<1)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 1 mask
.equ EVSYS_ASYNCUSER122_bm = (1<<2)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 2 mask
.equ EVSYS_ASYNCUSER123_bm = (1<<3)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 3 mask
.equ EVSYS_ASYNCUSER124_bm = (1<<4)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 4 mask
.equ EVSYS_ASYNCUSER125_bm = (1<<5)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 5 mask
.equ EVSYS_ASYNCUSER126_bm = (1<<6)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 6 mask
.equ EVSYS_ASYNCUSER127_bm = (1<<7)      ; Asynchronous User Ch 12 Input Selection - ADC0 bit 7 mask
.equ EVSYS_SYNCCH00_bm = (1<<0)          ; Synchronous Channel 0 Generator Selection bit 0 mask
.equ EVSYS_SYNCCH01_bm = (1<<1)          ; Synchronous Channel 0 Generator Selection bit 1 mask
.equ EVSYS_SYNCCH02_bm = (1<<2)          ; Synchronous Channel 0 Generator Selection bit 2 mask
.equ EVSYS_SYNCCH03_bm = (1<<3)          ; Synchronous Channel 0 Generator Selection bit 3 mask
.equ EVSYS_SYNCCH04_bm = (1<<4)          ; Synchronous Channel 0 Generator Selection bit 4 mask
.equ EVSYS_SYNCCH05_bm = (1<<5)          ; Synchronous Channel 0 Generator Selection bit 5 mask
.equ EVSYS_SYNCCH06_bm = (1<<6)          ; Synchronous Channel 0 Generator Selection bit 6 mask
.equ EVSYS_SYNCCH07_bm = (1<<7)          ; Synchronous Channel 0 Generator Selection bit 7 mask
.equ EVSYS_SYNCUSER00_bm = (1<<0)        ; Synchronous User Ch 0 - TCA0 bit 0 mask
.equ EVSYS_SYNCUSER01_bm = (1<<1)        ; Synchronous User Ch 0 - TCA0 bit 1 mask
.equ EVSYS_SYNCUSER02_bm = (1<<2)        ; Synchronous User Ch 0 - TCA0 bit 2 mask
.equ EVSYS_SYNCUSER03_bm = (1<<3)        ; Synchronous User Ch 0 - TCA0 bit 3 mask
.equ EVSYS_SYNCUSER04_bm = (1<<4)        ; Synchronous User Ch 0 - TCA0 bit 4 mask
.equ EVSYS_SYNCUSER05_bm = (1<<5)        ; Synchronous User Ch 0 - TCA0 bit 5 mask
.equ EVSYS_SYNCUSER06_bm = (1<<6)        ; Synchronous User Ch 0 - TCA0 bit 6 mask
.equ EVSYS_SYNCUSER07_bm = (1<<7)        ; Synchronous User Ch 0 - TCA0 bit 7 mask
.equ EVSYS_SYNCUSER10_bm = (1<<0)        ; Synchronous User Ch 1 - USART0 bit 0 mask
.equ EVSYS_SYNCUSER11_bm = (1<<1)        ; Synchronous User Ch 1 - USART0 bit 1 mask
.equ EVSYS_SYNCUSER12_bm = (1<<2)        ; Synchronous User Ch 1 - USART0 bit 2 mask
.equ EVSYS_SYNCUSER13_bm = (1<<3)        ; Synchronous User Ch 1 - USART0 bit 3 mask
.equ EVSYS_SYNCUSER14_bm = (1<<4)        ; Synchronous User Ch 1 - USART0 bit 4 mask
.equ EVSYS_SYNCUSER15_bm = (1<<5)        ; Synchronous User Ch 1 - USART0 bit 5 mask
.equ EVSYS_SYNCUSER16_bm = (1<<6)        ; Synchronous User Ch 1 - USART0 bit 6 mask
.equ EVSYS_SYNCUSER17_bm = (1<<7)        ; Synchronous User Ch 1 - USART0 bit 7 mask
.equ FUSE_ACTIVE0_bm = (1<<2)            ; BOD Operation in Active Mode bit 0 mask
.equ FUSE_ACTIVE1_bm = (1<<3)            ; BOD Operation in Active Mode bit 1 mask
.equ FUSE_LVL0_bm = (1<<5)               ; BOD Level bit 0 mask
.equ FUSE_LVL1_bm = (1<<6)               ; BOD Level bit 1 mask
.equ FUSE_LVL2_bm = (1<<7)               ; BOD Level bit 2 mask
.equ FUSE_SAMPFREQ_bm = 0x10             ; BOD Sample Frequency bit mask
.equ FUSE_SLEEP0_bm = (1<<0)             ; BOD Operation in Sleep Mode bit 0 mask
.equ FUSE_SLEEP1_bm = (1<<1)             ; BOD Operation in Sleep Mode bit 1 mask
.equ FUSE_FREQSEL0_bm = (1<<0)           ; Frequency Select bit 0 mask
.equ FUSE_FREQSEL1_bm = (1<<1)           ; Frequency Select bit 1 mask
.equ FUSE_OSCLOCK_bm = 0x80              ; Oscillator Lock bit mask
.equ FUSE_CRCSRC0_bm = (1<<6)            ; CRC Source bit 0 mask
.equ FUSE_CRCSRC1_bm = (1<<7)            ; CRC Source bit 1 mask
.equ FUSE_EESAVE_bm = 0x01               ; EEPROM Save bit mask
.equ FUSE_RSTPINCFG0_bm = (1<<2)         ; Reset Pin Configuration bit 0 mask
.equ FUSE_RSTPINCFG1_bm = (1<<3)         ; Reset Pin Configuration bit 1 mask
.equ FUSE_SUT0_bm = (1<<0)               ; Startup Time bit 0 mask
.equ FUSE_SUT1_bm = (1<<1)               ; Startup Time bit 1 mask
.equ FUSE_SUT2_bm = (1<<2)               ; Startup Time bit 2 mask
.equ FUSE_PERIOD0_bm = (1<<0)            ; Watchdog Timeout Period bit 0 mask
.equ FUSE_PERIOD1_bm = (1<<1)            ; Watchdog Timeout Period bit 1 mask
.equ FUSE_PERIOD2_bm = (1<<2)            ; Watchdog Timeout Period bit 2 mask
.equ FUSE_PERIOD3_bm = (1<<3)            ; Watchdog Timeout Period bit 3 mask
.equ FUSE_WINDOW0_bm = (1<<4)            ; Watchdog Window Timeout Period bit 0 mask
.equ FUSE_WINDOW1_bm = (1<<5)            ; Watchdog Window Timeout Period bit 1 mask
.equ FUSE_WINDOW2_bm = (1<<6)            ; Watchdog Window Timeout Period bit 2 mask
.equ FUSE_WINDOW3_bm = (1<<7)            ; Watchdog Window Timeout Period bit 3 mask
.equ LOCKBIT_LB0_bm = (1<<0)             ; Lock Bits bit 0 mask
.equ LOCKBIT_LB1_bm = (1<<1)             ; Lock Bits bit 1 mask
.equ LOCKBIT_LB2_bm = (1<<2)             ; Lock Bits bit 2 mask
.equ LOCKBIT_LB3_bm = (1<<3)             ; Lock Bits bit 3 mask
.equ LOCKBIT_LB4_bm = (1<<4)             ; Lock Bits bit 4 mask
.equ LOCKBIT_LB5_bm = (1<<5)             ; Lock Bits bit 5 mask
.equ LOCKBIT_LB6_bm = (1<<6)             ; Lock Bits bit 6 mask
.equ LOCKBIT_LB7_bm = (1<<7)             ; Lock Bits bit 7 mask
.equ NVMCTRL_CMD0_bm = (1<<0)            ; Command bit 0 mask
.equ NVMCTRL_CMD1_bm = (1<<1)            ; Command bit 1 mask
.equ NVMCTRL_CMD2_bm = (1<<2)            ; Command bit 2 mask
.equ NVMCTRL_APCWP_bm = 0x01             ; Application code write protect bit mask
.equ NVMCTRL_BOOTLOCK_bm = 0x02          ; Boot Lock bit mask
.equ NVMCTRL_EEREADY_bm = 0x01           ; EEPROM Ready bit mask
.equ NVMCTRL_EEBUSY_bm = 0x02            ; EEPROM busy bit mask
.equ NVMCTRL_FBUSY_bm = 0x01             ; Flash busy bit mask
.equ NVMCTRL_WRERROR_bm = 0x04           ; Write error bit mask
.equ PORT_INT0_bm = (1<<0)               ; Pin Interrupt bit 0 mask
.equ PORT_INT1_bm = (1<<1)               ; Pin Interrupt bit 1 mask
.equ PORT_INT2_bm = (1<<2)               ; Pin Interrupt bit 2 mask
.equ PORT_INT3_bm = (1<<3)               ; Pin Interrupt bit 3 mask
.equ PORT_INT4_bm = (1<<4)               ; Pin Interrupt bit 4 mask
.equ PORT_INT5_bm = (1<<5)               ; Pin Interrupt bit 5 mask
.equ PORT_INT6_bm = (1<<6)               ; Pin Interrupt bit 6 mask
.equ PORT_INT7_bm = (1<<7)               ; Pin Interrupt bit 7 mask
.equ PORT_INVEN_bm = 0x80                ; Inverted I/O Enable bit mask
.equ PORT_ISC0_bm = (1<<0)               ; Input/Sense Configuration bit 0 mask
.equ PORT_ISC1_bm = (1<<1)               ; Input/Sense Configuration bit 1 mask
.equ PORT_ISC2_bm = (1<<2)               ; Input/Sense Configuration bit 2 mask
.equ PORT_PULLUPEN_bm = 0x08             ; Pullup enable bit mask
.equ PORTMUX_EVOUT0_bm = 0x01            ; Event Output 0 bit mask
.equ PORTMUX_EVOUT1_bm = 0x02            ; Event Output 1 bit mask
.equ PORTMUX_EVOUT2_bm = 0x04            ; Event Output 2 bit mask
.equ PORTMUX_LUT0_bm = 0x10              ; Configurable Custom Logic LUT0 bit mask
.equ PORTMUX_LUT1_bm = 0x20              ; Configurable Custom Logic LUT1 bit mask
.equ PORTMUX_SPI0_bm = 0x04              ; Port Multiplexer SPI0 bit mask
.equ PORTMUX_USART0_bm = 0x01            ; Port Multiplexer USART0 bit mask
.equ PORTMUX_TCA00_bm = 0x01             ; Port Multiplexer TCA0 Output 0 bit mask
.equ PORTMUX_TCA01_bm = 0x02             ; Port Multiplexer TCA0 Output 1 bit mask
.equ PORTMUX_TCA02_bm = 0x04             ; Port Multiplexer TCA0 Output 2 bit mask
.equ PORTMUX_TCA03_bm = 0x08             ; Port Multiplexer TCA0 Output 3 bit mask
.equ PORTMUX_TCA04_bm = 0x10             ; Port Multiplexer TCA0 Output 4 bit mask
.equ PORTMUX_TCA05_bm = 0x20             ; Port Multiplexer TCA0 Output 5 bit mask
.equ PORTMUX_TCB0_bm = 0x01              ; Port Multiplexer TCB bit mask
.equ RSTCTRL_BORF_bm = 0x02              ; Brown out detector Reset flag bit mask
.equ RSTCTRL_EXTRF_bm = 0x04             ; External Reset flag bit mask
.equ RSTCTRL_PORF_bm = 0x01              ; Power on Reset flag bit mask
.equ RSTCTRL_SWRF_bm = 0x10              ; Software Reset flag bit mask
.equ RSTCTRL_UPDIRF_bm = 0x20            ; UPDI Reset flag bit mask
.equ RSTCTRL_WDRF_bm = 0x08              ; Watch dog Reset flag bit mask
.equ RSTCTRL_SWRE_bm = 0x01              ; Software reset enable bit mask
.equ RTC_CLKSEL0_bm = (1<<0)             ; Clock Select bit 0 mask
.equ RTC_CLKSEL1_bm = (1<<1)             ; Clock Select bit 1 mask
.equ RTC_PRESCALER0_bm = (1<<3)          ; Prescaling Factor bit 0 mask
.equ RTC_PRESCALER1_bm = (1<<4)          ; Prescaling Factor bit 1 mask
.equ RTC_PRESCALER2_bm = (1<<5)          ; Prescaling Factor bit 2 mask
.equ RTC_PRESCALER3_bm = (1<<6)          ; Prescaling Factor bit 3 mask
.equ RTC_RTCEN_bm = 0x01                 ; Enable bit mask
.equ RTC_RUNSTDBY_bm = 0x80              ; Run In Standby bit mask
.equ RTC_DBGRUN_bm = 0x01                ; Run in debug bit mask
.equ RTC_CMP_bm = 0x02                   ; Compare Match Interrupt enable bit mask
.equ RTC_OVF_bm = 0x01                   ; Overflow Interrupt enable bit mask
.equ RTC_PERIOD0_bm = (1<<3)             ; Period bit 0 mask
.equ RTC_PERIOD1_bm = (1<<4)             ; Period bit 1 mask
.equ RTC_PERIOD2_bm = (1<<5)             ; Period bit 2 mask
.equ RTC_PERIOD3_bm = (1<<6)             ; Period bit 3 mask
.equ RTC_PITEN_bm = 0x01                 ; Enable bit mask
.equ RTC_PI_bm = 0x01                    ; Periodic Interrupt bit mask
.equ RTC_CTRLBUSY_bm = 0x01              ; CTRLA Synchronization Busy Flag bit mask
.equ RTC_CMPBUSY_bm = 0x08               ; Comparator Synchronization Busy Flag bit mask
.equ RTC_CNTBUSY_bm = 0x02               ; Count Synchronization Busy Flag bit mask
.equ RTC_CTRLABUSY_bm = 0x01             ; CTRLA Synchronization Busy Flag bit mask
.equ RTC_PERBUSY_bm = 0x04               ; Period Synchronization Busy Flag bit mask
.equ SLPCTRL_SEN_bm = 0x01               ; Sleep enable bit mask
.equ SLPCTRL_SMODE0_bm = (1<<1)          ; Sleep mode bit 0 mask
.equ SLPCTRL_SMODE1_bm = (1<<2)          ; Sleep mode bit 1 mask
.equ SPI_CLK2X_bm = 0x10                 ; Enable Double Speed bit mask
.equ SPI_DORD_bm = 0x40                  ; Data Order Setting bit mask
.equ SPI_ENABLE_bm = 0x01                ; Enable Module bit mask
.equ SPI_MASTER_bm = 0x20                ; Master Operation Enable bit mask
.equ SPI_PRESC0_bm = (1<<1)              ; Prescaler bit 0 mask
.equ SPI_PRESC1_bm = (1<<2)              ; Prescaler bit 1 mask
.equ SPI_BUFEN_bm = 0x80                 ; Buffer Mode Enable bit mask
.equ SPI_BUFWR_bm = 0x40                 ; Buffer Write Mode bit mask
.equ SPI_MODE0_bm = (1<<0)               ; SPI Mode bit 0 mask
.equ SPI_MODE1_bm = (1<<1)               ; SPI Mode bit 1 mask
.equ SPI_SSD_bm = 0x04                   ; Slave Select Disable bit mask
.equ SPI_DREIE_bm = 0x20                 ; Data Register Empty Interrupt Enable bit mask
.equ SPI_IE_bm = 0x01                    ; Interrupt Enable bit mask
.equ SPI_RXCIE_bm = 0x80                 ; Receive Complete Interrupt Enable bit mask
.equ SPI_SSIE_bm = 0x10                  ; Slave Select Trigger Interrupt Enable bit mask
.equ SPI_TXCIE_bm = 0x40                 ; Transfer Complete Interrupt Enable bit mask
.equ SPI_BUFOVF_bm = 0x01                ; Buffer Overflow bit mask
.equ SPI_DREIF_bm = 0x20                 ; Data Register Empty Interrupt Flag bit mask
.equ SPI_RXCIF_bm = 0x80                 ; Receive Complete Interrupt Flag bit mask
.equ SPI_SSIF_bm = 0x10                  ; Slave Select Trigger Interrupt Flag bit mask
.equ SPI_TXCIF_bm = 0x40                 ; Transfer Complete Interrupt Flag bit mask
.equ SPI_IF_bm = 0x80                    ; Interrupt Flag bit mask
.equ SPI_WRCOL_bm = 0x40                 ; Write Collision bit mask
.equ SYSCFG_ENEXTBRK_bm = 0x01           ; External break enable bit mask
.equ TCA_SINGLE_CLKSEL0_bm = (1<<1)      ; Clock Selection bit 0 mask
.equ TCA_SINGLE_CLKSEL1_bm = (1<<2)      ; Clock Selection bit 1 mask
.equ TCA_SINGLE_CLKSEL2_bm = (1<<3)      ; Clock Selection bit 2 mask
.equ TCA_SINGLE_ENABLE_bm = 0x01         ; Module Enable bit mask
.equ TCA_SINGLE_ALUPD_bm = 0x08          ; Auto Lock Update bit mask
.equ TCA_SINGLE_CMP0EN_bm = 0x10         ; Compare 0 Enable bit mask
.equ TCA_SINGLE_CMP1EN_bm = 0x20         ; Compare 1 Enable bit mask
.equ TCA_SINGLE_CMP2EN_bm = 0x40         ; Compare 2 Enable bit mask
.equ TCA_SINGLE_WGMODE0_bm = (1<<0)      ; Waveform generation mode bit 0 mask
.equ TCA_SINGLE_WGMODE1_bm = (1<<1)      ; Waveform generation mode bit 1 mask
.equ TCA_SINGLE_WGMODE2_bm = (1<<2)      ; Waveform generation mode bit 2 mask
.equ TCA_SINGLE_CMP0OV_bm = 0x01         ; Compare 0 Waveform Output Value bit mask
.equ TCA_SINGLE_CMP1OV_bm = 0x02         ; Compare 1 Waveform Output Value bit mask
.equ TCA_SINGLE_CMP2OV_bm = 0x04         ; Compare 2 Waveform Output Value bit mask
.equ TCA_SINGLE_SPLITM_bm = 0x01         ; Split Mode Enable bit mask
.equ TCA_SINGLE_CMD0_bm = (1<<2)         ; Command bit 0 mask
.equ TCA_SINGLE_CMD1_bm = (1<<3)         ; Command bit 1 mask
.equ TCA_SINGLE_DIR_bm = 0x01            ; Direction bit mask
.equ TCA_SINGLE_LUPD_bm = 0x02           ; Lock Update bit mask
.equ TCA_SINGLE_CMP0BV_bm = 0x02         ; Compare 0 Buffer Valid bit mask
.equ TCA_SINGLE_CMP1BV_bm = 0x04         ; Compare 1 Buffer Valid bit mask
.equ TCA_SINGLE_CMP2BV_bm = 0x08         ; Compare 2 Buffer Valid bit mask
.equ TCA_SINGLE_PERBV_bm = 0x01          ; Period Buffer Valid bit mask
.equ TCA_SINGLE_DBGRUN_bm = 0x01         ; Debug Run bit mask
.equ TCA_SINGLE_CNTEI_bm = 0x01          ; Count on Event Input bit mask
.equ TCA_SINGLE_EVACT0_bm = (1<<1)       ; Event Action bit 0 mask
.equ TCA_SINGLE_EVACT1_bm = (1<<2)       ; Event Action bit 1 mask
.equ TCA_SINGLE_CMP0_bm = 0x10           ; Compare 0 Interrupt bit mask
.equ TCA_SINGLE_CMP1_bm = 0x20           ; Compare 1 Interrupt bit mask
.equ TCA_SINGLE_CMP2_bm = 0x40           ; Compare 2 Interrupt bit mask
.equ TCA_SINGLE_OVF_bm = 0x01            ; Overflow Interrupt bit mask
.equ TCA_SPLIT_CLKSEL0_bm = (1<<1)       ; Clock Selection bit 0 mask
.equ TCA_SPLIT_CLKSEL1_bm = (1<<2)       ; Clock Selection bit 1 mask
.equ TCA_SPLIT_CLKSEL2_bm = (1<<3)       ; Clock Selection bit 2 mask
.equ TCA_SPLIT_ENABLE_bm = 0x01          ; Module Enable bit mask
.equ TCA_SPLIT_HCMP0EN_bm = 0x10         ; High Compare 0 Enable bit mask
.equ TCA_SPLIT_HCMP1EN_bm = 0x20         ; High Compare 1 Enable bit mask
.equ TCA_SPLIT_HCMP2EN_bm = 0x40         ; High Compare 2 Enable bit mask
.equ TCA_SPLIT_LCMP0EN_bm = 0x01         ; Low Compare 0 Enable bit mask
.equ TCA_SPLIT_LCMP1EN_bm = 0x02         ; Low Compare 1 Enable bit mask
.equ TCA_SPLIT_LCMP2EN_bm = 0x04         ; Low Compare 2 Enable bit mask
.equ TCA_SPLIT_HCMP0OV_bm = 0x10         ; High Compare 0 Output Value bit mask
.equ TCA_SPLIT_HCMP1OV_bm = 0x20         ; High Compare 1 Output Value bit mask
.equ TCA_SPLIT_HCMP2OV_bm = 0x40         ; High Compare 2 Output Value bit mask
.equ TCA_SPLIT_LCMP0OV_bm = 0x01         ; Low Compare 0 Output Value bit mask
.equ TCA_SPLIT_LCMP1OV_bm = 0x02         ; Low Compare 1 Output Value bit mask
.equ TCA_SPLIT_LCMP2OV_bm = 0x04         ; Low Compare 2 Output Value bit mask
.equ TCA_SPLIT_SPLITM_bm = 0x01          ; Split Mode Enable bit mask
.equ TCA_SPLIT_CMD0_bm = (1<<2)          ; Command bit 0 mask
.equ TCA_SPLIT_CMD1_bm = (1<<3)          ; Command bit 1 mask
.equ TCA_SPLIT_DBGRUN_bm = 0x01          ; Debug Run bit mask
.equ TCA_SPLIT_HUNF_bm = 0x02            ; High Underflow Interrupt Enable bit mask
.equ TCA_SPLIT_LCMP0_bm = 0x10           ; Low Compare 0 Interrupt Enable bit mask
.equ TCA_SPLIT_LCMP1_bm = 0x20           ; Low Compare 1 Interrupt Enable bit mask
.equ TCA_SPLIT_LCMP2_bm = 0x40           ; Low Compare 2 Interrupt Enable bit mask
.equ TCA_SPLIT_LUNF_bm = 0x01            ; Low Underflow Interrupt Enable bit mask
.equ TCB_CLKSEL0_bm = (1<<1)             ; Clock Select bit 0 mask
.equ TCB_CLKSEL1_bm = (1<<2)             ; Clock Select bit 1 mask
.equ TCB_ENABLE_bm = 0x01                ; Enable bit mask
.equ TCB_RUNSTDBY_bm = 0x40              ; Run Standby bit mask
.equ TCB_SYNCUPD_bm = 0x10               ; Synchronize Update bit mask
.equ TCB_ASYNC_bm = 0x40                 ; Asynchronous Enable bit mask
.equ TCB_CCMPEN_bm = 0x10                ; Pin Output Enable bit mask
.equ TCB_CCMPINIT_bm = 0x20              ; Pin Initial State bit mask
.equ TCB_CNTMODE0_bm = (1<<0)            ; Timer Mode bit 0 mask
.equ TCB_CNTMODE1_bm = (1<<1)            ; Timer Mode bit 1 mask
.equ TCB_CNTMODE2_bm = (1<<2)            ; Timer Mode bit 2 mask
.equ TCB_DBGRUN_bm = 0x01                ; Debug Run bit mask
.equ TCB_CAPTEI_bm = 0x01                ; Event Input Enable bit mask
.equ TCB_EDGE_bm = 0x10                  ; Event Edge bit mask
.equ TCB_FILTER_bm = 0x40                ; Input Capture Noise Cancellation Filter bit mask
.equ TCB_CAPT_bm = 0x01                  ; Capture or Timeout bit mask
.equ TCB_RUN_bm = 0x01                   ; Run bit mask
.equ TWI_FMPEN_bm = 0x02                 ; FM Plus Enable bit mask
.equ TWI_SDAHOLD0_bm = (1<<2)            ; SDA Hold Time bit 0 mask
.equ TWI_SDAHOLD1_bm = (1<<3)            ; SDA Hold Time bit 1 mask
.equ TWI_SDASETUP_bm = 0x10              ; SDA Setup Time bit mask
.equ TWI_DBGRUN_bm = 0x01                ; Debug Run bit mask
.equ TWI_ENABLE_bm = 0x01                ; Enable TWI Master bit mask
.equ TWI_QCEN_bm = 0x10                  ; Quick Command Enable bit mask
.equ TWI_RIEN_bm = 0x80                  ; Read Interrupt Enable bit mask
.equ TWI_SMEN_bm = 0x02                  ; Smart Mode Enable bit mask
.equ TWI_TIMEOUT0_bm = (1<<2)            ; Inactive Bus Timeout bit 0 mask
.equ TWI_TIMEOUT1_bm = (1<<3)            ; Inactive Bus Timeout bit 1 mask
.equ TWI_WIEN_bm = 0x40                  ; Write Interrupt Enable bit mask
.equ TWI_ACKACT_bm = 0x04                ; Acknowledge Action bit mask
.equ TWI_FLUSH_bm = 0x08                 ; Flush bit mask
.equ TWI_MCMD0_bm = (1<<0)               ; Command bit 0 mask
.equ TWI_MCMD1_bm = (1<<1)               ; Command bit 1 mask
.equ TWI_ARBLOST_bm = 0x08               ; Arbitration Lost bit mask
.equ TWI_BUSERR_bm = 0x04                ; Bus Error bit mask
.equ TWI_BUSSTATE0_bm = (1<<0)           ; Bus State bit 0 mask
.equ TWI_BUSSTATE1_bm = (1<<1)           ; Bus State bit 1 mask
.equ TWI_CLKHOLD_bm = 0x20               ; Clock Hold bit mask
.equ TWI_RIF_bm = 0x80                   ; Read Interrupt Flag bit mask
.equ TWI_RXACK_bm = 0x10                 ; Received Acknowledge bit mask
.equ TWI_WIF_bm = 0x40                   ; Write Interrupt Flag bit mask
.equ TWI_ADDREN_bm = 0x01                ; Address Enable bit mask
.equ TWI_ADDRMASK0_bm = (1<<1)           ; Address Mask bit 0 mask
.equ TWI_ADDRMASK1_bm = (1<<2)           ; Address Mask bit 1 mask
.equ TWI_ADDRMASK2_bm = (1<<3)           ; Address Mask bit 2 mask
.equ TWI_ADDRMASK3_bm = (1<<4)           ; Address Mask bit 3 mask
.equ TWI_ADDRMASK4_bm = (1<<5)           ; Address Mask bit 4 mask
.equ TWI_ADDRMASK5_bm = (1<<6)           ; Address Mask bit 5 mask
.equ TWI_ADDRMASK6_bm = (1<<7)           ; Address Mask bit 6 mask
.equ TWI_APIEN_bm = 0x40                 ; Address/Stop Interrupt Enable bit mask
.equ TWI_DIEN_bm = 0x80                  ; Data Interrupt Enable bit mask
.equ TWI_PIEN_bm = 0x20                  ; Stop Interrupt Enable bit mask
.equ TWI_PMEN_bm = 0x04                  ; Promiscuous Mode Enable bit mask
.equ TWI_SCMD0_bm = (1<<0)               ; Command bit 0 mask
.equ TWI_SCMD1_bm = (1<<1)               ; Command bit 1 mask
.equ TWI_AP_bm = 0x01                    ; Slave Address or Stop bit mask
.equ TWI_APIF_bm = 0x40                  ; Address/Stop Interrupt Flag bit mask
.equ TWI_COLL_bm = 0x08                  ; Collision bit mask
.equ TWI_DIF_bm = 0x80                   ; Data Interrupt Flag bit mask
.equ TWI_DIR_bm = 0x02                   ; Read/Write Direction bit mask
.equ USART_ABEIE_bm = 0x04               ; Auto-baud Error Interrupt Enable bit mask
.equ USART_DREIE_bm = 0x20               ; Data Register Empty Interrupt Enable bit mask
.equ USART_LBME_bm = 0x08                ; Loop-back Mode Enable bit mask
.equ USART_RS4850_bm = (1<<0)            ; RS485 Mode internal transmitter bit 0 mask
.equ USART_RS4851_bm = (1<<1)            ; RS485 Mode internal transmitter bit 1 mask
.equ USART_RXCIE_bm = 0x80               ; Receive Complete Interrupt Enable bit mask
.equ USART_RXSIE_bm = 0x10               ; Receiver Start Frame Interrupt Enable bit mask
.equ USART_TXCIE_bm = 0x40               ; Transmit Complete Interrupt Enable bit mask
.equ USART_MPCM_bm = 0x01                ; Multi-processor Communication Mode bit mask
.equ USART_ODME_bm = 0x08                ; Open Drain Mode Enable bit mask
.equ USART_RXEN_bm = 0x80                ; Reciever enable bit mask
.equ USART_RXMODE0_bm = (1<<1)           ; Receiver Mode bit 0 mask
.equ USART_RXMODE1_bm = (1<<2)           ; Receiver Mode bit 1 mask
.equ USART_SFDEN_bm = 0x10               ; Start Frame Detection Enable bit mask
.equ USART_TXEN_bm = 0x40                ; Transmitter Enable bit mask
.equ USART_CMODE0_bm = (1<<6)            ; Communication Mode bit 0 mask
.equ USART_CMODE1_bm = (1<<7)            ; Communication Mode bit 1 mask
.equ USART_UCPHA_bm = 0x02               ; SPI Master Mode, Clock Phase bit mask
.equ USART_UDORD_bm = 0x04               ; SPI Master Mode, Data Order bit mask
.equ USART_CHSIZE0_bm = (1<<0)           ; Character Size bit 0 mask
.equ USART_CHSIZE1_bm = (1<<1)           ; Character Size bit 1 mask
.equ USART_CHSIZE2_bm = (1<<2)           ; Character Size bit 2 mask
.equ USART_PMODE0_bm = (1<<4)            ; Parity Mode bit 0 mask
.equ USART_PMODE1_bm = (1<<5)            ; Parity Mode bit 1 mask
.equ USART_SBMODE_bm = 0x08              ; Stop Bit Mode bit mask
.equ USART_ABMBP_bm = 0x80               ; Autobaud majority voter bypass bit mask
.equ USART_DBGRUN_bm = 0x01              ; Debug Run bit mask
.equ USART_IREI_bm = 0x01                ; IrDA Event Input Enable bit mask
.equ USART_BUFOVF_bm = 0x40              ; Buffer Overflow bit mask
.equ USART_DATA8_bm = 0x01               ; Receiver Data Register bit mask
.equ USART_FERR_bm = 0x04                ; Frame Error bit mask
.equ USART_PERR_bm = 0x02                ; Parity Error bit mask
.equ USART_RXCIF_bm = 0x80               ; Receive Complete Interrupt Flag bit mask
.equ USART_DATA0_bm = (1<<0)             ; RX Data bit 0 mask
.equ USART_DATA1_bm = (1<<1)             ; RX Data bit 1 mask
.equ USART_DATA2_bm = (1<<2)             ; RX Data bit 2 mask
.equ USART_DATA3_bm = (1<<3)             ; RX Data bit 3 mask
.equ USART_DATA4_bm = (1<<4)             ; RX Data bit 4 mask
.equ USART_DATA5_bm = (1<<5)             ; RX Data bit 5 mask
.equ USART_DATA6_bm = (1<<6)             ; RX Data bit 6 mask
.equ USART_DATA7_bm = (1<<7)             ; RX Data bit 7 mask
.equ USART_RXPL0_bm = (1<<0)             ; Receiver Pulse Lenght bit 0 mask
.equ USART_RXPL1_bm = (1<<1)             ; Receiver Pulse Lenght bit 1 mask
.equ USART_RXPL2_bm = (1<<2)             ; Receiver Pulse Lenght bit 2 mask
.equ USART_RXPL3_bm = (1<<3)             ; Receiver Pulse Lenght bit 3 mask
.equ USART_RXPL4_bm = (1<<4)             ; Receiver Pulse Lenght bit 4 mask
.equ USART_RXPL5_bm = (1<<5)             ; Receiver Pulse Lenght bit 5 mask
.equ USART_RXPL6_bm = (1<<6)             ; Receiver Pulse Lenght bit 6 mask
.equ USART_BDF_bm = 0x02                 ; Break Detected Flag bit mask
.equ USART_DREIF_bm = 0x20               ; Data Register Empty Flag bit mask
.equ USART_ISFIF_bm = 0x08               ; Inconsistent Sync Field Interrupt Flag bit mask
.equ USART_RXSIF_bm = 0x10               ; Receive Start Interrupt bit mask
.equ USART_TXCIF_bm = 0x40               ; Transmit Interrupt Flag bit mask
.equ USART_WFB_bm = 0x01                 ; Wait For Break bit mask
.equ USART_TXPL0_bm = (1<<0)             ; Transmit pulse length bit 0 mask
.equ USART_TXPL1_bm = (1<<1)             ; Transmit pulse length bit 1 mask
.equ USART_TXPL2_bm = (1<<2)             ; Transmit pulse length bit 2 mask
.equ USART_TXPL3_bm = (1<<3)             ; Transmit pulse length bit 3 mask
.equ USART_TXPL4_bm = (1<<4)             ; Transmit pulse length bit 4 mask
.equ USART_TXPL5_bm = (1<<5)             ; Transmit pulse length bit 5 mask
.equ USART_TXPL6_bm = (1<<6)             ; Transmit pulse length bit 6 mask
.equ USART_TXPL7_bm = (1<<7)             ; Transmit pulse length bit 7 mask
.equ VPORT_INT0_bm = (1<<0)              ; Pin Interrupt bit 0 mask
.equ VPORT_INT1_bm = (1<<1)              ; Pin Interrupt bit 1 mask
.equ VPORT_INT2_bm = (1<<2)              ; Pin Interrupt bit 2 mask
.equ VPORT_INT3_bm = (1<<3)              ; Pin Interrupt bit 3 mask
.equ VPORT_INT4_bm = (1<<4)              ; Pin Interrupt bit 4 mask
.equ VPORT_INT5_bm = (1<<5)              ; Pin Interrupt bit 5 mask
.equ VPORT_INT6_bm = (1<<6)              ; Pin Interrupt bit 6 mask
.equ VPORT_INT7_bm = (1<<7)              ; Pin Interrupt bit 7 mask
.equ VREF_ADC0REFSEL0_bm = (1<<4)        ; ADC0 reference select bit 0 mask
.equ VREF_ADC0REFSEL1_bm = (1<<5)        ; ADC0 reference select bit 1 mask
.equ VREF_ADC0REFSEL2_bm = (1<<6)        ; ADC0 reference select bit 2 mask
.equ VREF_DAC0REFSEL0_bm = (1<<0)        ; DAC0/AC0 reference select bit 0 mask
.equ VREF_DAC0REFSEL1_bm = (1<<1)        ; DAC0/AC0 reference select bit 1 mask
.equ VREF_DAC0REFSEL2_bm = (1<<2)        ; DAC0/AC0 reference select bit 2 mask
.equ VREF_ADC0REFEN_bm = 0x02            ; ADC0 reference enable bit mask
.equ VREF_DAC0REFEN_bm = 0x01            ; DAC0/AC0 reference enable bit mask
.equ WDT_PERIOD0_bm = (1<<0)             ; Period bit 0 mask
.equ WDT_PERIOD1_bm = (1<<1)             ; Period bit 1 mask
.equ WDT_PERIOD2_bm = (1<<2)             ; Period bit 2 mask
.equ WDT_PERIOD3_bm = (1<<3)             ; Period bit 3 mask
.equ WDT_WINDOW0_bm = (1<<4)             ; Window bit 0 mask
.equ WDT_WINDOW1_bm = (1<<5)             ; Window bit 1 mask
.equ WDT_WINDOW2_bm = (1<<6)             ; Window bit 2 mask
.equ WDT_WINDOW3_bm = (1<<7)             ; Window bit 3 mask
.equ WDT_LOCK_bm = 0x80                  ; Lock enable bit mask
.equ WDT_SYNCBUSY_bm = 0x01              ; Syncronization busy bit mask

 

Last Edited: Mon. Mar 15, 2021 - 11:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir Clawson,

Thankyou for the enlightening advice. Now I see the possibility of danger in using raw values as you have pointed out. I need to discipline my self in using the bitmasks/values with proper header terms to avoid such mistakes. I saw this file in the dependencies folder of studio7 but didn't know that this could come into use this way. Many lessons learned.

Thanks & Regards

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

darth vader wrote:
I saw this file in the dependencies folder of studio7 but didn't know that this could come into use this way.
Yeah one step "backwards" I think Atmel made at some stage is how .inc files are used. It used to be that that the way avrasm2 was invoked it had no idea what AVR you were building for then you would start your own Asm code with:

.include "tn804def.inc"
...
; etc.

so it was clear to you and everyone that the definitions for registers and bits within them would be coming from that file. Also if you ever posted the source code on the internet anyone finding it could look at this and instantly see "oh this is for tiny 804". But these days the way AS7 (now MCS7) invokes the assembler is that you, the user tell the IDE which micro you are building for. then, when it runs the assembler, it passes a command line parameter to say "build this for tiny 804" and part of that means there is a "hidden" include of tn804def.inc but as this happens automatically it may not be obvious to everyone (and I guess it wasn't to you) that this was the file that was being used and, therefore, you are free to use the register/bit names it defines.

 

Sometimes "progress" just seems like a step backwards!

 

(in its favour I suppose you could say that doing it this way (relying on the AVR you picked when you created the project) ensures the right file is included but that's about the only thing positive about it).

 

BTW as an example here's what happens when I build an Asm project that was set up for mega328P:

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avrassembler\avrasm2.exe -fI -o "asm_test.hex"  -m "asm_test.map"  -l "asm_test.lss"  -S "asm_test.tmp"  
-W+ie -I"C:/Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATmega_DFP\1.4.351\avrasm\inc"  -im328Pdef.inc 
-d "D:\test\asm_test\Debug\asm_test.obj"  "D:\test\asm_test\main.asm"  -I "C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avrassembler\Include" 

The -i command in there for m328Pdef.inc is the "hidden" command that says "build this as if it contains

.include "m328Pdef.inc"

on the first line".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Sir Clawson,

Thanks for the advice.

Earlier when i wrote code for attiny13 & attiny10 I used to add the  xxxdef.inc file at the beginning of the program. One time I forgot to do this but the program compiled and that's how I found out that the studio7 does it automatically. But then I stopped looking into the inc file and karma catches up.

Thanks & Regards

 

darth vader

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

It's actually safe to do the .include even if it is being done automatically anyway but ONLY if the command line option and the .include name the same micro (otherwise you get an error). To a certain extent I think it's a good idea to do so because if you now post the source on a web site to share with others or something like that it will be self documenting to say "this written for tiony13" or "this written for tiny804" etc. Otherwise it can be quite tricky simply reading through .asm to guess which micro it has been written for. (of course one could add a comment at the top!).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Members,

Thanking everyone for their valuable comments and help provided in resolving the concern and increasing my knowledge. Picture of 804speed & loop with OVF screens attached

Thanks,

gratitude

& regards

 

 

Attachment(s): 

darth vader