Go Down

Topic: New optiboot; beta testers welcome... (Read 182977 times) previous topic - next topic


Jun 13, 2012, 01:58 pm Last Edit: Jun 13, 2012, 02:08 pm by ChrisS Reason: 1
Dear Pro's,

to get rid of all that external issues with getting the basement work....IDE a.s.o.

would you please add an AVR Studio .elf Production Bundle... for testing also please.
(very easy for somebody who knows the settings)

So, the Betatesting of the Optiboot would be more comfortable... because we have to test the bootloader, not the ide config :)

Maybe, a Noob Dif .zip ala "extract this to the Arduino Rootfolder " would be helpfull as already mentioned...

Please add an verified .elf ...

Thank you very much!!!


(Would be great, in my case got an HV Programmer here, which i can't get work with Arduino Bootloader burning via IDE.
No Info on some Parameters like BOOTSZ, ... can't find LD_Section... )


Jul 08, 2012, 07:18 pm Last Edit: Jul 09, 2012, 07:59 am by ardnut Reason: 1
I was aiming at setting up a parallel port to program a atmega8535 using avrdude.

Could that be integrated in this setup?

Has optiboot been tested on that chip?



Neither the Arduino environment nor optiboot currently support the 8535.


Is that a complicated porting project or just a case of digging the doc and setting up a few parameters?

Is there a guide to adapting optiboot to other chips in the family?



It shouldn't be too complicated if the chip has the usual features.  8535 is pretty old.
There's no guide, but it's not very much code.   Getting the fuses and code addresses and such right is probably harder than the code modifications.


Apologies first, if this doesn't belong here.

I have started a separate thread on my issues trying to get optiboot run on Attiny84. http://arduino.cc/forum/index.php?topic=108989.0
I have come to a dead end, although Luminet (Attiny84 based) is said to work, I couldn't get results. If someone has walked that path, please advice on any tricks that need to be pulled down the sleeve.


Tom Carpenter

Aug 04, 2012, 08:11 pm Last Edit: Aug 04, 2012, 10:08 pm by Tom Carpenter Reason: 1
I have found a bug in Optiboots software UART.
Basically, when compiled the inline assembler for getch() does something rather weird. Both the recieved char (what is returned to the variable ch) and the bit count (how many bits to recieve) both end up using the same register which means it doesn't correctly recieve chars, and in some cases it gets stuck in an infinite loop.

Here is my solution:
Code: [Select]

#ifdef SOFT_UART
 __asm__ __volatile__ (
   "1: sbic  %[uartPin],%[uartBit]\n"  // Wait for start edge
   "   rjmp  1b\n"
   "   rcall uartDelay\n"          // Get to middle of start bit
   "2: rcall uartDelay\n"              // Wait 1 bit period
   "   rcall uartDelay\n"              // Wait 1 bit period
   "   clc\n"
   "   sbic  %[uartPin],%[uartBit]\n"
   "   sec\n"                          
   "   dec   %[bitCnt]\n"
   "   breq  3f\n"
   "   ror   %[ch]\n"
   "   rjmp  2b\n"
     [ch] "=r" (ch)
     "d" (0),
     [bitCnt] "d" (9),
     [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
     [uartBit] "I" (UART_RX_BIT)

Also, the TX pin should idle high, but it does not get set as such when it is set to being an output. The fix:
Code: [Select]
#ifdef SOFT_UART
  /* Set TX pin as output */
  UART_PORT |= _BV(UART_TX_BIT); //set high!


I have found a bug in Optiboots software UART.

Thanks Tom!
Based on your hints I've just added support for ATtiny85 to optiboot.
As there is no hardware bootloader in ATtiny85, the code exceeds 512 bytes due to virtual boot partition implementation.
Bootloader seems to work well even with the factory calibrated RC oscillator. Still, one might need to adjust the OSCCAL register when the communication speed error exceeds some limits. 


Tom Carpenter

I have a working version of optiboot as well for both tiny85's and tiny84's. As you say it does require the oscillator to be tuned, so I am currently working on including tinyTuner in the bootloader when you first burn it which will then callibrate the oscillator and store the calibrated value in program memory and apply it each time it loads.

My version of optiboot for the tiny's is 576 bytes, which is a bit smaller than the stock version as I made several other enhancements to make optiboot smaller - using unions in some places for example.

Once I have got the TinyTuner code added (it wont increase the size of the bootloader as it will be overwritten when you download the first sketch) I will release my bootloader, along with a partly rewritten Tiny core I am working on.

Coding Badly

Just so you know, the OSCCAL value is not like the fuses; it is not sticky.  The value is always set to the factory default on reset.  You will have to store the value in EEPROM or Flash and then, ideally, transfer it to OSCCAL at the start of the bootloader.

In my case, I store the tuned value at the end of EEPROM (E2END) with some other configuration data and bracketed by guard bytes.

Tom Carpenter

Sep 23, 2012, 11:26 pm Last Edit: Oct 19, 2012, 10:36 pm by Tom Carpenter Reason: 1
I have almost completed a bootloader which when you burn it includes TinyTuner. At the end of tinyTuner running, it saves the tuned value into the program memory as part of the bootloader, along with another byte which tells the bootloader to not run the tuning process again. Once tuned, the bootloader is unlocked and the tuning code is erased. From then on in, the OSCCAL value is set from the value stored in program memory.
I have got everything working apart from after the first program is downloaded using the bootloader it nothing works anymore and I haven't yet figured out why.
I know why it doesn't work, I am just trying to figure out how to make the compiler put a function in a specific place.
Got it working! I now have a self rewriting bootloader which has tiny tuner build in, but takes up no more space than it did before.


The bootloader can overwrite itself?!

Coding Badly

On ATtiny processors, yes.  The lock-bits are very limited.

Tom Carpenter

Oct 20, 2012, 10:58 am Last Edit: Oct 20, 2012, 11:08 am by Tom Carpenter Reason: 1
Yeah, it works as long as you don't try and overwrite code that is currently being executed (causes a crash) - provided that you write all data on a page. Also, if you need to set bits from 0 to 1 in a byte, you have to back up all flash that is on that page, erase the whole page, and then rewrite in all but the byte you wanted to change bit in. Fortunately is a byte is 0xFF to begin with, it is easy to write to by simply writing that byte to what you want, and all others on the page to 0xFF (leaves them unchanged as it can't program from 0 to 1).
This is what I came up with the make it work:
Code: [Select]

//In optiboot.c
const unsigned char ver[4] __attribute__ ((section (".version"))) = {0xFF, 0xFF, OPTIBOOT_MINVER, OPTIBOOT_MAJVER};

typedef union {
   uint16_t integer;
   uint8_t array[2];

void tinyTuner() __attribute__ ((naked)) __attribute__ ((noreturn));

//At the end of tinyTuner().

 uint16_t addrPtr;  
 //For this code we are assuming that the cleared value of each byte in the temporary page buffer is 0xFF
 //This is important as we have to write a page at a time which means that we will be overwriting bytes we
 //don't want to change - by using 0xFF this isn't an issue as programming can only convert a bit from a 1
 //to a 0 (otherwise it needs to erase which is not being done here). So if say you had 0b00100101, and reprogrammed
 //it with 0b11111111, the result would be 0b00100101 as none on the 0's can be turned into 1's.
 addrPtr = (uint16_t)(void*)ver; //get the pointer to the ver array in the flash memory.
 SPMCSR = CTPB; //clear the temporary page buffer - this sets all bytes to 0xFF so as not to change any bytes we don't want to
 twoByte oscProg;
 oscProg.array[1] = OSCCAL; //store the new OSCCAL value in the program memory so it can be restored by the bootloader at startup.
 oscProg.array[0] = (uint8_t)0x00; //tells the bootloader not to call tinyTuner again (good as it will be overwritten by bootloader later.
 __boot_page_fill_short((uint16_t)(void*)addrPtr,oscProg.integer); //store the two oscProg bytes to the temporary buffer
 __boot_page_write_short((uint16_t)(void*)addrPtr); //program the whole page. Any byte where temp=0xFF will remain as they were.
 boot_spm_busy_wait(); //wait for completion
 putstr_t(PSTR("Removing call to TinyTuner to reduce bootloader size by 2.3kbytes\r\n"));
 addrPtr = (uint16_t)(void*)bootloader; //get the page on which to bootloader starts;
 addrPtr += 0x0A; //move to the correct place in the bootloader (where the RCALL to tinyTuner() is)
 SPMCSR = CTPB; //clear the temporary page buffer - this sets all bytes to 0xFF so as not to change any bytes we don't want to
 __boot_page_fill_short((uint16_t)(void*)addrPtr,(uint16_t)0x00); //write a NOP instruction to prevent calling tinyTuner when it doesn't exist anymore.
 __boot_page_write_short((uint16_t)(void*)addrPtr); //program the whole page. Any byte where temp=0xFF will remain as they were.
 boot_spm_busy_wait(); //wait for completion
  putstr_t(PSTR("Calibration saved and TinyTuner Deleted\r\n"));
  putstr_t(PSTR("\r\n\r\nEnabling Bootloader and Rebooting\r\n\r\n"));

 __asm__ __volatile__ (
   // Jump to WDT vector
   "ldi r30,4\n"
   "clr r31\n"
   // Jump to RST vector
   "clr r30\n"
   "clr r31\n"
 while(1); //to shut the compiler up - really the code doesn't return.

Coding Badly

You really don't need the flag.  If everything is working correctly 0xFF will never be the tuned value (along with 0x00, 0x7F, and 0x80).

Go Up