You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
7.8 KiB
C
260 lines
7.8 KiB
C
/*-------------------------------------------------------------------------/
|
|
/ Stand-alone MMC boot loader R0.01
|
|
/--------------------------------------------------------------------------/
|
|
/
|
|
/ Copyright (C) 2010, ChaN, all right reserved.
|
|
/
|
|
/ * This software is a free software and there is NO WARRANTY.
|
|
/ * No restriction on use. You can use, modify and redistribute it for
|
|
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
|
/ * Redistributions of source code must retain the above copyright notice.
|
|
/
|
|
/--------------------------------------------------------------------------/
|
|
/ Dec 6, 2010 R0.01 First release
|
|
/--------------------------------------------------------------------------/
|
|
/ This is a stand-alone MMC/SD boot loader for megaAVRs. It requires a 4KB
|
|
/ boot section for code, four GPIO pins for MMC/SD as shown in sch.jpg and
|
|
/ nothing else. To port the boot loader into your project, follow the
|
|
/ instruction described below.
|
|
/
|
|
/ 1. Setup the hardware. Attach a memory card socket to the any GPIO port
|
|
/ where you like. Select boot size at least 4KB for the boot loader with
|
|
/ BOOTSZ fuses and enable boot loader with BOOTRST fuse.
|
|
/
|
|
/ 2. Setup the software. Change the four port definitions in the asmfunc.S.
|
|
/ Change MCU_TARGET, BOOT_ADR and MCU_FREQ in the Makefile. The BOOT_ADR
|
|
/ is a BYTE address of boot section in the flash. Build the boot loader
|
|
/ and write it to the device with a programmer.
|
|
/
|
|
/ 3. Build the application program and output it in binary form instead of
|
|
/ hex format. Rename the file "app.bin" and put it into the memory card.
|
|
/
|
|
/ 4. Insert the card and turn the target power on. When the boot loader found
|
|
/ the application file, the file is written into the flash memory prior to
|
|
/ start the application program. On-board LED lights (if exist) during
|
|
/ the flash programming operation.
|
|
/
|
|
/-------------------------------------------------------------------------*/
|
|
|
|
const char filename[13] ="1284BOOT.BIN\0"; // EDIT FILENAME HERE
|
|
#include <avr/io.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <avr/eeprom.h>
|
|
#include <util/delay.h>
|
|
#include <string.h>
|
|
#include "pff/src/pff.h"
|
|
#include <avr/wdt.h> //Watchdog
|
|
// The following code is recommended in http://avr-libc.nongnu.org/user-manual/group__avr__watchdog.html but is disabled for now because avr_boot doesn't currently do anything with mcusr_mirror so for now we will only reset MCUSR and disable WDT.
|
|
//uint8_t mcusr_mirror __attribute__ ((section (".noinit")));void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));void get_mcusr(void){mcusr_mirror = MCUSR;MCUSR = 0;wdt_disable();}
|
|
void disable_watchdog(void) __attribute__((naked)) __attribute__((section(".init3")));
|
|
void disable_watchdog(void)
|
|
{
|
|
#if defined(MCUCSR)
|
|
MCUCSR = ~(_BV(WDRF)); //Some MCUs require the watchdog reset flag to be cleared before WDT can be disabled. & operation is skipped to spare few bytes as bits in MCUSR can only be cleared.
|
|
#else
|
|
MCUSR = ~(_BV(WDRF)); //Some MCUs require the watchdog reset flag to be cleared before WDT can be disabled. & operation is skipped to spare few bytes as bits in MCUSR can only be cleared.
|
|
#endif
|
|
wdt_disable(); //immediately disable watchdog in case it was running in the application to avoid perpetual reset loop
|
|
}
|
|
|
|
#if BOOT_ADR > 0xFFFF
|
|
#define PGM_READ_BYTE(x) pgm_read_byte_far(x)
|
|
#else
|
|
#define PGM_READ_BYTE(x) pgm_read_byte(x)
|
|
#endif
|
|
|
|
#if USE_UART
|
|
#include "uart/uart.h"
|
|
#endif
|
|
|
|
#if USE_LED
|
|
void init_leds();
|
|
void led_power_on();
|
|
void led_power_off();
|
|
void led_power_toggle();
|
|
void led_write_on();
|
|
void led_write_off();
|
|
void led_write_toggle();
|
|
#endif
|
|
void flash_erase (DWORD); /* Erase a flash page (asmfunc.S) */
|
|
void flash_write (DWORD, const BYTE*); /* Program a flash page (asmfunc.S) */
|
|
|
|
|
|
FATFS Fatfs; // Petit-FatFs work area
|
|
BYTE Buff[SPM_PAGESIZE]; // Page data buffer
|
|
|
|
|
|
|
|
static uint8_t pagecmp(const DWORD fa, uint8_t buff[SPM_PAGESIZE])
|
|
{
|
|
UINT i;
|
|
uint8_t b_flash,b_buff;
|
|
for (i = 0; i < SPM_PAGESIZE; i++) {
|
|
b_flash = PGM_READ_BYTE(fa+i);
|
|
b_buff = buff[i];
|
|
if ( b_flash != b_buff) {
|
|
#if USE_UART //output first difference
|
|
UART_puthex32(fa);UART_puts(PSTR(":"));
|
|
UART_puthex(b_flash);UART_puts(PSTR(" "));
|
|
UART_puthex(b_buff); UART_newline();
|
|
#endif
|
|
return 1;
|
|
}
|
|
}
|
|
#if USE_UART //output first difference
|
|
UART_puthex32(fa);UART_puts(PSTR(":"));
|
|
UART_puts(PSTR("="));UART_newline();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void doFlash() {
|
|
DWORD fa; /* Flash address */
|
|
UINT br; /* Bytes read */
|
|
#if USE_LED
|
|
uint8_t i;
|
|
for(i=0;i<50;i++) { led_write_toggle();_delay_ms(100);} //Start Programming: Flash WRITE Wildly for 5 secs
|
|
#endif
|
|
|
|
|
|
for (fa = 0; fa < BOOT_ADR; fa += SPM_PAGESIZE) { /* Update all application pages */
|
|
|
|
memset(Buff, 0xFF, SPM_PAGESIZE); /* Clear buffer */
|
|
pf_read(Buff, SPM_PAGESIZE, &br); /* Load a page data */
|
|
|
|
if (pagecmp(fa, Buff)) { /* Only flash if page is changed */
|
|
#if USE_LED
|
|
led_write_off();
|
|
//led_power_on();
|
|
#endif
|
|
flash_erase(fa); /* Erase a page */
|
|
flash_write(fa, Buff); /* Write it if the data is available */
|
|
|
|
} else {
|
|
|
|
#if USE_LED
|
|
//led_power_off();
|
|
led_write_on();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void checkFile() {
|
|
uint8_t fresult;
|
|
|
|
fresult = pf_mount(&Fatfs); /* Initialize file system */
|
|
|
|
if (fresult != FR_OK) { /* File System could not be mounted */
|
|
#if USE_UART
|
|
UART_puts(PSTR("File not mounted"));
|
|
UART_newline();
|
|
#endif
|
|
|
|
#if USE_LED
|
|
//uint8_t i;
|
|
//led_write_on();
|
|
//for(i=0;i<2*fresult;i++) { led_power_toggle();_delay_ms(500);}//Give error number while Write led is on
|
|
//led_write_off();
|
|
#endif
|
|
return;
|
|
}
|
|
/*
|
|
|
|
WORD flashver = eeprom_read_word((const uint16_t *)E2END - 1);
|
|
if (flashver > 999) {
|
|
flashver = 0;
|
|
}
|
|
BYTE y, tmp;
|
|
WORD x;
|
|
BYTE found = 0;
|
|
|
|
for (x = flashver+10; x > flashver; x--) {
|
|
y = x / 100;
|
|
filename[5] = y + 0x30;
|
|
tmp = x % 100;
|
|
|
|
y = tmp / 10;
|
|
filename[6] = y + 0x30;
|
|
tmp = x % 10;
|
|
|
|
filename[7] = tmp + 0x30;
|
|
|
|
if (pf_open(filename) == FR_OK) { // File opens normally
|
|
found = 1;
|
|
doProgram();
|
|
}
|
|
led_power_toggle();
|
|
}
|
|
|
|
if (found == 0) {*/
|
|
|
|
fresult = pf_open(filename);
|
|
|
|
if (fresult != FR_OK) { /* File could not be opened */
|
|
|
|
#if USE_UART
|
|
UART_puts(PSTR("File not open"));
|
|
UART_newline();
|
|
#endif
|
|
#if USE_LED
|
|
//uint8_t i;
|
|
//led_power_on();
|
|
//for(i=0;i<2*fresult;i++) { led_write_toggle();_delay_ms(500);}//Give error number while Power led is on
|
|
//led_power_off();
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
doFlash();
|
|
|
|
#if USE_LED
|
|
led_write_off();
|
|
//led_power_off();
|
|
_delay_ms(2000);
|
|
uint8_t i;
|
|
//for(i=0;i<40;i++) { led_power_toggle();_delay_ms(50);}//SUCCESS FLASH WILDLY for 2 secs
|
|
for(i=0;i<40;i++) { led_write_toggle();_delay_ms(50);}//SUCCESS FLASH WILDLY for 2 secs
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main (void)
|
|
{
|
|
#if USE_LED
|
|
init_leds();
|
|
uint8_t i=0;
|
|
#endif
|
|
|
|
#if USE_UART
|
|
UART_init();
|
|
UART_puts(PSTR("AVR_BOOT"));
|
|
UART_newline();
|
|
#endif
|
|
while (1) {
|
|
#if USE_LED
|
|
//led_power_on();_delay_ms(200);led_power_off(); //Test Power Led
|
|
led_write_on();_delay_ms(200);led_write_off(); //Test Write Led
|
|
#endif
|
|
|
|
checkFile();
|
|
|
|
if (pgm_read_word(0) != 0xFFFF) ((void(*)(void))0)(); //EXIT BOOTLOADER
|
|
|
|
#if USE_UART
|
|
UART_puts(PSTR("retry"));
|
|
UART_newline();
|
|
#endif
|
|
#if USE_LED
|
|
//for(i=0;i<10;i++) { led_power_toggle();_delay_ms(200);} //SOMETHING WENT WRONG: Flash Power LED
|
|
for(i=0;i<10;i++) { led_write_toggle();_delay_ms(200);} //SOMETHING WENT WRONG: Flash Write LED
|
|
#endif
|
|
_delay_ms(5000); // Retry
|
|
}
|
|
}
|