- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I experience an intermittent alt_exception_unknown problem during data load on one of the fifoed_avalon_uart (IP version 9.3.0). The system instantiates a total of 7 fifoed_avalon_uart ports. The exception is generated from different places of the application. I registered custom instruction-generated exception handler and observed multiple executions of it with cause 2 (NIOS2_EXCEPTION_INTERRUPT). Is there any way to get more information about the problem during debugging? What can cause such problem? How can it be resolved?
The NIOS II documentation does not provide a lot of information on this subject. The comments in the alt_exception_unknown in alt_exception_entry.S talk about
- mismatch of the compiled SW and the actual NIOS II core (we compiled and are running on NIOS II/f so it is not the case)
- MMU/MPU exception (we don’t have them enabled)
- Trap instruction (does not look like our case)
- Illegal instruction (does not look like our case)
- HW spurious interrupts (we are using internal interrupt controller, how can we check for this problem?)
Thanks you!
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The alt_exception_unknown problem you're experiencing, particularly with NIOS2_EXCEPTION_INTERRUPT (cause 2), is a common but tricky issue in Nios II systems with multiple peripherals like your 7 instances of fifoed_avalon_uart.
Understanding the Exception: NIOS2_EXCEPTION_INTERRUPT in alt_exception_unknown
When you see alt_exception_unknown handling an exception with cause 2 (NIOS2_EXCEPTION_INTERRUPT), it means:
An interrupt was asserted. But the Nios II exception entry logic could not identify the correct interrupt service routine (ISR) via the normal interrupt dispatch mechanism. This typically points to a spurious interrupt — an interrupt that fires without a valid source or when the source is no longer active. Even though you're using the internal interrupt controller (IIC), spurious interrupts can still occur due to:
Race conditions in interrupt status/clear logic.
Timing issues on interrupt deassertion.
Hardware bugs in IP (especially older versions).
Shared interrupt lines or misconfigured vector mappings.
Why This Might Be Happening with fifoed_avalon_uart (v9.3.0)
The fifoed_avalon_uart is a common component, but version 9.3.0 is quite old, and known issues exist, especially under high load or with FIFO edge cases.
Known potential problems:
Spurious interrupt generation due to race condition between FIFO status change and interrupt clear.
Interrupt status not cleared properly if the FIFO is read too quickly or during state transitions.
Interrupt line remains asserted after service due to incorrect clearing sequence.
Multiple UARTs sharing interrupt priority levels or vectors, causing confusion in the IIC.
Note: You have 7 UARTs — this increases the likelihood of timing-sensitive interrupt issues, especially if they're active simultaneously. It may be hard for one Nios II processor to handle timely. If you prefer to debug further, you may try below methods. But I am not sure whether you can find the root cause with these methods.
Debugging Strategies
1. Enable Detailed Exception Logging
You’ve already installed a custom handler — good. Enhance it:
void custom_exception_handler(struct exception_context *ctx)
{
uint32_t exception = ctx->exception;
uint32_t badaddr = ctx->bad_addr;
uint32_t status = ctx->estatus;
uint32_t irq = (status & 0x3FFF); // Current interrupt level
printf("EXCEPTION: cause=%d, estatus=0x%08x, irq_level=%d\n",
exception, status, irq);
// Read the interrupt controller to see which IRQs are pending
uint32_t ipending = IORD_ALTERA_AVALON_PIC_IPENDING(
(void*)YOUR_PIC_BASE); // Replace with actual PIC base
printf("IPENDING: 0x%08x\n", ipending);
}
This helps determine:
Which interrupt level was active.
Whether any sources are still pending.
If the IPENDING register shows unexpected bits.
2. Check UART Interrupt Status Registers
Poll each UART's status register during the exception (or log it just before servicing):
uint32_t status = IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
if (status & ALTERA_AVALON_UART_STATUS_PE_MSK) {
printf("Parity error\n");
}
if (status & ALTERA_AVALON_UART_STATUS_OE_MSK) {
printf("Overrun error\n");
}
if (status & ALTERA_AVALON_UART_STATUS_RRDY_MSK) {
printf("RRDY set\n");
}
if (status & ALTERA_AVALON_UART_STATUS_DCTS_MSK) {
printf("DCTS set\n");
}
Look for overrun errors (OE) — they are a common cause of spurious or repeated interrupts.
3. Use On-Chip Debugger (OCD) + GDB
Use Nios II IDE with OCD to:
Set a breakpoint in alt_exception_unknown.
Examine ctx->estatus, ctx->ea, ctx->bad_addr.
Check the stack trace to see where the exception occurred.
Use hardware tracing (if available) to capture the last few instructions.
Tip: In GDB, use info registers, x/10i $pc-20 to see context.
4. Instrument Interrupt Handlers
Add logging at entry and exit of each UART ISR. Include:
Timestamp (cycle counter).
Status register value.
Number of bytes read.
This can reveal:
Whether an ISR is being called repeatedly without cause.
Whether FIFOs are empty when ISR runs (indicating spurious IRQ).
5. Check for Overrun and FIFO Management
Overrun (OE) happens when data arrives faster than it's read. This can:
Trigger an interrupt.
Cause the UART to assert interrupt again immediately.
Lead to chatter or spurious-looking behavior.
Ensure your ISR reads until FIFO is empty, not just one byte:
while (IORD_ALTERA_AVALON_UART_STATUS(base) & ALTERA_AVALON_UART_STATUS_RRDY_MSK) {
char c = IORD_ALTERA_AVALON_UART_RXDATA(base);
// process c
}
Also, consider increasing FIFO depth in Qsys if possible.
Potential Fixes and Mitigations
Add Interrupt Debouncing / Lockout
In your UART ISR:
Read status first.
1.If no valid reason (RRDY, DCTS, etc.), clear interrupt anyway and log it.
Example:
void uart_isr(void* context)
{
uint32_t status = IORD_ALTERA_AVALON_UART_STATUS(base);
if (!(status & (ALTERA_AVALON_UART_STATUS_RRDY_MSK |
ALTERA_AVALON_UART_STATUS_DCTS_MSK |
ALTERA_AVALON_UART_STATUS_PE_MSK |
ALTERA_AVALON_UART_STATUS_OE_MSK))) {
// Spurious interrupt — clear and return
return;
}
// Handle real interrupt...
}
2. Use Individual Interrupts (Not OR'd)
Ensure each UART has its own dedicated interrupt connection to the interrupt controller.
Avoid OR-ing multiple UART interrupts together unless you have a proper dispatching ISR.
In Qsys/System Console, verify each UART connects to a unique interrupt port.
3. Increase Interrupt Priority Separation
If multiple UARTs share the same priority level, consider giving high-traffic UARTs higher priority to avoid missed interrupts and overruns.
4. Add Software Interrupt Masking
Temporarily disable UART interrupts during critical sections or heavy load.
5. Check Clocking and Timing
Ensure:
UART clock is stable.
Baud rate is correctly derived.
No metastability issues (especially if external signals).
If the problem persists, consider reproducing with less UARTs to isolate whether it's a scale/concurrency issue.
Regards,
Archer

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page