AtTiny2313 Comms int errors, ASM => Solved

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

Hi A/all

I had a working AtTiny2313 board that i needed to use as a debug board to send messages to a second board using an AtMega168.

Apart from the messegs data sent, the only change required for the AtTiny2313 board software was the control of the RS485 'DIR' line.

The changes in the original code lead me to believe there is an error in either the interrupt enable bits or vectors.

When the TX routine completes, the program crashes, but only if the 'tx=complete' routine enables the TX Complete interrupt.

The error is that the watchdog times out and bites me in te arse if this line is enabled.
When disabled, the 'DIR' line remains high. (TX)

Here is the revalant ASM code:

RESET:
	rjmp	initialize		;Reset vector.
	rjmp	initialize	;Unused IRQ0 External Interrupt.
	rjmp	initialize	;Unused IRQ1 External Interrupt.
	rjmp	initialize	;Unused Timer1 Capture Interrupt.
	rjmp	initialize	;Unused Timer1 Compare Interrupt.
	rjmp	initialize	;Unused Timer1 Overflow Interrupt.
	rjmp	initialize	;Unused Timer0 Overflow interrupt.

	rjmp	rx_int			;UART RX Interrupt.
	rjmp	tx_tbe_int		;UART TX Buffer Emply Int.
	rjmp	tx_all_sent_int	;UART TX complete Interrupt.
	rjmp	initialize		;Analog Comparitor Interrupt.

;Dont think I've skipped any vectors.
init_uart:				;Init UART for 9600bps,n8,1,n.
	clr	temp
	out	UCSRA,temp		;U2X=0,Not multiprocessor mode.

;HB001	ldi	temp,0b10011000	;RXCIE=1,TXCIE=1,UDRE=0,RXEN=1,TXEN=1,UCSZ2=0,RXB8=0,TXB8=0.
	ldi	temp,0b10011000	;RXCIE=1,TXCIE=0,UDRIE=0,RXEN=1,TXEN=1,UCSZ2=0,RXB8=0,TXB8=0. <----HB011_TST version no TX ints.
	out	UCSRB,temp		;Enable RX complete interrupt only.

	ldi	temp,0b00000110	;URSEL=1,USMSEL=0,UPM1:0:=0,USBS=0,UCSZ1:0:=11,UCPOL=0.
	out	UCSRC,temp		;Select UCSRC_WR,UMSEL=0=async,No parity,1 stop bit,8 bit Data.

	ldi	temp,0b00000000	;Select UBRRH, No High byte for baudrate register.
	out	UBRRH,temp		;Set high byte of baudrate generator.

	ldi	temp,BAUDCONSTANT	;Load baudrate value for 9600bps
	out	UBRRL,temp		;Set low byte of baudrate generator.

	ldi	temp,BOARD_TYPE	;Setup board type & address.
	ori	temp,BOARD_ADDR
	sts	my_address,temp	;Save combined Board Type & Address.

init_outputs:

send_message:
	sbis	UCSRA,UDRE
	rjmp	send_message		;Ensure UDR is clear.

	sbi		PORTD,DIR			;Set DIR for RS485 TX.

	ldi	YL,low(tx_buffer)		;Point to start of tx_buffer.
	ldi	YH,high(tx_buffer)		;i.e. Total Mesage Length byte.

;Message format is: length, total number of bytes to send, then message data.

	ld		temp,Y+	;Get message total length byte & point to next byte to send.
	sts	tx_counter_ram,temp		;Initialize tx byte counter.

	sts	tx_bfr_ptr_low,YL		;Save TX buffer pointer low in ram.
	sts	tx_bfr_ptr_high,YH		;Save TX buffer pointer high in ram.

	ldi		temp,SYNC_BYTE		;Send a SYNC_BYTE to start message.
	out		UDR,temp

	sbi		UCSRB,UDRIE			;Enable TBE interrupts.

	ret							;Let Interrupts send the rest.

;------------------------------------------------------------------------------

tx_tbe_int:
	push	temp			;So that we may use it here.
	in		temp,SREG
	push	temp			;Save status on stack.
	push	YL
	push	YH

	lds	temp,tx_counter_ram	;Number of bytes to still be sent.
	tst		temp			;Any more bytes to be sent?
	breq	tx_complete		;Exit if not.

	cpi		temp,0xff		;Has tx already completed?
	breq	tx_complete	;Exit if so.

	dec		temp			;One less byte to send.
	sts	tx_counter_ram,temp	;Save number of bytes to still be sent.

	lds	YL,tx_bfr_ptr_low	;Get TX buffer pointer low from ram.
	lds	YH,tx_bfr_ptr_high	;Get TX buffer pointer high from ram.
	ld		temp,Y+			;Get next character to send & inc ptr.
	out		UDR,temp		;Send next character.

	sts	tx_bfr_ptr_low,YL	;Save updated TX buffer pointer low in ram.
	sts	tx_bfr_ptr_high,YH	;Save updated TX buffer pointer high in ram.

tx_tbe_int_exit:
	pop		YH
	pop		YL
	pop		temp			;Get SREG from stack.
	out		SREG,temp		;Restore SREG.
	pop		temp			;Restore original temp.
	reti

;--------------------------------------------------------------------

tx_complete:
	ser		temp			;Flag TX complete.
	sts	tx_counter_ram,temp	;Save TX Complete status.

	cbi	UCSRB,UDRIE			;Disable further TBE interrupts.
	sbi	UCSRB,TXCIE			;Enable TX Complete interrupt for RS485 DIR CTRL.

	rjmp	tx_tbe_int_exit

;------------------------------------------------------------------------------

tx_all_sent_int:			;UART TX Complete Interrupt.
	push	temp			;So that we may use it here.
	in		temp,SREG
	push	temp			;Save status on stack.

	sbi	UCSRA,TXC	;Added 00:30Hrs 21-SEP-10 moved up 1 line @ 00:42hrs
	cbi	UCSRB,UDRIE;TXCIE			;Disable TX Complete interrupt for RS485 DIR CTRL. 21-SEP-10

	cbi		PORTD,DIR		;Restore DIR back to RS485 RX.

	pop		temp			;Get SREG from stack.
	out		SREG,temp		;Restore SREG.
	pop		temp			;Restore original temp.
	reti

;------------------------------------------------------------------------------

Any help in this would be greatly accepted.
Kind Regards, Ron.

 

Last Edited: Wed. Sep 22, 2010 - 02:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try restructuring the tx_tbe_int UDRE Interrupt Response Code (ISR) such that after the final UDR write, you write a 1 to TXC (clear any stray TXC flag value), then enable TXCIE and finally disable UDRIE. Clearing TXC first ensures that any higher priority ISR code that could have taken long enough to execute and allowed the USART to empty the UDR buffer before tx_counter_ram = 0, then set TXC prematurely is always cleared. Clearing TXC immediately after the last UDR write ensures you never accidentally wipe out a valid TXC flag. Your current code checks tx_counter_ram in the wrong place to ensure tx_complete only happens immediately after the last UDR write without any delays.

Then the tx_all_sent_int TXC ISR will only need to do your PORTD DIR clear and clear TXCIE.

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

Quote:
The changes in the original code lead me to believe there is an error in either the interrupt enable bits or vectors.
There is a difference, the AtTiny2313 uses rjmp, anything with more than 8K flash uses jmp.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

An interrupt vector uses the .org directive.
.org 0x00
rjmp initialize
.org 0x07
rjmp rx_int ;UART RX Interrupt.
.org 0x08
rjmp tx_tbe_int ;UART TX Buffer Emply Int.
.org 0x09
rjmp tx_all_sent_int ;UART TX complete Interrupt

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

Hi A/all,

After reviewing the reply from MikeB and my code, the problem has been resolved. Thanks Mike, didn't do all you suggested, but enough to resolve the issue.

Many would exit here, but I will post the working code as it may help others.

This is the revised code:

;------------------------------------------------------------------------------

tx_tbe_int:
	push	temp			;So that we may use it here.
	in		temp,SREG
	push	temp			;Save status on stack.
	push	YL
	push	YH

	lds	temp,tx_counter_ram	;Number of bytes to still be sent.
	tst		temp			;Any more bytes to be sent?
	breq	tx_complete		;Prepare to switch DIR back to RX.

	cpi		temp,0xff		;Has tx already completed?
	breq	tx_tbe_int_exit	;Exit if so.

	dec		temp			;One less byte to send.
	sts	tx_counter_ram,temp	;Save number of bytes to still be sent.

	lds	YL,tx_bfr_ptr_low	;Get TX buffer pointer low from ram.
	lds	YH,tx_bfr_ptr_high	;Get TX buffer pointer high from ram.
	ld		temp,Y+			;Get next character to send & inc ptr.
	out		UDR,temp		;Send next character.

	sts	tx_bfr_ptr_low,YL	;Save updated TX buffer pointer low in ram.
	sts	tx_bfr_ptr_high,YH	;Save updated TX buffer pointer high in ram.

tx_tbe_int_exit:
	pop		YH
	pop		YL
	pop		temp			;Get SREG from stack.
	out		SREG,temp		;Restore SREG.
	pop		temp			;Restore original temp.
	reti

;--------------------------------------------------------------------
; Last byte sent, disable further TBE ints, Enable TXC Int, once.
;--------------------------------------------------------------------

tx_complete:
	ser		temp			;Flag TX Complete.
	sts	tx_counter_ram,temp	;Save TX Complete status.

	cbi	UCSRB,UDRIE			;Disable further TBE interrupts.
	sbi	UCSRA,TXC			;Clear any pending TXC Flags. Added 20:43Hrs 22-SEP-10
	sbi	UCSRB,TXCIE			;Enable TX Complete interrupt for RS485 DIR CTRL.

tx_complete_exit:
	rjmp	tx_tbe_int_exit

;------------------------------------------------------------------------------
; Switch RS485 back to RX once message is All Sent.
;------------------------------------------------------------------------------

tx_all_sent_int:			;UART TX Complete Interrupt.
	push	temp			;So that we may use it here.
	in		temp,SREG
	push	temp			;Save status on stack.

	cbi		UCSRB,TXCIE		;Disable TX Complete interrupt for RS485 DIR CTRL.

	cbi		PORTD,DIR		;Restore DIR back to RS485 RX.

	pop		temp			;Get SREG from stack.
	out		SREG,temp		;Restore SREG.
	pop		temp			;Restore original temp.
	reti

;------------------------------------------------------------------------------

Thanks to all who replied.

Regards, Ron.

 

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

Ron I hope you have modified your interrupt vectors by either using jmp insted of rjmp or using .org as geoelec suggested because the AtTiny2313 uses rjmp wich is 2 bytes whilst chips with more than 8K flash uses jmp (4 bytes).

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

John, the AtTiny2313 has 2K so rjmp is correct. The reset lable is at .org 0
I chose to use a full vector table to trap any interrups that were accidentally enabled by rjmp'ing to the initialize routine, rather than executing a few nop instructions and rjmp'ing to the wrong routine.

Did you see anything wrong with my vector table? Its as per the data sheet.

 

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

Quote:

chose to use a full vector table to trap any interrups that were accidentally enabled by rjmp'ing to the initialize routine, rather than executing a few nop instructions and rjmp'ing to the wrong routine.

What many Asm programmers and C compilers do is actually point the unused vectors to some kind of "catch" routine so that you can easily breakpoint on unhandled interrupts. Another option is to provide "empty" handlers for each of the unused vectors so you can even identify which one is triggering.

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

Actually, jumping to the initialization software routine may not produce a clean predictable program restart. None of the Special Function I/O Registers are in a known default state unless the AVR hardware is reset. Forcing a Watch Dog Timer reset is better than a software jump to accomplish a clean predictable deliberate program restart.

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

clawson wrote:

Quote:
What many Asm programmers and C compilers do is actually point the unused vectors to some kind of "catch" routine so that you can easily breakpoint on unhandled interrupts. Another option is to provide "empty" handlers for each of the unused vectors so you can even identify which one is triggering.
That is a good idea. I will implement that in my next project.
Mike B wrote:
Quote:
Actually, jumping to the initialization software routine may not produce a clean predictable program restart.
The point was to jump to the initialize routine, rather than the wrong isr.
I hope that that is what was achived.
Ron.

 

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

rberger wrote:
The point was to jump to the initialize routine, rather than the wrong isr. I hope that that is what was achived.
Ok, then explain to me what is the point of jumping to initialization software (reset vector) that can malfunction because the SFIOR values are messed up.

For example, have you tested your USART initialization code to see if it always works even when the USART is already busy running while you rerun the initialization code? Does your initialization code explicitly stop the USART and flush the UDR buffers first thing? The AVR hardware reset does things like this every time without fail for every function module in the entire AVR.

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

:oops: Sorry Ron, I reread you post and I see that the code is still running in the AtTiny2313. I kept on thinking that you had moved the code into the M168 therefore my comments. :oops:

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Thanks John.

Quote:
Ok, then explain to me what is the point of jumping to initialization software (reset vector) that can malfunction because the SFIOR values are messed up.
noted, Mike. I use this as an initial debug tool. Once the stack & Ports have been setup I can pulse a spare output line which I monitor with either a CRO or Data Analyzer. one pulse=OK, 2 or more=stuffup.
Quote:
The AVR hardware reset does things like this every time without fail for every function module in the entire AVR.
Once the initial bugs are resolved, there will only be a hardware reset and no spurious jumps to the initialisation code.
Ron.