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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

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] ="644BOOT.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
}
}