timer interrupt while bootloading

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

Hi, im working on the bootloader of the 1605-app-note. I want to use it in a XMEGA16E5. After some small changes the original version is working fine.

But i like to control the bootmodus (enter application-code or boot-code) not via pulling an GPIO down but with a serial command over USART. That works also fine, but if I dont entering a command a timer interrupt should abrort the boot-code and jumps to the application.

 

My Problem is: After jumping in the Timeroverflow-ISR, the controller does nothing. It seems that he jumps anywhere, but not back to the last code..

 

I know that I have to set the Interrupt vectors adresses to the boot section, Im doing this by:

 

/* Set interrupt vector location to boot section of flash | enable mid level ISRs */
void PMIC_SetVectorLocationToBoot( void )

{

    PMIC.CTRL = temp;
    CCP = CCP_IOREG_gc;
    PMIC.CTRL = temp;// PMIC_IVSEL_bm | PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm;    
}

 

 

In my Timer Overflow ISR is nothing more than:

 

ISR(TCC4_OVF_vect)
{
    timerovfl = 1;          //flag
    sendchar('t');           //just for debugging
    TCC4.INTFLAGS = TC4_OVFIF_bm;// Clear interrupt flag    
}

 

 

 

What is wrong in my code?

Last Edited: Tue. Jan 20, 2015 - 11:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe this is also intressting: The timerovfl flag is used in the function which polls the USART:

 

unsigned char recchar(void)
{	
	unsigned char ret;

	while((!(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT))) || (timerovfl == 1))// wait for data ODER TIMERÜBERLAUF
	{}
	
	// the cpu never reaches the following:
	if (timerovfl == 1)
	{
		sendchar('t');
	}
	else
	{
		sendchar('n');
	}
		
	ret = UART_DATA_REG;

	return ret;
}

thanks

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

Not sure I understand why you need to run the timer while in the bootloader. In fact doing interrupts in a bootloader is a very bad idea - far too complex - a bootloader should be simple. But if you are intent on doing it then 2 things:

 

1) enter the bootloader by forcing a chip reset. Either a watchdog or the Xmega has a built in soft reset. That way you get into the bootloader with everything "switched off"

 

2) Once in the bootloader look at "IVSEL". It might be called something different in Xmega, I only really know tiny/mega's where it is called IVSEL but the point is that it's a control bit that tells the AVR CPU to use a vector table at the start of the bootloader rather than a vector table at the start of the application area (because, during SPM writes, the application one will be "invisible"). Having done IVSEL the bootloader can then setup and launch any timer or other interrupts it needs to complete its job. The ISR() code used is that built into the bootloader not in the app code (because the app may not even be there). When the bootloader if finished it should turn off the interrupts, reset IVSEL back so that the vector table used will be the one down near 0. Then it should "JMP 0" to enter the app code. The app code will now setup and start interrupts and this time the ISR()s handling those interrupts will be the ones built into the app code.

 

Simples.

 

(I still think interrupts in a bootloader are a "BadIdea(tm)". If your uartReceive() needs timeouts just tick down something locally).

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

Thanks for your message.

1) I will implement that.

 

2) In my "SetVectorLocationToBoot"-function, I am setting the IVSEL-bit. And I think that works, the interrupt is started correctly. But it seems that it dosent jump back to the code which was executed before the interrupt.

 

3) Maybe you are right and its not a good idea to use a timer. But if I built a counter for timeout, I have to use a delay and isnt that also use a timer?

 

But I will think about that an try to manage that without a timer-ISR.

 

thanks 

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

But it seems that it dosent jump back to the code which was executed before the interrupt.

Well I'd trace that in a debugger - explore the stack frame on entry/exit to the ISR and just step it as it does the RETI but I'd also look to make sure the stack is set up correctly and in the right place (if you write C the CRT on the front of the bootloader code should be handling this for you).

I have to use a delay and isnt that also use a timer?

I'm just talking about some kind of countdown as you keep checking UART_STATUS_REG though I guess you could include a soft loop to do a delay within each iteration. But my point is this kind of "delay" does not involve timer hardware or that generating interrupts.

 

At the end of the day a bootloader is very simple - it sits listening to some comms then acts on what arrives and SPM's it - it is the only piece of software in the device that must be totally robust and 100% bug free (everything else can be replaced by the bootloader). Adding interrupts (and hence complexity) jeopardizes the likelihood of it being 100% bug free.

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

Okay, I've inserted a counter combined with a ms_delay in my rec_char() and it works great.

 

But I will have a look at the stack while debugging anyway...

 

thanks a lot for your advice

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

You can still use the timer and not use interrupts - just poll the interrupt flag.