AVR DB - GCC - first experiment with interrupt (from USART0), appliation restarts when first character received by USART0

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

AVR128DB18, MCS7 GCC, C executable.

I am experimenting with interrupt service routine (first attempt at writing and testing ISR on this platform.)

I am using USART0 in Async mode (which otherwise is working well without interrupts involved) as the test case. No other onboard peripherals are active, nor are peripheral interrupts enabled (except for the one instance at USART0 RXIE.)

I have not enabled watchdog timer (or brownout detection).

 

I believe I am configuring USART0 to cause an interrupt when a byte is received (however, not when a byte is sent, nor under any other circumstance.)  I am likely failing to do this properly (or set up ISR properly).

 

Once I enable CPU interrupts (sei), the program continues to work properly until the first byte arrives at the USART0 receive data port.

At that point, the program appears to restart, rather than enter the ISR as expected.

I have two ISRs defined - ISR(BADISR_vect) and ISR(USART0_RXC_vect); neither appears to be called

 

Am I missing something basic for this? I've read (and read and read)

 

https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

 

however, I've not been able to find my culprit.

 

Below is the code segment (abridged, so only the relevant initialization and ISRs are listed, and failure mode are described.) I've captured the bit-level settings of USART0 (in 0x8000..0x080E) as they are set before the first character is received when interrupts are enabled in a comment at the end. Once the first interrupt happens, the program resets, so I've not yet been able to capture any changes to those settings.

 

Thanks for any pointers!

Dave

 

#include <avr/io.h>
#include <avr/cpufunc.h>
#include <avr/interrupt.h>

ISR(BADISR_vect)
{
	// Do this for uncaught interrupt

	// This does not appear to ever be called
}

ISR(USART0_RXC_vect)
{
	// Do this when USART0 has received a character

	// This does not appear to ever be called
}

void initialize_usart0(void)
{
	// All the rest of initalizing USART0 details would go here (omitted) as without interrupts USART0 is receiving and transmitting data properly.
        // Asynchronous mode, 8 bits/character, 1 stop bit, no parity bit, normal speed mode, transmit data pin is set for output, receive enabled, transmit enabled.
        // The following change was made to enable interrupt when a byte is received in the USART:
	USART0_CTRLA = USART_RXCIF_bm; // Enable interrupt - should call ISR(USART0_RXC_vect) when a byte arrives at USART0 RxD pin
}

int main(void)
{
	// When the problem is triggered (USART0 receives one byte while it's interrupts are
	// enabled and CPU interrupts are enabled), we get back to this point unexpectedly,
	// without ever calling ISR(BADISR_vect) or ISR(USART0_RXCIF_vect)

	// All other initialization gets done here, except usart0 - no other peripherals have interrupts enabled
	initialize_usart0(); // Initialize usart0, and enable interrupt when character received (see above)
	// Everything works through this point in the code, interrupts are off

	sei(); // Turn on CPU interrupts

	// Everything works beyond this point, *until* the USART receives a character

	// When USART0 receives it's first incoming byte,
	// the program appears to restart (gets back to int main(void) above)
		// ISR(BADISR_vect) does not appear to be called
		// ISR(USART0_RXC_vect) does not appear to be called
}

/*
USART0 registers (before the first receive character with interrupts on)
RXDATAL  30 (the last character that was received while interrupts were off)
RXDATAH  00 (no errors or interrupt flags; 8-bit data so no 9th bit)
TXDATAL  20 (the last character that was sent)
TXDATAH  00 (8-bit data, so no 9th bit)
STATUS   40 TXCIF is high
CTRLA    80 RXCIE is high
CTRLB    C0 RXEN, TXEN are high
CTRLC    03 CHSIZE = 011 = 
BAUD     10 BAUD = 10000 (2710 hex)
OTHERS   00
*/

 

This topic has a solution.
Last Edited: Sun. Jan 2, 2022 - 03:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It would be nice to see complete code rather than comments.

 

USART0_CTRLA = USART_RXCIF_bm;

You want the interrupt enabled BIT (USART_RXCIE_bm ??) not the flag bit.

 

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, js for the quick reply -

 

Yes, the enable interrupt instruction I posted indeed had a typo (which as it turns out didn't change the behavior, a RXCIF_bm and RXCIE_bm are in the same bit position, but nonetheless a typo for sure). Fixing that didn't alter behavior, but certainly makes more sense in the source code!

 

I'll work on getting a better code sample posted (isolating the parts that are relevant so context is clear, without posting the whole somewhat larger program that's not core to the issue.)

 

Dave

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

I never worked with those chips but with Xmegas you also need to set the interrupt level, also BADISR_vect is used by the compiler for non initiated interrupts so you should not use it.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Couple of points:

 

1. Are you sure that empty ISRs are actually created by the linker/compiler? Optimization tends to do odd stuff with things that are not used.

 

2. Reset instead of an interrupt is often a consequence of an interrupt that is not present in code.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

Also AVR128DB18?? I couldn't find this version, only 28, 32, 48, 64

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have the BOOTSIZE fuse set to anything other than 0, your interrupt vector is no longer at address 0. That is one common scenario where all seems ok until an interrupt fires and you end up somewhere unexpected. One symptom of that on the avrDx could be be that you may end up rolling over to 0 (looks like a reset), but the next time an interrupt fires you do not get any interrupt action because there was never a reti so the LVL0EX bit is still set (need a 'real' reset to clear that bit, or a reti).

 

 

also BADISR_vect is used by the compiler for non initiated interrupts so you should not use it.

BADISR_vect is a defined alias in interrupt.h to __vector_default, which is what you use to check for unhandled interrupts (__vector_default is a weak named function you can override). The name that is used by the linked in vector table (crt*.o) is __bad_interrupt which you cannot override (so you get either the default jump to 0 from the weak __vector_default which is a bad idea, or you override that function with something of your own).

Last Edited: Sat. Jan 1, 2022 - 10:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your main() loop should actually have a loop in it, like   { while(1);  }  after the sei().  Otherwise, main() simply executes random instructions after doing sei().

 

There should also be a way to see if the ISRs have been entered, like toggling a output pin up and down when the ISR gets executed.  This could be captured by a digital oscilloscope to see if the ISR has been entered.  Or, turn on an LED if you have no scope.

 

" it's " is a contraction of "it is",  example: "...it's going to rain today..."     On the other hand, " its " is the possessive of an inanimate object,  example:"... the ISR and its code...".

Last Edited: Sat. Jan 1, 2022 - 10:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 like toggling a output pin up and down when the ISR gets executed.  

+++ absolutely.

but be sure to only toggle it once in the IRQ, so it will be wide enough to see on the scope...you don't want to try looking for 200ns pulses separated by 5 ms (when seeing how often ) the IRQ is happening

next IRQ=== >pin goes high

next IRQ===>pin goes low

next IRQ===>pin goes high

next IRQ===>pin goes low

etc

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

Otherwise, main() simply executes random instructions after doing sei().

avr-gcc does a cli then an infinite loop on a return from main. Returning from main is a problem here, and should result in simply spinning in circles with no interrupts. Maybe that is what is happening although the description said otherwise ('reset'-like symptoms).

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

Thanks for all of the helpful messages!

 

(yes, DB28, not DB18!)

 

curtvm had posted the path to the solution, and as I hadn't checked back for a few hours, I wandered into the same solution path. I've flagged that posting as the solution, because it was offered and would have solved my problem had I been checking back more frequently.

 

I had indeed previously divided flash (using fuse settings) into BOOT, CODE and DATA areas (so that I could experiment with writing flash from the application), but my (tiny) application actually lives in the boot area. This hadn't caused a problem until now, because I wasn't turning on interrupts. I hadn't changed fuse settings back (to single monolithic flash classification) for no good reason, just moved on.

 

I looked late today (for the first time) at the CPU interrupt controller section of the data sheet/book, that lead quickly to IVSEL, and indeed, I had left it at default (look for vectors in CODE space), and left Studio's GCC at it's default, which appears set to generate code that lands in the boot space. The handlers I had set up weren't being reached because the vector table wasn't where the CPU expected it to be.

 

Once I set IVSEL to look for vectors in the boot space (to accommodate the way I'm using the part right now), interrupts started acting as expected, at least as far as I've tested.

 

Thanks again for all of the help, advice and patience!

 

Dave