Skocz do zawartości

Pamięci FRAM SPI i STM32F103x


FlyingDutch

Pomocna odpowiedź

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:

STM32F103RB_Pinout.thumb.gif.64978b113c8fd44ff7b38752a4d31bbb.gif

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:

Schematic_STMF103-FRAMCypressSPI_Shee.png

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 przez FlyingDutch
  • Lubię! 2
Link do komentarza
Share on other sites

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

  • Lubię! 1
Link do komentarza
Share on other sites

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!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.