void FLASH_command(uint8_t cmd, uint8_t isWrite){ if (isWrite) { FLASH_command(SPIFLASH_WRITEENABLE, 0); // Write Enable FLASH_UNSELECT; } while(FLASH_busy()); //wait for chip to become available FLASH_SELECT; SPI_transfer(cmd); }
uint8_t FLASH_readByte(uint32_t addr) { FLASH_command(SPIFLASH_ARRAYREADLOWFREQ, 0); SPI_transfer(addr >> 16); SPI_transfer(addr >> 8); SPI_transfer(addr); //SPI.transfer(0); //"dont care", needed with SPIFLASH_ARRAYREAD command only uint8_t result = SPI_transfer(0); FLASH_UNSELECT; return result; }
void CheckFlashImage() { #ifdef DEBUG_ON putch('F'); #endif watchdogConfig(WATCHDOG_OFF); #ifdef ANARDUINO #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) DDRB |= _BV(SS) | _BV(PINB3) | _BV(PINB5); //OUTPUTS for SS, MOSI, SCK DDRD |= _BV(FLASHSS); //OUTPUTS for FLASH_SS FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__) DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #endif #else //MOTEINO //SPI INIT #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) DDRB |= _BV(FLASHSS) | _BV(SS) | _BV(PINB3) | _BV(PINB5); //OUTPUTS for FLASH_SS and SS, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__) DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #endif #endif // MOTEINO*/ //SPCR &= ~(_BV(DORD)); //MSB first //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0 //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2 //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK); // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT. SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value //FLASH_SELECT; FLASH_command(SPIFLASH_JEDECID,1); uint8_t deviceId = SPI_transfer(0); FLASH_UNSELECT; #ifdef DEBUG_ON putch(deviceId); #endif // Disabled check, as it only returns 0xFF or 0x00 for some reasons if (deviceId==0 || deviceId==0xFF) return; //global unprotect FLASH_command(SPIFLASH_STATUSWRITE, 1); SPI_transfer(0); FLASH_UNSELECT; #ifdef DEBUG_ON putch('I'); #endif //check if any flash image exists on external FLASH chip if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':') { #ifdef DEBUG_ON putch('L'); #endif uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8); if (imagesize%2!=0) return; //basic check that we got even # of bytes uint16_t b, i, nextAddress=0; LED_PIN |= _BV(LED); for (i=0; i<imagesize; i+=2) { #ifdef DEBUG_ON putch('*'); #endif //read 2 bytes (16 bits) from flash image, transfer them to page buffer b = FLASH_readByte(i+10); // flash image starts at position 10 on the external flash memory: FLX:XX:FLASH_IMAGE_BYTES_HERE...... (XX = two size bytes) b |= FLASH_readByte(i+11) << 8; //bytes are stored big endian on external flash, need to flip the bytes to little endian for transfer to internal flash __boot_page_fill_short((uint16_t)(void*)i,b); //when 1 page is full (or we're on the last page), write it to the internal flash memory if ((i+2)%SPM_PAGESIZE==0 || (i+2==imagesize)) { __boot_page_erase_short((uint16_t)(void*)nextAddress); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); // Write from programming buffer __boot_page_write_short((uint16_t)(void*)nextAddress ); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); nextAddress += SPM_PAGESIZE; } } LED_PIN &= ~_BV(LED); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif #ifdef DEBUG_ON putch('E'); #endif #ifdef ANARDUINO // Anarduino doesn't support 32K block erase. Do it, with 8 pages of 4k each int page; long address; for (page = 0, address=0; page< 8; page++) { FLASH_command(SPIFLASH_BLOCKERASE_4K, 1); SPI_transfer(address >> 16); SPI_transfer(address >> 8); SPI_transfer(address); FLASH_UNSELECT; while (FLASH_busy()); address += 0x1000; } #else // MOTEINO //erase the first 32/64K block where flash image resided (atmega328 should be less than 31K, and atmega1284 can be up to 64K) if (imagesize+10<=32768) FLASH_command(SPIFLASH_BLOCKERASE_32K, 1); else FLASH_command(SPIFLASH_BLOCKERASE_64K, 1); SPI_transfer(0); SPI_transfer(0); SPI_transfer(0); #endif FLASH_UNSELECT; //now trigger a watchdog reset watchdogConfig(WATCHDOG_16MS); // short WDT timeout while (1); // and busy-loop so that WD causes a reset and app start }
void CheckFlashImage() { #ifdef DEBUG_ON putch('F'); #endif watchdogConfig(WATCHDOG_OFF); //SPI INIT FLASHSS_DDR |= _BV(FLASHSS) | _BV(SS) | _BV(PB3) | _BV(PB5); //OUTPUTS for D8 and D10, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PINB |= _BV(SS); //set D10 HIGH //SPCR &= ~(_BV(DORD)); //MSB first //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0 //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2 //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK); // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT. SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value FLASH_SELECT; SPI_transfer(SPIFLASH_JEDECID); uint8_t deviceId = SPI_transfer(0); FLASH_UNSELECT; if (deviceId==0 || deviceId==0xFF) return; //global unprotect FLASH_command(SPIFLASH_STATUSWRITE, 1); SPI_transfer(0); FLASH_UNSELECT; //check if any flash image exists on external FLASH chip if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':') { #ifdef DEBUG_ON putch('L'); #endif uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8); if (imagesize%2!=0) return; //basic check that we got even # of bytes uint16_t b, i, nextAddress=0; LED_PIN |= _BV(LED); for (i=0; i<imagesize; i+=2) { #ifdef DEBUG_ON putch('*'); #endif //read 2 bytes (16 bits) from flash image, transfer them to page buffer b = FLASH_readByte(i+10); // flash image starts at position 10 on the external flash memory: FLX:XX:FLASH_IMAGE_BYTES_HERE...... (XX = two size bytes) b |= FLASH_readByte(i+11) << 8; //bytes are stored big endian on external flash, need to flip the bytes to little endian for transfer to internal flash __boot_page_fill_short((uint16_t)(void*)i,b); //when 1 page is full (or we're on the last page), write it to the internal flash memory if ((i+2)%SPM_PAGESIZE==0 || (i+2==imagesize)) { __boot_page_erase_short((uint16_t)(void*)nextAddress); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); // Write from programming buffer __boot_page_write_short((uint16_t)(void*)nextAddress ); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); nextAddress += SPM_PAGESIZE; } } LED_PIN &= ~_BV(LED); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif #ifdef DEBUG_ON putch('E'); #endif //erase the first 32K block where flash image resided FLASH_command(SPIFLASH_BLOCKERASE_32K, 1); SPI_transfer(0); SPI_transfer(0); SPI_transfer(0); FLASH_UNSELECT; //now trigger a watchdog reset watchdogConfig(WATCHDOG_16MS); // short WDT timeout while (1); // and busy-loop so that WD causes a reset and app start } #ifdef DEBUG_ON putch('X'); #endif }