Arduino code not start after boot-loader updae

HI

i use my own bootloader ,but i notice that when use arduino code
the code not run as long i not cycle power to the board , i knot it jump to application code
but not seem to run

have check for make sure IVSEL = 0 but still clue less

also have try to use watchdog but still need to cycle power for make it run ???

this is the interesting part of my code …

so reset vector jump to boot ,if MCUSR was clear we stay in boot

if MCUSR have some bit set (reset ,watchdog ,power ) we check if the flash checksum match
if match go to application ,if not we stay in boot and wait for encrypted hex file via RTU modbus …

any idea ??? ( that boot work whit other code that arduino )

.org 0x3e00    ;BSTART

RESET:

    wdr   
	
;	INITIALIZE Stack Pointer		
    ldi		temp,low(RAMEND)
    out		SPL,temp		
    ldi		temp,high(RAMEND)
    out		SPH,temp

	ldi		temp, 0xff
	out     DDRD,temp 
  	sbi     PORTD ,2  ; flag pin for know we are in boot (only for debog)

	cli 

	ldi		temp, (1<<RXEN0)|(1<<TXEN0)     ;  enable the reciever and the ransmitter
	sts		UCSR0B, temp

	ldi		temp, BAUDDIVH               ;  baudrate 
	sts		UBRR0H, temp
	ldi		temp, BAUDDIVL
	sts		UBRR0L, temp

    ldi     temp,0b00000000    ; ALL timer stoped
    out     tccr0A,temp

	clr     r10             ; used for end of file detected

    sbi     DDRC_485,DIR_485
	cbi     PORT_485,DIR_485

    ser     temp
    mov	    RC4_KEYINITD,temp		; set RC-4 as un-initialized

    in      temp,MCUSR      ; if aplication call bootloader syat in boot ..
    tst     temp
	breq    BOOTLOADER      ; if reset source is clear stay in boot

	rcall   Flash_Check_SUM	; Test Checksum If Bad Go Bootloader

	clr     R17	            ; Good Checksum so jump to aplication        	
	out     MCUSR,r17       ;clear the reset source

    cbi     ddrb,1
    sbi     portB,1
	nop
    sbic    pinB,1          ; if MOSI pin is low  stay in boot 

    jmp	    0x0000


BOOTLOADER:
 
    mov      HEX_type,r10
    cpi	     HEX_type,$21		   ; got last line of new to flash
    brne	 GET_RTU_Frame         ; no so stay in boot for next line

    jmp	     0x0000                ; yes so go in application


     
;----------------------------------------------------------------------------;
  
Flash_Check_SUM:

	clr     ZH
	clr     ZL 
	clr		XH
	clr     XL

FCK_1:
    wdr
	lpm     R1,z+
	add     XL,R1
	brcc    FCK_2
	inc     XH       ;carry set so inc Hi Bit

FCK_2:
	cpi     ZH,HIGH(BSTART*2 -16)
	brne    FCK_1
	cpi     ZL,LOW(BSTART*2 -16)
    brne    FCK_1

	lpm     R0,Z+
    lpm     R1,Z
    cp      R0,XH
    brne    CK_Fail
	cp      R1,XL
    brne    CK_Fail
	ret

CK_Fail:

	sbi     PORTD ,3  ; check sum fail

    rjmp	BOOTLOADER  ;Flash is Corup go self update .....

I guess you don't want to show to much of your code. Perhaps you can ask questions around how optiboot is implemented to see how to do your own code.

This shows the helper files for optiboot, that do the low level stuff like writing to flash.

https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/boot.h

While this has the main()

https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot.c

I am guessing that the jump to application coded is in the second one, but I don't see it right away so if you can point it out that would be cool, I am sort of hoping WestfW can find time to explain it.

I may be wrong but my understanding is that we can only write to flash from an instruction run within the bootloader section. And in the case of optiboot it runs first and once it passes execution to the application there is no reliable way to pass execution back to the bootloader (e.g. xboot, optiboot, otherboot).

void appStart(uint8_t rstFlags) {
  // save the reset flags in the designated register
  //  This can be saved in a main program by putting code in .init0 (which
  //  executes before normal c init code) to save R2 to a global variable.
  __asm__ __volatile__ ("mov r2, %0\n" :: "r" (rstFlags));

  watchdogConfig(WATCHDOG_OFF);
  // Note that appstart_vec is defined so that this works with either
  // real or virtual boot partitions.
  __asm__ __volatile__ (
    // Jump to 'save' or RST vector
    "ldi r30,%[rstvec]\n"
    "clr r31\n"
    "ijmp\n"::[rstvec] "M"(appstart_vec)
  );
}

That's how optiboot does it.

When I was doing some work with custom bootloaders last year, I remember having some trouble making the user code start correctly by jumping to the reset vector. I don't know exactly why, and I forget how I solved it.

i know it jump to application code but not seem to run

How do you know it jumps to the application code, and what does "does not seem to run" mean, exactly? What does it do instead? It's a bare-metal chip; it HAS to be running something...

Arduino sketches have no dependencies on the bootloader, so it shouldn't be anything IN the sketch causing problems.

Debugging mysterious bootloader problems without a real debugger is tough. Invest in an Atmel ATmega328p Xplained Mini...

HI

i actually debug it whit debug-wire on a avr dragon

put break point on "jmp 0x0000" , then i see i execute code on application section ,but hard to tell since that code was out of the boot .elf ,the avrdragon was not like a real ICE ...

but i knot that my application not run as expected ,no neopixel ,no modbus noting seen to work

and none of my debog flag tell me i was in the boot

so i try to keep copy MCUSR in R2 as optiboot do , but no luck

the adafruit bootloader seem to use

void (*app_start)(void) = 0x0000; so it like the jmp 0x0000 ?

my next try was try to make clr r30,r30 and ijmp

thank

Hi DrAzzy

i assume your boot last year was probably in relation whit GF200 ?

i the Martin hardware guy ;-)

so i try the ijmp and both do same ,it boot to application but code actually not seem to do anything

Does it work with a simpler sketch (blink.ino, perhaps)?

AS is a bit annoying to use if your binary does not match what it thinks is there, but it should be possible. If all else fails, you should be able merge the .hex files of bootloader and hex, and use the "open object file for debugging" option.

Do you use any interrupts in your bootloader? One possibility is that some interrupt is left enabled when the application starts. "default" ISRs are infinite loops with avr-gcc.

HI

i not use interrupt in boot

and the blinks example not run until i manually reset board or power cycle

i have no problem if it load assembler code

HI all

i finally catch it !!!!!

by disassemble the blink code i notice that Arduino code only do bit wise operation on TCCR0B in init

so a presaler or CLK/64 in Boot turn into a external clock in Arduino code

so millis() function go dead whit the remain of the code !!!

#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
 // this combination is for the standard 168/328/1280/2560
 sbi(TCCR0B, CS01);
 26e: 85 b5       in r24, 0x25 ; 37
 270: 82 60       ori r24, 0x02 ; 2
 272: 85 bd       out 0x25, r24 ; 37
 sbi(TCCR0B, CS00);
 274: 85 b5       in r24, 0x25 ; 37
 276: 81 60       ori r24, 0x01 ; 1
 278: 85 bd       out 0x25, r24 ; 37

so FIX was clear the TCCR0B before leave the bootlaoder ;-)

do bit wise operation in ini was quite dangerous thing ....

Heh - yup, it was the GF200 work I was talking about.

I'd just realized the potential for issues with the timer registers and came over to mention that but you've beaten me to it.

It's really reckless of the official core to do only bitwise operations - I don't think the official core developers have much concern for non-standard bootloaders. That said, it's best for the bootloader to clean up after itself, rather than have to do that in the application code.

Trying to follow… you are talking about when the timer is initialized by the Wiring core file, e.g. something like this.

 // set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
 // CPU specific: different values for the ATmega128
 TCCR0 |= (1<<CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
 // this combination is for the standard atmega8
 TCCR0 |= (1<<CS01);
 TCCR0 |= (1<<CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
 // this combination is for the standard 168/328/1280/2560
 TCCR0B |= (1<<CS01);
 TCCR0B |= (1<<CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
 // this combination is for the __AVR_ATmega645__ series
 TCCR0A |= (1<<CS01);
 TCCR0A |= (1<<CS00);
#else
 #error Timer 0 prescale factor 64 not set correctly
#endif

https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring.c#L255

If I understand correctly [that is doubtful] the problem happens when CS00 is set before CS01. Or something more complex with CS02 and an external pin.

ClockSelectBit.PNG

No, it's if the bootloader (he's not using the stock bootloader) doesn't clean up after itself, and jumps to the application leaving TCCR0B in something other than the normal startup state.

Now, instead of starting from TCCR0B = 0 it starts with TCCR0B set to some other value, and after performing the bit set/clear operations doesn't yield a working timer for millis.