I've tried all the tricks I know to sort out a strange behavior when using TIMER1 and INT2. With no luck.
In short I'm building myself a bus analyzer.
As one of the features there is a "logic scope" which only display "ones" or "zeros" on 128*64 LCD.
The scope buffer is 256 bytes for each of the two channels. When end of buffer is reached it wraps around to the start of buffer again.
The scope can be triggered on rising or falling edge using INT2.
When an edge is detected INT2 ISR is entered.
In ISR I save the first data to scope buffers, disable INT2 and enable TIMER1 to do IRQ at a user set rate.
When the pointer of buffers reach zero TIMER1 is turned off.
A subroutine is called from main when scope is running and test if buffer pointer is zero.
If so, the 128 first bytes of buffer is displayed on LCD and at the end of routine INT2 is enabled again.
Here are the relevant parts of code for this.
INT2 ISR:
trig_isr: in isr,sreg ;load SREG push isr ;save SREG out eimsk,zero ;disable INT 2 ISR lds isr,scale ;enable TIMER1 CTC mode sts tccr1b,isr ;with user set prescale ldi isr,0xff ;load a "1" sbis pina,6 ;if PA6 low ldi isr,0x80 ;load a "0" ldi yh,high(scope_a) ;load msb BCOPE A mov yl,scope_lsb ;load SCOPE LSB st y,isr ;save PA6 state to SCOPE A ldi isr,0xff ;load a "1" sbis pina,7 ;if PA7 low ldi isr,0x80 ;load a "0" ldi yh,high(scope_b) ;load msb SCOPE B st y+,isr ;save PA7 state to SCOPE B mov scope_lsb,yl ;save next SCOPE LSB sts test_0,scope_lsb pop isr ;restore out sreg,isr ;SREG reti ;return ISR
TIMER1 ISR:
scope_isr: in isr,sreg ;load SREG push isr ;save SREG ldi isr,0xff ;load a "1" sbis pina,6 ;if PA6 low ldi isr,0x80 ;load a "0" ldi yh,high(scope_a) ;load msb BCOPE A mov yl,scope_lsb ;load SCOPE LSB st y,isr ;save PA6 state to SCOPE A ldi isr,0xff ;load a "1" sbis pina,7 ;if PA7 low ldi isr,0x80 ;load a "0" ldi yh,high(scope_b) ;load msb SCOPE B st y+,isr ;save PA7 state to SCOPE B mov scope_lsb,yl ;save next SCOPE LSB tst scope_lsb ;while not BUFFER END brne scope_isr_exit ;run TIMER1 ldi isr,0x08 ;else TIMER1 CTC mode sts tccr1b,isr ;clock disabled scope_isr_exit: pop isr ;restore out sreg,isr ;SREG reti ;return ISR
And the LCD display routine:
show_scope: tst scope_lsb ;if end of SCOPE BUFFER breq run_scope ;display SCOPE DATA rjmp main ;else return MAIN run_scope: sbic gpior0,rs485 ;if RS485 SLAVE ON rcall spi_mode ;enable SPI for LCD ldi pge,0xb4 ;PAGE 4 ldi msb,0x10 ;MSB ldi lsb,0x00 ;LSB rcall dot_adr ;send ADDRESS ldi xh,high(scope_a) ;msb SCOPE A BUFFER ldi xl,low(scope_a) ;lsb SCOPE A BUFFER sbi portd,a0 ;LCD DATA show_scope_a: lds temp,ucsr1a ;load SPI status sbrs temp,udre1 ;wait for rjmp show_scope_a ;SPI done ld data,x+ ;load SCOPE A DATA sts udr1,data ;send SCOPE DATA cpi xl,129 ;loop until brne show_scope_a ;128 rows displayed ldi pge,0xb6 ;PAGE 6 rcall dot_adr ;send ADDRESS ldi xh,high(scope_b) ;msb SCOPE B BUFFER ldi xl,low(scope_b) ;lsb SCOPE B BUFFER sbi portd,a0 ;LCD DATA show_scope_b: lds temp,ucsr1a ;load SPI status sbrs temp,udre1 ;wait for rjmp show_scope_b ;SPI done ld data,x+ ;load SCOPE B DATA sts udr1,data ;send SCOPE DATA cpi xl,129 ;loop until brne show_scope_b ;128 rows displayed sts test_1,scope_lsb ldi temp,0x04 ;clear any pending out eifr,temp ;INT2 interrupts out eimsk,temp ;enable INT2 ISR sbic gpior0,rs485 ;if RS485 SLAVE ON rcall rs485_mode ;enable UART1 RX rjmp main ;return MAIN
For reasons that I don't figured out "test_0" var which >should be< 1 after trig_isr have higher values(actual value depend of TIMER1 rate).
If I try to reset the pointer to zero inside INT2 ISR I miss some of the bits in the first byte.
I fail to see why this happens. TIMER1 clock >should< stop running after buffer pointer wraps to zero inside TIMER1 ISR.
"test_1" is always zero when I enable INT2 again at the end of LCD routine.
Even more weird is that if I reset the pointer to zero at the same place the scope display gets very jumpy and trig at different places in the packet being sent.
If the pointer not is reset the scope display is steady and miss no bits, but the fact that the pointer is already i.e. 8 or 17 when captured inside INT2 ISR annoys me.
What am I missing?
Any suggestions are welcome.