返回列表 发新帖我要提问本帖赏金: 50.00元(功能说明)

[资料干货] 【每周分享】MRAM存储芯片S3A1004V0M的解读和使用分享

[复制链接]
305|1
dffzh 发表于 2026-2-3 13:26 | 显示全部楼层 |阅读模式
#申请原创# #技术资源#

这篇帖子主要从芯片介绍、手册解读和驱动代码三个部分与大家分享一下个人的所学内容,供大家使用和参考。
一、 芯片介绍
最近项目上使用了MRAM存储器芯片S3A1004V0M,而所谓的MRAM,英文全称Magnetoresistive Random Access Memory,即为一种基于磁阻的随机存取存储器,属于一种新型的存储技术,其利用电子自旋的磁性特性来存储数据,而不是传统的电荷存储方式,即与传统的半导体随机存取存储器(RAM)不同,MRAM使用磁性隧道结(MagneticTunnel Junction,MTJ)作为核心的存储单元,通过改变磁化方向来记录二进制数据;这种技术结合了DRAM的速度和闪存的非易失性,能够在断电后依然保留数据:
另外MRAM的应用也比较广泛,也有前景,因为MRAM的优势在于它在具有非易失性的同时在速度、功耗、成本上也较为折中。
MRAM有望根据不同的带宽需求逐步替代现有的不同类型的存储器,如 SRAM、DRAM以及 Flash 等,从而在消除各级存储器之间存在的互联延迟同时降低存储器的功耗。

我们所用的存储器芯片S3A1004V0M是NETSOL(纳索尔)公司开发的STT-MRAM型(自旋转移矩(spin-transfer torque,STT)MRAM)的MRAM,也就是存储单元MemoryCell对应的种类是STT-MRAM,也是目前用的比较多的类型:
二、 手册解读
第一次使用嘛,当然是先来通读一下芯片的用户手册,先不需要细读,可以先大概了解一下就可以,比如通信的方式和时序是什么啊,寄存器有哪些,都有什么功能啊等等吧。有些地方可以等到实际代码调试的时候再来有针对性的解读。

先看下通信方式吧,从手册上得知,是使用SPI进行通信:
支持Single SPI,Dual SPI,QuadSPI,就是对应SSPI,DSPI和QSPI,不同的场景需要使用不同的SPI类型,我们这个是基于MCU和S3A1004V0M的普通SPI通信,使用Single SPI就可以了,猜测应该有寄存器可以配置。

然后看了一下有个ID信息:
可以读取的ID信息,在板子上电的时候应该可以通过MCU回读回来,以确认是否通信连接成功。

接着看了一下功能框图和引脚说明,毕竟对于软件来说,肯定需要知道每个引脚的作用才行:
因为我们使用的是Single SPI,所以对照芯片引脚描述,使用下面四个引脚即可:
分别对应SPI的片选信号CS,时钟信号CLK,MOSI信号和MISO信号:
接着我们来看下寄存器相关的内容,找到寄存器描述这块,就可以逐个查看寄存器的说明:
这个芯片还有一些指令设置说明,初始化配置和写芯片数据的时候也是需要用到的:
指令类型主要包括控制指令、读寄存器指令、写寄存器指令、读内存数组指令、写内存数组指令以及自增的256字节区域指令,具体指令设置可以查看手册。

然后我们来看一下时序相关的内容,先看下SPI时钟模式,主要包括模式0和模式3,MCU配置SPI的时候需要注意:
再来看下时序图这块,可以了解一下,便于波形测试时候进行对比:
其他相关的指令操作时序,可以详细查看手册:
手册解读主要是这些内容,接下来与大家分享一下基于MCU的驱动代码。
三、 驱动代码
S3A1004V0M芯片基于MCU的驱动代码主要是以SSPI为例,使用MCU的标准SPI进行操作,驱动代码主要包括s3axx04x0m.c源文件和s3axx04x0m.h头文件。

其中s3axx04x0m.h头文件的代码主要如下:
  1. #ifndef __S3AXX04X0M_H__
  2. #define __S3AXX04X0M_H__

  3. #include "at32f403a_407.h"
  4. #include <stdio.h>

  5. #define S3AXX04_ID                0xd9010101


  6. #define  S3AXX04X0M_GPIO               GPIOB
  7. #define  S3AXX04X0M_CS_GPIO     GPIOB
  8. #define  S3AXX04X0M_CLK_GPIO    GPIOB
  9. #define  S3AXX04X0M_MISO_GPIO   GPIOB
  10. #define  S3AXX04X0M_MOSI_GPIO   GPIOB

  11. #define  S3AXX04X0M_CS_PIN            GPIO_PINS_6
  12. #define  S3AXX04X0M_CLK_PIN            GPIO_PINS_7
  13. #define  S3AXX04X0M_MISO_PIN        GPIO_PINS_8
  14. #define  S3AXX04X0M_MOSI_PIN        GPIO_PINS_9

  15. #define  S3AXX04X0M_CS_HIGH()      gpio_bits_write(S3AXX04X0M_CS_GPIO, S3AXX04X0M_CS_PIN, TRUE)
  16. #define  S3AXX04X0M_CS_LOW()       gpio_bits_write(S3AXX04X0M_CS_GPIO, S3AXX04X0M_CS_PIN, FALSE)

  17. #define  S3AXX04X0M_CLK_HIGH()     gpio_bits_write(S3AXX04X0M_CLK_GPIO, S3AXX04X0M_CLK_PIN, TRUE)
  18. #define  S3AXX04X0M_CLK_LOW()      gpio_bits_write(S3AXX04X0M_CLK_GPIO, S3AXX04X0M_CLK_PIN, FALSE)

  19. #define  S3AXX04X0M_MOSI_HIGH()    gpio_bits_write(S3AXX04X0M_MOSI_GPIO, S3AXX04X0M_MOSI_PIN, TRUE)
  20. #define  S3AXX04X0M_MOSI_LOW()     gpio_bits_write(S3AXX04X0M_MOSI_GPIO, S3AXX04X0M_MOSI_PIN, FALSE)

  21. #define  S3AXX04X0M_MISO_READ()    gpio_input_data_bit_read(S3AXX04X0M_MISO_GPIO, S3AXX04X0M_MISO_PIN)



  22. /* only sspi */
  23. typedef struct
  24. {
  25.     void (*s3axx04x0m_delay_us)(u32 us);
  26.     void (*spi_cs_set) (u8 state);
  27.     int (*spi_read_bytes) (u8 *read_buf, u32 len);
  28.     int (*spi_write_bytes) (u8 *write_buf, u32 len);
  29. }s3axx04x0m_spi_t;


  30. typedef enum {
  31.     S3AXX_STATUS_REG = 0x00,
  32.     S3AXX_CONFIG_REG1 = 0x02,
  33.     S3AXX_CONFIG_REG2 = 0x03,
  34.     S3AXX_CONFIG_REG3 = 0x04,
  35.     S3AXX_CONFIG_REG4 = 0x05,
  36.     S3AXX_DEVICE_IDENTIFICATION_REG = 0x30,
  37.     S3AXX_UNIQUE_IDENTIFICATION_REG = 0x40,
  38.     S3AXX_SERIAL_NUMBER_REG = 0x80,
  39. }s3axx04xom_reg_e;

  40. typedef enum {
  41.                           /* Instruction Name */             /* Interface Type(CMD-ADDR-Data) */
  42.     S3AXX_NOOP = 0x00,    /* No operation */                 /* 1-0-0, 2-0-0, 4-0-0 */
  43.     S3AXX_WREN = 0x06,    /* Write enable*/                  /* 1-0-0, 2-0-0, 4-0-0 */
  44.     S3AXX_WRDI = 0x04,    /* Write disable */                /* 1-0-0, 2-0-0, 4-0-0 */
  45.     S3AXX_DPIE = 0x37,    /* Enable DSPI */                  /* 1-0-0, 4-0-0 */
  46.     S3AXX_QPIE = 0x38,    /* Enable QSPI */                  /* 1-0-0, 2-0-0 */
  47.     S3AXX_SPIE = 0xFF,    /* Enable SSPI */                  /* 2-0-0, 4-0-0 */
  48.     S3AXX_DPDE = 0xB9,    /* Enter Deep Power Down  */       /* 1-0-0, 2-0-0, 4-0-0 */
  49.     S3AXX_DPDX = 0xAB,    /* Exit Deep Power Down  */        /* 1-0-0, 2-0-0, 4-0-0 */
  50.     S3AXX_SRTE = 0x66,    /* Software Reset Enable */        /* 1-0-0, 2-0-0, 4-0-0 */
  51.     S3AXX_SRST = 0x99,    /* Software Reset Enable */        /* 1-0-0, 2-0-0, 4-0-0 */
  52. }s3axx04xom_ctrl_ins_e;

  53. typedef enum {
  54.                           /* Instruction Name */                              /* Interface Type(CMD-ADDR-Data) */      /* Data Bytes */
  55.     S3AXX_RDSR = 0x05,    /* Read Status Register */                          /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  56.     S3AXX_RDC1 = 0x35,    /* Read Configuration Register 1 */                 /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  57.     S3AXX_RDC2 = 0x3F,    /* Read Configuration Register 2 */                 /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  58.     S3AXX_RDC3 = 0x44,    /* Read Configuration Register 3 */                 /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  59.     S3AXX_RDC4 = 0x45,    /* Read Configuration Register 4 */                 /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  60.     S3AXX_RDCX = 0x46,    /* Read Configuration Registers 1,2,3,4 */          /* 1-0-1, 2-0-2, 4-0-4 */                /* 4 */
  61.     S3AXX_RDID = 0x9F,    /* Read Device ID  */                               /* 1-0-1, 2-0-2, 4-0-4 */                /* 4 */
  62.     S3AXX_RUID = 0x4C,    /* Read Unique ID */                                /* 1-0-1, 2-0-2, 4-0-4 */                /* 8 */
  63.     S3AXX_RDSN = 0xC3,    /* Read Serial Number Register */                   /* 1-0-1, 2-0-2, 4-0-4 */                /* 8 */
  64.     S3AXX_RDAP = 0x14,    /* Read Augmented 256-byte Protection Register */   /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  65.     S3AXX_RDAR = 0x65,    /* Read Any Register-Address Based */               /* 1-1-1, 2-2-2, 4-4-4 */                /* 1,4,8 */
  66. }s3axx04xom_read_reg_ins_e;

  67. typedef enum {
  68.                           /* Instruction Name */                              /* Interface Type(CMD-ADDR-Data) */      /* Data Bytes */
  69.     S3AXX_WRSR = 0x01,    /* Write Status Register */                         /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  70.     S3AXX_WRCX = 0x87,    /* Write Configuration Registers 1,2,3,4*/          /* 1-0-1, 2-0-2, 4-0-4 */                /* 4 */
  71.     S3AXX_WRSN = 0xC2,    /* Write Serial Number Register */                  /* 1-0-1, 2-0-2, 4-0-4 */                /* 8 */
  72.     S3AXX_WRAP = 0x1A,    /* Write Augmented 256-byte Protection Register */  /* 1-0-1, 2-0-2, 4-0-4 */                /* 1 */
  73.     S3AXX_WRAR = 0x71,    /* Write Any Register-Address Based */              /* 1-1-1, 2-2-2, 4-4-4 */                /* 1,8 */
  74. }s3axx04xom_write_reg_ins_e;

  75. typedef enum {
  76.                           /* Instruction Name */                              /* Interface Type(CMD-ADDR-Data) */      /* Data Bytes */
  77.     S3AXX_READ = 0x03,    /* Read Memory Array-SDR */                         /* 1-1-1 */                              /* 1->鈭?*/
  78.     S3AXX_RDFT = 0x0B,    /* Fast Read Memory Array-SDR */                    /* 1-1-1, 2-2-2, 4-4-4 */                /* 1->鈭?*/
  79.     S3AXX_DRFR = 0x0D,    /* Fast Read Memory Array-DDR */                    /* 1-1-1, 2-2-2, 4-4-4 */                /* 1->鈭?*/
  80.     S3AXX_RDDO = 0x3B,    /* Read Dual Output Memory Array-SDR */             /* 1-1-2 */                              /* 1->鈭?*/
  81.     S3AXX_DRDO = 0x3D,    /* Read Dual Output Memory Array-DDR */             /* 1-1-2 */                              /* 1->鈭?*/
  82.     S3AXX_RDQO = 0x6B,    /* Read Quad Output Memory Array鈥揝DR */             /* 1-1-4 */                              /* 1->鈭?*/
  83.     S3AXX_DRQO = 0x6D,    /* Read Quad Output Memory Array鈥揇DR */             /* 1-1-4 */                              /* 1->鈭?*/
  84.     S3AXX_RDDI = 0xBB,    /* Read Dual I/O Memory Read-SDR */                 /* 1-2-2 */                              /* 1->鈭?*/
  85.     S3AXX_DRDI = 0xBD,    /* Read Dual I/O Memory Read-DDR */                 /* 1-2-2 */                              /* 1->鈭?*/
  86.     S3AXX_RDQI = 0xEB,    /* Read Quad I/O Memory Read-SDR */                 /* 1-4-4 */                              /* 1->鈭?*/
  87.     S3AXX_DRQI = 0xED,    /* Read Quad I/O Memory Read-DDR */                 /* 1-4-4 */                              /* 1->鈭?*/
  88. }s3axx04xom_read_memory_array_instruction_e;

  89. typedef enum {
  90.                           /* Instruction Name */                              /* Interface Type(CMD-ADDR-Data) */      /* Data Bytes */
  91.     S3AXX_WRTE = 0x02,    /* Write Memory Array-SDR */                        /* 1-1-1 */                              /* 1->鈭?*/
  92.     S3AXX_WRFT = 0xDA,    /* Fast Write Memory Array-SDR */                   /* 1-1-1, 2-2-2, 4-4-4 */                /* 1->鈭?*/
  93.     S3AXX_DRFW = 0xDE,    /* Fast Write Memory Array-DDR */                   /* 1-1-1, 2-2-2, 4-4-4 */                /* 1->鈭?*/
  94.     S3AXX_WDUI = 0xA2,    /* Write Dual Input Memory Array-SDR */             /* 1-1-2 */                              /* 1->鈭?*/
  95.     S3AXX_DWUI = 0xA4,    /* Write Dual Input Memory Array-DDR */             /* 1-1-2 */                              /* 1->鈭?*/
  96.     S3AXX_WQDI = 0x32,    /* Write Quad Input Memory Array-SDR */             /* 1-1-4 */                              /* 1->鈭?*/
  97.     S3AXX_DWQI = 0x32,    /* Write Quad Input Memory Array-DDR */             /* 1-1-4 */                              /* 1->鈭?*/
  98.     S3AXX_WDIO = 0xA1,    /* Write Dual I/O Memory Array-SDR */               /* 1-2-2 */                              /* 1->鈭?*/
  99.     S3AXX_DWIO = 0xA3,    /* Write Dual I/O Memory Array-DDR */               /* 1-2-2 */                              /* 1->鈭?*/
  100.     S3AXX_WQIO = 0xD2,    /* Write Quad I/O Memory Array-SDR */               /* 1-4-4 */                              /* 1->鈭?*/
  101.     S3AXX_DWQO = 0xD1,    /* Write Quad I/O Memory Array-DDR */               /* 1-4-4 */                              /* 1->鈭?*/
  102. }s3axx04xom_write_memory_array_ins_e;

  103. typedef enum {
  104.                           /* Instruction Name */                              /* Interface Type(CMD-ADDR-Data) */      /* Data Bytes */
  105.     S3AXX_RDAS = 0x4B,    /* Read Augmented 256-Byte Area-SDR */              /* 1-1-1 */                              /* 1->256 */
  106.     S3AXX_WRAS = 0x42,    /* Write Augmented 256-Byte Area-SDR */             /* 1-1-1 */                              /* 1->256 */
  107. }s3axx04xom_augmented_256_byte_area_ins_e;

  108. /************************Status register************************/
  109. #define S3AXX_STA_REG_WPEN(x)           ((x) << 7)
  110. #define S3AXX_STA_REG_SNPEN(x)          ((x) << 6)
  111. #define S3AXX_STA_REG_TB(x)             ((x) << 5)
  112. #define S3AXX_STA_REG_BP(x)             ((x) << 2)
  113. #define S3AXX_STA_REG_WREN(x)           ((x) << 1)

  114. typedef enum {
  115.     WRITE_PROTECT_DISENABLE_LOW_WP = 0x00,
  116.     WRITE_PROTECT_ENABLE_LOW_WP = 0x01,
  117. }s3axx04x0m_sta_reg_WPEN_e;

  118. typedef enum {
  119.     SERIAL_NUMBER_WRITABLE = 0x00,
  120.     SERIAL_NUMBER_WRITE_PROTECTED = 0x01,
  121. }s3axx04x0m_sta_reg_SNPEN_e;

  122. typedef enum {
  123.     TOP_PROTECTION_ENABLE = 0x00,
  124.     BOTTOM_PROTECTION_ENABLE = 0x01,
  125. }s3axx04x0m_sta_reg_TB_e;

  126. typedef enum {
  127.     PP_NONE = 0x00,
  128.     UPPER_LOWER_1_64 = 0x01,
  129.     UPPER_LOWER_1_32 = 0x02,
  130.     UPPER_LOWER_1_16 = 0x03,
  131.     UPPER_LOWER_1_8 = 0x04,
  132.     UPPER_LOWER_1_4 = 0x05,
  133.     UPPER_LOWER_1_2 = 0x06,
  134.     PP_ALL = 0x07,
  135. }s3axx04x0m_sta_reg_BP_e;

  136. typedef enum {
  137.     WRITE_PROTECT_ENABLE = 0x00,
  138.     WRITE_PROTECT_DISENABLE = 0x01,
  139. }s3axx04x0m_sta_reg_WREN_e;

  140. /************************Augmented 256-Byte Area Protection register************************/
  141. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP7(x)    ((x) << 7)
  142. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP6(x)    ((x) << 6)
  143. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP5(x)    ((x) << 5)
  144. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP4(x)    ((x) << 4)
  145. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP3(x)    ((x) << 3)
  146. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP2(x)    ((x) << 2)
  147. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP1(x)    ((x) << 1)
  148. #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP0(x)    ((x) << 0)

  149. typedef enum {
  150.     PROTECTION_DISENABLE = 0x00,
  151.     PROTECTION_ENABLE = 0x01,
  152. }s3axx04x0m_augmented_protection_reg_WREN_e;

  153. /************************Configuration register 1************************/
  154. #define S3AXX_CFG_REG1_MAPLK(x)         ((x) << 2)
  155. #define S3AXX_CFG_REG1_ASPLK(x)         ((x) << 0)

  156. typedef enum {
  157.     UNLOCK_TB_BP = 0x00,
  158.     LOCK_TB_BP = 0x01,
  159. }s3axx04x0m_cfg_reg1_MAPLK_e;

  160. typedef enum {
  161.     DEPENDING_ON_ASP_0_7 = 0x00,
  162.     REGARDLESS_ASP_0_7 = 0x01,
  163. }s3axx04x0m_cfg_reg1_ASPLK_e;;

  164. /************************Configuration register 2************************/
  165. #define S3AXX_CFG_REG2_QPIEN(x)         ((x) << 6)
  166. #define S3AXX_CFG_REG2_DPIEN(x)         ((x) << 4)
  167. #define S3AXX_CFG_REG2_READ_LATENCY(x)  ((x) << 0)

  168. typedef enum {
  169.     QPIEN_SINGLE_SPI = 0x00,
  170.     QPIEN_QUAN_SPI = 0x01,
  171. }s3axx04x0m_cfg_reg2_QPIEN_e;

  172. typedef enum {
  173.     DPIEN_SINGLE_SPI = 0x00,
  174.     DPIEN_DUAL_SPI = 0x01,
  175. }s3axx04x0m_cfg_reg2_DPIEN_e;

  176. typedef enum {
  177.     LATENCY_0CYCLE = 0x00,
  178.     LATENCY_1CYCLE = 0x01,
  179.     LATENCY_2CYCLE = 0x02,
  180.     LATENCY_3CYCLE = 0x03,
  181.     LATENCY_4CYCLE = 0x04,
  182.     LATENCY_5CYCLE = 0x05,
  183.     LATENCY_6CYCLE = 0x06,
  184.     LATENCY_7CYCLE = 0x07,
  185.     LATENCY_8CYCLE = 0x08,
  186.     LATENCY_9CYCLE = 0x09,
  187.     LATENCY_10CYCLE = 0x0A,
  188.     LATENCY_11CYCLE = 0x0B,
  189.     LATENCY_12CYCLE = 0x0C,
  190.     LATENCY_13CYCLE = 0x0D,
  191.     LATENCY_14CYCLE = 0x0E,
  192.     LATENCY_15CYCLE = 0x0F,
  193. }s3axx04x0m_cfg_reg2_read_latency_e;

  194. /************************Configuration register 3************************/
  195. #define S3AXX_CFG_REG3_DRV(x)           ((x) << 5)
  196. #define S3AXX_CFG_REG3_WRPEN(x)         ((x) << 4)
  197. #define S3AXX_CFG_REG3_WRPL(x)          ((x) << 0)

  198. typedef enum {
  199.     DRV_36_35_OHM = 0x00,
  200.     DRV_100_95_OHM = 0x01,
  201.     DRV_75_63_OHM = 0x02,
  202.     DRV_60_50_OHM = 0x03,
  203.     DRV_48_40_OHM = 0x04,
  204.     DRV_42_30_OHM = 0x05,
  205.     DRV_29_26_OHM = 0x06,
  206.     DRV_24_22_OHM = 0x07,
  207. }s3axx04x0m_cfg_reg3_DRV_e;

  208. typedef enum {
  209.     READ_WRAP_DISABLE = 0x00,
  210.     READ_WRAP_ENABLE = 0x01,
  211. }s3axx04x0m_cfg_reg3_WRPEN_e;

  212. typedef enum {
  213.     WRPL_16_BYTE_WARP = 0x00,
  214.     WRPL_32_BYTE_WARP = 0x01,
  215.     WRPL_64_BYTE_WARP = 0x02,
  216.     WRPL_128_BYTE_WARP = 0x03,
  217.     WRPL_256_BYTE_WARP = 0x04,
  218.     WRPL_512_BYTE_WARP = 0x05,
  219.     WRPL_1K_BYTE_WARP = 0x06,
  220. }s3axx04x0m_cfg_reg3_WRPL_e;

  221. /************************Configuration register 4************************/
  222. #define S3AXX_CFG_REG4_WRENS(x)         ((x) << 0)

  223. typedef enum {
  224.     NORMAL = 0x00,
  225.     SRAM = 0x01,
  226.     BACK_TO_BACK = 0x02,
  227. }s3axx04x0m_cfg_reg4_WRENS_e;

  228. void s3axx04x0m_continue_read(u8 cmd, u32 addr, u8 *read_buf, u32 len);
  229. void s3axx04x0m_continue_write(u8 cmd, u32 addr, u8 *write_buf, u32 len);
  230. void s3axx04x0m_deep_power_down(void);
  231. void s3axx04x0m_exit_deep_power_down_by_cmd(void);
  232. void s3axx04x0m_software_reset(void);
  233. void s3axx04x0m_cmd_set(u8 ctrl_instruction);
  234. void s3axx04x0m_cmd_read(u8 ctrl_instruction, u8 *read_buff, u32 len);
  235. void s3axx04x0m_cmd_write(u8 ctrl_instruction, u8 *write_buff, u32 len);
  236. void s3axx04x0m_READ_without_XIP(u32 addr, u8 *read_buff, u32 len);
  237. void s3axx04x0m_WRTE(u32 addr, u8 *write_buff, u32 len);
  238. void s3axx04x0m_RDAR(u32 addr, u8 *read_buff, u32 len);
  239. void s3axx04x0m_WRAR(u32 addr, u8 *write_buff, u32 len);
  240. void s3axx04x0m_init(void);
  241. void s3axx04x0m_write_memory(u8 *write_buff, u32 addr, u32 len);
  242. void s3axx04x0m_read_memory(u8 *read_buff, u32 addr, u32 len);
  243. u32 s3axx04x0m_read_device_id(void);

  244. #endif /* __S3AXX04X0M_H__ */
里面的与MCU底层配置相关的部分可以根据MCU平台进行相应修改。

其中s3axx04x0m.c源文件的代码主要如下:
  1. #include "s3axx04x0m.h"
  2. #include "bsp_spi_bus.h"

  3. s3axx04x0m_spi_t s3axx04x0m_spi0;

  4. void s3axx_delay_us(u32 us)
  5. {
  6.         u16 cnt;
  7.         if(us == 0)
  8.                 return;
  9.         while(us--)
  10.         {
  11.                 cnt = 8;
  12.                 while(cnt--);
  13.         }
  14. }

  15. void gpio_cs_set(u8 set)
  16. {
  17.         switch(set)
  18.         {
  19.             case 0:
  20.                     S3AXX04X0M_CS_LOW();
  21.                     break;

  22.             case 1:
  23.                     S3AXX04X0M_CS_HIGH();
  24.                     break;
  25.         }
  26. }

  27. /*spi read(when data is 0) or write*/
  28. static uint8_t spi_rw(uint8_t data)  
  29. {
  30.         uint8_t temp = 0;

  31.     while(spi_i2s_flag_get(S3A1004VOM_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
  32.         spi_i2s_data_transmit(S3A1004VOM_SPI_TYPE, data);

  33.         while(spi_i2s_flag_get(S3A1004VOM_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
  34.         temp = spi_i2s_data_receive(S3A1004VOM_SPI_TYPE);

  35.     return temp;
  36. }

  37. int spi0_read_bytes(u8 *read_buf, u32 len)
  38. {
  39.         if(read_buf == 0)
  40.                 return -1;

  41.         for(int i = 0; i < len; i++)
  42.         {
  43.                 read_buf[i] = spi_rw(0);
  44.         }
  45.     return 0;
  46. }

  47. int spi0_write_bytes(u8 *write_buf, u32 len)
  48. {
  49.         if(write_buf == 0)
  50.                 return -1;

  51.         for(int i = 0; i < len; i++)
  52.         {
  53.                 spi_rw(write_buf[i]);
  54.         }

  55.     return 0;
  56. }

  57. void s3axx04x0m_read_byte(u8 cmd, u32 addr, u8 *read_buf)
  58. {
  59.     u8 write_data = 0;

  60.     S3AXX04X0M_CS_LOW();
  61.     spi_rw(cmd);
  62.     for(int i = 0; i < 3; i ++)
  63.     {
  64.         write_data = addr >> ((2-i)*8);
  65.         spi_rw(write_data);
  66.     }

  67.     *read_buf = spi_rw(0);
  68.     S3AXX04X0M_CS_HIGH();
  69. }

  70. void s3axx04x0m_write_byte(u8 cmd, u32 addr, u8 *write_buf)
  71. {
  72.     u8 write_data = 0;

  73.     S3AXX04X0M_CS_LOW();
  74.     spi_rw(cmd);
  75.     for(int i = 0; i < 3; i ++)
  76.     {
  77.         write_data = addr >> ((2-i)*8);
  78.         spi_rw(write_data);
  79.     }

  80.     spi_rw(*write_buf);
  81.     S3AXX04X0M_CS_HIGH();
  82. }

  83. void s3axx04x0m_XIP_read(u8 cmd, u32 addr, u8 *read_buf)
  84. {

  85. }

  86. void s3axx04x0m_continue_read(u8 cmd, u32 addr, u8 *read_buf, u32 len)
  87. {
  88.     u8 write_data = 0;
  89.     u8 tmp = 0;

  90.     S3AXX04X0M_CS_LOW();
  91.     spi_rw(cmd);
  92.     for(int i = 0; i < 3; i ++)
  93.     {
  94.         write_data = addr >> ((2-i)*8);
  95.         spi_rw(write_data);
  96.     }

  97.     for(int i = 0; i < len; i++)
  98.     {
  99.             read_buf[i] = spi_rw(0);
  100.     }

  101.     S3AXX04X0M_CS_HIGH();
  102. }

  103. void s3axx04x0m_continue_write(u8 cmd, u32 addr, u8 *write_buf, u32 len)
  104. {
  105.     u8 write_data = 0;

  106.     S3AXX04X0M_CS_LOW();
  107.     spi_rw(cmd);
  108.     for(int i = 0; i < 3; i ++)
  109.     {
  110.         write_data = addr >> ((2-i)*8);
  111.         spi_rw(write_data);
  112.     }

  113.     for(int i = 0; i < len; i++)
  114.     {
  115.             spi_rw(write_buf[i]);
  116.     }
  117.     S3AXX04X0M_CS_HIGH();
  118. }

  119. void s3axx04x0m_deep_power_down(void)
  120. {
  121.     u8 write_data = 0;

  122.     S3AXX04X0M_CS_LOW();
  123.     write_data = S3AXX_DPDE;
  124.     spi_rw(write_data);
  125.     S3AXX04X0M_CS_HIGH();
  126.     for(int i = 0; i < 10; i++);
  127. }

  128. void s3axx04x0m_exit_deep_power_down_by_cmd(void)
  129. {
  130.     u8 write_data = 0;

  131.     S3AXX04X0M_CS_LOW();
  132.     write_data = S3AXX_DPDX;
  133.     spi_rw(write_data);
  134.     S3AXX04X0M_CS_HIGH();
  135.     for(int i = 0; i < 10; i++);
  136. }


  137. void s3axx04x0m_software_reset(void)
  138. {
  139.     u8 write_data = 0;

  140.     S3AXX04X0M_CS_LOW();
  141.     write_data = S3AXX_SRTE;
  142.     spi_rw(write_data);
  143.     S3AXX04X0M_CS_HIGH();

  144.     S3AXX04X0M_CS_LOW();
  145.     write_data = S3AXX_SRST;
  146.     spi_rw(write_data);
  147.     S3AXX04X0M_CS_HIGH();
  148.     //3.3V tSRST_max = 0.3ms 1.8V tSRST_max = 2ms
  149. //    s3axx04x0m_spi0.s3axx04x0m_delay_us(500);
  150.     s3axx_delay_us(500);
  151. }

  152. void s3axx04x0m_cmd_set(u8 ctrl_instruction)
  153. {
  154.     u8 write_data = 0;

  155.     S3AXX04X0M_CS_LOW();

  156.     write_data = ctrl_instruction;
  157.     spi_rw(write_data);

  158.     S3AXX04X0M_CS_HIGH();
  159. }

  160. void s3axx04x0m_cmd_read(u8 ctrl_instruction, u8 *read_buff, u32 len)
  161. {
  162.     S3AXX04X0M_CS_LOW();

  163.     spi_rw(ctrl_instruction);
  164.     for(int i = 0; i < len; i++)
  165.     {
  166.             read_buff[i] = spi_rw(0);
  167.     }

  168.     S3AXX04X0M_CS_HIGH();
  169. }

  170. void s3axx04x0m_cmd_write(u8 ctrl_instruction, u8 *write_buff, u32 len)
  171. {
  172.     S3AXX04X0M_CS_LOW();

  173.     spi_rw(ctrl_instruction);
  174.     for(int i = 0; i < len; i++)
  175.     {
  176.             spi_rw(write_buff[i]);
  177.     }

  178.     S3AXX04X0M_CS_HIGH();
  179. }

  180. void s3axx04x0m_READ_without_XIP(u32 addr, u8 *read_buff, u32 len)
  181. {
  182.     s3axx04x0m_continue_read(S3AXX_READ, addr, read_buff, len);
  183. }

  184. void s3axx04x0m_WRTE(u32 addr, u8 *write_buff, u32 len)
  185. {
  186.     s3axx04x0m_continue_write(S3AXX_WRTE, addr, write_buff, len);
  187. }

  188. void s3axx04x0m_RDAS(u32 addr, u8 *read_buff, u32 len)
  189. {
  190. }

  191. void s3axx04x0m_WRAS(u32 addr, u8 *write_buff, u32 len)
  192. {
  193. }

  194. void s3axx04x0m_RDAR(u32 addr, u8 *read_buff, u32 len)
  195. {
  196.     u8 write_data = 0;

  197.     write_data = S3AXX_RDAR;
  198.     S3AXX04X0M_CS_LOW();
  199.     spi_rw(write_data);
  200.     for(int i = 0; i < 3; i ++)
  201.     {
  202.         write_data = addr >> ((2-i)*8);
  203.         spi_rw(write_data);
  204.     }

  205.     write_data = 0xFF;
  206.     spi_rw(write_data);

  207.     for(int i = 0; i < len; i++)
  208.     {
  209.             read_buff[i] = spi_rw(0);
  210.     }
  211.     S3AXX04X0M_CS_HIGH();
  212. }

  213. void s3axx04x0m_WRAR(u32 addr, u8 *write_buff, u32 len)
  214. {
  215.     s3axx04x0m_continue_write(S3AXX_WRAR, addr, write_buff, len);
  216. }

  217. void s3axx04x0m_RDFT(u32 addr, u8 *read_buff, u32 len)
  218. {

  219. }

  220. void s3axx04x0m_WRFT(u32 addr, u8 *write_buff, u32 len)
  221. {

  222. }

  223. void s3axx04x0m_register(void)
  224. {
  225.     s3axx04x0m_spi0.spi_cs_set = gpio_cs_set;
  226.     s3axx04x0m_spi0.spi_read_bytes = spi0_read_bytes;
  227.     s3axx04x0m_spi0.spi_write_bytes = spi0_write_bytes;
  228.     s3axx04x0m_spi0.s3axx04x0m_delay_us = s3axx_delay_us;
  229. }

  230. void s3axx04x0m_init(void)
  231. {
  232.     u8 write_reg_data[4] = {0};

  233.     //s3axx04x0m_register();

  234. /************************Status register************************/
  235.     //config WP protect bit based on hardware
  236.     write_reg_data[0] |= S3AXX_STA_REG_WPEN(WRITE_PROTECT_ENABLE_LOW_WP);
  237.     write_reg_data[0] |= S3AXX_STA_REG_SNPEN(SERIAL_NUMBER_WRITE_PROTECTED);
  238.     write_reg_data[0] |= S3AXX_STA_REG_TB(TOP_PROTECTION_ENABLE);
  239.     write_reg_data[0] |= S3AXX_STA_REG_BP(PP_ALL);
  240.     write_reg_data[0] |= S3AXX_STA_REG_WREN(WRITE_PROTECT_ENABLE);

  241.     s3axx04x0m_cmd_write(S3AXX_WRSR, write_reg_data, 1);
  242.     memset(write_reg_data, 0, sizeof(write_reg_data));

  243. /************************Augmented 256-Byte Area Protection register************************/
  244.     /*config add protection enable/disable*/
  245.     write_reg_data[0] |= (S3AXX04_AUGMENTED_PROTECTION_REG_ASP7(PROTECTION_DISENABLE) |
  246.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP6(PROTECTION_DISENABLE) |
  247.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP5(PROTECTION_DISENABLE) |
  248.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP4(PROTECTION_DISENABLE) |
  249.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP3(PROTECTION_DISENABLE) |
  250.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP2(PROTECTION_DISENABLE) |
  251.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP1(PROTECTION_DISENABLE) |
  252.                         S3AXX04_AUGMENTED_PROTECTION_REG_ASP0(PROTECTION_DISENABLE));
  253.     s3axx04x0m_cmd_write(S3AXX_WRAP, write_reg_data, 1);
  254.     memset(write_reg_data, 0, sizeof(write_reg_data));

  255. /************************Configuration register 1************************/
  256.     //unlock TB BP
  257.     write_reg_data[0] |= S3AXX_CFG_REG1_MAPLK(UNLOCK_TB_BP);
  258.     //config Augmented 256-Byte Area Data protect whether with ASP
  259.     write_reg_data[0] |= S3AXX_CFG_REG1_ASPLK(DEPENDING_ON_ASP_0_7);

  260. /************************Configuration register 2************************/
  261.     //config use sspi/dspi/qspi
  262.     write_reg_data[1] |= S3AXX_CFG_REG2_QPIEN(QPIEN_SINGLE_SPI);
  263.     write_reg_data[1] |= S3AXX_CFG_REG2_DPIEN(DPIEN_SINGLE_SPI);
  264.     //config read delay period, different period of different cmd
  265.     write_reg_data[1] |= S3AXX_CFG_REG2_READ_LATENCY(LATENCY_0CYCLE);

  266. /************************Configuration register 3************************/
  267.     //config output strength
  268.     write_reg_data[2] |= S3AXX_CFG_REG3_DRV(DRV_36_35_OHM);
  269.     //enable/disable read/write boundary
  270.     write_reg_data[2] |= S3AXX_CFG_REG3_WRPEN(READ_WRAP_ENABLE);
  271.     //config rewind length of read boundary
  272.     write_reg_data[2] |= S3AXX_CFG_REG3_WRPL(WRPL_16_BYTE_WARP);

  273. /************************Configuration register 4************************/
  274.     //config write enable
  275.     write_reg_data[3] |= S3AXX_CFG_REG4_WRENS(NORMAL);

  276.     s3axx04x0m_cmd_write(S3AXX_WRCX, write_reg_data, 4);
  277. }

  278. void s3axx04x0m_write_memory(u8 *write_buff, u32 addr, u32 len)
  279. {
  280.     s3axx04x0m_cmd_set(S3AXX_WREN);
  281.     s3axx04x0m_continue_write(S3AXX_WRTE, addr, write_buff, len);
  282.     s3axx04x0m_cmd_set(S3AXX_WRDI);
  283. }

  284. void s3axx04x0m_read_memory(u8 *read_buff, u32 addr, u32 len)
  285. {
  286.     s3axx04x0m_continue_read(S3AXX_READ, addr, read_buff, len);
  287. }

  288. u32 s3axx04x0m_read_device_id(void)
  289. {
  290.     u8 device_id[4] = {0};
  291.     u32 reval = 0;

  292.     s3axx04x0m_cmd_read(S3AXX_RDID, device_id, 4);

  293.     reval = device_id[0] << 24 | device_id[1] << 16 | device_id[2] << 8 | device_id[3];

  294.     return reval;
  295. }
里面的SPI底层读写接口spi_rw的代码可以根据MCU平台进行相应修改。

实际应用的时候,上电初始化调用一次s3axx04x0m_init来对芯片进行寄存器等配置操作,然后可以调用s3axx04x0m_read_device_id来读取一下芯片设备ID,判断是否与宏S3AXX04_ID的值相等以进行异常错误处理等:
设备ID的相关信息可以参考下面这个设备制造商身份信息寄存器:
可以了解到接口类型,工作电压范围和工作温度范围等信息。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

打赏榜单

21小跑堂 打赏了 50.00 元 2026-05-14
理由:恭喜通过原创审核!期待您更多的原创作品~~

评论

文章从芯片介绍、手册解读和驱动代码三方面展开,详细阐述了该STT-MRAM芯片基于SPI通信的特性、引脚定义及寄存器配置,并提供了基于MCU的SPI驱动源码与移植思路,是一个不错的应用参考。   发表于 2026-5-14 17:11
您需要登录后才可以回帖 登录 | 注册

本版积分规则

533

主题

3826

帖子

26

粉丝
快速回复 在线客服 返回列表 返回顶部
0