TIMER1 issue

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

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.

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

Did you try debugging? Or at least a simulator and a stimuli?

sts   tccr1b,isr      ;clock disabled

This one halts TCNT1, but does not disable interrupts. Are you sure there are no pending interrupts waiting? You do not clear TCNT1 register when restarting so it can restart from the middle.

There are literally no asserts in your code.

No RSTDISBL, no fun!

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

Thanks for your reply.
Actually managed to find the problem yesterday that caused me to miss the first bits in the packet.
Was enabling INT2 >after< sending the buffers to LCD.
When INT2 was enabled next packet already had started.
Solution was to move all on/off control of TIMER1 and INT2 inside ISR's.
Regarding last part of your post, I don't think TCNT1 will get very far with the new code since TCNT1 is disabled at the top of ISR.
There is now 2 perfectly stable traces to catch i.e. a 4-byte TWI transfer.[img][/img]
Or a serial 4-byte packet at 9600 kbaud.[img][/img]
The main task for the device is though to catch user defined packets and save and display them.[img][/img]
Todays mission will be to make the scope capture conditional in same way to isolate and display a desired byte combination inside a bus with heavy traffic.
This is the revised ISR code, where some cycles also been shaved off:

trig_isr:
	out	eimsk,zero		;disable INT 2 ISR
	lds	isr,scale		;enable TIMER1 CTC mode
	sts	tccr1b,isr		;with user set prescale
	ldi	yl,low(scope_a)	;load lsb SCOPE A base
	rjmp	scope_isr_first	;save SCOPE DATA
	
scope_isr:
	in	yh,sreg		;catch SREG
	mov	yl,scope_lsb	;load SCOPE LSB
	cpi	yl,0xff		;until SCOPE BUFFER END
	brne	scope_isr_run	;run SCOPE ISR	
	sts	tccr1b,zero		;else TIMER1 disabled
	ldi	isr,0x04		;clear any pending
	out	eifr,isr		;INT2 interrupts
	out	eimsk,isr		;enable INT2 ISR
scope_isr_run:
	out	sreg,yh		;restore SREG
scope_isr_first:
	ldi	yh,high(scope_a)	;load msb BCOPE A
	ldi	isr,0xff		;load a "1"
	sbis	pina,6		;if PA6 low
	ldi	isr,0x80		;load a "0"
	st	y,isr			;save PA6 state to SCOPE A
	ldi	yh,high(scope_b)	;load msb SCOPE B
	ldi	isr,0xff		;load a "1"
	sbis	pina,7		;if PA7 low
	ldi	isr,0x80		;load a "0"
	st	y+,isr		;save PA7 state to SCOPE B
	mov	scope_lsb,yl	;save next SCOPE LSB
	reti				;return ISR

Attachment(s): 

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

Quote:
There is now 2 perfectly stable traces to catch i.e. a 4-byte TWI transfer.

What about SPI? Does not it have all the features you require to log the data? Buffering, speed, accuracy..

No RSTDISBL, no fun!

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

The purpose of this gadget is to catch, save and display user defined packets in TWI, SPI, RS232, RS485 and serial TTL bus formats.
4 software "channels" are set up by user to perform transfers either as TX/Master or RX/Slave thus 4 packets can be sent/received simultaneous in any of the formats.
RS232 bus can also echo bytes/packets to a terminal program or a flash memory.

Reason for building this is I'm getting bored chasing desired packets within a bus with heavy traffic using my DSO.
This way you can see the cherry-picked data captured as hex on a screen.
Portable terminal program for several interfaces?