Bootloader for dsPic33F

In order to unify our development tools, we decided to use a bootloader through Serial communication. This bootloader is mainly used to load our program into microcontroller. Also the bootloader can be use to read and dump the memory of the microcontroller.

How does it work?

The bootloader is composed of a small piece of program loaded into the microcontroller and an application hosted by PC (or Mac). This host application is actually an Eclipse plug-in (you know how much we do love Eclipse :-)). The plug-in parses the hex file and send it page by page through RS232 to the target.

Memory Usage

First of all, a short introduction of the dsPic33F memory organization is necessary. The flash memory device is divided in Pages. Each page is 512 instructions wide. Before writing an instruction into memory, it must be erased. The device erases, either by mass erasing, or by erasing individual page (512 instructions). The dsPic33f microcontroller has a 24 bits instruction set, so each page has a size of 1536 bytes. Microchip proposes the following architecture:

They place the bootloader at the beginning of program memory area. Because the first page is also used to store the Interrupt Vector Table, they store the bootloader on the second page and some memory space (a half page) is lost on the first page. To avoid this memory loss, we decided to load the bootloader at the end of the flash memory.

Configuration bits

For security reason, we decided to set the configuration bits with the bootloader program. Configuration register won't be overridden by the user application programming to avoid unpredictable behavior of the bootloader. Bootloader configuration bits need to be generic enough to allow all the needed device configurations.

Setting up the bootloader

Link Script modification

By default, Microchip provides GLD linker script for each devices. These linker scripts contain addresses of the different sections of the code. By editing it, we can select the location of our code into the flash memory. So we modified it to place the bootloader into the two last pages of the memory, and the program that we want to load from the first available address (0x200) to the end of the memory minus the two last pages reserved for the bootloader. The modification concerns the memory description section. This example has been done for dsPic33F128MC80x (128K memory)

/*
** Memory Regions
*/
MEMORY
{
  data  (a!xr) : ORIGIN = 0x800,         LENGTH = 0x4000
  reset        : ORIGIN = 0x0,           LENGTH = 0x4
  ivt          : ORIGIN = 0x4,           LENGTH = 0xFC
  aivt         : ORIGIN = 0x104,         LENGTH = 0xFC
  program (xr) : ORIGIN = 0x15000,       LENGTH = 0x800		/* Last address for 128K memory is 0x15800 and bootloader
                                                                  * needs 2 pages so 0x15800 - 0x800 = 0x15000*/
  FBS          : ORIGIN = 0xF80000,      LENGTH = 0x2
  FSS          : ORIGIN = 0xF80002,      LENGTH = 0x2
  FGS          : ORIGIN = 0xF80004,      LENGTH = 0x2
  FOSCSEL      : ORIGIN = 0xF80006,      LENGTH = 0x2
  FOSC         : ORIGIN = 0xF80008,      LENGTH = 0x2
  FWDT         : ORIGIN = 0xF8000A,      LENGTH = 0x2
  FPOR         : ORIGIN = 0xF8000C,      LENGTH = 0x2
  FICD         : ORIGIN = 0xF8000E,      LENGTH = 0x2
  FUID0        : ORIGIN = 0xF80010,      LENGTH = 0x2
  FUID1        : ORIGIN = 0xF80012,      LENGTH = 0x2
  FUID2        : ORIGIN = 0xF80014,      LENGTH = 0x2
  FUID3        : ORIGIN = 0xF80016,      LENGTH = 0x2
}

__FBS = 0xF80000;
__FSS = 0xF80002;
__FGS = 0xF80004;
__FOSCSEL = 0xF80006;
__FOSC = 0xF80008;
__FWDT = 0xF8000A;
__FPOR = 0xF8000C;
__FICD = 0xF8000E;
__FUID0 = 0xF80010;
__FUID1 = 0xF80012;
__FUID2 = 0xF80014;
__FUID3 = 0xF80016;

__IVT_BASE  = 0x4;
__AIVT_BASE = 0x104;
__DATA_BASE = 0x800;
__YDATA_BASE = 0x2800;
__DMA_BASE = 0x4000;
__DMA_END = 0x47FF;
__CODE_BASE = 0x15000;

First modification is this line

program (xr) : ORIGIN = 0x15000,       LENGTH = 0x800

Second modification is this line:

__CODE_BASE = 0x15000;

Now you should have a link script ready. Let's now adapt the code to your hardware platform

Code modification

The code is organize as below.

  • gld-bootloader -> Contains the GLD script modified for the bootloader
  • gld-program -> Contains the GLD script for the software we want to load (we'll use it later)
  • inc -> Include folder with the config.h file that allow you to tune the display LED for bootloading status, the baudrate and the Frequency
    #define FCY   40000000					/**< CPU frequency */
    #define LED		LATBbits.LATB8		/**< IO driving LED */
    #define BAUDRATE        115200				/**< UART BAUDRATE */
    
  • src -> C-file and ASM code. It's in main.c you have to set the uart you want to use and your port mapping. Here is an example with UART1
    TRISB = 0x0E24;
    TRISC = 0x0208;
    
    PPSUnLock; // Unlock registers
    
    /*Inputs*/
    RPINR18bits.U1RXR = 9; //uart1
    /*Outputs*/
    RPOR11bits.RP22R = 3; //uart1
    
    PPSLock; // Lock registers
    
    U1MODE = 0x8000; /* Reset UART to 8-n-1, alt pins, and enable */
    
    U1BRG = BRGVAL;
    
    U1STA  = 0x0400; /* Reset status register and enable TX */
    
    

Now you can compile and program the bootloader with PicKit? or ICD, etc.

Linking step of the software

As explained before, we use the last pages of memory for the bootloader. So the application must not be written on those pages. To be sure, we'll modify the GLD script of your application to decrease the space for the code.

/*
** Memory Regions
*/
MEMORY
{
  data  (a!xr) : ORIGIN = 0x800,         LENGTH = 0x4000
  reset        : ORIGIN = 0x0,           LENGTH = 0x4
  ivt          : ORIGIN = 0x4,           LENGTH = 0xFC
  aivt         : ORIGIN = 0x104,         LENGTH = 0xFC
  program (xr) : ORIGIN = 0x200,         LENGTH = 0x14E00	/* Start after aivt so 0x200, memory size is
  															 * 0x15800 - 0x200 - 0x800 (bootloader) = 0x14E00 */
  FBS          : ORIGIN = 0xF80000,      LENGTH = 0x2
  FSS          : ORIGIN = 0xF80002,      LENGTH = 0x2
  FGS          : ORIGIN = 0xF80004,      LENGTH = 0x2
  FOSCSEL      : ORIGIN = 0xF80006,      LENGTH = 0x2
  FOSC         : ORIGIN = 0xF80008,      LENGTH = 0x2
  FWDT         : ORIGIN = 0xF8000A,      LENGTH = 0x2
  FPOR         : ORIGIN = 0xF8000C,      LENGTH = 0x2
  FICD         : ORIGIN = 0xF8000E,      LENGTH = 0x2
  FUID0        : ORIGIN = 0xF80010,      LENGTH = 0x2
  FUID1        : ORIGIN = 0xF80012,      LENGTH = 0x2
  FUID2        : ORIGIN = 0xF80014,      LENGTH = 0x2
  FUID3        : ORIGIN = 0xF80016,      LENGTH = 0x2
}

__FBS = 0xF80000;
__FSS = 0xF80002;
__FGS = 0xF80004;
__FOSCSEL = 0xF80006;
__FOSC = 0xF80008;
__FWDT = 0xF8000A;
__FPOR = 0xF8000C;
__FICD = 0xF8000E;
__FUID0 = 0xF80010;
__FUID1 = 0xF80012;
__FUID2 = 0xF80014;
__FUID3 = 0xF80016;

__IVT_BASE  = 0x4;
__AIVT_BASE = 0x104;
__DATA_BASE = 0x800;
__YDATA_BASE = 0x2800;
__DMA_BASE = 0x4000;
__DMA_END = 0x47FF;
__CODE_BASE = 0x200;

First modification is this line

program (xr) : ORIGIN = 0x200,         LENGTH = 0x14E00

Second modification is this line (if you started with the original file from Microchip, this line should be OK):

__CODE_BASE = 0x200;

Now you can compile your application. It's ready to load with the bootloader. To simplify the process, we provide the GLD file modified in the bootloader folder : gld-program

Let's program the software!

To send the program, we have developed an Eclipse plug-in. You just have to install through software update system of Eclipse from your favorite site (http://www.yumantech.org/update if you have forgotten). After restarting eclipse, you can display the contextual menu by right clicking on the project your want to program.

  • Go to YumanTech? > Program Target Device

  • Select the .hex file and the serial communication device and click OK.

Programming is in progress... Once it's finished the bootloader start the application. The video is an example of programming through bootloader

Attachments