Overview
In this tutorial, you will learn how to use an STM32 SPI FRAM device to store and retrieve data using the MB85RS64B memory chip. This guide walks through the hardware setup, SPI configuration, and the code required to communicate with the FRAM device. By the end, you will understand how to perform fast, reliable non-volatile data storage in your STM32 projects.
What You Will Learn
- How to connect the MB85RS64B SPI FRAM breakout to an STM32F439ZI Nucleo board
- How to configure SPI and GPIO chip select for the FRAM device
- How to write and read single bytes and multi-byte data from FRAM
- How to verify FRAM communication using USART output and a logic analyzer
Prerequisites
- Basic familiarity with STM32CubeIDE and STM32CubeMX project configuration
- Basic understanding of SPI communication
- An STM32F439ZI Nucleo board or compatible STM32 development board
- A serial terminal connection for viewing USART output
Materials List
- FTDI to USB
- NUCLEO-F439ZI
- Adafruit SPI Non-Volatile FRAM Breakout – 64Kbit / 8KByte
- Breadboards Kit Include 2PCS 830 Point 2PCS 400 Point Solderless Breadboards
- Logic 8 – Saleae 8-Channel Logic Analyzer
Project Structure
STM32 SPI FRAM project
├── Core
│ ├── Inc
│ │ ├── main.h
│ │ └── ada1897_mb85rs64b.h
│ └── Src
│ ├── main.c
│ └── ada1897_mb85rs64b.c
└── STM32CubeIDE project configuration
Hardware Configuration / Pinouts
This project uses an STM32F439ZI Nucleo board, an FTDI USB-to-serial adapter for terminal output, and an Adafruit MB85RS64B SPI FRAM breakout connected over SPI. The following sections collect the pinout references, breakout details, and project schematic.
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

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 FRAM Project

Project Setup
Configure the STM32 project for SPI communication, USART output, and a GPIO-controlled chip select line for the FRAM breakout. The following configuration screenshots show the CubeIDE and CubeMX setup used for this project.
Pinouts & Configurations
Code Walkthrough
The code initializes SPI and USART, configures the FRAM chip select line, and runs repeated write/read tests against several FRAM addresses. The code listings are preserved below exactly as they appear in the original post.
Code Listings
/* 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;
}
#endifvoid 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 */
/**
* @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 */
/*
* 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_ */
/*
* 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.





