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