Mercurial > public > ostc4
view BootLoader/Src/externLogbookFlash_mini.c @ 987:45a2bd04b156 BootloaderOstc5
Removed Font144 references because Font cause a linker problem and is not used by Bootloader
author | Ideenmodellierer |
---|---|
date | Sun, 30 Mar 2025 21:39:52 +0200 (3 weeks ago) |
parents | aeafa631147d |
children |
line wrap: on
line source
/** ****************************************************************************** * @copyright heinrichs weikamp * @file externLogbookFlash.c * @author heinrichs weikamp gmbh * @date 07-Aug-2014 * @version V0.0.4 * @since 29-Sept-2015 * @brief Main File to access the new 1.8 Volt Spansion S25FS256S 256 Mbit (32 Mbyte) * @bug * @warning * @verbatim ============================================================================== ##### Logbook Header (TOC) ##### ============================================================================== [..] Memory useage: NEW: Spansion S25FS-S256S only 8x 4KB and 1x 32KB, remaining is 64KB or 256KB Sector Size (kbyte) Sector Count Sector Range Address Range (Byte Address) Notes 4 8 SA00 00000000h-00000FFFh : : SA07 00007000h-00007FFFh 32 1 SA08 00008000h-0000FFFFh 64 511 SA09 00010000h-0001FFFFh : : SA519 01FF0000h-01FFFFFFh OLD: 1kB each header with predive header at beginning and postdive header with 0x400 HEADER2OFFSET 4kB (one erase) has two dives with 4 headers total total of 512 kB (with 256 header ids (8 bit)) Size is 280 Byte (as of 25.Nov. 2014) [..] Output to PC / UART is postdive header [..] Block Protection Lock-Down is to erase logbook only [..] Timing (see page 137 of LOGBOOK_V3_S25FS-S_00-271247.pdf bulk erase is 2 minutes typ., 6 minutes max. ============================================================================== ##### DEMOMODE ##### ============================================================================== 151215: ext_flash_write_settings() is DISABLED! ============================================================================== ##### bug fixes ##### ============================================================================== 150917: end in header and length of sample was one byte too long as stated by Jef Driesen email 15.09.2015 @endverbatim ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2> * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" #include "externLogbookFlash.h" #include "ostc.h" #include "settings.h" #include "gfx_engine.h" /* Private types -------------------------------------------------------------*/ #define FLASHSTART 0x000000 //#define FLASHSTOP 0x01FFFFFF all 32 MB with 4byte addressing #define FLASHSTOP 0x00FFFFFF //#define FLASHSTOP 0x3FFFFF #define RELEASE 1 #define HOLDCS 0 #define HEADER2OFFSET 0x400 typedef enum{ EF_HEADER, EF_SAMPLE, EF_DEVICEDATA, EF_VPMDATA, EF_SETTINGS, EF_FIRMWARE, EF_FIRMWARE2, }which_ring_enum; typedef struct{ uint8_t IsBusy:1; uint8_t IsWriteEnabled:1; uint8_t BlockProtect0:1; uint8_t BlockProtect1:1; uint8_t BlockProtect2:1; uint8_t BlockProtect3:1; uint8_t IsAutoAddressIncMode:1; uint8_t BlockProtectL:1; } extFlashStatusUbit8_t; typedef union{ extFlashStatusUbit8_t ub; uint8_t uw; } extFlashStatusBit8_Type; /* Exported variables --------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static uint32_t actualAddress = 0; static uint32_t preparedPageAddress = 0; static uint32_t closeSectorAddress = 0; static uint32_t actualPointerHeader = 0; static uint32_t actualPointerSample = 0; static uint32_t actualPointerDevicedata = DDSTART; static uint32_t actualPointerVPM = 0; static uint32_t actualPointerSettings = SETTINGSSTART; static uint32_t actualPointerFirmware = 0; static uint32_t actualPointerFirmware2 = 0; /* Private function prototypes -----------------------------------------------*/ static void chip_unselect(void); static void chip_select(void); static void write_spi(uint8_t data, uint8_t unselect_CS_afterwards); static uint8_t read_spi(uint8_t unselect_CS_afterwards); static void write_address(uint8_t unselect_CS_afterwards); static void Error_Handler_extflash(void); static void wait_chip_not_busy(void); static void ext_flash_incf_address(uint8_t type); //void ext_flash_incf_address_ring(void); static void ext_flash_erase4kB(void); static void ext_flash_erase32kB(void); static void ext_flash_erase64kB(void); static uint8_t ext_flash_erase_if_on_page_start(void); static void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase); static void ext_flash_read_block(uint8_t *getByte, uint8_t type); static void ext_flash_read_block_multi(void *getByte, uint32_t size, uint8_t type); static void ext_flash_read_block_stop(void); static void ef_hw_rough_delay_us(uint32_t delayUs); static void ef_erase_64K(uint32_t blocks); /* Exported functions --------------------------------------------------------*/ void ext_flash_write_firmware(uint8_t *pSample1, uint32_t length1)//, uint8_t *pSample2, uint32_t length2) { general32to8_Type lengthTransform; lengthTransform.u32 = length1; actualPointerFirmware = FWSTART; ef_write_block(lengthTransform.u8,4, EF_FIRMWARE, 1); ef_write_block(pSample1,length1, EF_FIRMWARE, 1); // if(length2) // ef_write_block(pSample2,length2, EF_FIRMWARE, 1); } uint8_t ext_flash_read_firmware_version(char *text) { uint32_t backup = actualAddress; uint8_t buffer[4]; // + 4 for length data, see ext_flash_write_firmware actualAddress = FWSTART + 4 + 0x10000; ext_flash_read_block_start(); ext_flash_read_block(&buffer[0], EF_FIRMWARE); ext_flash_read_block(&buffer[1], EF_FIRMWARE); ext_flash_read_block(&buffer[2], EF_FIRMWARE); ext_flash_read_block(&buffer[3], EF_FIRMWARE); ext_flash_read_block_stop(); actualAddress = backup; uint8_t ptr = 0; text[ptr++] = 'V'; ptr += gfx_number_to_string(2,0,&text[ptr],buffer[0] & 0x3F); text[ptr++] = '.'; ptr += gfx_number_to_string(2,0,&text[ptr],buffer[1] & 0x3F); text[ptr++] = '.'; ptr += gfx_number_to_string(2,0,&text[ptr],buffer[2] & 0x3F); text[ptr++] = ' '; if(buffer[3]) { text[ptr++] = 'b'; text[ptr++] = 'e'; text[ptr++] = 't'; text[ptr++] = 'a'; text[ptr++] = ' '; } return ptr; } uint32_t ext_flash_read_firmware(uint8_t *pSample1, uint32_t max_length, uint8_t *magicByte) { uint32_t backup = actualAddress; general32to8_Type lengthTransform; actualAddress = FWSTART; ext_flash_read_block_start(); ext_flash_read_block(&lengthTransform.u8[0], EF_FIRMWARE); ext_flash_read_block(&lengthTransform.u8[1], EF_FIRMWARE); ext_flash_read_block(&lengthTransform.u8[2], EF_FIRMWARE); ext_flash_read_block(&lengthTransform.u8[3], EF_FIRMWARE); if(lengthTransform.u32 == 0xFFFFFFFF) { lengthTransform.u32 = 0xFFFFFFFF; } else if(lengthTransform.u32 > max_length) { lengthTransform.u32 = 0xFF000000; } else { for(uint32_t i = 0; i<lengthTransform.u32; i++) { ext_flash_read_block(&pSample1[i], EF_FIRMWARE); } } ext_flash_read_block_stop(); if(magicByte) { *magicByte = pSample1[0x10000 + 0x3E]; // 0x3E == 62 } actualAddress = backup; return lengthTransform.u32; } void ext_flash_write_firmware2(uint32_t offset, uint8_t *pSample1, uint32_t length1, uint8_t *pSample2, uint32_t length2) { general32to8_Type lengthTransform, offsetTransform; lengthTransform.u32 = length1 + length2; offsetTransform.u32 = offset; actualPointerFirmware2 = FWSTART2; ef_write_block(lengthTransform.u8,4, EF_FIRMWARE2, 1); ef_write_block(offsetTransform.u8,4, EF_FIRMWARE2, 1); ef_write_block(pSample1,length1, EF_FIRMWARE2, 1); if(length2) ef_write_block(pSample2,length2, EF_FIRMWARE2, 1); } uint32_t ext_flash_read_firmware2(uint32_t *offset, uint8_t *pSample1, uint32_t max_length1, uint8_t *pSample2, uint32_t max_length2) { uint32_t backup = actualAddress; uint32_t length1, length2; general32to8_Type lengthTransform, offsetTransform; actualAddress = FWSTART2; ext_flash_read_block_start(); ext_flash_read_block(&lengthTransform.u8[0], EF_FIRMWARE2); ext_flash_read_block(&lengthTransform.u8[1], EF_FIRMWARE2); ext_flash_read_block(&lengthTransform.u8[2], EF_FIRMWARE2); ext_flash_read_block(&lengthTransform.u8[3], EF_FIRMWARE2); ext_flash_read_block(&offsetTransform.u8[0], EF_FIRMWARE2); ext_flash_read_block(&offsetTransform.u8[1], EF_FIRMWARE2); ext_flash_read_block(&offsetTransform.u8[2], EF_FIRMWARE2); ext_flash_read_block(&offsetTransform.u8[3], EF_FIRMWARE2); *offset = offsetTransform.u32; if(lengthTransform.u32 == 0xFFFFFFFF) { lengthTransform.u32 = 0xFFFFFFFF; } else if(lengthTransform.u32 > max_length1 + max_length2) { lengthTransform.u32 = 0xFF000000; } else { if(lengthTransform.u32 < max_length1) { length1 = lengthTransform.u32; length2 = 0; } else { length1 = max_length1; length2 = lengthTransform.u32 - max_length1; } if(pSample1) { for(uint32_t i = 0; i<length1; i++) { ext_flash_read_block(&pSample1[i], EF_FIRMWARE2); } if(pSample2) { for(uint32_t i = 0; i<length2; i++) { ext_flash_read_block(&pSample2[i], EF_FIRMWARE2); } } } else if(pSample2) { actualAddress += length1; for(uint32_t i = 0; i<length2; i++) { ext_flash_read_block(&pSample2[i], EF_FIRMWARE2); } } } ext_flash_read_block_stop(); actualAddress = backup; return lengthTransform.u32; } void ext_flash_read_fixed_16_devicedata_blocks_formated_128byte_total(uint8_t *buffer) { SDeviceLine data[16]; uint8_t tempLengthIngnore; uint16_t count; uint8_t transfer; RTC_DateTypeDef Sdate; RTC_TimeTypeDef Stime; actualAddress = DDSTART; ext_flash_read_block_start(); ext_flash_read_block(&tempLengthIngnore, EF_DEVICEDATA); ext_flash_read_block(&tempLengthIngnore, EF_DEVICEDATA); ext_flash_read_block_multi((uint8_t *)data,16*3*4, EF_DEVICEDATA); ext_flash_read_block_stop(); count = 0; for(int i=0;i<16;i++) { transfer = (data[i].value_int32 >> 24) & 0xFF; buffer[count++] = transfer; transfer = (data[i].value_int32 >> 16) & 0xFF; buffer[count++] = transfer; transfer = (data[i].value_int32 >> 8) & 0xFF; buffer[count++] = transfer; transfer = (data[i].value_int32) & 0xFF; buffer[count++] = transfer; translateDate(data[i].date_rtc_dr, &Sdate); translateTime(data[i].time_rtc_tr, &Stime); buffer[count++] = Sdate.Year; buffer[count++] = Sdate.Month; buffer[count++] = Sdate.Date; buffer[count++] = Stime.Hours; } } void ext_flash_erase_firmware(void) { uint32_t size, blocks_64k; actualAddress = FWSTART; size = 1 + FWSTOP - FWSTART; blocks_64k = size / 0x10000; ef_erase_64K(blocks_64k); } void ext_flash_erase_firmware2(void) { uint32_t size, blocks_64k; actualAddress = FWSTART2; size = 1 + FWSTOP2 - FWSTART2; blocks_64k = size / 0x10000; ef_erase_64K(blocks_64k); } static void ext_flash_erase4kB(void) { wait_chip_not_busy(); write_spi(0x06,RELEASE);/* WREN */ write_spi(0x20,HOLDCS);/* sector erase cmd */ write_address(RELEASE); } /* be careful - might not work with entire family and other products * see page 14 of LOGBOOK_V3_S25FS-S_00-271247.pdf */ static void ext_flash_erase32kB(void) { uint32_t actualAddress_backup; actualAddress_backup = actualAddress; actualAddress = 0; wait_chip_not_busy(); write_spi(0x06,RELEASE);/* WREN */ write_spi(0xD8,HOLDCS);/* sector erase cmd */ write_address(RELEASE); actualAddress = actualAddress_backup; } static void ext_flash_erase64kB(void) { wait_chip_not_busy(); write_spi(0x06,RELEASE);/* WREN */ write_spi(0xD8,HOLDCS);/* sector erase cmd */ write_address(RELEASE); } void ext_flash_read_block_start(void) { wait_chip_not_busy(); write_spi(0x03,HOLDCS); /* WREN */ write_address(HOLDCS); } /* 4KB, 32KB, 64 KB, not the upper 16 MB with 4 Byte address at the moment */ static uint8_t ext_flash_erase_if_on_page_start(void) { if(actualAddress < 0x00008000) { /* 4K Byte is 0x1000 */ if((actualAddress & 0xFFF) == 0) { ext_flash_erase4kB(); return 1; } } else if(actualAddress < 0x00010000) { /* 32K Byte is only one page */ if(actualAddress == 0x00010000) { ext_flash_erase32kB(); return 1; } } else { /* 64K Byte is 0x10000 */ if((actualAddress & 0xFFFF) == 0) { if(preparedPageAddress == actualAddress) /* has page already been prepared before? (at the moment for samples only) */ { preparedPageAddress = 0; } else { ext_flash_erase64kB(); } return 1; } } return 0; } static void ext_flash_read_block(uint8_t *getByte, uint8_t type) { *getByte = read_spi(HOLDCS);/* read data */ ext_flash_incf_address(type); } static void ext_flash_read_block_multi(void *getByte, uint32_t size, uint8_t type) { uint8_t *data; data = getByte; for(uint32_t i=0;i<size;i++) { data[i] = read_spi(HOLDCS);/* read data */ ext_flash_incf_address(type); } } static void ext_flash_read_block_stop(void) { chip_unselect(); } /* Private functions ---------------------------------------------------------*/ static void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase) { uint32_t remaining_page_size, remaining_length, remaining_space_to_ring_end; uint32_t i=0; if(!length) return; uint32_t ringStart, ringStop; switch(type) { case EF_HEADER: actualAddress = actualPointerHeader; ringStart = HEADERSTART; ringStop = HEADERSTOP; break; case EF_SAMPLE: actualAddress = actualPointerSample; ringStart = SAMPLESTART; ringStop = SAMPLESTOP; break; case EF_DEVICEDATA: actualAddress = actualPointerDevicedata; ringStart = DDSTART; ringStop = DDSTOP; break; case EF_VPMDATA: actualAddress = actualPointerVPM; ringStart = VPMSTART; ringStop = VPMSTOP; break; case EF_SETTINGS: actualAddress = actualPointerSettings; ringStart = SETTINGSSTART; ringStop = SETTINGSSTOP; break; case EF_FIRMWARE: actualAddress = actualPointerFirmware; ringStart = FWSTART; ringStop = FWSTOP; break; case EF_FIRMWARE2: actualAddress = actualPointerFirmware2; ringStart = FWSTART2; ringStop = FWSTOP2; break; default: ringStart = FLASHSTART; ringStop = FLASHSTOP; break; } /* safety */ if(actualAddress < ringStart) actualAddress = ringStart; if(do_not_erase == 0) { ext_flash_erase_if_on_page_start(); } while( i<length) { ef_hw_rough_delay_us(5); wait_chip_not_busy(); write_spi(0x06,RELEASE); /* WREN */ write_spi(0x02,HOLDCS); /* write cmd */ write_address(HOLDCS); remaining_length = length - i; remaining_page_size = 0xFF - (uint8_t)(actualAddress & 0xFF) +1; remaining_space_to_ring_end = ringStop - actualAddress; if(remaining_length >= 256) { remaining_length = 255; /* up to 256 bytes may be written in one burst. Last byte is written with release */ } else { remaining_length--; /* last byte needed for release */ } if(remaining_length >= (remaining_page_size) ) /* use 256 byte page and calculate number of bytes left */ { remaining_length = remaining_page_size - 1; } if( (remaining_space_to_ring_end >= 256)) { for(int j=0; j<remaining_length; j++) { write_spi(sendByte[i],HOLDCS);/* write data */ actualAddress++; i++; } } /* byte with RELEASE */ write_spi(sendByte[i],RELEASE);/* write data */ actualAddress++; i++; if(actualAddress > ringStop) actualAddress = ringStart; if(do_not_erase == 0) ext_flash_erase_if_on_page_start(); } switch(type) { case EF_HEADER: actualPointerHeader = actualAddress; break; case EF_SAMPLE: actualPointerSample = actualAddress; break; case EF_DEVICEDATA: actualPointerDevicedata = actualAddress; break; case EF_VPMDATA: actualPointerVPM = actualAddress; break; case EF_SETTINGS: actualPointerSettings = actualAddress; break; case EF_FIRMWARE: actualPointerFirmware = actualAddress; break; case EF_FIRMWARE2: actualPointerFirmware2 = actualAddress; break; default: break; } } static void ef_erase_64K(uint32_t blocks) { for(uint32_t i = 0; i < blocks; i++) { wait_chip_not_busy(); write_spi(0x06,RELEASE);/* WREN */ write_spi(0xD8,HOLDCS);/* 64k erase cmd */ write_address(RELEASE); actualAddress += 0x10000; HAL_Delay(25); } } static void chip_unselect(void) { HAL_GPIO_WritePin(EXTFLASH_CSB_GPIO_PORT,EXTFLASH_CSB_PIN,GPIO_PIN_SET); // chip select } static void chip_select(void) { HAL_GPIO_WritePin(EXTFLASH_CSB_GPIO_PORT,EXTFLASH_CSB_PIN,GPIO_PIN_RESET); // chip select } static uint8_t read_spi(uint8_t unselect_CS_afterwards) { uint8_t byte; chip_select(); if(HAL_SPI_Receive(&hspiDisplay, &byte, 1, 10000) != HAL_OK) Error_Handler_extflash(); while (HAL_SPI_GetState(&hspiDisplay) != HAL_SPI_STATE_READY) { } if(unselect_CS_afterwards) chip_unselect(); return byte; } static void write_spi(uint8_t data, uint8_t unselect_CS_afterwards) { chip_select(); if(HAL_SPI_Transmit(&hspiDisplay, &data, 1, 10000) != HAL_OK) Error_Handler_extflash(); while (HAL_SPI_GetState(&hspiDisplay) != HAL_SPI_STATE_READY) { } if(unselect_CS_afterwards) chip_unselect(); } static void write_address(uint8_t unselect_CS_afterwards) { uint8_t hi, med ,lo; hi = (actualAddress >> 16) & 0xFF; med = (actualAddress >> 8) & 0xFF; lo = actualAddress & 0xFF; write_spi(hi, HOLDCS); write_spi(med, HOLDCS); write_spi(lo, unselect_CS_afterwards); } static void wait_chip_not_busy(void) { uint8_t status; chip_unselect(); write_spi(0x05,HOLDCS); /* RDSR */ status = read_spi(HOLDCS);/* read status */ while(status & 0x01) { HAL_Delay(1); status = read_spi(HOLDCS);/* read status */ } chip_unselect(); } static void ext_flash_incf_address(uint8_t type) { uint32_t ringStart, ringStop; actualAddress += 1; switch(type) { case EF_HEADER: ringStart = HEADERSTART; ringStop = HEADERSTOP; break; case EF_SAMPLE: ringStart = SAMPLESTART; ringStop = SAMPLESTOP; break; case EF_DEVICEDATA: ringStart = DDSTART; ringStop = DDSTOP; break; case EF_VPMDATA: ringStart = VPMSTART; ringStop = VPMSTOP; break; case EF_SETTINGS: ringStart = SETTINGSSTART; ringStop = SETTINGSSTOP; break; case EF_FIRMWARE: ringStart = FWSTART; ringStop = FWSTOP; break; case EF_FIRMWARE2: ringStart = FWSTART2; ringStop = FWSTOP2; break; default: ringStart = FLASHSTART; ringStop = FLASHSTOP; break; } if((actualAddress < ringStart) || (actualAddress > ringStop)) actualAddress = ringStart; } static void ef_hw_rough_delay_us(uint32_t delayUs) { if(!delayUs) return; delayUs*= 12; while(delayUs--); return; } static void Error_Handler_extflash(void) { while(1) { } } void ext_flash_CloseSector(void) { uint32_t actualAddressBackup = actualAddress; int i=0; if(closeSectorAddress != 0) { /* write some dummy bytes to the sector which is currently used for storing samples. This is done to "hide" problem if function is calles again */ actualAddress = closeSectorAddress; wait_chip_not_busy(); write_spi(0x06,RELEASE); /* WREN */ write_spi(0x02,HOLDCS); /* write cmd */ write_address(HOLDCS); for(i = 0; i<8; i++) { write_spi(0xA5,HOLDCS);/* write data */ actualAddress++; } /* byte with RELEASE */ write_spi(0xA5,RELEASE);/* write data */ actualAddress = actualAddressBackup; closeSectorAddress = 0; } } uint8_t ext_flash_erase_firmware_if_not_empty(void) { const uint8_t TESTSIZE_FW = 4; uint8_t data[TESTSIZE_FW]; uint8_t notEmpty = 0; actualAddress = FWSTART; ext_flash_read_block_start(); for(int i = 0; i < TESTSIZE_FW; i++) { ext_flash_read_block(&data[i], EF_FIRMWARE); if(data[i] != 0xFF) notEmpty = 1; } ext_flash_read_block_stop(); if(notEmpty) { ext_flash_erase_firmware(); return 1; } else return 0; } uint8_t ext_flash_erase_firmware2_if_not_empty(void) { const uint8_t TESTSIZE_FW = 4; uint8_t data[TESTSIZE_FW]; uint8_t notEmpty = 0; actualAddress = FWSTART2; ext_flash_read_block_start(); for(int i = 0; i < TESTSIZE_FW; i++) { ext_flash_read_block(&data[i], EF_FIRMWARE2); if(data[i] != 0xFF) notEmpty = 1; } ext_flash_read_block_stop(); if(notEmpty) { ext_flash_erase_firmware2(); return 1; } else return 0; }