Informacje odnoście metody jaką należy zastosować można znaleźć w nocie aplikacyjnej AN3969.
[Źródłó: http://www.st.com/en/evaluation-tools/stm32f4discovery.html]
Opis:
Do zapisu danych dostępne są dwa bloki o numerach 2 i 3, każdy o wielkości 16kByte. Pozwala to na uzyskanie pamięci w której można przechowywać ustawienia konfiguracyjne itp.
Adresy startowe bloków to odpowiednio 0x08008000 oraz 0x800C0000. Rozmiar sektora wynosi 0x4000.
Zapis danych musi być poprzedzony ich wyczyszczeniem.
Program:
Do przygotowania poniższych kodów wykorzystałem przykłady od firmy ST.
Funkcja inicjalizująca całą pamięć, oraz sprawdzająca poprawność jej uruchomienia:
- uint8_t Internal_FLASH_Init(void)
- {
- uint16_t PageStatus0;
- uint16_t PageStatus1;
- uint16_t indexLoop;
- int16_t x = -1;
- int32_t read_value;
- uint16_t dat;
- /* Unlocks the FLASH control register access */
- FLASH_Unlock();
- /* Write page adress */
- PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
- PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
- /* Check status */
- if(PageStatus0 == MEMORY_ERASED)
- {
- if (PageStatus1 == MEMORY_VALID_PAGE)
- {
/* First sector to erase, set voltage level */
- if(FLASH_EraseSector(PAGE0_ID,(uint8_t)VoltageRange_3) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- else if (PageStatus1 == MEMORY_RECEIVE_DATA)
- {
- if(FLASH_EraseSector(PAGE0_ID, (uint8_t)VoltageRange_3) != FLASH_COMPLETE){
- return 0; /* Error */
- }
- if(FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, MEMORY_VALID_PAGE) != FLASH_COMPLETE){
- return 0; /* Error */
- }
- }
- else
- {
- if (Internal_Flash_Format() != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- }
- else if(PageStatus0 == MEMORY_RECEIVE_DATA)
- {
- if (PageStatus1 == MEMORY_VALID_PAGE)
- {
- x=-1;
- for (indexLoop = 0; indexLoop < FLASH_MAX_ADDRESS; indexLoop++)
- {
- if (( *(__IO uint16_t*)(PAGE0_BASE_ADDRESS + 6)) == indexLoop) { x = indexLoop; }
- if (indexLoop != x)
- {
- read_value = Internal_FLASH_Read(indexLoop);
- if (read_value >= 0)
- {
- dat=(uint16_t)(read_value);
- if (Internal_Flash_VerifyPage(indexLoop, dat) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- }
- }
- if(FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, MEMORY_VALID_PAGE) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- if(FLASH_EraseSector(PAGE1_ID, (uint8_t)VoltageRange_3) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- else if (PageStatus1 == MEMORY_ERASED)
- {
- if(FLASH_EraseSector(PAGE1_ID, (uint8_t)VoltageRange_3) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- if(FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, MEMORY_VALID_PAGE) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- else
- {
- if(Internal_Flash_Format() != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- }
- else if(PageStatus0 == MEMORY_VALID_PAGE)
- {
- if (PageStatus1 == MEMORY_VALID_PAGE)
- {
- if(Internal_Flash_Format() != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- else if (PageStatus1 == MEMORY_ERASED)
- {
- if(FLASH_EraseSector(PAGE1_ID, (uint8_t)VoltageRange_3) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- else
- {
- x=-1;
- for (indexLoop = 0; indexLoop < FLASH_MAX_ADDRESS; indexLoop++)
- {
- if ((*(__IO uint16_t*)(PAGE1_BASE_ADDRESS + 6)) == indexLoop)
- {
- x = indexLoop;
- }
- if (indexLoop != x)
- {
- read_value = Internal_FLASH_Read(indexLoop);
- if (read_value >= 0)
- {
- dat=(uint16_t)(read_value);
- if(Internal_Flash_VerifyPage(indexLoop, dat) != FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- }
- }
- if(FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, MEMORY_VALID_PAGE)!= FLASH_COMPLETE) {
- return 0; /* Error */
- }
- if(FLASH_EraseSector(PAGE0_ID, (uint8_t)VoltageRange_3)!= FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- }
- else
- {
- if(Internal_Flash_Format()!= FLASH_COMPLETE) {
- return 0; /* Error */
- }
- }
- return 1;
- }
Odczyt z pamięci Flash.
- uint16_t Internal_FLASH_Read(uint16_t readAddress)
- {
- uint16_t return_value=0;
- uint16_t value = 0;
- uint16_t checkPage = 0;
- uint16_t AddressValue = 0;
- uint32_t Address = 0;
- uint32_t PageStartAddress = 0;
- if(readAddress>=FLASH_MAX_ADDRESS){ return 0; /* Error*/ }
- checkPage=Internal_Flash_CheckValidPage(READ_FROM_PAGE);
- if(checkPage==MEMORY_PAGE0)
- {
- PageStartAddress = (uint32_t)PAGE0_BASE_ADDRESS;
- Address = (uint32_t)(PAGE0_END_ADDRESS-1);
- }
- else if(checkPage==MEMORY_PAGE1)
- {
- PageStartAddress = (uint32_t)PAGE1_BASE_ADDRESS;
- Address = (uint32_t)(PAGE1_END_ADDRESS-1);
- }
- else
- {
- return 0; /* Error*/
- }
- while (Address > (PageStartAddress + 2))
- {
- AddressValue = (*(volatile uint16_t*)Address);
- if (AddressValue == readAddress)
- {
- value = (*(volatile uint16_t*)(Address - 2));
- return_value=0;
- break;
- }
- else
- {
- Address = Address - 4;
- }
- }
- if(return_value==0) {
- return (uint16_t)value;
- }
- return return_value;
- }
Zapis danych do pamięci:
- uint8_t Internal_FLASH_Write(uint16_t Address, uint16_t Data)
- {
- uint16_t Status = MEMORY_NO_ERROR;
- if(Address>=FLASH_MAX_ADDRESS) { return 1; }
- if(Internal_Flash_VerifyPage(Address, Data) == MEMORY_PAGE_FULL) {
- if(Internal_Flash_TranferPage(Address, Data) != FLASH_COMPLETE) {
- return 2;
- }
- }
- return 0;
- }
Pozostałe funkcje są funkcjami statycznymi. Zostały one zdefiniowane bezpośrednio w bibliotece.
Cały kod można pobrać z dysku Google pod tym linkiem.