FlyingDutch Napisano Luty 13, 2019 Udostępnij Napisano Luty 13, 2019 (edytowany) Cześć, jakiś czas temu zrobiłem próbę z pamięcią FRAM firmy Cypress typu: FM25L16B (Pamięć FRAM, szeregowa, 16Kb, 2Kbx8, interfejs SPI, obudowa SO8) z płytką "Arduino UNO". Link do postu tutaj: Docelowo potrzebowałem użyć tych pamięci w projekcie opartym na bibliotece SPL z MCU STM32F103VGTx. Pomimo poszukiwań w internecie nie znalazłem działającej biblioteki wykorzystującej ten typ pamięci z MCU STM32F103x i współpracującej z firmware STM32F1 opartym na "Standard Peripheral Library". Niestety "odziedziczyłem" część kodu dla systemu opartego na procesorach STM32F103 (kilka typów płytek połączonych magistralą CAN w jeden system) jako wynik grantu badawczego z UTP w moim mieście. System ten jest zbyt rozbudowany, żeby opłacało mi się przepisywać całość na HAL'a lub LL, zresztą nie widzę takiej potrzeby ponieważ kod jest dobrze napisany. Potrzebuję pamięci FRAM do rejestracji parametrów pracy systemu w długim czasie, oraz zapisu danych konfiguracyjnych. Właściwie to potrzebowałem obsłużyć dwa typy pamięci FRAM z interfejsem SPI różniących się pojemnościami - jedna 2Kx8bit, a druga 32Kx8bit (firm Cypress i Fujitsu : na jednym typie płytek jest mniejsza pamięć a na drugim ta o większej pojemności). Typy tych pamięci to: 1) FM25L16B firmy Cypress (2KB) 2) MB85RS256 firmy Fujitsu(32KB) Te dwa typy zostały wybrane ponieważ mają taką samą magistralę komunikacyjną SPI, zbliżone parametry elektryczne (także PINOUT i max. prędkość transmisji) oraz budowę programową (zgodność nawet co do kodów operacji). Tutaj wklejam datasheets dla tych dwóch typów pamięci: FM25L16B_FRAM_Cypress.pdf FRAM_MB85RS256fs.pdf Postanowiłem użyć jako punktu wyjścia biblioteki Adafruit do obsługi FRAM opisanej we wcześniejszym poście dot. Arduino. Ponieważ docelowe płytki projektu są bardzo skomplikowane, postanowiłem do prac nad wersją bibliotek dla STM32F103 (SPL) użyć zestawu uruchomieniowego STM32 NUCLEO-F103RB: https://botland.com.pl/pl/stm32-nucleo/2238-stm32-nucleo-f103rb-stm32f103rbt6-arm-cortex-m3.html Tutaj PINOUT dla tej płytki: Jako IDE i kompilator użyłem darmowego "System Workbench for STM32" (najnowsza wersja), pomocniczo używałem też aplikacji "STM32CubeMX" (najnowsza wersja) - OS Windows10. Ponieważ działająca wersja biblioteki dla FRAM Cypress była napisana obiktowo (klasa C++). Najpierw przerobiłem ten kod na wersję obiektową C++ dla podanego zestawu uruchomieniowego. Wybrałem SPI1 z STM32F103 - tutaj użyte piny: uint8_t FRAM_CS = 0; //port C - PC0 uint8_t FRAM_SCK = 5; //PA5 uint8_t FRAM_MISO = 6; //PA6 uint8_t FRAM_MOSI = 7; //PA7 Piny WP i HOLD (aktywne LOW) FRAM podpięte na stałe do VCC (+3,3V). Podaję kod biblioteki: 1) Adafruit_FRAM_SPI.h: #ifndef _ADAFRUIT_FRAM_SPI_H_ #define _ADAFRUIT_FRAM_SPI_H_ #include "stm32f1xx_it.h" #include "stm32f1xx_nucleo.h" #include "stm32f10x_conf.h" #include "stm32f10x_spi.h" #include <stdbool.h> typedef enum opcodes_e { OPCODE_WREN = 0b00000110, /* Write Enable Latch */ OPCODE_WRDI = 0b00000100, /* Reset Write Enable Latch */ OPCODE_RDSR = 0b00000101, /* Read Status Register */ OPCODE_WRSR = 0b00000001, /* Write Status Register */ OPCODE_READ = 0b00000011, /* Read Memory */ OPCODE_WRITE = 0b00000010, /* Write Memory */ OPCODE_RDID = 0b10011111 /* Read Device ID */ //Dla pamiÄ™ci FRAM firmy Cypress - niedostepne } opcodes_t; class Adafruit_FRAM_SPI { public: Adafruit_FRAM_SPI(); Adafruit_FRAM_SPI(int8_t cs); Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi, int8_t cs); bool begin (); bool begin (uint8_t nAddressSizeBytes); bool begin (int8_t cs, uint8_t nAddressSizeBytes); void writeEnable (bool enable); void write8 (uint32_t addr, uint8_t value); void write (uint32_t addr, const uint8_t *values, size_t count); uint8_t read8 (uint32_t addr); void read (uint32_t addr, uint8_t *values, size_t count); void getDeviceID(uint8_t *manufacturerID, uint16_t *productID); uint8_t getStatusRegister(void); void setStatusRegister(uint8_t value); void setAddressSize(uint8_t nAddressSize); private: uint8_t SPItransfer(uint8_t x); void writeAddress(uint32_t addr); uint8_t spi_sendrecv(uint8_t byte); //Wyslij Odbierz dane po SPI void spiConfiguration(void); //Konfiguracja sprzetowa SPI bool _framInitialised; uint8_t _nAddressSizeBytes; int8_t _cs, _clk, _mosi, _miso; }; #endif 2) Adafruit_FRAM_SPI.cpp: #include <stdlib.h> #include <math.h> #include "Adafruit_FRAM_SPI.h" /*========================================================================*/ /* PRIVATE FUNCTIONS */ /*========================================================================*/ void Adafruit_FRAM_SPI::spiConfiguration(void) { GPIO_InitTypeDef gpio; SPI_InitTypeDef spi; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; // SCK, MOSI gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_6; // MISO gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_0; // CS gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &gpio); GPIO_SetBits(GPIOC, GPIO_Pin_0); SPI_StructInit(&spi); spi.SPI_Mode = SPI_Mode_Master; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; SPI_Init(SPI1, &spi); SPI_Cmd(SPI1, ENABLE); GPIO_ResetBits(GPIOC, GPIO_Pin_0); spi_sendrecv(0x40); GPIO_SetBits(GPIOC, GPIO_Pin_0); } /* OLD uint8_t Adafruit_FRAM_SPI::spi_sendrecv(uint8_t byte) { // poczekaj az bufor nadawczy bedzie wolny while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_SendData8(SPI1, byte); // poczekaj na dane w buforze odbiorczym while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_ReceiveData8(SPI1); } */ uint8_t Adafruit_FRAM_SPI::spi_sendrecv(uint8_t byte) { // poczekaj az bufor nadawczy bedzie wolny while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, byte); // poczekaj na dane w buforze odbiorczym while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); } /*========================================================================*/ /* CONSTRUCTORS */ /*========================================================================*/ /**************************************************************************/ /*! Constructor */ /**************************************************************************/ Adafruit_FRAM_SPI::Adafruit_FRAM_SPI() { _cs = _clk = _mosi = _miso = -1; _framInitialised = false; } Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t cs) { _cs = cs; _clk = _mosi = _miso = -1; _framInitialised = false; } Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi, int8_t cs) { _cs = cs; _clk = clk; _mosi = mosi; _miso = miso; _framInitialised = false; } /*========================================================================*/ /* PUBLIC FUNCTIONS */ /*========================================================================*/ /**************************************************************************/ /*! Initializes SPI and configures the chip (call this function before doing anything else) */ /**************************************************************************/ bool Adafruit_FRAM_SPI::begin() { return begin(_cs, 2); } bool Adafruit_FRAM_SPI::begin(uint8_t nAddressSizeBytes) { return begin(_cs, nAddressSizeBytes); } bool Adafruit_FRAM_SPI::begin(int8_t cs, uint8_t nAddressSizeBytes) { if (cs == -1) { //Serial.println("No cs pin specified!"); return false; } _cs = cs; setAddressSize(nAddressSizeBytes); /* Configure SPI */ // pinMode(_cs, OUTPUT); //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0); //CS this->spiConfiguration(); /* Everything seems to be properly initialised and connected */ _framInitialised = true; return true; } /**************************************************************************/ /*! @brief Enables or disables writing to the SPI flash @params[in] enable True enables writes, false disables writes */ /**************************************************************************/ void Adafruit_FRAM_SPI::writeEnable (bool enable) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS if (enable) { SPItransfer(OPCODE_WREN); } else { SPItransfer(OPCODE_WRDI); } //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Writes a byte at the specific FRAM address @params[in] addr The 32-bit address to write to in FRAM memory @params[in] i2cAddr The 8-bit value to write at framAddr */ /**************************************************************************/ void Adafruit_FRAM_SPI::write8 (uint32_t addr, uint8_t value) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_WRITE); writeAddress(addr); SPItransfer(value); /* CS on the rising edge commits the WRITE */ //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Writes count bytes starting at the specific FRAM address @params[in] addr The 32-bit address to write to in FRAM memory @params[in] values The pointer to an array of 8-bit values to write starting at addr @params[in] count The number of bytes to write */ /**************************************************************************/ void Adafruit_FRAM_SPI::write (uint32_t addr, const uint8_t *values, size_t count) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_WRITE); writeAddress(addr); for (size_t i = 0; i < count; i++) { SPItransfer(values[i]); } /* CS on the rising edge commits the WRITE */ //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Reads an 8 bit value from the specified FRAM address @params[in] addr The 32-bit address to read from in FRAM memory @returns The 8-bit value retrieved at framAddr */ /**************************************************************************/ uint8_t Adafruit_FRAM_SPI::read8 (uint32_t addr) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_READ); writeAddress(addr); uint8_t x = SPItransfer(0); //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS return x; } /**************************************************************************/ /*! @brief Read count bytes starting at the specific FRAM address @params[in] addr The 32-bit address to write to in FRAM memory @params[out] values The pointer to an array of 8-bit values to read starting at addr @params[in] count The number of bytes to read */ /**************************************************************************/ void Adafruit_FRAM_SPI::read (uint32_t addr, uint8_t *values, size_t count) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_READ); writeAddress(addr); for (size_t i = 0; i < count; i++) { uint8_t x = SPItransfer(0); values[i] = x; } //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Reads the Manufacturer ID and the Product ID from the IC @params[out] manufacturerID The 8-bit manufacturer ID (Fujitsu = 0x04) @params[out] productID The memory density (bytes 15..8) and proprietary Product ID fields (bytes 7..0). Should be 0x0302 for the MB85RS64VPNF-G-JNERE1. */ /**************************************************************************/ void Adafruit_FRAM_SPI::getDeviceID(uint8_t *manufacturerID, uint16_t *productID) { uint8_t a[4] = { 0, 0, 0, 0 }; //uint8_t results; GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_RDID); a[0] = SPItransfer(0); a[1] = SPItransfer(0); a[2] = SPItransfer(0); a[3] = SPItransfer(0); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS /* Shift values to separate manuf and prod IDs */ /* See p.10 of http://www.fujitsu.com/downloads/MICRO/fsa/pdf/products/memory/fram/MB85RS64V-DS501-00015-4v0-E.pdf */ *manufacturerID = (a[0]); *productID = (a[2] << 8) + a[3]; } /**************************************************************************/ /*! @brief Reads the status register */ /**************************************************************************/ uint8_t Adafruit_FRAM_SPI::getStatusRegister(void) { uint8_t reg = 0; GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_RDSR); reg = SPItransfer(0); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS return reg; } /**************************************************************************/ /*! @brief Sets the status register */ /**************************************************************************/ void Adafruit_FRAM_SPI::setStatusRegister(uint8_t value) { GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_WRSR); SPItransfer(value); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } void Adafruit_FRAM_SPI::setAddressSize(uint8_t nAddressSize) { _nAddressSizeBytes = nAddressSize; } uint8_t Adafruit_FRAM_SPI::SPItransfer(uint8_t x) { return spi_sendrecv(x); /* if (_clk == -1) { //return SPI.transfer(x); return spi_sendrecv(x); } else { // Serial.println("Software SPI"); uint8_t reply = 0; for (int i=7; i>=0; i--) { reply <<= 1; //digitalWrite(_clk, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS //digitalWrite(_mosi, x & (1<<i)); if ((x & (1<<i)) > 0) GPIO_SetBits(GPIOA, GPIO_Pin_7); //MOSI else GPIO_ResetBits(GPIOA, GPIO_Pin_7); //MOSI //digitalWrite(_clk, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS //if (digitalRead(_miso)) if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == 1) reply |= 1; } return reply; } */ } void Adafruit_FRAM_SPI::writeAddress(uint32_t addr) { if (_nAddressSizeBytes>3) SPItransfer((uint8_t)(addr >> 24)); if (_nAddressSizeBytes>2) SPItransfer((uint8_t)(addr >> 16)); SPItransfer((uint8_t)(addr >> 8)); SPItransfer((uint8_t)(addr & 0xFF)); } 3) main.cpp; /** ****************************************************************************** * @file main.c * @author Ac6 * @version V1.0 * @date 01-December-2013 * @brief Default main function. ****************************************************************************** */ #include "stm32f10x.h" #include "stm32f1xx_nucleo.h" #include <stdlib.h> #include <math.h> #include "UART_Init.h" #include "Adafruit_FRAM_SPI.h" /* Example code to interrogate SPI FRAM chip for address size and storage capacity */ uint8_t FRAM_CS = 0; //port C //Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS); // use hardware SPI uint8_t FRAM_SCK = 5; uint8_t FRAM_MISO = 6; uint8_t FRAM_MOSI = 7; //Or use software SPI, any pins! Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS); uint8_t addrSizeInBytes = 2; //Default to address size of two bytes uint32_t memSize; int32_t readBack(uint32_t addr, int32_t data) { int32_t check = !data; int32_t wrapCheck, backup; fram.read(addr, (uint8_t*)&backup, sizeof(int32_t)); fram.writeEnable(true); fram.write(addr, (uint8_t*)&data, sizeof(int32_t)); fram.writeEnable(false); fram.read(addr, (uint8_t*)&check, sizeof(int32_t)); fram.read(0, (uint8_t*)&wrapCheck, sizeof(int32_t)); fram.writeEnable(true); fram.write(addr, (uint8_t*)&backup, sizeof(int32_t)); fram.writeEnable(false); // Check for warparound, address 0 will work anyway if (wrapCheck==check) check = 0; return check; } bool testAddrSize(uint8_t addrSize) { fram.setAddressSize(addrSize); if (readBack(16, 0xbeefbead) == 0xbeefbead) return true; return false; } //-------- Main loop ------------------------------------------------ int main(void) { Init_UART2(); //9600 bodow send_string("Program started. \r\n"); if (fram.begin(FRAM_CS, addrSizeInBytes)) { send_string("Found SPI FRAM\r\n"); } else { send_string("No SPI FRAM found ... check your connections\r\n"); //while (1); } //test of writing all memory 2K uint8_t value; for (uint16_t a = 0; a < 2048; a++) { fram.writeEnable(true); if ((a % 2) == 0) { value=0xAA; fram.write8(a,value); //0b10101010 } else { value=0x55; fram.write8(a, value); //0b01010101 } fram.writeEnable(false); } // dump the entire 2K of memory! ------------------------ fram.writeEnable(false); for (uint16_t a = 0; a < 2048; a++) { value = fram.read8(a); char buffer[10]; itoa (value,buffer,16); send_string(buffer); send_string("\r\n"); } for(;;); } Tutaj spakowany cały projekt dla zestawu uruchomieniowego dla "System Workbench for STM32" FRAMCypressF103SPI.zip Projekt został przetestowany dla pamięci FRAM FM25L16B firmy Cypress i działa poprawnie. Niestety do rozwoju docelowego projektu sprzętowego używam IDE "ride7" wraz z kompilatorem "RKit-ARM for Ride7". Cały projekt jest napisany nieobiektowo w C i ten kompilator słabo sobie radzi z "mieszanym" kodem w C i C++ (zresztą nie chciałem niepotrzebnie dodawać C++ do tego projektu), więc napisałem nieobiektową wersję biblioteki do obsługi FRAM (poprzez prostą zamianę klasy na strukturę). Ze względu na objętość postu nie będę już tutaj wklejał kodu źródłowego, tylko zamieszczam spakowane archiwum z tą nieobiektową wersją biblioteki: FRAM_SPI_Struct.zip A tutaj spakowany projekt dla "System Workbench for STM32": FRAMCypressF103SPIStruct.zip Ta nieobiektowa wersja biblioteki została przetestowana zarówno z pamięcią FRAM firmy Cypress jak i Fujitsu (z podanym wcześniej zestawem uruchomieniowym) i działa poprawnie. W pliku main.c w funkcji main dla obu pętli for należy zmienić zakres zmiennej sterującej na 2048 dla pamięci Cypress (mniejsza pojemność pamięći). Patrz ten kod: int main(void) { Init_UART2(); //9600 bodow send_string("Program started. \r\n"); Adafruit_FRAM_SPI2(fram, FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS); if (begin2(fram, FRAM_CS, addrSizeInBytes)) { send_string("Found SPI FRAM\r\n"); } else { send_string("No SPI FRAM found ... check your connections\r\n"); //while (1); } //test of writing all memory 2K uint8_t value; //int value; for (uint16_t a = 0; a < 32767; a++) { writeEnable(true); if ((a % 2) == 0) { value=0xAA; write8(fram, a,value); //0b10101010 } else { value=0x55; write8(fram, a, value); //0b01010101 } //send_string("writing\r\n"); /* value=0xAA; write8(fram, a,value); //0b10101010 send_string("writing\r\n"); char buffer[3]; itoa (value,buffer,16); send_string(buffer); send_string("\r\n"); */ writeEnable(false); } // dump the entire 2K of memory! ------------------------ writeEnable(false); for (uint16_t a = 0; a < 32767; a++) { value = read8(fram, a); //send_string("reading\r\n"); /* if ((a % 32) == 0) { Serial.print("\n 0x"); Serial.print(a, HEX); Serial.print(": "); } Serial.print("0x"); if (value < 0x1) Serial.print('0'); */ char buffer[3]; itoa (value,buffer,16); send_string(buffer); send_string("\r\n"); } for(;;); } //end main UWAGA: pamięci FRAM wymagają bardzo stabilnego zasilania - dla pamięci firmy Fujitsu bez kondensatora (10 nF) pomiędzy GND i +Vcc odczyty z zapisanej pamięci mogą być przekłamane. Warto umieścić kondensator wygładzający zasilanie dla obu tych typów pamieći na płytce blisko samej kostki pamięci. Jestem już po próbach obu typów pamięci w docelowych płytkach projektu i zapis i odczyt działa poprawnie. Zdaję sobie sprawę, że można było pewnie ładniej napisać kod źródłówy - chętnie dowiem się o propozycjach ulepszeń. Teraz mam zamiar dodać automatyczne obliczanie sum kontrolnych dla przesyłanych bloków pamięci, oraz dodać kod zapewniający integralność danych przechowywanych w pamięci. Tutaj wklejam taki prymitywny schemat połączenia pamięci z zestawem uruchomieniowym: W rzeczywistości piny WP i HOLD są podpięte do plusa zasilania przez rezystor 500 om. Gdyby ktoś musiał zmienić pin CS (chip select - pamięci to należy to zrobić w kodzie biblioteki). Mam nadzieję, że podany kod może się komuś przydać w jego projekcie 😉 BTW: właśnie wypróbowałem liczenie sumy kontrolnej CRC32 (dla bufora 16 x liczba 32 bity - uint32_t) i działa to bardzo fajnie. STM32F103 posiada sprzętowy moduł liczenia sumy kontrolnej (w 4 taktach zegara) CRC-32. Patrz ta dokumentacja "CRC calculation unit": https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf Dodam sprawdzanie sum kontrolnych podczas zapisu i odczytu danych do/z FRAM do tej biblioteki w najbliższym czasie. Poza tym może użyję też jakiegoś prostszego kodu korekcyjnego (który poza sprawdzeniem integralności danych będzie też w stanie "naprawić" dane w przypadku mniejszych błędów). Pozdrawiam Edytowano Luty 14, 2019 przez FlyingDutch 2 Cytuj Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Luty 14, 2019 Udostępnij Luty 14, 2019 @FlyingDutch super, bardzo dziękuję za ciekawy materiał 🙂 Przy okazji podrzucam link do ogólnego artykułu na temat pamięci (gdyby ktoś nie znał FRAM): Kompendium pamięci zewnętrznych: EEPROM, FLASH, FRAM 1 Cytuj Link do komentarza Share on other sites More sharing options...
FlyingDutch Luty 20, 2019 Autor tematu Udostępnij Luty 20, 2019 Cześć, dzisiaj wypróbowałem zapis i odczyt z pamięci FRAM z kontrolą sumy CRC32 (obliczanej sprzętowo: moduł MCU STM32F103). Zapisuję liczby "unsigned long" - 32 bitowe (4bajty) w pamięci FRAM i dla każde3j takiej liczby sumę kontrolną CRC32, też liczba uint32_t.Najpierw liczę sumę CRC32 dla liczby uint32_t i zapamiętuję, potem za pomocą operacji przesunięć bitowych dzielę tą liczbę na cztery bajty typ "uint8_t" (pamięć FRAM ma organizację bajtową) i zapisuję w czterech komórkach pamięci. Potem odczytuję te cztery zapisane komórki - łączę za pomocą przesunięć bitowych i operacji sumy bitowej i ponownie obliczam sumę CRC32 (z liczby uint32_t), Jeśli te dwie sumy CRC są różne powtarzam zapis całej 4-ro bajtowej liczby jeszcze 3 razy. Jeśli 4 próby zapisu kończą się niepowiedzeniem sygnalizuję błąd pamięci FRAM i przerywam program. Jutro może wrzucę zmodyfikowany kod biblioteki dla FRAM rozszerzonej o te funkcje. Pozdrawim 1 Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!