AT32UC3C0512 100+ cycles Interrupt handling delay

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

Dear experts!

Continuing the discussion which ended the following topic: https://www.avrfreaks.net/forum/p...

 

I am facing an issue with the AT32UC3C0512 processor for some weeks now;

I am building an algorithm which controls a power converter (HF cycle by cycle).

The converter should be able to run at switching cycles up to 200kHz.

I make use of as many hardware peripherals as possible to minimize software dependency.

Unfortunately due to the control principle I have to handle 2 interrupts (based on pin changes) during each HF cycle.

 

It turns out that the handling on an interrupt (which is based on a rising edge of designated pin) takes 100+!!! cycles before it is executed.

I check this by toggling a pin when entering the function (and comparing this with a scope to the timing of the original input signal).

I am sure the controller runns at 64mHz but still the delay can be up to 2us (which I see happening twice in each HF cycle)!

The delayed timing is very consistent.

 

I make use of ASF to configure the controller and peripherals.

 

The only thing I can conclude is that there must be a HUGE ASF overhead in the interrupt handling..

But 128 cycles just feels extreme and highly unlikely!

Is there some option (debug or optimisation) I am missing which maybe reduces the amount of data put on stack>?

Can I see or check what the processor is doing duing these cycles?

 

What can I do?

Please help; I have spend days looking for an answer!

 

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

luc_V wrote:
The only thing I can conclude is that there must be a HUGE ASF overhead in the interrupt handling..

ASF is provided as source - so you should be able to easily confirm whether that is actually the case.

 

From using ASF on SAM D chips, I would say that it is certainly not optimised for speed - it is optimised for "programmer convenience" (although many would argue even with that).

 

ASF is great for getting something that works. Once you having something that works, you can consider whether the performance is adequate.

 

What can I do?

The same thing you'd do with any other software:

  • Examine the code 
  • Look for the bottlenecks
  • Adjust the code accordingly.

 

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

luc_V wrote:
The only thing I can conclude is that there must be a HUGE ASF overhead in the interrupt handling..

ASF is provided as source - so you should be able to easily confirm whether that is actually the case.

 

From using ASF on SAM D chips, I would say that it is certainly not optimised for speed - it is optimised for "programmer convenience" (although many would argue even with that).

 

ASF is great for getting something that works. Once you having something that works, you can consider whether the performance is adequate.

 

What can I do?

The same thing you'd do with any other software:

  • Examine the code 
  • Look for the bottlenecks
  • Adjust the code accordingly.

 

 

 

I agree with you here.. But as a hardware engineer the following files (which are the ASF files that handle the interrupt) look very advanced to me.

I am used to 8-bit processors in which such problems never occured.. with this 32-bit giant I cannot oversee the complexity (which "forced" me to use ASF).

I was hoping someone else encountered a simular problem and knew where to focus..

 

I found the following peculiar text in the ASF files ; This procedure indeed does not sound "optimal"; But I do not dare to change anything in the .exception file because I have no idea whats going on there.

 


/**
 * \brief Gets the interrupt handler of the current event at the \a int_level
 *        interrupt priority level (called from exception.S).
 *
 * \param int_level Interrupt priority level to handle.
 *
 * \return Interrupt handler to execute.
 */
__int_handler _get_interrupt_handler(uint32_t int_level);
__int_handler _get_interrupt_handler(uint32_t int_level)
{
	/* ICR3 is mapped first, ICR0 last.
	Code in exception.S puts int_level in R12 which is used by the compiler
	to pass a single argument to a function. */
	uint32_t int_grp = AVR32_INTC.icr[AVR32_INTC_INT3 - int_level];
	uint32_t int_req = AVR32_INTC.irr[int_grp];

	/* As an interrupt may disappear while it is being fetched by the CPU
	(spurious interrupt caused by a delayed response from an MCU peripheral
	to an interrupt flag clear or interrupt disable instruction), check if
	there are remaining interrupt lines to process.
	If a spurious interrupt occurs, the status register (SR) contains an
	execution mode and interrupt level masks corresponding to a level 0
	interrupt, whatever the interrupt priority level causing the spurious
	event. This behavior has been chosen because a spurious interrupt has
	not to be a priority one and because it may not cause any trouble to
	other interrupts.
	However, these spurious interrupts place the hardware in an unstable
	state and could give problems in other/future versions of the CPU, so
	the software has to be written so that they never occur. The only safe
	way of achieving this is to always clear or disable peripheral
	interrupts with the following sequence:
	1: Mask the interrupt in the CPU by setting GM (or IxM) in SR.
	2: Perform the bus access to the peripheral register that clears or
	disables the interrupt.
	3: Wait until the interrupt has actually been cleared or disabled by the
	peripheral. This is usually performed by reading from a register in the
	same peripheral (it DOES NOT have to be the same register that was
	accessed in step 2, but it MUST be in the same peripheral), what takes
	bus system latencies into account, but peripheral internal latencies
	(generally 0 cycle) also have to be considered.
	4: Unmask the interrupt in the CPU by clearing GM (or IxM) in SR.
	Note that steps 1 and 4 are useless inside interrupt handlers as the
	corresponding interrupt level is automatically masked by IxM (unless IxM
	is explicitly cleared by the software).*/

	/* Get the right IRQ handler.

	If several interrupt lines are active in the group, the interrupt line
	with the highest number is selected. This is to be coherent with the
	prioritization of interrupt groups performed by the hardware interrupt
	controller.

	If no handler has been registered for the pending interrupt,
	_unhandled_interrupt will be selected thanks to the initialization of
	_int_line_handler_table_x by INTC_init_interrupts.

	exception.S will provide the interrupt handler with a clean interrupt
	stack frame, with nothing more pushed onto the stack. The interrupt
	handler must manage the `rete' instruction, which can be done using
	pure assembly, inline assembly or the `__attribute__((__interrupt__))'
	C function attribute.*/
	return (int_req)
		? _int_handler_table[int_grp]._int_line_handler_table[32
			- clz(int_req) - 1]
		: NULL;
}

And exception.s file:

 

/**
 * \file
 *
 * \brief Exception and interrupt vectors mapping for the INTC Software Driver.
 *
 * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 *    Atmel microcontroller product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \asf_license_stop
 *
 */

#if !__AVR32_UC__ && !__AVR32_AP__
  #error Implementation for the AVR32 architecture only.
#endif


#include <avr32/io.h>


//! @{
//! \verbatim


.section  .exception, "ax", @progbits


// Start of Exception Vector Table.

/*
 * EVBA must be aligned with a power of two strictly greater than the
 * EVBA-relative offset of the last vector.
 */
.balign 0x200

// Export symbol.
.global _evba
.type _evba, @function
_evba:

	.org  0x000
	// Unrecoverable Exception.
_handle_Unrecoverable_Exception:
	rjmp $

	.org  0x004
	// TLB Multiple Hit.
_handle_TLB_Multiple_Hit:
	rjmp $

	.org  0x008
	// Bus Error Data Fetch.
_handle_Bus_Error_Data_Fetch:
	rjmp $

	.org  0x00C
	// Bus Error Instruction Fetch.
_handle_Bus_Error_Instruction_Fetch:
	rjmp $

	.org  0x010
	// NMI.
_handle_NMI:
	rjmp $

	.org  0x014
	// Instruction Address.
_handle_Instruction_Address:
	rjmp $

	.org  0x018
	// ITLB Protection.
_handle_ITLB_Protection:
	rjmp $

	.org  0x01C
	// Breakpoint.
_handle_Breakpoint:
	rjmp $

	.org  0x020
	// Illegal Opcode.
_handle_Illegal_Opcode:
	rjmp $

	.org  0x024
	// Unimplemented Instruction.
_handle_Unimplemented_Instruction:
	rjmp $

	.org  0x028
	// Privilege Violation.
_handle_Privilege_Violation:
	rjmp $

	.org  0x02C
	// Floating-Point: UNUSED IN AVR32UC and AVR32AP.
_handle_Floating_Point:
	rjmp $

	.org  0x030
	// Coprocessor Absent: UNUSED IN AVR32UC.
_handle_Coprocessor_Absent:
	rjmp $

	.org  0x034
	// Data Address (Read).
_handle_Data_Address_Read:
	rjmp $

	.org  0x038
	// Data Address (Write).
_handle_Data_Address_Write:
	rjmp $

	.org  0x03C
	// DTLB Protection (Read).
_handle_DTLB_Protection_Read:
	rjmp $

	.org  0x040
	// DTLB Protection (Write).
_handle_DTLB_Protection_Write:
	rjmp $

	.org  0x044
	// DTLB Modified: UNUSED IN AVR32UC.
_handle_DTLB_Modified:
	rjmp $

	.org  0x050
	// ITLB Miss.
_handle_ITLB_Miss:
	rjmp $

	.org  0x060
	// DTLB Miss (Read).
_handle_DTLB_Miss_Read:
	rjmp $

	.org  0x070
	// DTLB Miss (Write).
_handle_DTLB_Miss_Write:
	rjmp $

	.org  0x100
	// Supervisor Call.
_handle_Supervisor_Call:
	rjmp $


/*
 * Interrupt support.
 * The interrupt controller must provide the offset address relative to EVBA.
 * Important note:
 * All interrupts call a C function named _get_interrupt_handler.
 * This function will read group and interrupt line number to then return in
 *R12 a pointer to a user-provided interrupt handler.
 */

.balign 4

.irp    priority, 0, 1, 2, 3
.global _int\priority
.type   _int\priority, @function
_int\priority:
#if __AVR32_UC__
	/*
	 * R8-R12, LR, PC and SR are automatically pushed onto the system stack
	 * by the CPU upon interrupt entry. No other register is saved by
	 * hardware.
	 */
#elif __AVR32_AP__
	/*
	 * PC and SR are automatically saved in respectively RAR_INTx and
	 * RSR_INTx by the CPU upon interrupt entry. No other register is saved
	 * by hardware.
	 */
	pushm   r8-r12, lr
#endif
	// Pass the int_level parameter to the _get_interrupt_handler function.
	mov     r12, \priority
	call    _get_interrupt_handler
	// Get the pointer to the interrupt handler returned by the function.
	cp.w    r12, 0
#if __AVR32_UC__
	/*
	 * If this was not a spurious interrupt (R12 != NULL), jump to the
	 * handler.
	 */
	movne   pc, r12
#elif __AVR32_AP__
	// If this was a spurious interrupt (R12 == NULL), branch.
	breq    spint\priority
	/*
	 * Push the pointer to the interrupt handler onto the system stack since
	 * no register may be altered.
	 */
	st.w    --sp, r12
	popm    r8-r12, lr, pc  // Restore registers and jump to the handler.
spint\priority:
	popm    r8-r12, lr
#endif
	/*
	 * If this was a spurious interrupt (R12 == NULL), return from event
	 * handler.
	 */
	rete
.endr


//! \endverbatim
//! @}

Any suggestions what to do or where to look for?

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

The AVR32 hardware requires that all the interrupt/exception handlers are located within a 16 kbyte 'block'.
Unlike the AVR8s the start of that 'block' is not at a fixed address, instead it starts at the address that is put into the EVBA register.
The exception vectors are at fixed offsets relative to the EVBA, ( eg the NMI exception handler (or a jump to somewhere else) should be placed at EVBA +0x10 ).


So., how does one coerce the C/C++ compiler/linker to put the interrupt-handlers into a region that is within EVBA + 0x0000 to EVBA + 0x3FFF ?
well.,
- you can use 'sections' to coalesce all the interrupt stuff., unfortunately there does not appear to be a way to control the ordering, which means that some handlers might be placed 'below' the EVBA.
- you can fiddle with the linker-script, which is probably the best solution andi wish you good fortune in understanding its' language and syntax.


The ASF takes a simpler and more general approach to the problem by using a jump-table.
ie. the interrupts jump to a piece of code which then extracts your interrupt-handler from a table.
The advantages are that your C interrupt-handlers can be located anywhere within the executable address-space, plus you don't need to worry about handling the interrupt Groups and Lines.
The disadvantages are longer latency before your handler is invoked, plus ram-usage for the lookup table.


Note that the AVR32 will always save R8-R12 on an INT 0,1,2,3 interrupt which means that the minimum interrupt-overhead is at least 25 cycles.


How to reduce the latency ?
- compile with optimisations on. (-O0 means that the ASF _get_interrupt_handler uses about 30 instructions).
- you could create a new scheme to reduce the overhead,
eg. put a table for all the interrupt-groups into exception.s, point the INTC IPRs there, put jump instructions to your group-handlers into the table.
(downside is that your group-handler will need to do more work when there is more than 1 interrupt-line per group).

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

There is also the hidden overhead from c - where it caches variables between the physical beginning of the ISR and when the visible code begins. That will, I think I have been told, depend on how much is IN the ISR, though that may well be different for UC3 compared to AVR. You will need to look at the disassembled assembler version of the compiler output to see how much is really there.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

luc_V wrote:
as a hardware engineer the following files ... look very advanced to me.

Is this for a commercial or hobby project?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

luc_V wrote:
as a hardware engineer the following files ... look very advanced to me.

Is this for a commercial or hobby project?

The question is related to my graduation project (master degree in (power) Engineering); the project is hosted within a commercial company (Philips).

The past 12 months I made a theoretical analysis of an optimal control and power solution for a given (very specific) specification set (wirelessly dimmable retrofit LED bulb).

 

The analysis converged to a specific power converter and control principle which I wanted to validate with a practical prototype.

All parts are designed, finished, functioning and behave according to my analysis.

The only problem I face is the limited switching frequency; I cannot run it above 150kHz (which is beneficial for the efficiency).

 

I discussed the interrupt issue (and the content of this topic) with my supervisors and they advise me not to spend to much time on this (while I still think the current issue is very interesting!).

There is a rather strict deadline and this issue is (according to my supervisors) out of scope for my assignment.

 

Still I want to thank you all for your contribution; much appreciated.

(This weekend I will try if I can implement the suggestions of Mikech)

 

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

luc_V wrote:
I discussed the interrupt issue (and the content of this topic) with my supervisors and they advise me not to spend to much time on this ... this issue is (according to my supervisors) out of scope for my assignment.

That sounds like good advice to me.

 

You say you're a hardware engineer, and it does sound very much like a detailed software question.

 

It's good to hear someone actually making proper use of their supervisors!

 

Good luck.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

luc_V wrote:

 

The analysis converged to a specific power converter and control principle which I wanted to validate with a practical prototype.

All parts are designed, finished, functioning and behave according to my analysis.

The only problem I face is the limited switching frequency; I cannot run it above 150kHz (which is beneficial for the efficiency).

 

I discussed the interrupt issue (and the content of this topic) with my supervisors and they advise me not to spend to much time on this (while I still think the current issue is very interesting!).

 

There is a rather strict deadline and this issue is (according to my supervisors) out of scope for my assignment.

 

 

You have achieved the goal of the project, therefore I'm sure your supervisors just want you to go on and write your Master's thesis ASAP. They are right; keep to the deadline.