PM004MNIA驱动

13k words

概述

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文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#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文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#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文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#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__ */


欢迎关注本人微信公众号: