Difference between pages "ARDUINO MEGA Update Bootloader" and "Recursion"

From ROBOTC API Guide
(Difference between pages)
Jump to: navigation, search
(Software Needed)
 
 
Line 1: Line 1:
'''Note: This document only applies to the MEGA 2560 and MEGA ADK Arduino Boards. All other Arduino boards bootloaders are good!'''
+
<yambe:breadcrumb self="Recursion">General|General Programming</yambe:breadcrumb>
 +
<br />
  
== Arduino 2560 Bootloader Issue ==
+
{{tl|1|1}}
The current bootloader burned onto the Arduino MEGA 2560/ADK is not compatible with ROBOTC. In its current form, you will be able to download the ROBOTC Firmware to the Arduino MEGA 2560/ADK, but you will not able to download any user programs.
+
<br />
  
The reason for this is because there is a bug in the Arduino MEGA 2560/ADK firmware that does not allow flash write commands to start at anywhere but the beginning of flash memory (0x000000). See the bottom of this page for more technical details.
+
== Recursion ==
 +
{| class="wikiText"
 +
|-
 +
| Recursion is the ability for a function to call itself. Normally for a function to be called it must be created and then called from task main. However, with recursion a function can call itself multiple times; the downside of this is that until a function reaches its end brace '}' or reaches a 'return' command, it will stay in memory. This can lead to situations where the available memory fills up with too many concurrently running functions and causes a crash. Recursion in ROBOTC works on a "Last In First Out" (LIFO) process; the most recent function called will be the first one closed when a return command or an end brace '}' is reached.
 +
<br />
 +
|-
 +
|For example, see the program below. First, a function called 'looping' is created and initialized. Inside of it there is a single 'return' command, which exits the function and 'returns' the program flow back to where the function was originally called from.  Next, there is task main with a single call to the function 'looping'.
 +
|-
 +
|[[File:Recursion_Return.png]]
 +
<br />
 +
|-
 +
|When the program runs, the function 'looping' is created and the program starts at task main. The first command in task main is to call the function 'looping'. The Call Stack debugger window shows both task main and the function 'looping' being in memory at this point.
 +
|-
 +
|[[File:Recursion_Return_Two.png]]
 +
<br />
 +
|-
 +
|After 'looping' is called, its first command is to return to task main. This ends the function and clears it from memory (since the function has been exited, this can be seen in the Call Stack debugger window).
 +
|}
 +
<br />
 +
== Memory Overload ==
 +
{|
 +
|One of the major issues that can arise when utilizing recursion is memory overload. This occurs when the onboard memory of a computer system or microprocessor is filled beyond maximum, or 'overloaded'.
 +
|-
 +
|In the next example, we have simply placed a recursive call in 'looping' back to itself before the 'return' command. Now, each time 'looping' is called it reaches the recursive command first and opens up another copy of the function in memory. Since the program flow is directed to the new calling of the function before the return command or a closing brace is reached, each function remains open in memory.
 +
|-
 +
|[[File:Recursion_Overload.png]]
 +
<br />
 +
|-
 +
|This eventually overloads the memory and causes a crash.
 +
|-
 +
|[[File:Recursion_Error.png]]
 +
<br />
 +
|-
 +
|}
  
Because ROBOTC is not able to burn a new bootloader as of today, you will need to use the Arduino's Open Source language with our a modified bootloader file to re-burn your bootloader on your Arduino MEGA 2560/ADK boards. '''The enhanced bootloader is backwards compatible with the original one.  That means you'll still be able to program it through the Arduino programming environment as before, in addition to ROBOTC for Arduino.'''
+
== Controlled Recursion ==
 +
{| style="color:black;" width="100%" cellpadding="5%" cellspacing="0" border="0"
 +
|-
 +
|To use function recursion without running into a memory overload issue, the function must be set up to exit at some point. This can be done a variety of ways.
 +
|-
 +
|One such possibility is to set up a simple if-else statement that checks a condition and 'returns' if one of the conditions are met. In the example below, the if-else statement checks to see if the integer variable x (which starts with a value of 0) is less than 5. If it is, x is incremented by one and the function calls itself again. This process repeats until x is no longer less than 5 (the else statement), at which point the function ends and program flow returns to where the function was originally called from.
 +
|-
 +
|[[File:Recursion_If_Else.png]]
 +
<br />
 +
|-
 +
|A variant of this program that also works is to utilize parameters. By creating 'looping' with the integer x as its parameter, we can pass a value of 0 from task main and increment the value of x when it is passed to a new copy of looping every time recursion occurs.
 +
|-
 +
|[[File:Recursion_If_Params.png]]
 +
<br />
 +
|-
 +
|}
  
== Hardware Needed  ==
+
== Ending Functions ==
To burn a new version of the Arduino bootloader to your MEGA 2560/ADK, you'll need an AVR ISP Compatible downloader.
+
{|
 
+
|-
'''Using an AVR ISP (In System Programmer)'''
+
|If the above programs are manually stepped through, there will be 5 steps to go through before task main is returned to. Remember, each time a function is called it opens another 'copy' of the function. Those extra steps are for the first, second, third, and fourth copies of the 'looping' function. The functions only clear out of memory when their end brace '}' or a return command is reached.
*Your Arduino MEGA 2560/ADK (to program)
+
|-
*An AVR Programmer such as the [http://www.sparkfun.com/products/9825 AVR Pocket Programmer]
+
|}
*An AVR Programming Cable (the pocket programmer comes with one)
+
<br />
 
+
----
+
 
+
If you have extra Arduino boards, but no ISP programmer, SparkFun.com has a cool tutorial on how to flash a bootloader using an Arduino as an ISP.
+
 
+
'''Using another Arduino as an ISP'''
+
*Your Arduino MEGA 2560/ADK (to program)
+
*A Working Arduino (doesn't matter what kind)
+
*Some Male-to-Male Jumper Cables
+
 
+
For instructions on this method, take a look at the SparkFun.com website: http://www.sparkfun.com/tutorials/247
+
 
+
== Software Needed ==
+
ROBOTC is not currently able to burn a bootloader onto an Arduino board, so you'll need to download a copy of the latest version of the Arduino Open-Source programming language.
+
*Arduino Official Programming Language - [http://arduino.cc/en/Main/Software|Arduino Download Page]
+
 
+
In addition, you'll need the ROBOTC modified bootloader. You can download that here:
+
*ROBOTC Modified MEGA 2560/ADK Bootloader - [http://cdn.robotc.net/downloads/arduino/stk500boot_v2_mega2560.hex Modified Bootloader]
+
 
+
== Bootload Download Instructions ==
+
* Download the [http://arduino.cc/en/Main/Software Arduino Open Source Software] and a copy of the [http://cdn.robotc.net/downloads/arduino/stk500boot_v2_mega2560.hex Modified Bootloader] File
+
* Copy the Modified Bootloader File into the /Arduino-1.0/hardware/arduino/bootloaders/stk500v2/ and overwrite the existing bootloader.
+
[[File:CopyBootloader.png|800px]]
+
* Power up your Arduino MEGA 2560/ADK (either via USB or external power)
+
* Plug in your AVR ISP Programmer to your computer (make sure you have any required drivers installed)
+
* Connect your AVR ISP Programmer into your Arduino MEGA 2560/ADK Board via the ISP Header (the 2x3 header pins right above the Arduino Logo)
+
* Launch the Arduino Open Source Software
+
[[File:ArduinoLaunch.png]]
+
* Change your settings in the Arduino Software to look for an Arduino MEGA 2560/ADK
+
[[File:ArduinoSelectPlatform.png]]
+
* Change your settings in the Arduino Software to select your ISP Programmer Type (Check your programmer's documentation for the exact model)
+
[[File:ArduinoSelectProgrammer.png]]
+
* Select the "Burn Bootloader" option under the "Tools" menu. The modified bootloader will now be sent to your Arduino. This typically take a minute or so.
+
[[File:BurnBootloader.png]]
+
* You should be all set to download ROBOTC firmware and start using your Arduino MEGA 2560/ADK with ROBOTC!
+
 
+
== Technical Details ==
+
The Arduino Bootloader sets the "eraseAddress" to zero every time the bootloader is called. ROBOTC called the "Load Address" command to set the address in which we want to write/verify when downloading program.
+
 
+
When writing a page of memory to the arduino, the Arduino bootloader will erase the existing page and write a whole new page.
+
 
+
In the scenario of downloading firmware, everything is great because the Erase Address and the Loaded Address both start at zero.
+
 
+
In the scenario of writing a user program, we start writing at memory location 0x7000, but the Bootloader erases information starting at location zero because the "Load Address" command doesn't update where to erase.
+
 
+
Our modification is to set both the Load Address and the Erase Address so the activity of writing a user program doesn't cause the firmware to be accidentally erased!
+
 
+
=== Original Bootloader ===
+
<syntaxhighlight lang="ROBOTC">
+
case CMD_LOAD_ADDRESS:
+
#if defined(RAMPZ)
+
  address = (((address_t)(msgBuffer[1])<<24)|((address_t)(msgBuffer[2])<<16)|
+
            ((address_t)(msgBuffer[3])<<8)|msgBuffer[4]))<<1;
+
#else
+
  address = (((msgBuffer[3])<<8)|(msgBuffer[4]))<<1;  //convert word to byte address
+
#endif
+
msgLength = 2;
+
msgBuffer[1] = STATUS_CMD_OK;
+
break;
+
 
+
case CMD_PROGRAM_FLASH_ISP:
+
case CMD_PROGRAM_EEPROM_ISP:
+
{
+
  unsigned int size = ((msgBuffer[1])<<8) | msgBuffer[2];
+
  unsigned char *p = msgBuffer+10;
+
  unsigned int data;
+
  unsigned char highByte, lowByte;
+
  address_t tempaddress = address;
+
 
+
  if ( msgBuffer[0] == CMD_PROGRAM_FLASH_ISP )
+
  {
+
    // erase only main section (bootloader protection)
+
    if (eraseAddress < APP_END )
+
    {
+
      boot_page_erase(eraseAddress); // Perform page erase
+
      boot_spm_busy_wait(); // Wait until the memory is erased.
+
      eraseAddress += SPM_PAGESIZE; // point to next page to be erase
+
    }
+
</syntaxhighlight>
+
=== ROBOTC Compatible Modification ===
+
<syntaxhighlight lang="ROBOTC">
+
case CMD_PROGRAM_FLASH_ISP:
+
case CMD_PROGRAM_EEPROM_ISP:
+
{
+
  unsigned int size = ((msgBuffer[1])<<8) | msgBuffer[2];
+
  unsigned char *p = msgBuffer+10;
+
  unsigned int data;
+
  unsigned char highByte, lowByte;
+
  address_t tempaddress = address;
+
 
+
 
+
  if ( msgBuffer[0] == CMD_PROGRAM_FLASH_ISP )
+
  {
+
    eraseAddress = address & 0xFFFFFF00;  // ROBOTC Custom Bootloader Addition
+
 
+
    // erase only main section (bootloader protection)
+
    if (eraseAddress < APP_END )
+
    {
+
      boot_page_erase(eraseAddress); // Perform page erase
+
      boot_spm_busy_wait(); // Wait until the memory is erased.
+
      eraseAddress += SPM_PAGESIZE; // point to next page to be erase
+
    }
+
</syntaxhighlight>
+

Latest revision as of 20:53, 20 March 2014

General Programming → Recursion


Color Key
Function:
Variable:


Recursion

Recursion is the ability for a function to call itself. Normally for a function to be called it must be created and then called from task main. However, with recursion a function can call itself multiple times; the downside of this is that until a function reaches its end brace '}' or reaches a 'return' command, it will stay in memory. This can lead to situations where the available memory fills up with too many concurrently running functions and causes a crash. Recursion in ROBOTC works on a "Last In First Out" (LIFO) process; the most recent function called will be the first one closed when a return command or an end brace '}' is reached.


For example, see the program below. First, a function called 'looping' is created and initialized. Inside of it there is a single 'return' command, which exits the function and 'returns' the program flow back to where the function was originally called from. Next, there is task main with a single call to the function 'looping'.
Recursion Return.png


When the program runs, the function 'looping' is created and the program starts at task main. The first command in task main is to call the function 'looping'. The Call Stack debugger window shows both task main and the function 'looping' being in memory at this point.
Recursion Return Two.png


After 'looping' is called, its first command is to return to task main. This ends the function and clears it from memory (since the function has been exited, this can be seen in the Call Stack debugger window).


Memory Overload

One of the major issues that can arise when utilizing recursion is memory overload. This occurs when the onboard memory of a computer system or microprocessor is filled beyond maximum, or 'overloaded'.
In the next example, we have simply placed a recursive call in 'looping' back to itself before the 'return' command. Now, each time 'looping' is called it reaches the recursive command first and opens up another copy of the function in memory. Since the program flow is directed to the new calling of the function before the return command or a closing brace is reached, each function remains open in memory.
Recursion Overload.png


This eventually overloads the memory and causes a crash.
Recursion Error.png


Controlled Recursion

To use function recursion without running into a memory overload issue, the function must be set up to exit at some point. This can be done a variety of ways.
One such possibility is to set up a simple if-else statement that checks a condition and 'returns' if one of the conditions are met. In the example below, the if-else statement checks to see if the integer variable x (which starts with a value of 0) is less than 5. If it is, x is incremented by one and the function calls itself again. This process repeats until x is no longer less than 5 (the else statement), at which point the function ends and program flow returns to where the function was originally called from.
Recursion If Else.png


A variant of this program that also works is to utilize parameters. By creating 'looping' with the integer x as its parameter, we can pass a value of 0 from task main and increment the value of x when it is passed to a new copy of looping every time recursion occurs.
Recursion If Params.png


Ending Functions

If the above programs are manually stepped through, there will be 5 steps to go through before task main is returned to. Remember, each time a function is called it opens another 'copy' of the function. Those extra steps are for the first, second, third, and fourth copies of the 'looping' function. The functions only clear out of memory when their end brace '}' or a return command is reached.