Mercurial > public > ostc4
view Discovery/Src/externLogbookFlash.c @ 319:d8e86af78474 fix-version
bugfix: correct packed main version number in dive header
This fixes a rather mysterious bug. Users report that up to 1.3.5 beta,
a correct version number is shown in libdivecomputer based
applications (like in Subsurface, in the extra data tab). Careful
examining the code in both libdivecomputer and the firmware shows
a subtle error in the bit mask and shift operation to pack a full
X.Y.Z.beta version number in 2 bytes (as is available in the
dive header) in the firmware end (as the libdivecomputer code
looks sane, assuming this is the right way to pack things).
Likely, this bug crept in in the conversion from the closed
source Keil period into the open source GCC setup of
the code base. So its impossible to document the exact
history of this problem here.
Further notice that the main version number is only 1 of 3 version
numbers, denoting the full version of the firmware (besides Font
and RTE).
Finally notice that this way of packing is limited to 2^5 bits
(decimal 32), so we could easily build a 1.4.21, but not a
1.4.55.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
author | Jan Mulder <jlmulder@xs4all.nl> |
---|---|
date | Wed, 19 Jun 2019 14:31:50 +0200 |
parents | c7e665e0b08f |
children | 2174fb133dbe |
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" #ifndef BOOTLOADER_STANDALONE #include "logbook.h" #endif /* 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 entryPoint = 0; static uint32_t actualPointerHeader = 0; static uint32_t actualPointerSample = 0; static uint32_t LengthLeftSampleRead = 0; static uint32_t actualPointerDevicedata = 0; static uint32_t actualPointerVPM = 0; static uint32_t actualPointerSettings = 0; 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 error_led_on(void); static void error_led_off(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_decf_address_ring(uint8_t type); 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); static void ext_flash_overwrite_sample_without_erase(uint8_t *pSample, uint16_t length); static void ext_flash_disable_protection(void); static _Bool ext_flash_test_remaining_space_of_page_empty(uint32_t pointer, uint16_t length); static void ext_flash_set_to_begin_of_next_page(uint32_t *pointer, uint8_t type); static void ext_flash_find_start(void); /* 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; } } #ifndef BOOTLOADER_STANDALONE void ext_flash_write_devicedata(void) { uint8_t *pData; const uint16_t length = sizeof(SDevice); uint8_t length_lo, length_hi; uint8_t dataLength[2] = { 0 }; ext_flash_disable_protection(); pData = (uint8_t *)stateDeviceGetPointer(); actualPointerDevicedata = DDSTART; length_lo = (uint8_t)(length & 0xFF); length_hi = (uint8_t)(length >> 8); dataLength[0] = length_lo; dataLength[1] = length_hi; ef_write_block(dataLength,2, EF_DEVICEDATA, 0); ef_write_block(pData,length, EF_DEVICEDATA, 0); } uint16_t ext_flash_read_devicedata(uint8_t *buffer, uint16_t max_length) { uint16_t length; uint8_t length_lo, length_hi; actualAddress = DDSTART; ext_flash_read_block_start(); ext_flash_read_block(&length_lo, EF_DEVICEDATA); ext_flash_read_block(&length_hi, EF_DEVICEDATA); length = (length_hi * 256) + length_lo; if(length > max_length) return 0; ext_flash_read_block_multi(buffer,length,EF_DEVICEDATA); ext_flash_read_block_stop(); return length; } void ext_flash_write_vpm(SVpm *vpmInput) { uint8_t *pData; const uint16_t length = sizeof(SVpm); uint8_t length_lo, length_hi; uint8_t dataLength[2] = { 0 }; pData = (uint8_t *)vpmInput; actualPointerVPM = VPMSTART; length_lo = (uint8_t)(length & 0xFF); length_hi = (uint8_t)(length >> 8); dataLength[0] = length_lo; dataLength[1] = length_hi; ef_write_block(dataLength,2, EF_VPMDATA, 0); ef_write_block(pData,length, EF_VPMDATA, 0); } int ext_flash_read_vpm(SVpm *vpmOutput) { uint8_t *pData; const uint16_t length = sizeof(SVpm); uint8_t length_lo, length_hi; int output; actualAddress = VPMSTART; ext_flash_read_block_start(); ext_flash_read_block(&length_lo, EF_VPMDATA); ext_flash_read_block(&length_hi, EF_VPMDATA); if((length_lo == (uint8_t)(length & 0xFF)) &&(length_hi == (uint8_t)(length >> 8))) { pData = (uint8_t *)vpmOutput; for(uint16_t i = 0; i < length; i++) ext_flash_read_block(&pData[i], EF_VPMDATA); output = length; } else output = 0; ext_flash_read_block_stop(); return output; } #ifdef DEMOMODE void ext_flash_write_settings(void) { return; } #else void ext_flash_write_settings(void) { uint8_t *pData; const uint16_t length = sizeof(SSettings); uint8_t length_lo, length_hi; uint8_t dataLength[2] = { 0 }; ext_flash_disable_protection(); if(stateRealGetPointer()->lastKnownBatteryPercentage) { settingsGetPointer()->lastKnownBatteryPercentage = stateRealGetPointer()->lastKnownBatteryPercentage; } settingsGetPointer()->backup_localtime_rtc_tr = stateRealGetPointer()->lifeData.timeBinaryFormat; settingsGetPointer()->backup_localtime_rtc_dr = stateRealGetPointer()->lifeData.dateBinaryFormat; pData = (uint8_t *)settingsGetPointer(); actualPointerSettings = SETTINGSSTART; length_lo = (uint8_t)(length & 0xFF); length_hi = (uint8_t)(length >> 8); dataLength[0] = length_lo; dataLength[1] = length_hi; ef_write_block(dataLength,2, EF_SETTINGS, 0); ef_write_block(pData,length, EF_SETTINGS, 0); // ext_flash_enable_protection(); } #endif /* CHANGES 150929 hw * this now allows to read old settings too * but make sure that everything is fixed in * set_new_settings_missing_in_ext_flash * new settings should be fine as they are added * and loaded before calling this function */ uint8_t ext_flash_read_settings(void) { uint8_t returnValue = HAL_BUSY; uint8_t *pData; const uint16_t lengthStandardNow = sizeof(SSettings); uint8_t length_lo, length_hi; uint16_t lengthOnEEPROM; uint32_t header; SSettings *pSettings = settingsGetPointer(); actualAddress = SETTINGSSTART; ext_flash_read_block_start(); ext_flash_read_block(&length_lo, EF_SETTINGS); ext_flash_read_block(&length_hi, EF_SETTINGS); lengthOnEEPROM = length_hi * 256; lengthOnEEPROM += length_lo; if(lengthOnEEPROM <= lengthStandardNow) { ext_flash_read_block_multi(&header, 4, EF_SETTINGS); if((header <= pSettings->header) && (header >= pSettings->updateSettingsAllowedFromHeader)) { returnValue = HAL_OK; pSettings->header = header; pData = (uint8_t *)pSettings + 4; /* header */ for(uint16_t i = 0; i < (lengthOnEEPROM-4); i++) ext_flash_read_block(&pData[i], EF_SETTINGS); } else { returnValue = HAL_ERROR; } } ext_flash_read_block_stop(); return returnValue; } /* ext_flash_start_new_dive_log_and_set_actualPointerSample * prepares the write sample pointer * to be used by ext_flash_write_sample() * to be set in the * pHeaderPreDive * for write with ext_flash_create_new_dive_log() and ext_flash_close_new_dive_log() */ void ext_flash_start_new_dive_log_and_set_actualPointerSample(uint8_t *pHeaderPreDive) { convert_Type data; SSettings *settings = settingsGetPointer(); /* new 5. Jan. 2015 */ actualPointerSample = settings->logFlashNextSampleStartAddress; if(!ext_flash_test_remaining_space_of_page_empty(actualPointerSample, 4)) ext_flash_set_to_begin_of_next_page(&actualPointerSample, EF_SAMPLE); if((actualPointerSample < SAMPLESTART) || (actualPointerSample > SAMPLESTOP)) actualPointerSample = SAMPLESTART; data.u32bit = actualPointerSample; pHeaderPreDive[2] = data.u8bit.byteLow; pHeaderPreDive[3] = data.u8bit.byteMidLow; pHeaderPreDive[4] = data.u8bit.byteMidHigh; /* to start sample writing and header etc. pp. */ ext_flash_disable_protection_for_logbook(); } /* ext_flash_create_new_dive_log * uses the first header without HEADER2OFFSET * for the header it is not important to be complete * and can be reconstructed * ext_flash_start_new_dive_log_and_set_actualPointerSample() * has to be called before to set the actualPointerSample * in the header * the following func writes to header to the ext_flash */ void ext_flash_create_new_dive_log(uint8_t *pHeaderPreDive) { SSettings *settings; uint8_t id, id_next; uint8_t header1, header2; settings = settingsGetPointer(); id = settings->lastDiveLogId; actualAddress = HEADERSTART + (0x800 * id); ext_flash_read_block_start(); ext_flash_read_block(&header1, EF_SAMPLE); ext_flash_read_block(&header2, EF_SAMPLE); ext_flash_read_block_stop(); if((header1 == 0xFA) && (header2 == 0xFA)) { id += 1; /* 0-255, auto rollover */ if(id & 1) { actualAddress = HEADERSTART + (0x800 * id); ext_flash_read_block_start(); ext_flash_read_block(&header1, EF_SAMPLE); ext_flash_read_block(&header2, EF_SAMPLE); ext_flash_read_block_stop(); if((header1 == 0xFA) && (header2 == 0xFA)) id += 1; } } else { id = 0; } /* delete next header */ id_next = id + 1; actualPointerHeader = HEADERSTART + (0x800 * id_next); ef_write_block(0,0, EF_HEADER, 0); settings->lastDiveLogId = id; actualPointerHeader = HEADERSTART + (0x800 * id); if(pHeaderPreDive != 0) ef_write_block(pHeaderPreDive,HEADERSIZE, EF_HEADER, 0); } void ext_flash_close_new_dive_log(uint8_t *pHeaderPostDive ) { SSettings * settings = settingsGetPointer(); uint8_t id; convert_Type startAddress; convert_Type data; uint32_t backup; uint8_t sampleData[3]; actualAddress = actualPointerSample; sampleData[0] = 0xFD; sampleData[1] = 0xFD; ext_flash_write_sample(sampleData, 2); /* end of sample data, pointing to the last sample 0xFD */ actualAddress = actualPointerSample; // change hw 17.09.2015 ext_flash_decf_address_ring(EF_SAMPLE); // 17.09.2015: this decf actualAddress only!! actualPointerSample = actualAddress; // change hw 17.09.2015 data.u32bit = actualPointerSample; pHeaderPostDive[5] = data.u8bit.byteLow; pHeaderPostDive[6] = data.u8bit.byteMidLow; pHeaderPostDive[7] = data.u8bit.byteMidHigh; /* take data written before, calculate length and write SLogbookHeader has different order: length (byte# 8,9,10) prior to profile version (byte# 11) */ startAddress.u8bit.byteLow = pHeaderPostDive[2]; startAddress.u8bit.byteMidLow = pHeaderPostDive[3]; startAddress.u8bit.byteMidHigh = pHeaderPostDive[4]; startAddress.u8bit.byteHigh = 0; if(startAddress.u32bit < actualPointerSample) data.u32bit = 1 + actualPointerSample - startAddress.u32bit; else data.u32bit = 2 + (actualPointerSample - SAMPLESTART) + (SAMPLESTOP - startAddress.u32bit); pHeaderPostDive[8] = data.u8bit.byteLow; pHeaderPostDive[9] = data.u8bit.byteMidLow; pHeaderPostDive[10] = data.u8bit.byteMidHigh; /* set id and write post-dive-header */ id = settings->lastDiveLogId; actualPointerHeader = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ef_write_block(pHeaderPostDive,HEADERSIZE, EF_HEADER, 0); /* write length at beginning of sample and write proper beginning for next dive to actualPointerSample */ backup = actualPointerSample; actualPointerSample = startAddress.u32bit; // is still 0xFF sampleData[0] = data.u8bit.byteLow; sampleData[1] = data.u8bit.byteMidLow; sampleData[2] = data.u8bit.byteMidHigh; ext_flash_overwrite_sample_without_erase(sampleData, 3); actualAddress = backup; ext_flash_incf_address(EF_SAMPLE); actualPointerSample = actualAddress; ext_flash_enable_protection(); } void ext_flash_write_sample(uint8_t *pSample, uint16_t length) { ef_write_block(pSample,length, EF_SAMPLE, 0); SSettings *settings = settingsGetPointer(); settings->logFlashNextSampleStartAddress = actualPointerSample; } static void ext_flash_overwrite_sample_without_erase(uint8_t *pSample, uint16_t length) { ef_write_block(pSample,length, EF_SAMPLE, 1); } uint8_t ext_flash_count_dive_headers(void) { uint8_t id = 0; uint8_t counter = 0; uint16_t headerStartData = 0x0000; id = settingsGetPointer()->lastDiveLogId; do { actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ext_flash_read_block_start(); ext_flash_read_block_multi((uint8_t *)&headerStartData, 2, EF_HEADER); ext_flash_read_block_stop(); counter++; id -=1; } while((headerStartData == 0xFAFA) && (counter < 255)); return (counter - 1); } void ext_flash_read_dive_header(uint8_t *pHeaderToFill, uint8_t StepBackwards) { SSettings *settings; uint8_t id; uint16_t i; settings = settingsGetPointer(); id = settings->lastDiveLogId; id -= StepBackwards; /* 0-255, auto rollover */ actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ext_flash_read_block_start(); for(i = 0; i < HEADERSIZE; i++) ext_flash_read_block(&pHeaderToFill[i], EF_HEADER); ext_flash_read_block_stop(); } void ext_flash_read_dive_header2(uint8_t *pHeaderToFill, uint8_t id, _Bool bOffset) { uint16_t i; actualAddress = HEADERSTART + (0x800 * id) ; if(bOffset) actualAddress += HEADER2OFFSET; ext_flash_read_block_start(); for(i = 0; i < HEADERSIZE; i++) ext_flash_read_block(&pHeaderToFill[i], EF_HEADER); ext_flash_read_block_stop(); } uint32_t ext_flash_read_dive_raw_with_double_header_1K(uint8_t *data, uint32_t max_size, uint8_t StepBackwards) { if(max_size < 0x800) return 0; uint8_t id; convert_Type dataStart, dataEnd; uint32_t LengthAll = 0; id = settingsGetPointer()->lastDiveLogId; id -= StepBackwards; /* 0-255, auto rollover */ // clear data for(int i=0;i<0x800;i++) data[i] = 0xFF; // copy primary/pre-dive actualAddress = HEADERSTART + (0x800 * id); ext_flash_read_block_start(); for(int i = 0; i < HEADERSIZE; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // copy main/secondary/post-dive actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ext_flash_read_block_start(); for(int i = 0x400; i < HEADERSIZE+0x400; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // data dataStart.u8bit.byteHigh = 0; dataStart.u8bit.byteLow = data[0x402]; dataStart.u8bit.byteMidLow = data[0x403]; dataStart.u8bit.byteMidHigh = data[0x404]; dataEnd.u8bit.byteHigh = 0; dataEnd.u8bit.byteLow = data[0x405]; dataEnd.u8bit.byteMidLow = data[0x406]; dataEnd.u8bit.byteMidHigh = data[0x407]; actualPointerSample = dataStart.u32bit; if(dataEnd.u32bit >= dataStart.u32bit) LengthAll = 1 + dataEnd.u32bit - dataStart.u32bit; else LengthAll = 2 + (dataStart.u32bit - SAMPLESTART) + (SAMPLESTOP - dataEnd.u32bit); LengthAll += 0x800; if(LengthAll > max_size) return 0x800; actualAddress = actualPointerSample; ext_flash_read_block_start(); for(uint32_t i = 0x800; i < LengthAll; i++) ext_flash_read_block(&data[i], EF_SAMPLE); ext_flash_read_block_stop(); return LengthAll; } void ext_flash_write_dive_raw_with_double_header_1K(uint8_t *data, uint32_t length) { convert_Type dataStart, dataEnd; SLogbookHeader headerTemp; // set actualPointerSample and get pointer to sample storage and disable flash write protect ext_flash_start_new_dive_log_and_set_actualPointerSample((uint8_t *)&headerTemp); dataStart.u8bit.byteHigh = 0; dataStart.u8bit.byteLow = headerTemp.pBeginProfileData[0]; dataStart.u8bit.byteMidLow = headerTemp.pBeginProfileData[1]; dataStart.u8bit.byteMidHigh = headerTemp.pBeginProfileData[2]; dataEnd.u32bit = dataStart.u32bit + length - 0x801; if(dataEnd.u32bit > SAMPLESTOP) dataEnd.u32bit -= SAMPLESTOP + SAMPLESTART - 1; data[0x002] = data[0x402] = dataStart.u8bit.byteLow; data[0x003] = data[0x403] = dataStart.u8bit.byteMidLow; data[0x004] = data[0x404] = dataStart.u8bit.byteMidHigh; data[0x005] = data[0x405] = dataEnd.u8bit.byteLow; data[0x006] = data[0x406] = dataEnd.u8bit.byteMidLow; data[0x007] = data[0x407] = dataEnd.u8bit.byteMidHigh; // set actualPointerHeader to next free header and update lastDiveLogId ext_flash_create_new_dive_log(0); // copy header data ef_write_block(data,0x800,EF_HEADER, 1); // copy sample data ef_write_block(&data[0x800], length-0x800, EF_SAMPLE, 1); // update logFlashNextSampleStartAddress settingsGetPointer()->logFlashNextSampleStartAddress = actualPointerSample; } // =============================================================================== // ext_flash_read_header_memory /// @brief This function returns the entire header space 1:1 /// @date 04-April-2016 /// /// @param *data 256KB output // =============================================================================== void ext_flash_read_header_memory(uint8_t *data) { actualAddress = HEADERSTART; actualPointerHeader = actualAddress; ext_flash_read_block_start(); for(int i=0;i<8;i++) ext_flash_read_block_multi(&data[0x8000 * i], 0x8000, EF_HEADER); ext_flash_read_block_stop(); } // =============================================================================== // ext_flash_read_header_memory /// @brief This function erases and overwrites the entire logbook header block /// @date 04-April-2016 /// /// @param *data 256KB input of header memory 1:1 // =============================================================================== void ext_flash_write_header_memory(uint8_t *data) { actualAddress = HEADERSTART; actualPointerHeader = actualAddress; ef_write_block(data, 0x40000, EF_HEADER, 0); } void ext_flash_open_read_sample(uint8_t StepBackwards, uint32_t *totalNumberOfBytes) { SSettings *settings = settingsGetPointer(); uint8_t id; convert_Type dataStart, dataEnd; uint8_t header1, header2; id = settings->lastDiveLogId; id -= StepBackwards; /* 0-255, auto rollover */ # actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; actualPointerHeader = actualAddress; ext_flash_read_block_start(); /* little endian */ ext_flash_read_block(&header1, EF_HEADER); ext_flash_read_block(&header2, EF_HEADER); dataStart.u8bit.byteHigh = 0; ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); dataEnd.u8bit.byteHigh = 0; ext_flash_read_block(&dataEnd.u8bit.byteLow, EF_HEADER); ext_flash_read_block(&dataEnd.u8bit.byteMidLow, EF_HEADER); ext_flash_read_block(&dataEnd.u8bit.byteMidHigh, EF_HEADER); ext_flash_read_block_stop(); actualPointerSample = dataStart.u32bit; if(dataEnd.u32bit >= dataStart.u32bit) LengthLeftSampleRead = 1 + dataEnd.u32bit - dataStart.u32bit; else LengthLeftSampleRead = 2 + (dataStart.u32bit - SAMPLESTART) + (SAMPLESTOP - dataEnd.u32bit); *totalNumberOfBytes = LengthLeftSampleRead; actualAddress = actualPointerSample; ext_flash_read_block_start(); } void ext_flash_read_next_sample_part(uint8_t *pSample, uint8_t length) { for(uint16_t i = 0; i < length; i++) ext_flash_read_block(&pSample[i], EF_SAMPLE); } void ext_flash_close_read_sample(void) { actualPointerSample = actualAddress; ext_flash_read_block_stop(); } void ext_flash_set_entry_point(void) { entryPoint = actualAddress; } void ext_flash_reopen_read_sample_at_entry_point(void) { error_led_on(); chip_unselect(); wait_chip_not_busy(); actualAddress = entryPoint; ext_flash_read_block_start(); error_led_off(); } /* uint8_t ext_flash_point_to_64k_block_in_headerSpace(uint8_t logId) { uint32_t pointerToData = logId * 0x800; return pointerToData / 0x10000; } */ // =============================================================================== // ext_flash_repair_dive_numbers_starting_count_helper /// @brief /// @date 22-June-2016 // =============================================================================== static uint16_t ext_flash_repair_dive_numbers_starting_count_helper(uint8_t *data, uint8_t *change64k, uint16_t startNumber, uint8_t lastLogId) { const uint32_t headerStep = 0x800; uint8_t actualLogId = 0; uint16_t oldNumber = 0; uint16_t actualNumber = 0; SLogbookHeader *ptrLogbookHeader = 0; if(startNumber == 0) return 0; actualNumber = startNumber - 1; // where is the oldest dive (Which is now getting startNumber) // use first header for ease (without HEADER2OFFSET for end of dive header) // compare for lastLogId to prevent endless loop if(*(uint16_t*)&data[lastLogId * headerStep] != 0xFAFA) return 0; actualLogId = lastLogId - 1; while((*(uint16_t*)&data[actualLogId * headerStep] == 0xFAFA) && (actualLogId != lastLogId)) { actualLogId--; } // now pointing to one behind the last while(actualLogId != lastLogId) { actualLogId++; actualNumber++; ptrLogbookHeader = (SLogbookHeader *)&data[actualLogId * headerStep]; oldNumber = ptrLogbookHeader->diveNumber; if(oldNumber != actualNumber) { // change64k[ext_flash_point_to_64k_block_in_headerSpace(actualLogId )] = 1; change64k[(actualLogId * 0x800)/0x10000] = 1; ptrLogbookHeader->diveNumber = actualNumber; ptrLogbookHeader = (SLogbookHeader *)(&data[actualLogId * headerStep] + HEADER2OFFSET); ptrLogbookHeader->diveNumber = actualNumber; } } return actualNumber; } // =============================================================================== // ext_flash_repair_SPECIAL_dive_numbers_starting_count_with /// @brief This function /// @date 04-April-2016 /// problem (160621): 64K blocks (32 dives) in the new flash memory chip /// This block needs to be deleted /// these where only 4KB block before /// @output endCount, last diveNumber // =============================================================================== uint16_t ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(uint16_t startCount) { uint32_t logCopyDataPtr = 0; uint8_t *data; uint16_t lastCount; uint8_t listOfChanged64kBlocks[8]; // 32 dives each 64K logCopyDataPtr = getFrame(97); data = (uint8_t *)logCopyDataPtr; for(int i=0;i<8;i++) listOfChanged64kBlocks[i] = 0; actualAddress = HEADERSTART; ext_flash_read_block_start(); ext_flash_read_block_multi(data,0x100000,EF_HEADER); ext_flash_read_block_stop(); lastCount = ext_flash_repair_dive_numbers_starting_count_helper(data, listOfChanged64kBlocks, startCount, settingsGetPointer()->lastDiveLogId); for(int i=0;i<8;i++) { if(listOfChanged64kBlocks[i] != 0) { actualPointerHeader = HEADERSTART + (i * 0x10000); ef_write_block(&data[i * 0x10000], 0x10000, EF_HEADER, 0); } } releaseFrame(97,logCopyDataPtr); if(settingsGetPointer()->totalDiveCounter < lastCount) { settingsGetPointer()->totalDiveCounter = lastCount; } return lastCount; } /* void OLD_ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(uint16_t startCount) { uint16_t counterStorage[256]; uint8_t start = 0xFF; uint32_t logCopyDataPtr = 0; uint8_t *data; uint8_t startAbsolute = 0; int16_t count = 0; _Bool repair = 0; uint8_t startBackup = 0; SLogbookHeader tempLogbookHeader; SLogbookHeader *ptrHeaderInData1a; SLogbookHeader *ptrHeaderInData1b; SLogbookHeader *ptrHeaderInData2a; SLogbookHeader *ptrHeaderInData2b; logCopyDataPtr = getFrame(97); data = (uint8_t *)logCopyDataPtr; ptrHeaderInData1a = (SLogbookHeader *)logCopyDataPtr; ptrHeaderInData1b = (SLogbookHeader *)(logCopyDataPtr + HEADER2OFFSET); ptrHeaderInData2a = (SLogbookHeader *)(logCopyDataPtr + 0x800); ptrHeaderInData2b = (SLogbookHeader *)(logCopyDataPtr + 0x800 + HEADER2OFFSET); // get data for(int StepBackwards = 0; StepBackwards < 255; StepBackwards++) { logbook_getHeader(StepBackwards, &tempLogbookHeader); counterStorage[StepBackwards+1] = tempLogbookHeader.diveNumber; if(tempLogbookHeader.diveHeaderStart == 0xFAFA) start = StepBackwards; else break; } if(start == 0xFF) return; count = start + 1; startAbsolute = settingsGetPointer()->lastDiveLogId; if(start%2) { if(counterStorage[start] != startCount) { // clear data for(int i=0;i<0x800*2;i++) data[i] = 0xFF; uint8_t id = settingsGetPointer()->lastDiveLogId; id -= start; // 0-255, auto rollover // copy primary/pre-dive actualAddress = HEADERSTART + (0x800 * id); ext_flash_read_block_start(); for(int i = 0; i < HEADERSIZE; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // copy main/secondary/post-dive actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ext_flash_read_block_start(); for(int i = 0x400; i < HEADERSIZE+0x400; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // repair ptrHeaderInData2a->diveNumber = startCount; ptrHeaderInData2b->diveNumber = startCount; startCount++; // write actualAddress = HEADERSTART + (0x800 * (id-1)); ef_write_block(data,0x800*2,EF_HEADER, 0); } start--; } // for(int count = start; count > -1; count -= 2) while(count > 0) { // clear data for(int i=0;i<0x1000;i++) data[i] = 0xFF; repair = 0; startBackup = startAbsolute; if(startAbsolute%2) // 0x800 to 0x1000 { // copy second pre-dive actualAddress = HEADERSTART + (0x800 * startAbsolute); ext_flash_read_block_start(); for(int i = 0x800; i < HEADERSIZE+0x800; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // copy second post-dive actualAddress = HEADERSTART + HEADER2OFFSET + (0x800 * startAbsolute); ext_flash_read_block_start(); for(int i = 0xC00; i < HEADERSIZE+0xC00; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); if(counterStorage[count] != startCount) { ptrHeaderInData2a->diveNumber = startCount; ptrHeaderInData2b->diveNumber = startCount; repair = 1; } startCount += 1; startAbsolute -= 1; count -= 1; if(count > 0) { // copy first pre-dive actualAddress = HEADERSTART + (0x800 * startAbsolute); ext_flash_read_block_start(); for(int i = 0; i < HEADERSIZE; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // copy first post-dive actualAddress = HEADERSTART + (0x800 * startAbsolute); ext_flash_read_block_start(); for(int i = 0x400; i < HEADERSIZE+0x400; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); if(counterStorage[count] != startCount) { ptrHeaderInData1a->diveNumber = startCount; ptrHeaderInData1b->diveNumber = startCount; repair = 1; } startCount += 1; startAbsolute -= 1; count -= 1; } } else { // copy first pre-dive actualAddress = HEADERSTART + (0x800 * startAbsolute); ext_flash_read_block_start(); for(int i = 0; i < HEADERSIZE; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); // copy first post-dive actualAddress = HEADERSTART + (0x800 * startAbsolute); ext_flash_read_block_start(); for(int i = 0x400; i < HEADERSIZE+0x400; i++) ext_flash_read_block(&data[i], EF_HEADER); ext_flash_read_block_stop(); if(counterStorage[count] != startCount) { ptrHeaderInData1a->diveNumber = startCount; ptrHeaderInData1b->diveNumber = startCount; repair = 1; } startCount += 1; startAbsolute -= 1; count -= 1; } // write if(repair) { actualPointerHeader = HEADERSTART + (0x1000 * startBackup%2); ef_write_block(data,0x1000,EF_HEADER, 0); } } releaseFrame(97,logCopyDataPtr); settingsGetPointer()->totalDiveCounter = startCount; } */ // =============================================================================== // ext_flash_repair_dive_log /// @brief This function /// does set /// logFlashNextSampleStartAddress /// and /// lastDiveLogId /// void ext_flash_repair_dive_log(void) { uint8_t header1, header2; convert_Type dataStart; for(int id = 0; id < 255;id++) { actualAddress = HEADERSTART + (0x800 * id); ext_flash_read_block_start(); ext_flash_read_block(&header1, EF_HEADER); ext_flash_read_block(&header2, EF_HEADER); dataStart.u8bit.byteHigh = 0; ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); ext_flash_read_block_stop(); if((header1 == 0xFA) && (header2 == 0xFA)) { actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ext_flash_read_block_start(); ext_flash_read_block(&header1, EF_HEADER); ext_flash_read_block(&header2, EF_HEADER); ext_flash_read_block_stop(); if((header1 != 0xFA) || (header2 != 0xFA)) { actualPointerSample = dataStart.u32bit; actualAddress = actualPointerSample; logbook_recover_brokenlog(id); SSettings *settings = settingsGetPointer(); settings->logFlashNextSampleStartAddress = actualPointerSample; } } } ext_flash_find_start(); } static void ext_flash_find_start(void) { uint8_t id; uint8_t header1, header2; convert_Type dataStart, dataEnd; for(id = 0; id < 255;id++) { actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; ext_flash_read_block_start(); ext_flash_read_block(&header1, EF_HEADER); ext_flash_read_block(&header2, EF_HEADER); dataStart.u8bit.byteHigh = 0; ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); ext_flash_read_block_stop(); if((header1 == 0xFF) && (header2 == 0xFF)) { break; } } id--; SSettings *settings = settingsGetPointer(); settings->lastDiveLogId = id; actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; actualPointerHeader = actualAddress; ext_flash_read_block_start(); ext_flash_read_block(&header1, EF_HEADER); ext_flash_read_block(&header2, EF_HEADER); dataStart.u8bit.byteHigh = 0; ext_flash_read_block(&dataStart.u8bit.byteLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER); ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER); dataEnd.u8bit.byteHigh = 0; ext_flash_read_block(&dataEnd.u8bit.byteLow, EF_HEADER); ext_flash_read_block(&dataEnd.u8bit.byteMidLow, EF_HEADER); ext_flash_read_block(&dataEnd.u8bit.byteMidHigh, EF_HEADER); ext_flash_read_block_stop(); //Find free space if((header1 == 0xFA) && (header2 == 0xFA)) { uint8_t uiRead = 0; int countFF = 0; //End of last complete dive actualPointerSample = dataEnd.u32bit ; actualAddress = actualPointerSample; //Check if there are samples of dives with less than half a minute while(true) { ext_flash_read_block_start(); ext_flash_read_block(&uiRead, EF_SAMPLE); if(uiRead == 0xFF) countFF++; else countFF = 0; if(countFF == 10) { actualAddress -= 10; break; } //New page: clear if(ext_flash_erase_if_on_page_start()) break; } // Set new start address actualPointerSample = actualAddress; settings->logFlashNextSampleStartAddress = actualPointerSample; } else { settings->logFlashNextSampleStartAddress = SAMPLESTART; } } #endif static void ext_flash_disable_protection(void) { /* extFlashStatusBit8_Type status; status.uw = 0; wait_chip_not_busy(); write_spi(0x50,RELEASE); // EWSR write_spi(0x01,HOLDCS); // WRSR write_spi(status.uw,RELEASE); // new status */ } void ext_flash_disable_protection_for_logbook(void) { /* extFlashStatusBit8_Type status; status.uw = 0; status.ub.BlockProtect0 = 1; status.ub.BlockProtect1 = 0; status.ub.BlockProtect2 = 1; status.ub.BlockProtect3 = 0; // not set in OSTC3. Why? wait_chip_not_busy(); write_spi(0x50,RELEASE); // EWSR write_spi(0x01,HOLDCS); // WRSR write_spi(status.uw,RELEASE); // new status */ } void ext_flash_enable_protection(void) { /* extFlashStatusBit8_Type status; status.uw = 0; status.ub.BlockProtect0 = 1; status.ub.BlockProtect1 = 1; status.ub.BlockProtect2 = 1; status.ub.BlockProtect3 = 1; // not set in OSTC3. Why? wait_chip_not_busy(); write_spi(0x50,RELEASE); // EWSR write_spi(0x01,HOLDCS); // WRSR write_spi(status.uw,RELEASE); // new status */ } /*void ext_flash_erase_chip(void) { wait_chip_not_busy(); write_spi(0x06,RELEASE); write_spi(0x60,RELEASE); wait_chip_not_busy(); }*/ 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); } void ext_flash_erase_logbook(void) { uint32_t size, blocks_64k; ext_flash_disable_protection_for_logbook(); actualAddress = SAMPLESTART; size = 1 + SAMPLESTOP - SAMPLESTART; blocks_64k = size / 0x10000; ef_erase_64K(blocks_64k); actualAddress = HEADERSTART; size = 1 + HEADERSTOP - HEADERSTART; blocks_64k = size / 0x10000; ef_erase_64K(blocks_64k); ext_flash_enable_protection(); } 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) { 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; 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(); for(uint32_t i=0;i<length;i++) { 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 = actualAddress & 0xFF; remaining_space_to_ring_end = ringStop - actualAddress; if((remaining_page_size == 0) && (remaining_length >= 256) && (remaining_space_to_ring_end >= 256)) { for(int j=0; j<255; j++) { write_spi(sendByte[i],HOLDCS);/* write data */ actualAddress++; i++; } } /* byte with RELEASE */ write_spi(sendByte[i],RELEASE);/* write data */ actualAddress++; 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 _Bool ext_flash_test_remaining_space_of_page_empty(uint32_t pointer, uint16_t length) { if((pointer & 0xFFF) == 0) return 1; uint32_t backup = actualAddress; uint8_t data; uint32_t size_to_page_end; size_to_page_end = 0x1000 - (pointer & 0xFFF); if(length > size_to_page_end) length = size_to_page_end; actualAddress = pointer; ext_flash_read_block_start(); for(uint16_t i = 0; i<length; i++) { ext_flash_read_block(&data, 255); // 255 = ENTIRE FLASH if(data != 0xFF) { ext_flash_read_block_stop(); actualAddress = backup; return 0; } } ext_flash_read_block_stop(); actualAddress = backup; return 1; } static void ext_flash_set_to_begin_of_next_page(uint32_t *pointer, uint8_t type) { uint32_t ringStart, ringStop; 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; default: ringStart = FLASHSTART; ringStop = FLASHSTOP; break; } *pointer = (*pointer & 0xFFF) + 0x1000; if((*pointer < ringStart) || (*pointer >= ringStop)) *pointer = ringStart; } 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 void error_led_on(void) { HAL_GPIO_WritePin(OSCILLOSCOPE_GPIO_PORT,OSCILLOSCOPE_PIN,GPIO_PIN_SET); } static void error_led_off(void) { HAL_GPIO_WritePin(OSCILLOSCOPE_GPIO_PORT,OSCILLOSCOPE_PIN,GPIO_PIN_RESET); } 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 ext_flash_decf_address_ring(uint8_t type) { uint32_t ringStart, ringStop; 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 = ringStop; else actualAddress -= 1; } 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) { } } /* 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; }*/