STM32F439Zi – SPI 8KB FRAM ADA1897/MB85RS64B with USART


Using an ADA1897/MB85RS64B for Storage.

In this exciting tutorial, we’ll dive into the fascinating world of data storage by harnessing the power of the SPI 8KB FRAM ADA1897/MB85RS64B alongside the STM32F439Zi Nucleo Board. Imagine the possibilities! Whether you’re capturing vital data from sensors or storing any other information, this setup opens the door to a myriad of real-world applications. Dream about sending stunning images to an LCD Display Module, or effortlessly managing your application configuration parameters with ease. This is not just a tutorial; it’s a gateway to enhancing your technical skills and creativity! As you embark on this journey, remember that you’re part of a vibrant and collaborative community here at MicroControllersTech. We encourage you to explore, experiment, and share your experiences in our forums—because learning and troubleshooting are best done together! So, let’s get started and unlock new project possibilities that await you!



Materials List


FTDI Pinouts

FTDI to USB Pinout from right to left

  • Pin 1 – GND
  • Pin 2 – CTS
  • Pin 3 – VCC
  • Pin 4 – TX
  • Pin 5 – RX
  • Pin 6 – DTR
  • USB Mini – Connect to PC via USB cable

Make sure the jumper is set for 5v or 3v which ever is being used to power the FTDI device. If we look below at the schematic, it is showing in this case as 5v.


Adafruit SPI Non-Volatile FRAM Breakout – 64Kbit / 8KByte

FRAM Breakout board datasheet


Nucleo-STM32F439Zi Pin out Diagrams

The following website provides some of the best diagrams as a reference for pin outs to various STM32 boards. Although this link is for the F429zi board, it is compatible with the F439zi board.


Schematic for the SPI 8KB FRAM ADA1897/MB85RS64B for Storage Project


Pinouts & Configurations


Code Listings

C
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "ada1897_mb85rs64b.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

#ifdef REDIRECT_PRINTF
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#endif

#ifdef REDIRECT_PRINTF
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART2 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}
#endif
C
void testFRAM(uint16_t address) {
	char sendBuf[512] = {0x00};
	char recvBuf[512] = {0x00};
	char usartBuf[2000];

	sprintf(sendBuf, "1234567890");
	int len = strlen(sendBuf);

	printf("Starting the test!!!!\r\n\r\n");

	FRAM_init(&hspi1);

	printf("Finished Initialization!!!\r\n\r\n");

	printf("Writing %s to FRAM @ address 0x%4.4x\r\n", sendBuf, address);

	for (int i = 0; i <= len; i ++) {	// We want to write out the strings NULL termination
		FRAM_write((uint16_t) i + address, (uint8_t) sendBuf[i]);
	}

	printf("Now Reading from FRAM @ address 0x%4.4x\r\n", address);

	for (uint16_t i = 0; i <= len; i ++) {
		recvBuf[i] = FRAM_read(address + i);
	}

	sprintf(usartBuf, "Returned Data: %s\r\n\r\n", recvBuf);
	printf(usartBuf);

	char str[1024] = {0x00};
	char rStr[1024] = {0x00};

	sprintf(str, "Now is the time for kitties to have snacks!!!");
	len = strlen(str);

	printf("Writing to address 0x%4.4x:\r\n%s\r\n\r\n", address, str);

	FRAM_WriteBytes(address, (uint8_t *) str, len + 1);
	FRAM_ReadBytes(address, (uint8_t *) rStr, len + 1);

	sprintf(usartBuf, "Returned Data from address 0x%4.4x:\r\n%s\r\n\r\n", address, rStr);
	printf(usartBuf);


	sprintf(str, "If you want something done right, do it yourself.\r\nNo one can make you feel inferior without your consent.\r\nIf you want something done right, do it yourself.\r\n");
	len = strlen(str);

	printf("Writing to address 0x%4.4x:\r\n%s\r\n", address, str);

	FRAM_WriteBytes(address, (uint8_t *) str, len + 1);
	FRAM_ReadBytes(address, (uint8_t *) rStr, len + 1);

	sprintf(usartBuf, "Returned Data from address 0x%4.4x:\r\n%s\r\n\r\n", address, rStr);
	printf(usartBuf);

}
/* USER CODE END 0 */
C
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  uint16_t addresses[] = {0x0000, 0x0AFB, 0x0FE0, 0x1BE8, 0x1E10, 0x01F6, 0x00FF};

  printf("\x1b[2J\x1b[H");	// Clear the dumb terminal screen

  // Test the Chip Select LED
  FRAM_CS_DISABLE;

  FRAM_CS_ENABLE;
  HAL_Delay(2000);
  FRAM_CS_DISABLE;
  // End Testing the Chip Select LED

  int counter = 0;
  int addressCnt = sizeof(addresses) / sizeof(uint16_t);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  uint16_t address = addresses[counter];

	  testFRAM(address);

	  counter ++;

	  if (counter > (addressCnt - 1)) {
		  counter = 0;
	  }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_Delay(5000);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 180;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Activate the Over-Drive mode
  */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 19200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SPI1_FRAM_CS_GPIO_Port, SPI1_FRAM_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : SPI1_FRAM_CS_Pin */
  GPIO_InitStruct.Pin = SPI1_FRAM_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SPI1_FRAM_CS_GPIO_Port, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */


/**
 * @brief  This function is executed in case of error occurrence.
 * @param  file: The file name as string.
 * @param  line: The line in file as a number.
 * @retval None
 */
void _Error_Handler(const char *file, int line)
{
	/* USER CODE BEGIN Error_Handler_Debug */
	  __disable_irq();
#ifdef REDIRECT_PRINTF
	char buf[80];
	sprintf(buf, "Trapped in Error_Handler().  Called from: %s, line: %d\r\n", file, line);
	printf(buf);
#endif
	/* User can add his own implementation to report the HAL error return state */
	while(1)
	{
	}
}

/* USER CODE END 4 */

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
C
/*
 * ada1897_mb85rs64b.h
 *
 *  Created on: Nov 13, 2024
 *      Author: jpgroulx
 */

#ifndef ADA1897_MB85RS64B_H_
#define ADA1897_MB85RS64B_H_

#define FRAM_CS_ENABLE HAL_GPIO_WritePin(SPI1_FRAM_CS_GPIO_Port, SPI1_FRAM_CS_Pin, 0);
#define FRAM_CS_DISABLE HAL_GPIO_WritePin(SPI1_FRAM_CS_GPIO_Port, SPI1_FRAM_CS_Pin, 1);

void FRAM_init(SPI_HandleTypeDef *hspix);
void FRAM_write(uint16_t address, uint8_t byte);
uint8_t FRAM_read(uint16_t address);
void FRAM_WriteBytes(uint16_t address, uint8_t *pData, uint16_t size);
void FRAM_ReadBytes(uint16_t address, uint8_t *pData, uint16_t size);

#endif /* ADA1897_MB85RS64B_H_ */
C
/*
 * ada1897_mb85rs64b.c
 *
 *  Created on: Nov 13, 2024
 *      Author: jpgroulx
 */

#include "main.h"
#include "ada1897_mb85rs64b.h"

const uint8_t FRAM_WRSR		= 0b00000001;	// 0x01
const uint8_t FRAM_WRITE	= 0b00000010;	// 0x02
const uint8_t FRAM_READ		= 0b00000011;	// 0x03
const uint8_t FRAM_WRDI		= 0b00000100;	// 0x04
const uint8_t FRAM_RDSR		= 0b00000101;	// 0x05
const uint8_t FRAM_WREN		= 0b00000110;	// 0x06

SPI_HandleTypeDef *hspi;

void FRAM_init(SPI_HandleTypeDef *hspix)
{
	uint8_t spiCMD;
	HAL_StatusTypeDef halStatus = HAL_OK;

	hspi = hspix;

    spiCMD = FRAM_WRDI;	// 0x04
    FRAM_CS_ENABLE;
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);
    FRAM_CS_DISABLE;

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    spiCMD = FRAM_WREN;	// 0x06
    FRAM_CS_ENABLE;
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);
    FRAM_CS_DISABLE;

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    spiCMD = FRAM_WRSR;	// 0x01
    FRAM_CS_ENABLE;
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);
    FRAM_CS_DISABLE;

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    spiCMD = FRAM_RDSR;	// 0x05
    FRAM_CS_ENABLE;
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);
    FRAM_CS_DISABLE;

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }
}

void FRAM_write(uint16_t address, uint8_t byte)
{
	uint8_t spiCMD;
	uint8_t spiAddrByte;
	HAL_StatusTypeDef halStatus = HAL_OK;

	spiCMD = FRAM_WREN;
    FRAM_CS_ENABLE;
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);
    FRAM_CS_DISABLE;

    spiCMD = FRAM_WRITE;

    //enable Chip Select
    FRAM_CS_ENABLE;

    //send WRITE command
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send upper 8 bits of address
    spiAddrByte = ((address & 0x3f00) >> 8);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send lower 8 bits of address
    spiAddrByte = (address & 0x00ff);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //sent data byte
    halStatus = HAL_SPI_Transmit(hspi, &byte, sizeof(byte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //disable Chip Select
    FRAM_CS_DISABLE;
}

uint8_t FRAM_read(uint16_t address)
{
	uint8_t spiCMD;
	uint8_t spiAddrByte;
	uint8_t byte;
	HAL_StatusTypeDef halStatus = HAL_OK;

	spiCMD = FRAM_READ;

    //enable Chip Select
    FRAM_CS_ENABLE;

    //send READ command
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send upper 8 bits of address
    spiAddrByte = ((address & 0x3f00) >> 8);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send lower 8 bits of address
    spiAddrByte = (address & 0x00ff);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //receive data byte
    halStatus = HAL_SPI_Receive(hspi, &byte, sizeof(byte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //disable Chip Select
    FRAM_CS_DISABLE;

    return(byte);
}

void FRAM_WriteBytes(uint16_t address, uint8_t *pData, uint16_t size)
{
	uint8_t spiCMD;
	uint8_t spiAddrByte;
	HAL_StatusTypeDef halStatus = HAL_OK;

	spiCMD = FRAM_WREN;

    FRAM_CS_ENABLE;
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);
    FRAM_CS_DISABLE;

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    spiCMD = FRAM_WRITE;

    //enable Chip Select
    FRAM_CS_ENABLE;
    //send WRITE command
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send upper 8 bits of address
    spiAddrByte = ((address & 0x3f00) >> 8);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send lower 8 bits of address
    spiAddrByte = (address & 0x00ff);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //sent data byte
    halStatus = HAL_SPI_Transmit(hspi, pData, size, HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //disable Chip Select
    FRAM_CS_DISABLE;
}

void FRAM_ReadBytes(uint16_t address, uint8_t *pData, uint16_t size)
{
	uint8_t spiCMD;
	uint8_t spiAddrByte;
	HAL_StatusTypeDef halStatus = HAL_OK;

	spiCMD = FRAM_READ;

    //enable Chip Select
    FRAM_CS_ENABLE;

    //send READ command
    halStatus = HAL_SPI_Transmit(hspi, &spiCMD, sizeof(spiCMD), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send upper 8 bits of address
    spiAddrByte = ((address & 0x3f00) >> 8);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //send lower 8 bits of address
    spiAddrByte = (address & 0x00ff);
    halStatus = HAL_SPI_Transmit(hspi, &spiAddrByte, sizeof(spiAddrByte), HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //receive data byte
    halStatus = HAL_SPI_Receive(hspi, pData, size, HAL_MAX_DELAY);

    if (halStatus != HAL_OK) {
    	Error_Handler();
    }

    //disable Chip Select
    FRAM_CS_DISABLE;
}

USART Output

Starting the test!!!!

Finished Initialization!!!

Writing 1234567890 to FRAM @ address 0x0000
Now Reading from FRAM @ address 0x0000
Returned Data: 1234567890

Writing to address 0x0000:
Now is the time for kitties to have snacks!!!

Returned Data from address 0x0000:
Now is the time for kitties to have snacks!!!

Writing to address 0x0000:
If you want something done right, do it yourself.
No one can make you feel inferior without your consent.
If you want something done right, do it yourself.

Returned Data from address 0x0000:
If you want something done right, do it yourself.
No one can make you feel inferior without your consent.
If you want something done right, do it yourself.
                                                                                
                                                                                
Starting the test!!!!                                                           
                                                                                
Finished Initialization!!!                                                      
                                                                                
Writing 1234567890 to FRAM @ address 0x0afb                                     
Now Reading from FRAM @ address 0x0afb                                          
Returned Data: 1234567890                                                       
                                                                                
Writing to address 0x0afb:                                                      
Now is the time for kitties to have snacks!!!                                   
                                                                                
Returned Data from address 0x0afb:                                              
Now is the time for kitties to have snacks!!!                                   
                                                                                
Writing to address 0x0afb:                                                      
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
Returned Data from address 0x0afb:                                              
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
                                                                                
Starting the test!!!!                                                           
                                                                                
Finished Initialization!!!                                                      
                                                                                
Writing 1234567890 to FRAM @ address 0x0fe0                                     
Now Reading from FRAM @ address 0x0fe0                                          
Returned Data: 1234567890                                                       
                                                                                
Writing to address 0x0fe0:                                                      
Now is the time for kitties to have snacks!!!                                   
                                                                                
Returned Data from address 0x0fe0:                                              
Now is the time for kitties to have snacks!!!                                   
                                                                                
Writing to address 0x0fe0:                                                      
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
Returned Data from address 0x0fe0:                                              
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
                                                                                
Starting the test!!!!                                                           
                                                                                
Finished Initialization!!!                                                      
                                                                                
Writing 1234567890 to FRAM @ address 0x1be8                                     
Now Reading from FRAM @ address 0x1be8                                          
Returned Data: 1234567890                                                       
                                                                                
Writing to address 0x1be8:                                                      
Now is the time for kitties to have snacks!!!                                   
                                                                                
Returned Data from address 0x1be8:                                              
Now is the time for kitties to have snacks!!!                                   
                                                                                
Writing to address 0x1be8:                                                      
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
Returned Data from address 0x1be8:                                              
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
                                                                                
Starting the test!!!!                                                           
                                                                                
Finished Initialization!!!                                                      
                                                                                
Writing 1234567890 to FRAM @ address 0x1e10                                     
Now Reading from FRAM @ address 0x1e10                                          
Returned Data: 1234567890                                                       
                                                                                
Writing to address 0x1e10:                                                      
Now is the time for kitties to have snacks!!!                                   
                                                                                
Returned Data from address 0x1e10:                                              
Now is the time for kitties to have snacks!!!                                   
                                                                                
Writing to address 0x1e10:                                                      
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
Returned Data from address 0x1e10:                                              
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
                                                                                
Starting the test!!!!                                                           
                                                                                
Finished Initialization!!!                                                      
                                                                                
Writing 1234567890 to FRAM @ address 0x01f6                                     
Now Reading from FRAM @ address 0x01f6                                          
Returned Data: 1234567890                                                       
                                                                                
Writing to address 0x01f6:                                                      
Now is the time for kitties to have snacks!!!                                   
                                                                                
Returned Data from address 0x01f6:                                              
Now is the time for kitties to have snacks!!!                                   
                                                                                
Writing to address 0x01f6:                                                      
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
Returned Data from address 0x01f6:                                              
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
                                                                                
Starting the test!!!!                                                           
                                                                                
Finished Initialization!!!                                                      
                                                                                
Writing 1234567890 to FRAM @ address 0x00ff                                     
Now Reading from FRAM @ address 0x00ff                                          
Returned Data: 1234567890                                                       
                                                                                
Writing to address 0x00ff:                                                      
Now is the time for kitties to have snacks!!!                                   
                                                                                
Returned Data from address 0x00ff:                                              
Now is the time for kitties to have snacks!!!                                   
                                                                                
Writing to address 0x00ff:                                                      
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                               
                                                                                
Returned Data from address 0x00ff:                                              
If you want something done right, do it yourself.                               
No one can make you feel inferior without your consent.                         
If you want something done right, do it yourself.                                                                                                   

Logic Analyzer Output

In the screen capture below from the logic analyzer, you can see the output from the FRAM_init(&hspi1) function call.

In the following screen capture, the FRAM_WriteBytes(address, (uint8_t *) str, len + 1) first sends the FRAM_WREN command 0x06 followed by the FRAM_WRITE command 0x02 which also includes the address 0x00 0x00.
The next group of bytes being transmitted is the actual string.

This next screen capture shows the remaining string bytes being written to the FRAM. The next group of bytes are the FRAM_ReadBytes(address, (uint8_t *) rStr, len + 1) operations. Which include the command 0x03 FRAM_READ, followed by the bytes 0x00 0x00 which is the memory location to read from. The FRAM then starts to transmit back to the MCU using the MISO data line the string bytes
that were stored in that memory location.

This is the same screen capture from above, but shifted to the right so that more string bytes read are visible on the window.