#申请原创# #技术资源#
这篇帖子主要从芯片介绍、手册解读和驱动代码三个部分与大家分享一下个人的所学内容,供大家使用和参考。 一、 芯片介绍 最近项目上使用了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头文件的代码主要如下: - #ifndef __S3AXX04X0M_H__
- #define __S3AXX04X0M_H__
- #include "at32f403a_407.h"
- #include <stdio.h>
- #define S3AXX04_ID 0xd9010101
- #define S3AXX04X0M_GPIO GPIOB
- #define S3AXX04X0M_CS_GPIO GPIOB
- #define S3AXX04X0M_CLK_GPIO GPIOB
- #define S3AXX04X0M_MISO_GPIO GPIOB
- #define S3AXX04X0M_MOSI_GPIO GPIOB
- #define S3AXX04X0M_CS_PIN GPIO_PINS_6
- #define S3AXX04X0M_CLK_PIN GPIO_PINS_7
- #define S3AXX04X0M_MISO_PIN GPIO_PINS_8
- #define S3AXX04X0M_MOSI_PIN GPIO_PINS_9
- #define S3AXX04X0M_CS_HIGH() gpio_bits_write(S3AXX04X0M_CS_GPIO, S3AXX04X0M_CS_PIN, TRUE)
- #define S3AXX04X0M_CS_LOW() gpio_bits_write(S3AXX04X0M_CS_GPIO, S3AXX04X0M_CS_PIN, FALSE)
- #define S3AXX04X0M_CLK_HIGH() gpio_bits_write(S3AXX04X0M_CLK_GPIO, S3AXX04X0M_CLK_PIN, TRUE)
- #define S3AXX04X0M_CLK_LOW() gpio_bits_write(S3AXX04X0M_CLK_GPIO, S3AXX04X0M_CLK_PIN, FALSE)
- #define S3AXX04X0M_MOSI_HIGH() gpio_bits_write(S3AXX04X0M_MOSI_GPIO, S3AXX04X0M_MOSI_PIN, TRUE)
- #define S3AXX04X0M_MOSI_LOW() gpio_bits_write(S3AXX04X0M_MOSI_GPIO, S3AXX04X0M_MOSI_PIN, FALSE)
- #define S3AXX04X0M_MISO_READ() gpio_input_data_bit_read(S3AXX04X0M_MISO_GPIO, S3AXX04X0M_MISO_PIN)
- /* only sspi */
- typedef struct
- {
- void (*s3axx04x0m_delay_us)(u32 us);
- void (*spi_cs_set) (u8 state);
- int (*spi_read_bytes) (u8 *read_buf, u32 len);
- int (*spi_write_bytes) (u8 *write_buf, u32 len);
- }s3axx04x0m_spi_t;
- typedef enum {
- S3AXX_STATUS_REG = 0x00,
- S3AXX_CONFIG_REG1 = 0x02,
- S3AXX_CONFIG_REG2 = 0x03,
- S3AXX_CONFIG_REG3 = 0x04,
- S3AXX_CONFIG_REG4 = 0x05,
- S3AXX_DEVICE_IDENTIFICATION_REG = 0x30,
- S3AXX_UNIQUE_IDENTIFICATION_REG = 0x40,
- S3AXX_SERIAL_NUMBER_REG = 0x80,
- }s3axx04xom_reg_e;
- typedef enum {
- /* Instruction Name */ /* Interface Type(CMD-ADDR-Data) */
- S3AXX_NOOP = 0x00, /* No operation */ /* 1-0-0, 2-0-0, 4-0-0 */
- S3AXX_WREN = 0x06, /* Write enable*/ /* 1-0-0, 2-0-0, 4-0-0 */
- S3AXX_WRDI = 0x04, /* Write disable */ /* 1-0-0, 2-0-0, 4-0-0 */
- S3AXX_DPIE = 0x37, /* Enable DSPI */ /* 1-0-0, 4-0-0 */
- S3AXX_QPIE = 0x38, /* Enable QSPI */ /* 1-0-0, 2-0-0 */
- S3AXX_SPIE = 0xFF, /* Enable SSPI */ /* 2-0-0, 4-0-0 */
- S3AXX_DPDE = 0xB9, /* Enter Deep Power Down */ /* 1-0-0, 2-0-0, 4-0-0 */
- S3AXX_DPDX = 0xAB, /* Exit Deep Power Down */ /* 1-0-0, 2-0-0, 4-0-0 */
- S3AXX_SRTE = 0x66, /* Software Reset Enable */ /* 1-0-0, 2-0-0, 4-0-0 */
- S3AXX_SRST = 0x99, /* Software Reset Enable */ /* 1-0-0, 2-0-0, 4-0-0 */
- }s3axx04xom_ctrl_ins_e;
- typedef enum {
- /* Instruction Name */ /* Interface Type(CMD-ADDR-Data) */ /* Data Bytes */
- S3AXX_RDSR = 0x05, /* Read Status Register */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_RDC1 = 0x35, /* Read Configuration Register 1 */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_RDC2 = 0x3F, /* Read Configuration Register 2 */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_RDC3 = 0x44, /* Read Configuration Register 3 */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_RDC4 = 0x45, /* Read Configuration Register 4 */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_RDCX = 0x46, /* Read Configuration Registers 1,2,3,4 */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 4 */
- S3AXX_RDID = 0x9F, /* Read Device ID */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 4 */
- S3AXX_RUID = 0x4C, /* Read Unique ID */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 8 */
- S3AXX_RDSN = 0xC3, /* Read Serial Number Register */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 8 */
- S3AXX_RDAP = 0x14, /* Read Augmented 256-byte Protection Register */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_RDAR = 0x65, /* Read Any Register-Address Based */ /* 1-1-1, 2-2-2, 4-4-4 */ /* 1,4,8 */
- }s3axx04xom_read_reg_ins_e;
- typedef enum {
- /* Instruction Name */ /* Interface Type(CMD-ADDR-Data) */ /* Data Bytes */
- S3AXX_WRSR = 0x01, /* Write Status Register */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_WRCX = 0x87, /* Write Configuration Registers 1,2,3,4*/ /* 1-0-1, 2-0-2, 4-0-4 */ /* 4 */
- S3AXX_WRSN = 0xC2, /* Write Serial Number Register */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 8 */
- S3AXX_WRAP = 0x1A, /* Write Augmented 256-byte Protection Register */ /* 1-0-1, 2-0-2, 4-0-4 */ /* 1 */
- S3AXX_WRAR = 0x71, /* Write Any Register-Address Based */ /* 1-1-1, 2-2-2, 4-4-4 */ /* 1,8 */
- }s3axx04xom_write_reg_ins_e;
- typedef enum {
- /* Instruction Name */ /* Interface Type(CMD-ADDR-Data) */ /* Data Bytes */
- S3AXX_READ = 0x03, /* Read Memory Array-SDR */ /* 1-1-1 */ /* 1->鈭?*/
- S3AXX_RDFT = 0x0B, /* Fast Read Memory Array-SDR */ /* 1-1-1, 2-2-2, 4-4-4 */ /* 1->鈭?*/
- S3AXX_DRFR = 0x0D, /* Fast Read Memory Array-DDR */ /* 1-1-1, 2-2-2, 4-4-4 */ /* 1->鈭?*/
- S3AXX_RDDO = 0x3B, /* Read Dual Output Memory Array-SDR */ /* 1-1-2 */ /* 1->鈭?*/
- S3AXX_DRDO = 0x3D, /* Read Dual Output Memory Array-DDR */ /* 1-1-2 */ /* 1->鈭?*/
- S3AXX_RDQO = 0x6B, /* Read Quad Output Memory Array鈥揝DR */ /* 1-1-4 */ /* 1->鈭?*/
- S3AXX_DRQO = 0x6D, /* Read Quad Output Memory Array鈥揇DR */ /* 1-1-4 */ /* 1->鈭?*/
- S3AXX_RDDI = 0xBB, /* Read Dual I/O Memory Read-SDR */ /* 1-2-2 */ /* 1->鈭?*/
- S3AXX_DRDI = 0xBD, /* Read Dual I/O Memory Read-DDR */ /* 1-2-2 */ /* 1->鈭?*/
- S3AXX_RDQI = 0xEB, /* Read Quad I/O Memory Read-SDR */ /* 1-4-4 */ /* 1->鈭?*/
- S3AXX_DRQI = 0xED, /* Read Quad I/O Memory Read-DDR */ /* 1-4-4 */ /* 1->鈭?*/
- }s3axx04xom_read_memory_array_instruction_e;
- typedef enum {
- /* Instruction Name */ /* Interface Type(CMD-ADDR-Data) */ /* Data Bytes */
- S3AXX_WRTE = 0x02, /* Write Memory Array-SDR */ /* 1-1-1 */ /* 1->鈭?*/
- S3AXX_WRFT = 0xDA, /* Fast Write Memory Array-SDR */ /* 1-1-1, 2-2-2, 4-4-4 */ /* 1->鈭?*/
- S3AXX_DRFW = 0xDE, /* Fast Write Memory Array-DDR */ /* 1-1-1, 2-2-2, 4-4-4 */ /* 1->鈭?*/
- S3AXX_WDUI = 0xA2, /* Write Dual Input Memory Array-SDR */ /* 1-1-2 */ /* 1->鈭?*/
- S3AXX_DWUI = 0xA4, /* Write Dual Input Memory Array-DDR */ /* 1-1-2 */ /* 1->鈭?*/
- S3AXX_WQDI = 0x32, /* Write Quad Input Memory Array-SDR */ /* 1-1-4 */ /* 1->鈭?*/
- S3AXX_DWQI = 0x32, /* Write Quad Input Memory Array-DDR */ /* 1-1-4 */ /* 1->鈭?*/
- S3AXX_WDIO = 0xA1, /* Write Dual I/O Memory Array-SDR */ /* 1-2-2 */ /* 1->鈭?*/
- S3AXX_DWIO = 0xA3, /* Write Dual I/O Memory Array-DDR */ /* 1-2-2 */ /* 1->鈭?*/
- S3AXX_WQIO = 0xD2, /* Write Quad I/O Memory Array-SDR */ /* 1-4-4 */ /* 1->鈭?*/
- S3AXX_DWQO = 0xD1, /* Write Quad I/O Memory Array-DDR */ /* 1-4-4 */ /* 1->鈭?*/
- }s3axx04xom_write_memory_array_ins_e;
- typedef enum {
- /* Instruction Name */ /* Interface Type(CMD-ADDR-Data) */ /* Data Bytes */
- S3AXX_RDAS = 0x4B, /* Read Augmented 256-Byte Area-SDR */ /* 1-1-1 */ /* 1->256 */
- S3AXX_WRAS = 0x42, /* Write Augmented 256-Byte Area-SDR */ /* 1-1-1 */ /* 1->256 */
- }s3axx04xom_augmented_256_byte_area_ins_e;
- /************************Status register************************/
- #define S3AXX_STA_REG_WPEN(x) ((x) << 7)
- #define S3AXX_STA_REG_SNPEN(x) ((x) << 6)
- #define S3AXX_STA_REG_TB(x) ((x) << 5)
- #define S3AXX_STA_REG_BP(x) ((x) << 2)
- #define S3AXX_STA_REG_WREN(x) ((x) << 1)
- typedef enum {
- WRITE_PROTECT_DISENABLE_LOW_WP = 0x00,
- WRITE_PROTECT_ENABLE_LOW_WP = 0x01,
- }s3axx04x0m_sta_reg_WPEN_e;
- typedef enum {
- SERIAL_NUMBER_WRITABLE = 0x00,
- SERIAL_NUMBER_WRITE_PROTECTED = 0x01,
- }s3axx04x0m_sta_reg_SNPEN_e;
- typedef enum {
- TOP_PROTECTION_ENABLE = 0x00,
- BOTTOM_PROTECTION_ENABLE = 0x01,
- }s3axx04x0m_sta_reg_TB_e;
- typedef enum {
- PP_NONE = 0x00,
- UPPER_LOWER_1_64 = 0x01,
- UPPER_LOWER_1_32 = 0x02,
- UPPER_LOWER_1_16 = 0x03,
- UPPER_LOWER_1_8 = 0x04,
- UPPER_LOWER_1_4 = 0x05,
- UPPER_LOWER_1_2 = 0x06,
- PP_ALL = 0x07,
- }s3axx04x0m_sta_reg_BP_e;
- typedef enum {
- WRITE_PROTECT_ENABLE = 0x00,
- WRITE_PROTECT_DISENABLE = 0x01,
- }s3axx04x0m_sta_reg_WREN_e;
- /************************Augmented 256-Byte Area Protection register************************/
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP7(x) ((x) << 7)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP6(x) ((x) << 6)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP5(x) ((x) << 5)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP4(x) ((x) << 4)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP3(x) ((x) << 3)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP2(x) ((x) << 2)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP1(x) ((x) << 1)
- #define S3AXX04_AUGMENTED_PROTECTION_REG_ASP0(x) ((x) << 0)
- typedef enum {
- PROTECTION_DISENABLE = 0x00,
- PROTECTION_ENABLE = 0x01,
- }s3axx04x0m_augmented_protection_reg_WREN_e;
- /************************Configuration register 1************************/
- #define S3AXX_CFG_REG1_MAPLK(x) ((x) << 2)
- #define S3AXX_CFG_REG1_ASPLK(x) ((x) << 0)
- typedef enum {
- UNLOCK_TB_BP = 0x00,
- LOCK_TB_BP = 0x01,
- }s3axx04x0m_cfg_reg1_MAPLK_e;
- typedef enum {
- DEPENDING_ON_ASP_0_7 = 0x00,
- REGARDLESS_ASP_0_7 = 0x01,
- }s3axx04x0m_cfg_reg1_ASPLK_e;;
- /************************Configuration register 2************************/
- #define S3AXX_CFG_REG2_QPIEN(x) ((x) << 6)
- #define S3AXX_CFG_REG2_DPIEN(x) ((x) << 4)
- #define S3AXX_CFG_REG2_READ_LATENCY(x) ((x) << 0)
- typedef enum {
- QPIEN_SINGLE_SPI = 0x00,
- QPIEN_QUAN_SPI = 0x01,
- }s3axx04x0m_cfg_reg2_QPIEN_e;
- typedef enum {
- DPIEN_SINGLE_SPI = 0x00,
- DPIEN_DUAL_SPI = 0x01,
- }s3axx04x0m_cfg_reg2_DPIEN_e;
- typedef enum {
- LATENCY_0CYCLE = 0x00,
- LATENCY_1CYCLE = 0x01,
- LATENCY_2CYCLE = 0x02,
- LATENCY_3CYCLE = 0x03,
- LATENCY_4CYCLE = 0x04,
- LATENCY_5CYCLE = 0x05,
- LATENCY_6CYCLE = 0x06,
- LATENCY_7CYCLE = 0x07,
- LATENCY_8CYCLE = 0x08,
- LATENCY_9CYCLE = 0x09,
- LATENCY_10CYCLE = 0x0A,
- LATENCY_11CYCLE = 0x0B,
- LATENCY_12CYCLE = 0x0C,
- LATENCY_13CYCLE = 0x0D,
- LATENCY_14CYCLE = 0x0E,
- LATENCY_15CYCLE = 0x0F,
- }s3axx04x0m_cfg_reg2_read_latency_e;
- /************************Configuration register 3************************/
- #define S3AXX_CFG_REG3_DRV(x) ((x) << 5)
- #define S3AXX_CFG_REG3_WRPEN(x) ((x) << 4)
- #define S3AXX_CFG_REG3_WRPL(x) ((x) << 0)
- typedef enum {
- DRV_36_35_OHM = 0x00,
- DRV_100_95_OHM = 0x01,
- DRV_75_63_OHM = 0x02,
- DRV_60_50_OHM = 0x03,
- DRV_48_40_OHM = 0x04,
- DRV_42_30_OHM = 0x05,
- DRV_29_26_OHM = 0x06,
- DRV_24_22_OHM = 0x07,
- }s3axx04x0m_cfg_reg3_DRV_e;
- typedef enum {
- READ_WRAP_DISABLE = 0x00,
- READ_WRAP_ENABLE = 0x01,
- }s3axx04x0m_cfg_reg3_WRPEN_e;
- typedef enum {
- WRPL_16_BYTE_WARP = 0x00,
- WRPL_32_BYTE_WARP = 0x01,
- WRPL_64_BYTE_WARP = 0x02,
- WRPL_128_BYTE_WARP = 0x03,
- WRPL_256_BYTE_WARP = 0x04,
- WRPL_512_BYTE_WARP = 0x05,
- WRPL_1K_BYTE_WARP = 0x06,
- }s3axx04x0m_cfg_reg3_WRPL_e;
- /************************Configuration register 4************************/
- #define S3AXX_CFG_REG4_WRENS(x) ((x) << 0)
- typedef enum {
- NORMAL = 0x00,
- SRAM = 0x01,
- BACK_TO_BACK = 0x02,
- }s3axx04x0m_cfg_reg4_WRENS_e;
- void s3axx04x0m_continue_read(u8 cmd, u32 addr, u8 *read_buf, u32 len);
- void s3axx04x0m_continue_write(u8 cmd, u32 addr, u8 *write_buf, u32 len);
- void s3axx04x0m_deep_power_down(void);
- void s3axx04x0m_exit_deep_power_down_by_cmd(void);
- void s3axx04x0m_software_reset(void);
- void s3axx04x0m_cmd_set(u8 ctrl_instruction);
- void s3axx04x0m_cmd_read(u8 ctrl_instruction, u8 *read_buff, u32 len);
- void s3axx04x0m_cmd_write(u8 ctrl_instruction, u8 *write_buff, u32 len);
- void s3axx04x0m_READ_without_XIP(u32 addr, u8 *read_buff, u32 len);
- void s3axx04x0m_WRTE(u32 addr, u8 *write_buff, u32 len);
- void s3axx04x0m_RDAR(u32 addr, u8 *read_buff, u32 len);
- void s3axx04x0m_WRAR(u32 addr, u8 *write_buff, u32 len);
- void s3axx04x0m_init(void);
- void s3axx04x0m_write_memory(u8 *write_buff, u32 addr, u32 len);
- void s3axx04x0m_read_memory(u8 *read_buff, u32 addr, u32 len);
- u32 s3axx04x0m_read_device_id(void);
- #endif /* __S3AXX04X0M_H__ */
里面的与MCU底层配置相关的部分可以根据MCU平台进行相应修改。
其中s3axx04x0m.c源文件的代码主要如下: - #include "s3axx04x0m.h"
- #include "bsp_spi_bus.h"
- s3axx04x0m_spi_t s3axx04x0m_spi0;
- void s3axx_delay_us(u32 us)
- {
- u16 cnt;
- if(us == 0)
- return;
- while(us--)
- {
- cnt = 8;
- while(cnt--);
- }
- }
- void gpio_cs_set(u8 set)
- {
- switch(set)
- {
- case 0:
- S3AXX04X0M_CS_LOW();
- break;
- case 1:
- S3AXX04X0M_CS_HIGH();
- break;
- }
- }
- /*spi read(when data is 0) or write*/
- static uint8_t spi_rw(uint8_t data)
- {
- uint8_t temp = 0;
- while(spi_i2s_flag_get(S3A1004VOM_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
- spi_i2s_data_transmit(S3A1004VOM_SPI_TYPE, data);
- while(spi_i2s_flag_get(S3A1004VOM_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
- temp = spi_i2s_data_receive(S3A1004VOM_SPI_TYPE);
- return temp;
- }
- int spi0_read_bytes(u8 *read_buf, u32 len)
- {
- if(read_buf == 0)
- return -1;
- for(int i = 0; i < len; i++)
- {
- read_buf[i] = spi_rw(0);
- }
- return 0;
- }
- int spi0_write_bytes(u8 *write_buf, u32 len)
- {
- if(write_buf == 0)
- return -1;
- for(int i = 0; i < len; i++)
- {
- spi_rw(write_buf[i]);
- }
- return 0;
- }
- void s3axx04x0m_read_byte(u8 cmd, u32 addr, u8 *read_buf)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- spi_rw(cmd);
- for(int i = 0; i < 3; i ++)
- {
- write_data = addr >> ((2-i)*8);
- spi_rw(write_data);
- }
- *read_buf = spi_rw(0);
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_write_byte(u8 cmd, u32 addr, u8 *write_buf)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- spi_rw(cmd);
- for(int i = 0; i < 3; i ++)
- {
- write_data = addr >> ((2-i)*8);
- spi_rw(write_data);
- }
- spi_rw(*write_buf);
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_XIP_read(u8 cmd, u32 addr, u8 *read_buf)
- {
- }
- void s3axx04x0m_continue_read(u8 cmd, u32 addr, u8 *read_buf, u32 len)
- {
- u8 write_data = 0;
- u8 tmp = 0;
- S3AXX04X0M_CS_LOW();
- spi_rw(cmd);
- for(int i = 0; i < 3; i ++)
- {
- write_data = addr >> ((2-i)*8);
- spi_rw(write_data);
- }
- for(int i = 0; i < len; i++)
- {
- read_buf[i] = spi_rw(0);
- }
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_continue_write(u8 cmd, u32 addr, u8 *write_buf, u32 len)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- spi_rw(cmd);
- for(int i = 0; i < 3; i ++)
- {
- write_data = addr >> ((2-i)*8);
- spi_rw(write_data);
- }
- for(int i = 0; i < len; i++)
- {
- spi_rw(write_buf[i]);
- }
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_deep_power_down(void)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- write_data = S3AXX_DPDE;
- spi_rw(write_data);
- S3AXX04X0M_CS_HIGH();
- for(int i = 0; i < 10; i++);
- }
- void s3axx04x0m_exit_deep_power_down_by_cmd(void)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- write_data = S3AXX_DPDX;
- spi_rw(write_data);
- S3AXX04X0M_CS_HIGH();
- for(int i = 0; i < 10; i++);
- }
- void s3axx04x0m_software_reset(void)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- write_data = S3AXX_SRTE;
- spi_rw(write_data);
- S3AXX04X0M_CS_HIGH();
- S3AXX04X0M_CS_LOW();
- write_data = S3AXX_SRST;
- spi_rw(write_data);
- S3AXX04X0M_CS_HIGH();
- //3.3V tSRST_max = 0.3ms 1.8V tSRST_max = 2ms
- // s3axx04x0m_spi0.s3axx04x0m_delay_us(500);
- s3axx_delay_us(500);
- }
- void s3axx04x0m_cmd_set(u8 ctrl_instruction)
- {
- u8 write_data = 0;
- S3AXX04X0M_CS_LOW();
- write_data = ctrl_instruction;
- spi_rw(write_data);
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_cmd_read(u8 ctrl_instruction, u8 *read_buff, u32 len)
- {
- S3AXX04X0M_CS_LOW();
- spi_rw(ctrl_instruction);
- for(int i = 0; i < len; i++)
- {
- read_buff[i] = spi_rw(0);
- }
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_cmd_write(u8 ctrl_instruction, u8 *write_buff, u32 len)
- {
- S3AXX04X0M_CS_LOW();
- spi_rw(ctrl_instruction);
- for(int i = 0; i < len; i++)
- {
- spi_rw(write_buff[i]);
- }
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_READ_without_XIP(u32 addr, u8 *read_buff, u32 len)
- {
- s3axx04x0m_continue_read(S3AXX_READ, addr, read_buff, len);
- }
- void s3axx04x0m_WRTE(u32 addr, u8 *write_buff, u32 len)
- {
- s3axx04x0m_continue_write(S3AXX_WRTE, addr, write_buff, len);
- }
- void s3axx04x0m_RDAS(u32 addr, u8 *read_buff, u32 len)
- {
- }
- void s3axx04x0m_WRAS(u32 addr, u8 *write_buff, u32 len)
- {
- }
- void s3axx04x0m_RDAR(u32 addr, u8 *read_buff, u32 len)
- {
- u8 write_data = 0;
- write_data = S3AXX_RDAR;
- S3AXX04X0M_CS_LOW();
- spi_rw(write_data);
- for(int i = 0; i < 3; i ++)
- {
- write_data = addr >> ((2-i)*8);
- spi_rw(write_data);
- }
- write_data = 0xFF;
- spi_rw(write_data);
- for(int i = 0; i < len; i++)
- {
- read_buff[i] = spi_rw(0);
- }
- S3AXX04X0M_CS_HIGH();
- }
- void s3axx04x0m_WRAR(u32 addr, u8 *write_buff, u32 len)
- {
- s3axx04x0m_continue_write(S3AXX_WRAR, addr, write_buff, len);
- }
- void s3axx04x0m_RDFT(u32 addr, u8 *read_buff, u32 len)
- {
- }
- void s3axx04x0m_WRFT(u32 addr, u8 *write_buff, u32 len)
- {
- }
- void s3axx04x0m_register(void)
- {
- s3axx04x0m_spi0.spi_cs_set = gpio_cs_set;
- s3axx04x0m_spi0.spi_read_bytes = spi0_read_bytes;
- s3axx04x0m_spi0.spi_write_bytes = spi0_write_bytes;
- s3axx04x0m_spi0.s3axx04x0m_delay_us = s3axx_delay_us;
- }
- void s3axx04x0m_init(void)
- {
- u8 write_reg_data[4] = {0};
- //s3axx04x0m_register();
- /************************Status register************************/
- //config WP protect bit based on hardware
- write_reg_data[0] |= S3AXX_STA_REG_WPEN(WRITE_PROTECT_ENABLE_LOW_WP);
- write_reg_data[0] |= S3AXX_STA_REG_SNPEN(SERIAL_NUMBER_WRITE_PROTECTED);
- write_reg_data[0] |= S3AXX_STA_REG_TB(TOP_PROTECTION_ENABLE);
- write_reg_data[0] |= S3AXX_STA_REG_BP(PP_ALL);
- write_reg_data[0] |= S3AXX_STA_REG_WREN(WRITE_PROTECT_ENABLE);
- s3axx04x0m_cmd_write(S3AXX_WRSR, write_reg_data, 1);
- memset(write_reg_data, 0, sizeof(write_reg_data));
- /************************Augmented 256-Byte Area Protection register************************/
- /*config add protection enable/disable*/
- write_reg_data[0] |= (S3AXX04_AUGMENTED_PROTECTION_REG_ASP7(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP6(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP5(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP4(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP3(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP2(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP1(PROTECTION_DISENABLE) |
- S3AXX04_AUGMENTED_PROTECTION_REG_ASP0(PROTECTION_DISENABLE));
- s3axx04x0m_cmd_write(S3AXX_WRAP, write_reg_data, 1);
- memset(write_reg_data, 0, sizeof(write_reg_data));
- /************************Configuration register 1************************/
- //unlock TB BP
- write_reg_data[0] |= S3AXX_CFG_REG1_MAPLK(UNLOCK_TB_BP);
- //config Augmented 256-Byte Area Data protect whether with ASP
- write_reg_data[0] |= S3AXX_CFG_REG1_ASPLK(DEPENDING_ON_ASP_0_7);
- /************************Configuration register 2************************/
- //config use sspi/dspi/qspi
- write_reg_data[1] |= S3AXX_CFG_REG2_QPIEN(QPIEN_SINGLE_SPI);
- write_reg_data[1] |= S3AXX_CFG_REG2_DPIEN(DPIEN_SINGLE_SPI);
- //config read delay period, different period of different cmd
- write_reg_data[1] |= S3AXX_CFG_REG2_READ_LATENCY(LATENCY_0CYCLE);
- /************************Configuration register 3************************/
- //config output strength
- write_reg_data[2] |= S3AXX_CFG_REG3_DRV(DRV_36_35_OHM);
- //enable/disable read/write boundary
- write_reg_data[2] |= S3AXX_CFG_REG3_WRPEN(READ_WRAP_ENABLE);
- //config rewind length of read boundary
- write_reg_data[2] |= S3AXX_CFG_REG3_WRPL(WRPL_16_BYTE_WARP);
- /************************Configuration register 4************************/
- //config write enable
- write_reg_data[3] |= S3AXX_CFG_REG4_WRENS(NORMAL);
- s3axx04x0m_cmd_write(S3AXX_WRCX, write_reg_data, 4);
- }
- void s3axx04x0m_write_memory(u8 *write_buff, u32 addr, u32 len)
- {
- s3axx04x0m_cmd_set(S3AXX_WREN);
- s3axx04x0m_continue_write(S3AXX_WRTE, addr, write_buff, len);
- s3axx04x0m_cmd_set(S3AXX_WRDI);
- }
- void s3axx04x0m_read_memory(u8 *read_buff, u32 addr, u32 len)
- {
- s3axx04x0m_continue_read(S3AXX_READ, addr, read_buff, len);
- }
- u32 s3axx04x0m_read_device_id(void)
- {
- u8 device_id[4] = {0};
- u32 reval = 0;
- s3axx04x0m_cmd_read(S3AXX_RDID, device_id, 4);
- reval = device_id[0] << 24 | device_id[1] << 16 | device_id[2] << 8 | device_id[3];
- return reval;
- }
里面的SPI底层读写接口spi_rw的代码可以根据MCU平台进行相应修改。
实际应用的时候,上电初始化调用一次s3axx04x0m_init来对芯片进行寄存器等配置操作,然后可以调用s3axx04x0m_read_device_id来读取一下芯片设备ID,判断是否与宏S3AXX04_ID的值相等以进行异常错误处理等: 设备ID的相关信息可以参考下面这个设备制造商身份信息寄存器: 可以了解到接口类型,工作电压范围和工作温度范围等信息。
|