Interrupts cause reset in bootloader program while IVSEL is enabled

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

I'm trying to write a custom bootloader that uses UART to communicate with PC. I want to add a timeout to USART_ReceiveByte(); So I used timer 1 and interrupts.

The program works OK when it is in the application section (0x0000).

But when I put it in the bootloader section (0x1c00)(ATMega16A) and add "GICR = (1<<IVCE);GICR = (1<<IVSEL);", the program starts from the main each time the timer overflows.

It doesn't reach the "asm("JMP 0x0000");" and even doesn't pass the "while ( (!(UCSRA &(1<<RXC))) && (timer1_OFC <= TO) );" line (remains on this line until the overflow and then goes straight to the main). It even doesn't reach "timer1_OFC++; ".Found these while debugging (Simulator).

Here is my code:

#define F_CPU 8000000UL  //8 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define USART_BAUDRATE 38400
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
volatile unsigned int timer1_OFC;

void USART_Init(void);
void USART_Shutdown(void);
void USART_SendByte(uint8_t Data);
uint8_t USART_ReceiveByte(float TimeOut);

int main(void)
{
    UBRRL = BAUD_PRESCALE;
    UBRRH = (BAUD_PRESCALE >> 8);
    
    uint8_t sreg = SREG;
    cli();
    GICR = (1<<IVCE);
    GICR = (1<<IVSEL);
    USART_Init();
    
    DDRC = 0b00100000;
    PORTC = ~PORTC;
    _delay_ms(2000);
    PORTC = ~PORTC;
    _delay_ms(500);
    
    
    PORTC = ~PORTC;
    USART_SendByte('>');
    USART_SendByte(SIGNATURE_0);
    USART_SendByte(SIGNATURE_1);
    USART_SendByte(SIGNATURE_2);
    _delay_ms(500);
    PORTC = ~PORTC;
    
    if (USART_ReceiveByte(200) != '<')
    {
        asm("JMP 0x0000");
    }
    //continue...
}


void Timer1_Init(void)
{
    TCCR1B = (1<<CS10);
    TCNT1 = 0;
    TIMSK = (1<<TOIE1);
    sei();
    timer1_OFC = 0;
}

void Timer1_shutdown(void)
{
    TCCR1B = 0;
    TCNT1 = 0;
    TIMSK = 0;
    timer1_OFC = 0;
    cli();
}

void USART_Init(void)
{
    UCSRB = ((1<<TXEN)|(1<<RXEN));
}

void USART_Shutdown(void)
{
    UCSRB = 0;
}

void USART_SendByte(uint8_t Data)
{
    while (!(UCSRA &(1<<UDRE)));
    UDR = Data;
}

uint8_t USART_ReceiveByte(float TimeOut)
{
    Timer1_Init();
    unsigned int TO = TimeOut/4.096;
    if (TimeOut > 0)
    {
    while ( (!(UCSRA &(1<<RXC))) && (timer1_OFC <= TO) );
    } 
    else
    {
        while ( !(UCSRA &(1<<RXC)) );
    }
    Timer1_shutdown();
    if (UCSRA &(1<<RXC))
    {
        return UDR;
    }
    else
    {
        return 0;
    }
}

ISR(TIMER1_OVF_vect)
{
    timer1_OFC++;
}

Why this happens? I changed the interrupt vectors but seems that the program still goes to the application section each time the overflow happens.

This topic has a solution.
Last Edited: Tue. Sep 17, 2019 - 06:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interrupts in a bootloader? Recipe for disaster!

 

But anyway what does "\\continue..." actually look like?

 

 

Also the ATmega16a is a 16K chip which means it's last flash address is 0x3FFF so I wonder about

pajuhesh80 wrote:
in the bootloader section (0x1c00)

I guess you really mean 0x3800. So are you using some system that takes 0x1C00 and doubles it to make -Ttext=0x3800 or --section-start=.text=0x3800 or have you accidentally used 0x1C00 (in which case you IVT is in completely the wrong place).

 

Oh, and of course, IVSEL just puts the IVT at the BOOTSZ location anyway so is BOOTSZ set correctly (to pick the 1C00/3800 option) as well?

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

Thanks for replay.

"Recipe for disaster!", So what should I do for that timeout?

"//continue" looks like nothing! I'll write code there later.

To locate the code in bootloader section, I wrote "-Wl,-section-start=.text=0x1c00" in "project properties>toolchain>AVR/GNU Linker>Miscellaneous>Other linker flags". Wrong? Should I change 0x1c00 to 0x3800?

fuses: BOOTRST enabled, BOOTSZ = 1024 words start address=$1c00

Note: The problem exists on both simulator and real hardware.

Something strange: Each time I program the simulator fuses in device programming, when I go there again, fuses are reset.

 
Last Edited: Tue. Sep 17, 2019 - 04:02 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pajuhesh80 wrote:
"Recipe for disaster!", So what should I do for that timeout?
soft delays.
pajuhesh80 wrote:
I wrote "-Wl,-section-start=.text=0x1c00"
which is wrong. The GNU tools use BYTE not WORD addressing. Rather confusingly Atmel treat flash as if it has a 16 bit granularity so they, on the other hand, talk about everything in terms of words. So when they say 0x1C00 they mean WORD address 0x1C00 which is BYTE address 0x3800. So when you told the GNU tools to place .text at 0x1C00 you only managed in getting the code a little under half way up the chip.

 

Almost more confusing is that in AS7 they have a section called memories in which you can type things like ".text=0x1C00" and they actually double that and pass it to the GNU tools as 0x3800. But as you put this in "Other linker flags" you need to put the GNu value there so it's definitely 3800.

 

(always assuming, as I said above, that BOOTSZ is set to the 1C00/3800 value!)

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

Thanks! Changed 0x1c00 to 0x3800 and the main problem seems to be fixed! Just two questions:
1- In the memories section I can add new sections like .text but it doesn't give me an option to set its address; just name. How should I set address for sectiins in memory section?
2- As you can see in my code, I used the timer to count the time while checking the RXC parallel (which happens sooner). If soft delay means _delay_ms or _delay_us, as I know I can't run anything else while running them. One way is this:

for(int i<0; i {
_delay_ms(1);
if(UCSRA&(1<<RXC))
{
break;
}
}

But it's not accurate. Which is should I select? "Recipe for disaster" or less accuracy?!

Last Edited: Tue. Sep 17, 2019 - 08:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why do you need accuracy for a UART timeout? If it's 53ms or 61ms or 67.2326ms why would it matter if you were aiming for "somewhere around the 60ms mark"?

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

You are right. So I'll use that "for" loop instead of timer.
About the first question: in
Toolchain>AVR/GNU Linker>Memory Settings
When I pressed Add item in FLASH Segment, Add FLASH Segment dialog with just one text box appeared. I wrote ".text = 0x1c00" and it worked.

Last Edited: Tue. Sep 17, 2019 - 08:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup because Atmel do a x2 on whatever  number you put there (but only for "flash" )