使用QSPI驅動PM004MNIA
概述
STT-MRAM PM004MNIA 是一種具有 隨機存取(Random Access) 特性的非易失性存儲器,無需擦除操作,可進行 任意地址的讀寫操作。它的核心基于 自旋轉移扭矩(Spin Transfer Torque, STT) 技術,通過控制電流方向來改變磁性存儲單元的狀態,從而實現數據的存儲與讀取。支持寫無延遲(Write No Delay) 的特性,顯著提高了存儲效率。 廣泛應用于需要 高速讀寫、低功耗和長期數據保存 的場景,例如 IoT 設備、工業控制模塊、可穿戴設備、傳感器系統 等。
| 特性 | 描述 |
|---|---|
| 存儲容量 | 4Mbit |
| 存儲技術 | 自旋轉移扭矩磁隨機存取存儲器(STT-MRAM) |
| 隨機存取能力 | 支持任意地址的讀寫操作,無需擦除,寫入延遲低 |
| 接口支持 | SPI 和 QPI(四線并行) |
| 最大 SPI 頻率 | 50MHz |
| 低功耗 | Sleep 模式下僅需 2μA |
| 數據保留時間 | 可達 20 年(在 85°C 環境下) |
| 寫入耐久性 | 支持高達 10? 次 P/E 周期 |
| 寫保護功能 | 支持配置寫保護區域,確保數據安全 |
附錄-使用STM32H750驅動程序
1、外設初始化文件
- quadspi.c文件
#include "quadspi.h"
QSPI_HandleTypeDef hqspi;
/**
* @brief quad spi 外設初始化函數
* @param 無
* @retval 無
*/
void QUADSPI_Init(void)
{
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 5; /* QSPI時鐘預分頻器(決定實際通信時鐘頻率) */
hqspi.Init.FifoThreshold = 32; /* FIFO閾值(單位:字節),當FIFO中的數據量達到該值時觸發中斷/DMA請求 */
/* 采樣移位模式:
* HALFCYCLE:在時鐘半周期時采樣(提高時序余量)
* NONE:不在半周期采樣 */
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 23 - 1; /* FLASH內存大小 = 2 ^ (FlashSize + 1) */
/* 片選高電平時間:
* 表示兩次傳輸之間CS保持高電平的最小時鐘周期數 */
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
/* 時鐘模式:
* MODE_0:CLK空閑低電平,第1邊沿(上升沿)采樣
* MODE_3:CLK空閑高電平,第2邊沿(下降沿)采樣
* 需與Flash芯片規格書一致 */
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
/* Flash芯片選擇:
* ID_1:使用Bank1(對應BK1_IOx引腳)
* ID_2:使用Bank2(僅雙Flash模式) */
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
/* 雙Flash模式:
* DISABLE:單Flash模式
* ENABLE:并聯兩個Flash(地址空間翻倍) */
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief quad spi 外設初始化回調函數
* @param qspiHandle:QSPI句柄
* @retval 無
*/
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(qspiHandle->Instance==QUADSPI)
{
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PB6 ------> QUADSPI_BK1_NCS
PF6 ------> QUADSPI_BK1_IO3
PF7 ------> QUADSPI_BK1_IO2
PF8 ------> QUADSPI_BK1_IO0
PF10 ------> QUADSPI_CLK
PF9 ------> QUADSPI_BK1_IO1
*/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
}
}
/**
* @brief quad spi 外設重初始化回調函數
* @param qspiHandle:QSPI句柄
* @retval 無
*/
void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* qspiHandle)
{
if(qspiHandle->Instance==QUADSPI)
{
/* Peripheral clock disable */
__HAL_RCC_QSPI_CLK_DISABLE();
/**QUADSPI GPIO Configuration
PB6 ------> QUADSPI_BK1_NCS
PF6 ------> QUADSPI_BK1_IO3
PF7 ------> QUADSPI_BK1_IO2
PF8 ------> QUADSPI_BK1_IO0
PF10 ------> QUADSPI_CLK
PF9 ------> QUADSPI_BK1_IO1
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
HAL_GPIO_DeInit(GPIOF, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_10
|GPIO_PIN_9);
}
}
- quadspi.h文件
#ifndef __QUADSPI_H__
#define __QUADSPI_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "string.h"
extern QSPI_HandleTypeDef hqspi;
void QUADSPI_Init(void);
#ifdef __cplusplus
}
#endif
#endif /* __QUADSPI_H__ */
2、驅動文件
- bsp_pm004mniatr.c文件
#include "bsp_pm004mniatr.h"
#include "quadspi.h"
/**
* @brief 讀NOR Flash的狀態寄存器
* @param addr: 狀態寄存器地址(寄存器1、2、3 對應地址為 0x00、0x01、0x02)
* @retval 狀態寄存器的值
*/
uint8_t pm004mniatr_read_sr(uint8_t addr)
{
uint8_t byte;
QSPI_CommandTypeDef qspi_command_struct = {0};
qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_1_LINE;
qspi_command_struct.Instruction = PM004MNIATR_COMMAND_READ_MODE_REGISTER;
qspi_command_struct.AddressMode = QSPI_ADDRESS_1_LINE;
qspi_command_struct.AddressSize = QSPI_ADDRESS_24_BITS;
qspi_command_struct.Address = addr;
qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
qspi_command_struct.DummyCycles = 2;
qspi_command_struct.DataMode = QSPI_DATA_1_LINE;
qspi_command_struct.NbData = 1;
qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE;
qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
qspi_command_struct.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Receive(&hqspi, &byte, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
return byte;
}
/**
* @brief 寫NOR Flash的狀態寄存器
* @param addr: 狀態寄存器地址(寄存器1、2、3 對應地址為 0x00、0x01、0x02)
* @param byte:寄存器寫入值
* @retval 無
*/
void pm004mniatr_write_sr(uint8_t addr, uint8_t byte)
{
QSPI_CommandTypeDef qspi_command_struct = {0};
qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_1_LINE;
qspi_command_struct.Instruction = PM004MNIATR_COMMAND_WRITE_MODE_REGISTER;
qspi_command_struct.AddressMode = QSPI_ADDRESS_1_LINE;
qspi_command_struct.AddressSize = QSPI_ADDRESS_24_BITS;
qspi_command_struct.Address = addr;
qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
qspi_command_struct.DummyCycles = 0;
qspi_command_struct.DataMode = QSPI_DATA_1_LINE;
qspi_command_struct.NbData = 1;
qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE;
qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
qspi_command_struct.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Transmit(&hqspi, &byte, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
}
/**
* @brief 發送快速指令
* @param 無
* @retval 無
*/
void pm004mniatr_send_command(uint8_t command)
{
QSPI_CommandTypeDef qspi_command_struct = {0};
qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 設置指令模式:使用1線傳輸模式 */
qspi_command_struct.Instruction = command; /* 設置指令代碼 */
qspi_command_struct.AddressMode = QSPI_ADDRESS_NONE; /* 地址模式:不使用地址 */
qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 備用字節模式:不使用 */
qspi_command_struct.DummyCycles = 0; /* 空周期數:0 */
qspi_command_struct.DataMode = QSPI_DATA_NONE; /* 數據模式:不使用數據傳輸 */
qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE; /* DDR模式:禁用雙倍數據率模式 */
qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR半周期保持:使用模擬延遲 */
qspi_command_struct.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* SIOO模式:每次發送指令 */
HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
}
/**
* @brief 啟用quad spi 操作模式
* @param 無
* @retval 無
*/
static inline void pm004mniatr_qspi_mode_enable(void)
{
pm004mniatr_send_command(PM004MNIATR_COMMAND_ENTER_QSPI);
}
/**
* @brief 退出quad spi 操作模式
* @param 無
* @retval 無
*/
void inline pm004mniatr_qspi_mode_disable(void)
{
pm004mniatr_send_command(PM004MNIATR_COMMAND_EXIT_QSPI);
}
/**
* @brief 寫使能NOR Flash
* @param 無
* @retval 無
*/
static inline void pm004mniatr_write_enable(void)
{
pm004mniatr_send_command(PM004MNIATR_COMMAND_WRITE_ENABLE);
}
/**
* @brief 進入睡眠模式
* @param 無
* @retval 無
*/
static inline void pm004mniatr_sleep(void)
{
pm004mniatr_send_command(PM004MNIATR_COMMAND_ENTRY_SLEEP);
}
/**
* @brief 喚醒PM004MNIA
* @param 無
* @retval 無
*/
static inline void pm004mniatr_wake_up(void)
{
pm004mniatr_send_command(PM004MNIATR_COMMAND_EXIT_SLEEP);
}
/**
* @brief 復位PM004MNIA
* @param 無
* @retval 無
*/
static inline void pm004mniatr_reset(void)
{
pm004mniatr_send_command(PM004MNIATR_COMMAND_RESE_ENABLE);
pm004mniatr_send_command(PM004MNIATR_COMMAND_RESET);
}
/**
* @brief 初始化 PM004MNIA
* @param 無
* @retval 無
*/
void pm004mniatr_init(void)
{
/* 初始化quad spi外設 */
QUADSPI_Init();
/* ------------------安全啟動 --------------------*/
delay_ms(20);
/* 復位PM004MNIA */
pm004mniatr_reset();
delay_ms(10);
/* 進入睡眠狀態 */
pm004mniatr_sleep();
delay_ms(10);
/* 喚醒 */
pm004mniatr_wake_up();
delay_ms(10);
/* ----------------安全啟動 END -----------------*/
/* 啟動寫使能 */
pm004mniatr_write_enable();
/* 進入qspi操作模式 */
pm004mniatr_qspi_mode_enable();
}
/**
* @brief 讀PM004MNIA芯片ID
* @param 無
* @retval PM004MNIA芯片ID
*/
uint16_t pm004mniatr_read_id(void)
{
uint8_t id[16];
QSPI_CommandTypeDef qspi_command_struct = {0};
qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1線指令模式 */
qspi_command_struct.Instruction = PM004MNIATR_COMMAND_READ_ID; /* 讀取指令 */
qspi_command_struct.AddressMode = QSPI_ADDRESS_1_LINE; /* 無地址模式 */
qspi_command_struct.AddressSize = QSPI_ADDRESS_24_BITS; /* 24位地址 */
qspi_command_struct.Address = 0x000000; /* 地址 */
qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 無交替字節 */
qspi_command_struct.DummyCycles = 0; /* 空白周期個數 */
qspi_command_struct.DataMode = QSPI_DATA_1_LINE; /* 1線數據模式 */
qspi_command_struct.NbData = 2;
qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE;
qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
qspi_command_struct.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Receive(&hqspi, id, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
return (((uint16_t)id[0] << 8) | id[1]);
}
/**
* @brief 從PM004MNIA指定地址開始讀取指定長度的數據
* @param pbuf : 讀取到數據保存的地址
* @param addr : 指定開始讀取的地址
* @param datalen: 指定讀取數據的字節數
* @retval 無
*/
void pm004mniatr_read_data(uint32_t addr, uint8_t *pbuf, uint16_t datalen)
{
QSPI_CommandTypeDef qspi_command_struct = {0};
qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_4_LINES;
qspi_command_struct.Instruction = PM004MNIATR_COMMAND_READ_DATA;
qspi_command_struct.AddressMode = QSPI_ADDRESS_4_LINES;
qspi_command_struct.AddressSize = QSPI_ADDRESS_24_BITS;
qspi_command_struct.Address = addr;
qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
qspi_command_struct.DummyCycles = 12;
qspi_command_struct.DataMode = QSPI_DATA_4_LINES;
qspi_command_struct.NbData = datalen;
qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE;
qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
qspi_command_struct.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Receive(&hqspi, pbuf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
}
/**
* @brief PM004MNIA指定地址寫入指定長度的數據
* @note 寫入數據的長度不能超過指定地址所在頁的剩余字節數
* @param addr : 指定開始寫入數據的地址
* @param pbuf : 寫入數據指針
* @param datalen: 指定寫入數據的字節數
* @retval 無
*/
void pm004mniatr_write_data(uint32_t addr, uint8_t *pbuf, uint16_t datalen)
{
QSPI_CommandTypeDef qspi_command_struct = {0};
qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_4_LINES;
qspi_command_struct.Instruction = PM004MNIATR_COMMAND_WRITE_DATA;
qspi_command_struct.AddressMode = QSPI_ADDRESS_4_LINES;
qspi_command_struct.AddressSize = QSPI_ADDRESS_24_BITS;
qspi_command_struct.Address = addr;
qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
qspi_command_struct.DummyCycles = 0;
qspi_command_struct.DataMode = QSPI_DATA_4_LINES;
qspi_command_struct.NbData = datalen;
qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE;
qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
qspi_command_struct.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Transmit(&hqspi, pbuf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
}
- bsp_pm004mniatr.h文件
#ifndef __BSP_PM004MNIATR_H__
#define __BSP_PM004MNIATR_H__
#include "stdint.h"
#include "main.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PM004MNIATR_MODE_REGISTER_1_ADDR 0x00
#define PM004MNIATR_MODE_REGISTER_2_ADDR 0x01
#define PM004MNIATR_MODE_REGISTER_3_ADDR 0x02
#define PM004MNIATR_COMMAND_READ_ID 0x9F
#define PM004MNIATR_COMMAND_ENTER_QSPI 0x35
#define PM004MNIATR_COMMAND_EXIT_QSPI 0xF5
#define PM004MNIATR_COMMAND_WRITE_ENABLE 0x06
#define PM004MNIATR_COMMAND_WRITE_MODE_REGISTER 0xB1
#define PM004MNIATR_COMMAND_READ_MODE_REGISTER 0xB5
#define PM004MNIATR_COMMAND_WRITE_DATA 0x02
#define PM004MNIATR_COMMAND_READ_DATA 0x03
#define PM004MNIATR_COMMAND_ENTRY_SLEEP 0xB9
#define PM004MNIATR_COMMAND_EXIT_SLEEP 0xAB
#define PM004MNIATR_COMMAND_RESE_ENABLE 0x66
#define PM004MNIATR_COMMAND_RESET 0x99
void pm004mniatr_init(void);
uint8_t pm004mniatr_read_sr(uint8_t addr);
void pm004mniatr_write_sr(uint8_t addr, uint8_t byte);
void pm004mniatr_read_data(uint32_t addr, uint8_t *pbuf, uint16_t datalen);
void pm004mniatr_write_data(uint32_t addr, uint8_t *pbuf, uint16_t datalen);
#ifdef __cplusplus
}
#endif
#endif /* __BSP_PM004MNIATR_H__ */

浙公網安備 33010602011771號