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