/* * Copyright (C) OpenTX * * Based on code named * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "opentx.h" //After reset, write is not allowed in the Flash control register (FLASH_CR) to protect the //Flash memory against possible unwanted operations due, for example, to electric //disturbances. The following sequence is used to unlock this register: //1. Write KEY1 = 0x45670123 in the Flash key register (FLASH_KEYR) //2. Write KEY2 = 0xCDEF89AB in the Flash key register (FLASH_KEYR) //Any wrong sequence will return a bus error and lock up the FLASH_CR register until the //next reset. //The FLASH_CR register can be locked again by software by setting the LOCK bit in the //FLASH_CR register. void unlockFlash() { FLASH->KEYR = 0x45670123; FLASH->KEYR = 0xCDEF89AB; } void lockFlash() { while (FLASH->SR & FLASH_SR_BSY); FLASH->CR |= FLASH_CR_LOCK; } void waitFlashIdle() { while (FLASH->SR & FLASH_FLAG_BSY) { wdt_reset(); } } #define SECTOR_MASK ((uint32_t)0xFFFFFF07) void eraseSector(uint32_t sector) { waitFlashIdle(); FLASH->CR &= CR_PSIZE_MASK; FLASH->CR |= FLASH_PSIZE_WORD; FLASH->CR &= SECTOR_MASK; FLASH->CR |= FLASH_CR_SER | (sector << 3); FLASH->CR |= FLASH_CR_STRT; /* Wait for operation to be completed */ waitFlashIdle(); /* if the erase operation is completed, disable the SER Bit */ FLASH->CR &= (~FLASH_CR_SER); FLASH->CR &= SECTOR_MASK; } void flashWrite(uint32_t * address, uint32_t * buffer) // page size is 256 bytes { if ((uint32_t) address == 0x08000000) { eraseSector(0); } else if ((uint32_t) address == 0x08004000) { eraseSector(1); } else if ((uint32_t) address == 0x08008000) { eraseSector(2); } else if ((uint32_t) address == 0x0800C000) { eraseSector(3); } else if ((uint32_t) address == 0x08010000) { eraseSector(4); } else if ((uint32_t) address == 0x08020000) { eraseSector(5); } else if ((uint32_t) address == 0x08040000) { eraseSector(6); } else if ((uint32_t) address == 0x08060000) { eraseSector(7); } for (uint32_t i=0; iCR &= CR_PSIZE_MASK; FLASH->CR |= FLASH_PSIZE_WORD; FLASH->CR |= FLASH_CR_PG; *address = *buffer; /* Wait for operation to be completed */ waitFlashIdle(); FLASH->CR &= (~FLASH_CR_PG); /* Check the written value */ if (*address != *buffer) { /* Flash content doesn't match SRAM content */ return; } /* Increment FLASH destination address */ address += 1; buffer += 1; } } uint32_t isFirmwareStart(const uint8_t * buffer) { const uint32_t * block = (const uint32_t *)buffer; #if defined(PCBX9E) if ((block[0] & 0xFFFC0000) != 0x10000000 && (block[0] & 0xFFFC0000) != 0x20000000) { return 0; } if ((block[1] & 0xFFF00000) != 0x08000000) { return 0; } if ((block[2] & 0xFFF00000) != 0x08000000) { return 0; } #else if ((block[0] & 0xFFFC0000) != 0x20000000) { return 0; } if ((block[1] & 0xFFF00000) != 0x08000000) { return 0; } if ((block[2] & 0xFFF00000) != 0x08000000) { return 0; } #endif return 1; } uint32_t isBootloaderStart(const uint8_t * buffer) { const uint32_t * block = (const uint32_t *)buffer; for (int i=0; i<256; i++) { if (block[i] == 0x544F4F42/*BOOT*/) { return 1; } } return 0; }