Mercurial > public > ostc4
diff Discovery/Src/externLogbookFlash.c @ 430:30580cf5ee77
Merged in Ideenmodellierer/ostc4/ImprovmentNVM_2 (pull request #39)
ImprovmentNVM 2
author | heinrichsweikamp <bitbucket@heinrichsweikamp.com> |
---|---|
date | Tue, 18 Feb 2020 07:20:29 +0000 |
parents | 7f351c25608a |
children | 9a9e4908ce2e b90ddf57f7f1 |
line wrap: on
line diff
--- a/Discovery/Src/externLogbookFlash.c Mon Feb 10 08:23:15 2020 +0000 +++ b/Discovery/Src/externLogbookFlash.c Tue Feb 18 07:20:29 2020 +0000 @@ -116,14 +116,17 @@ /* Private variables ---------------------------------------------------------*/ static uint32_t actualAddress = 0; +static uint32_t preparedPageAddress = 0; +static uint32_t closeSectorAddress = 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 actualPointerDevicedata = DDSTART; +static uint32_t actualPointerDevicedata_Read = DDSTART; static uint32_t actualPointerVPM = 0; -static uint32_t actualPointerSettings = 0; +static uint32_t actualPointerSettings = SETTINGSSTART; static uint32_t actualPointerFirmware = 0; static uint32_t actualPointerFirmware2 = 0; @@ -392,18 +395,24 @@ #ifndef BOOTLOADER_STANDALONE -void ext_flash_write_devicedata(void) +void ext_flash_write_devicedata(uint8_t resetRing) { uint8_t *pData; const uint16_t length = sizeof(SDevice); uint8_t length_lo, length_hi; uint8_t dataLength[2] = { 0 }; + uint32_t tmpBlockStart; ext_flash_disable_protection(); pData = (uint8_t *)stateDeviceGetPointer(); - actualPointerDevicedata = DDSTART; + /* Reset the Ring to the start address if requested (e.g. because we write the default block during shutdown) */ + if((resetRing) || ((actualPointerDevicedata + length) >= DDSTOP)) + { + actualPointerDevicedata = DDSTART; + } + tmpBlockStart = actualPointerDevicedata; length_lo = (uint8_t)(length & 0xFF); length_hi = (uint8_t)(length >> 8); @@ -412,6 +421,9 @@ ef_write_block(dataLength,2, EF_DEVICEDATA, 0); ef_write_block(pData,length, EF_DEVICEDATA, 0); + + actualPointerDevicedata_Read = tmpBlockStart; + } @@ -420,20 +432,37 @@ uint16_t length; uint8_t length_lo, length_hi; - actualAddress = DDSTART; + actualAddress = actualPointerDevicedata_Read; + length = 0; + length_lo = 0; + length_hi = 0; 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); + while ((length_lo != 0xFF) && (length_hi != 0xFF)) + { + 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(&length_lo, EF_DEVICEDATA); /* check if another devicedata set is available */ + ext_flash_read_block(&length_hi, EF_DEVICEDATA); /* length will be 0xFFFF if a empty memory is read */ + } + ext_flash_decf_address_ring(EF_DEVICEDATA); /* set pointer back to empty address */ + ext_flash_decf_address_ring(EF_DEVICEDATA); ext_flash_read_block_stop(); - + + if(actualAddress > actualPointerDevicedata) /* the write pointer has not yet been set up probably */ + { + actualPointerDevicedata = actualAddress; + } return length; } @@ -493,7 +522,7 @@ return; } #else -void ext_flash_write_settings(void) +void ext_flash_write_settings(uint8_t resetRing) { uint8_t *pData; const uint16_t length = sizeof(SSettings); @@ -511,7 +540,11 @@ pData = (uint8_t *)settingsGetPointer(); - actualPointerSettings = SETTINGSSTART; + /* Reset the Ring to the start address if requested (e.g. because we write the default block during shutdown) */ + if((resetRing) || ((actualPointerSettings + length) >= SETTINGSSTOP)) + { + actualPointerSettings = SETTINGSSTART; + } length_lo = (uint8_t)(length & 0xFF); length_hi = (uint8_t)(length >> 8); @@ -548,23 +581,36 @@ 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) + while ((length_lo != 0xFF) && (length_hi != 0xFF)) /* get the latest stored setting block */ { - ext_flash_read_block_multi(&header, 4, EF_SETTINGS); - if((header <= pSettings->header) && (header >= pSettings->updateSettingsAllowedFromHeader)) + lengthOnEEPROM = length_hi * 256; + lengthOnEEPROM += length_lo; + if(lengthOnEEPROM <= lengthStandardNow) { - 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); + 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; + } } - else - { - returnValue = HAL_ERROR; - } + ext_flash_read_block(&length_lo, EF_SETTINGS); + ext_flash_read_block(&length_hi, EF_SETTINGS); + } + ext_flash_decf_address_ring(EF_SETTINGS); /* set pointer back to empty address */ + ext_flash_decf_address_ring(EF_SETTINGS); + ext_flash_read_block_stop(); + + if(actualAddress > actualPointerSettings) /* the write pointer has not yet been set up probably */ + { + actualPointerSettings = actualAddress; } ext_flash_read_block_stop(); return returnValue; @@ -614,7 +660,7 @@ void ext_flash_create_new_dive_log(uint8_t *pHeaderPreDive) { SSettings *settings; - uint8_t id, id_next; + uint8_t id; uint8_t header1, header2; settings = settingsGetPointer(); @@ -622,10 +668,12 @@ 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(&header1, EF_SAMPLE); /* the sample ring is increased instead of header... not sure if that is planned intention */ + ext_flash_read_block(&header2, EF_SAMPLE); /* does not matter because actual address is reset in write_block call */ ext_flash_read_block_stop(); + /* TODO Cleanup_Ref_2: The code below should not be necessary in case of a proper shutdown and startup */ + /* the implementation fixes an issue which might happen at Cleanup_Ref_1 (in case of more then 254 dives) */ if((header1 == 0xFA) && (header2 == 0xFA)) { id += 1; /* 0-255, auto rollover */ @@ -645,11 +693,6 @@ 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); @@ -726,10 +769,28 @@ void ext_flash_write_sample(uint8_t *pSample, uint16_t length) { + uint32_t actualAdressBackup = 0; + ef_write_block(pSample,length, EF_SAMPLE, 0); SSettings *settings = settingsGetPointer(); settings->logFlashNextSampleStartAddress = actualPointerSample; + + if(0xFFFF - (actualAddress & 0x0000FFFF) < 255) /* are we close to a sector border? */ + { + if (((actualAddress & 0x0000FFFF) != 0) && (preparedPageAddress == 0)) /* only prepare if not already at start of sector */ + { + actualAdressBackup = actualAddress; + actualAddress = (actualAddress & 0xFFFF0000) + 0x00010000; /* Set to start of next 64k sector */ + if(actualAddress >= SAMPLESTOP) + { + actualAddress = SAMPLESTART; + } + preparedPageAddress = actualAddress; + ext_flash_erase64kB(); + actualAddress = actualAdressBackup; + } + } } static void ext_flash_overwrite_sample_without_erase(uint8_t *pSample, uint16_t length) @@ -1316,16 +1377,16 @@ 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)) + if((header1 == 0xFA) && (header2 == 0xFA)) /* Header is indicating the start of a dive */ { 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)) + if((header1 != 0xFA) || (header2 != 0xFA)) /* Secondary header was not written at the end of a dive */ { - actualPointerSample = dataStart.u32bit; + actualPointerSample = dataStart.u32bit; /* Set datapointer to position stored in header written at beginning of dive */ actualAddress = actualPointerSample; logbook_recover_brokenlog(id); SSettings *settings = settingsGetPointer(); @@ -1343,6 +1404,9 @@ uint8_t header1, header2; convert_Type dataStart, dataEnd; + /* TODO Cleanup_Ref_1: cleanup logFlashNextSampleStartAddress and lastDiveLogId */ + /* The implementation below would cause problems in case more then 254 dives would be done. */ + /* This is avoided by Cleanup_Ref2 */ for(id = 0; id < 255;id++) { actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET; @@ -1578,7 +1642,7 @@ ext_flash_erase4kB(); return 1; } - } + } else if(actualAddress < 0x00010000) { @@ -1588,16 +1652,25 @@ ext_flash_erase32kB(); return 1; } - } + } else { /* 64K Byte is 0x10000 */ if((actualAddress & 0xFFFF) == 0) { - ext_flash_erase64kB(); + 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; } @@ -1633,7 +1706,8 @@ 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; @@ -1688,7 +1762,7 @@ if(do_not_erase == 0) ext_flash_erase_if_on_page_start(); - for(uint32_t i=0;i<length;i++) + while( i<length) { ef_hw_rough_delay_us(5); wait_chip_not_busy(); @@ -1697,12 +1771,24 @@ write_address(HOLDCS); remaining_length = length - i; - remaining_page_size = actualAddress & 0xFF; + remaining_page_size = 0xFF - (uint8_t)(actualAddress & 0xFF) +1; remaining_space_to_ring_end = ringStop - actualAddress; - if((remaining_page_size == 0) && (remaining_length >= 256) && (remaining_space_to_ring_end >= 256)) + if(remaining_length >= 256) + { + remaining_length = 255; /* up to 256 bytes may be written in one burst. Last byte is written with release */ + } + else { - for(int j=0; j<255; j++) + 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++; @@ -1712,8 +1798,11 @@ /* 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(); } @@ -2026,6 +2115,131 @@ { } } + +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; + } +} + +uint32_t ext_flash_AnalyseSampleBuffer(char *pstrResult) +{ + uint8_t sectorState[16]; /* samples are stored in 16 sector / 64k each */ + uint32_t curAddress = SAMPLESTART; + uint8_t curSector = 0; + uint8_t samplebuffer[10]; + uint32_t actualAddressBackup = actualAddress; + uint8_t emptyCellCnt = 0; + uint32_t i = 0; + uint8_t startedSectors = 0; + uint8_t lastSectorInuse = 0; + +/* check if a sector is used till its end */ + for(curSector = 0; curSector < 16; curSector++) + { + sectorState[curSector] = 0; + emptyCellCnt = 0; + curAddress = SAMPLESTART + (curSector * 0x10000); /* set address to begin of sector and check if it is used */ + actualAddress = curAddress; + ext_flash_read_block_start(); + for(uint32_t i=0;i<10;i++) + { + samplebuffer[i] = read_spi(HOLDCS);/* read data */ + if(samplebuffer[i] == 0xFF) + { + emptyCellCnt++; + } + } + ext_flash_read_block_stop(); + if(emptyCellCnt == 10) + { + sectorState[curSector] = SECTOR_NOTUSED; + } + emptyCellCnt = 0; + curAddress = SAMPLESTART + (curSector * 0x10000) + 0xFFF5; /* set address to end of sector and check if it is used */ + actualAddress = curAddress; + ext_flash_read_block_start(); + for(i=0;i<10;i++) + { + samplebuffer[i] = read_spi(HOLDCS);/* read data */ + if(samplebuffer[i] == 0xFF) + { + emptyCellCnt++; + } + } + ext_flash_read_block_stop(); + if(emptyCellCnt == 10) + { + sectorState[curSector] |= SECTOR_INUSE; /* will become SECTOR_EMPTY if start is NOTUSED */ + } + } + + for(i=0;i<16;i++) + { + if( sectorState[i] == SECTOR_INUSE) + { + startedSectors++; + lastSectorInuse = i; + } + *(pstrResult+i) = sectorState[i] + 48; + } + + if(startedSectors > 1) /* more than one sector is in used => ring buffer corrupted */ + { + if(startedSectors == 2) /* only fix issue if only two sectors are in used. Otherwise fixing will cause more worries than help */ + { + /* the logic behind healing of the problem is that the larger address is the oldest one => restore the largest address */ + curAddress = SAMPLESTART + (lastSectorInuse * 0x10000); + emptyCellCnt = 0; + actualAddress = curAddress; + ext_flash_read_block_start(); + while((emptyCellCnt < 10) && (actualAddress < curAddress + 0x10000)) + { + samplebuffer[0] = read_spi(HOLDCS);/* read data */ + if(samplebuffer[0] == 0xFF) + { + emptyCellCnt++; + } + else + { + emptyCellCnt = 0; + } + actualAddress++; + } + ext_flash_read_block_stop(); + actualAddress -= 10; /* step 10 bytes back to the start of free bytes */ + actualPointerSample = actualAddress; + + closeSectorAddress = settingsGetPointer()->logFlashNextSampleStartAddress & 0xFFFF0000; + closeSectorAddress += 0xFFF5; /* to be used once next time a dive is logged. Needed because NextSampleID is derived at every startup */ + settingsGetPointer()->logFlashNextSampleStartAddress = actualPointerSample; /* store new position to be used for next dive */ + } + } + actualAddress = actualAddressBackup; + *(pstrResult+i) = 0; + return startedSectors; +} + /* uint8_t ext_flash_erase_firmware_if_not_empty(void) {