0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【技术分享】Apollo3 SDK平台添加支持复旦微FM25Q128 SPI Flash的方法

润欣科技Fortune 2019-03-14 13:39 次阅读


上海润欣科技股份有限公司创研社

本文详细介绍了,如何在Apollo3 SDK v2.0平台上增加对复旦微FM25Q128 SPI Flash支持的方法。本文将结合软件和硬件,阐述如何通过Apollo3片上串行外设MSPI接口Quad SPI模式访问SPI Flash的底层驱动代码的实现步骤。

1、 什么是MSPI

MSPI,即Multi-bit SPI的缩写,Apollo3新引入的串行外设,可以支持单线SPIDual SPIQuad SPI,以及八线Octal SPI(可以是单个Octal设备,也可以是两个Quad Pair组成的Octal 设备)等模式,最高速率24MHz,可以外接串行存储设备,如PSRAMSPI Nor Flash等,支持XIP片上直接运行代码。MPSI支持全部的4SPI CPOL/CPHA模式,即模式0-3支持DMA。支持Command Queue2个片选,以Quad-SPI为例,MSPI最多支持两路Quad-SPI,这两路共用一个MSPI CLK。两路QSPI分时操作。MSPI具体的管脚复用图如下图1

pIYBAFyJ4o6ASN_iAACdRZ2ZE98973.jpg

图1 MSPI管脚复用图

2、 MSPI连接SPI FlashQuad SPI四线模式,如图2

pIYBAFyJ4qeAPytNAAA5X0_h2nA803.jpg

2 MSPI采用Quad SPI接口连接外部SPI Flash器件原理图

3、根据以上图2所示硬件原理图,我们需要对SDK中的BSP库进行相应的修改,将MSPI使用到的相关管脚一一进行分配和初始化,如这里用到的:

GP1 --- CE0 (片选)

GP26 --- DQ1(数据IO1, SPI DO)

GP4 --- DQ2 (数据IO2SPI WP#)

GP22 --- DQ0 (数据IO0SPI DI)

GP24 --- CLK (时钟信号)

GP23 --- DQ3 (数据IO3SPI HOLD#)

打开SDK v2.0目录下的工程libam_bsp,找到文件am_bsp_pins.h,按照上面分配的管脚修改定义:

o4YBAFyJ4qSAI83dAAAoaddPYOc912.jpg

o4YBAFyJ4qyAAoEmAAAzhcLlGzc157.jpg

pIYBAFyJ4sWAG_7eAACOpnpxWZk395.jpg

再在同一工程里面找到am_bsp_pins.c文件,逐一修改以上管脚对应的属性结构体,如下:

o4YBAFyJ4ruAfqnAAAA43j13LXs270.jpg

pIYBAFyJ4tWAfIwQAABSGRBvxAM164.jpg

o4YBAFyJ4syAfG-eAABtOp1fyrg823.jpg

pIYBAFyJ4uSAIn85AABrYDmY9h0857.jpg

如果不需要修改其他外设接口的管脚定义,保存文件后退出编辑模式,SDK v2.0下的示例代码默认包含BSPHAL库文件进行编译,所以,这里需要重新将libam_bsp工程进行重新编译,假设我们使用Keil MDK编译器,那么生成的库文件为libam_bsp.lib,可以直接包含到其他的Keil MDK示例工程下进行使用。IAR生成的库文件为libam_bsp.a

4、了解复旦微 SPI Flash器件FM25Q128的基本特性

FM25Q128是复旦微电子生产的串行SPI接口Nor Flash存储器,支持单线SPI, 双线Dual SPI和四线Quad SPIQPI)模式,我们采用的是Quad SPI,即器件的QPI模式(4-4-4)

FM25Q128的容量为128Mbit16MB),单个Sector扇区大小为4KB,支持32KB或者64KB大小的Block块,可编程页大小为256字节。Sector扇区,Block块大小和数量的宏定义详见如下代码:

pIYBAFyJ4vaACgB5AAAzLA10akY216.jpg

我们采用的芯片封装和引脚定义如下图3所示;

o4YBAFyJ4u2ABPLxAAA04I6luJ0766.jpg

3 FM25Q125芯片引脚定义图

请特别注意管脚WP#HOLD#/RESET#DQ3)的描述

pIYBAFyJ4wWALFWOAABNQphmlqc025.jpg

出厂时,QE位为0,芯片处于单线SPI模式,硬件上,芯片的Pin3WP#信号,Pin7HOLD#/RESET#信号,继续了解WP#HOLD#硬件关键的特点,

说明: D:\AmbiqMicro\Apollo3\WP和HOLD脚注意事项.png

o4YBAFyJ4wWAbDj7AABTEGzP2W8426.jpg

SPI模式下,如果WP#管脚为低,则禁止改写Status状态寄存器的值;当HOLD#为低时,即使芯片CS片选脚被激活,芯片仍将进入暂停模式,SPI总线无法正常访问SPI Flash,包括读取Status状态寄存器的值,芯片相当于进入了复位状态。因为芯片出厂默认模式是单线SPI模式,因此,我们需要先通过Apollo3MSPI接口的单线SPI模式(1-1-1)来初始化器件,让器件进入QPI模式(4-4-4)后,然后再使用Quad SPI进行访问SPI Flash,以实现利用最高的效率访问SPI Flash外设。SPI的不同接口类型在传输指令码、地址码、数据码时所使用的传输通道数量不同,如下图4所示:

pIYBAFyJ4x-ANTiKAAA84EAqpfY395.jpg

4 SPI不同接口类型的区别

FM25Q128上电初始化流程如下图所示,要使能芯片的QPI模式,需要使能状态寄存器Status Register-2中的bit1QE,然后使用0x38命令使能进入QPI模式。退出QPI模式可以发送0xFF命令或者发送软件复位序列0x66 + 0x99,如下图5所示。

o4YBAFyJ4xiAZrXOAAA-8bPi8pU401.jpg

5 FM25Q125上电初始化流程

如上所述,初次上电后,Flash芯片处于单线SPI模式,WP#HOLD#管脚可能影响状态寄存器的写入操作,实际调试底层驱动代码的过程中,笔者也发现了这个问题,由于HOLD#没有外接上拉电阻,在SPI模式下Flash芯片的HOLD#脚电平不稳,导致读写状态寄存器时而正常,时而失败,开发板正常,客户的板子失败等现象,调试了很长时间才发现问题根源在于此。我们可以将Apollo3芯片的MSPI接口配置成SPI模式,并将连接到FM25Q128DQ2(WP#)DQ3HOLD#/RESET#)的管脚GP4GP23配置成GPIO输出,使能内部上拉电阻,并且同时输出高电平,让WP#HOLD#管脚处于非激活状态

我们先通过阅读Datasheet来了解一下Apollo3GPIO口结构,以及内部上拉电阻的配置。

pIYBAFyJ4zOANC7IAAB2QiZF-4Q737.jpg

pIYBAFyJ4zqALAeSAAA-y9FUHc4639.jpg

o4YBAFyJ4zOANEuTAACP7LEqSMk897.jpg

o4YBAFyJ4zuAOm9xAAAp4_3KgaI060.jpg

Apollo3的所有的GPIO都可以通过软件来配置(PADnPULL)使能内部上拉电阻(除了GPIO20为下拉),上拉电阻默认状态是禁用的。另外,包含有I2C功能的GPIO的内部上拉电阻是可以选择四种不同阻值的。我们用到的GP4GP23不包含I2C功能,因此不能选择上拉电阻的阻值。经过与AmbiqMicro原厂工程师沟通,了解到内部通用上拉电阻的阻值大约为63KΩ,这个内部的弱上拉足可以保证在SPI模式初始化SPI Flash时,WP#HOLD#/RESET#管脚稳定为高电平状态。参考代码如下:

#define AM_BSP_GPIO_GP23 23

#define AM_BSP_GPIO_GP4 4

const am_hal_gpio_pincfg_t g_AM_BSP_GPIO_GP23_HOLD =

{

.uFuncSel = AM_HAL_PIN_23_GPIO,

.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_8MA,

.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK,

.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL,

.eGPInput = AM_HAL_GPIO_PIN_INPUT_NONE

};

const am_hal_gpio_pincfg_t g_AM_BSP_GPIO_GP4_WP =

{

.uFuncSel = AM_HAL_PIN_4_GPIO,

.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_8MA,

.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK,

.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL,

.eGPInput = AM_HAL_GPIO_PIN_INPUT_NONE

};

static void ConfigGP23AsGpioOutputForPullHighHoldPin (void)

{

//

// Configure the pin as a push-pull GPIO output.

//

am_hal_gpio_pinconfig(AM_BSP_GPIO_GP23, g_AM_BSP_GPIO_GP23_HOLD);

//

// Disable the output driver, and set the output value to the high level

// state. Note that for Apollo3 GPIOs in push-pull mode, the output

// enable, normally a tri-state control, instead functions as an enable

// for Fast GPIO. Its state does not matter on previous chips, so for

// normal GPIO usage on Apollo3, it must be disabled.

//

am_hal_gpio_state_write(AM_BSP_GPIO_GP23, AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE);

am_hal_gpio_state_write(AM_BSP_GPIO_GP23, AM_HAL_GPIO_OUTPUT_SET); // pull high

}

static void ConfigGP4AsGpioOutputForPullHighWPPin (void)

{

//

// Configure the pin as a push-pull GPIO output.

//

am_hal_gpio_pinconfig(AM_BSP_GPIO_GP4, g_AM_BSP_GPIO_GP4_WP); //

// Disable the output driver, and set the output value to the high level

// state. Note that for Apollo3 GPIOs in push-pull mode, the output

// enable, normally a tri-state control, instead functions as an enable

// for Fast GPIO. Its state does not matter on previous chips, so for

// normal GPIO usage on Apollo3, it must be disabled.

//

am_hal_gpio_state_write(AM_BSP_GPIO_GP4, AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE);

am_hal_gpio_state_write(AM_BSP_GPIO_GP4, AM_HAL_GPIO_OUTPUT_SET); // pull high

}

pIYBAFyJ41WACI0NAABaNOJchtA211.jpg

代码详见SDK v2.0目录下的示例工程mspi_quad_example,文件am_devices_mspi_flash.c

5、 SDK v2.0示例代码mspi_quad_example的基础上添加FM25Q128的支持

am_devices_mspi_flash.h文件中增加器件型号宏定义:#define FUDAN_FM25Q128

以及器件支持的相关操作命令,ID码以及容量宏定义

#if defined (FUDAN_FM25Q128)

//*******************************************************************

//

// Device specific identification.

//

//*******************************************************************

#define AM_DEVICES_MSPI_FLASH_ID 0x001840A1

#define AM_DEVICES_MSPI_FLASH_ID_MASK 0x00FFFFFF

//*******************************************************************

//

// Device specific definitions for flash commands

//

//*******************************************************************

#define AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER1 0x05 // RDSR1, read STATUS_REGISTER 1

#define AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER2 0x35 // RDSR2, read STATUS_REGISTER 2

#define AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER3 0x15 // RDSR3, read STATUS_REGISTER 3

#define AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER1 0x01 // WRSR1, write STATUS_REGISTER 1

#define AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER2 0x31 // WRSR2, write STATUS_REGISTER 2

#define AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER3 0x11 // WRSR3, write STATUS_REGISTER 3

#define AM_DEVICES_MSPI_FLASH_ENABLE_QPI_MODE 0x38 // EQIO, Enable QPI

#define AM_DEVICES_MSPI_FLASH_DISABLE_QPI_MODE 0xFF // Disable QPI

#define AM_DEVICES_MSPI_FLASH_ENABLE_RESET 0x66 // Enable Reset

#define AM_DEVICES_MSPI_FLASH_RESET 0x99 // Reset

#define AM_DEVICES_MSPI_FLASH_WRITE_ENABLE_VOLATILE 0x50 // Write Enable for Volatile Status Register

//*******************************************************************

//

// Device specific definitions for the Configuration register(s)

//

//*******************************************************************

#define AM_DEVICES_MSPI_CLEAR_STATUS_REGISTER1 (0x00) // the value to clear the status register-1

#define AM_DEVICES_MSPI_ENABLE_QUAD_STATUS_REGISTER2 (0xF2) // LC = 11b, dummy cycles = 4 for quad enable, 0 for spi mdode

#define AM_DEVICES_MSPI_CLEAR_STATUS_REGISTER3 (0xFC) // to clear the status register-3, the reserved bits will be bypassed

//*******************************************************************

//

// Device specific definitions for the flash size information

//

//*******************************************************************

#define AM_DEVICES_MSPI_FLASH_PAGE_SIZE 0x100 // 256 bytes, minimum program unit

#define AM_DEVICES_MSPI_FLASH_SECTOR_SIZE 0x1000 // 4K bytes

#define AM_DEVICES_MSPI_FLASH_BLOCK_SIZE 0x10000 // 64K bytes.

#define AM_DEVICES_MSPI_FLASH_MAX_SECTORS 4096 // Sectors within 3-byte address range. 4096 * 4KB = 16MB

#define AM_DEVICES_MSPI_FLASH_MAX_BLOCKS 256 // 256 * 64KB = 16MB

#endif

上电后初始化先清除SR1SR3中的相应的状态位和错误标志位。

说明:状态寄存器SR2-3中的有些位标注为R,其为Reserved Bit,即保留位,不能被软件改写,建议采用先读出SR2-3的值,再使用与或操作置位或者清除可以改写的位,同时保留那些原有标注R的位的值。

o4YBAFyJ406AA3FYAAB7ozmMiIY662.jpg

o4YBAFyJ41WALn2iAABa4XVTD5A085.jpg

pIYBAFyJ426AIa7gAAC_OkGu6P8829.jpg

o4YBAFyJ42eAKdOIAAA2p2KUyKA587.jpg

o4YBAFyJ426ADISRAABOFMPd8-8356.jpg

pIYBAFyJ44aAa2WGAACK7hv9JCA897.jpg

am_devices_mspi_flash.c文件中增加对FM25Q128支持的初始化代码:

SPI接口初始化宏定义:

// Configure the MSPI for Serial operation during initialization

am_hal_mspi_dev_config_t SerialCE0MSPIConfig = // MSPI SERIAL CE0(SPI mode)

{

.eSpiMode = AM_HAL_MSPI_SPI_MODE_0,

.eClockFreq = AM_HAL_MSPI_CLK_3MHZ, // lower speed rate for more stable initialization operation

#if defined(MICRON_N25Q256A)

.ui8TurnAround = 3,

#elif defined (CYPRESS_S25FS064S)

.ui8TurnAround = 3,

#elif defined (MACRONIX_MX25U12835F)

.ui8TurnAround = 8,

#elif defined (FUDAN_FM25Q128)

.ui8TurnAround = 8, // The dummy clocks is 8 under SPI mode by default. will update automatically

#endif

.eAddrCfg = AM_HAL_MSPI_ADDR_3_BYTE,

.eInstrCfg = AM_HAL_MSPI_INSTR_1_BYTE,

.eDeviceConfig = AM_HAL_MSPI_FLASH_SERIAL_CE0,

.bSeparateIO = true,

.bSendInstr = true,

.bSendAddr = true,

.bTurnaround = true,

.ui8ReadInstr = AM_DEVICES_MSPI_FLASH_FAST_READ,

.ui8WriteInstr = AM_DEVICES_MSPI_FLASH_PAGE_PROGRAM,

.ui32TCBSize = 0,

.pTCB = NULL,

.scramblingStartAddr = 0,

.scramblingEndAddr = 0,

};

上电后,选择将MSPI配置为CE0,单线SPI模式,各参数说明如下:

AM_HAL_MSPI_SPI_MODE_0 配置为SPI Mode

AM_HAL_MSPI_CLK_3MHZ 配置较低的SPI速率提高稳定性和兼容性

.ui8TurnAround = 8:芯片出厂LC默认值为00,对应的SPI模式下dummy cycles8

AM_HAL_MSPI_ADDR_3_BYTE 24位即3字节地址码

AM_HAL_MSPI_INSTR_1_BYTE 1字节指令码

AM_HAL_MSPI_FLASH_SERIAL_CE0 单线SPI模式,片选通道CE0

FM25Q128初始化代码如下:

//*******************************************************************

//

// FUDAN FM25Q128 Support

// Added by Roger

//

//*******************************************************************

#if defined (FUDAN_FM25Q128)

//

// Device specific initialization function.

//

uint32_t am_device_init_flash(am_hal_mspi_dev_config_t *psMSPISettings)

{

uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;

// workaround for the HOLD# pin bug

// When read the SPI Flash device at the first time powered-on, the device will present as SPI mode

// If the WP# or Hold# pin is tied directly to a low level (such as, connect to the ground) during standard SPI

// or Dual SPI operation, the QE bit should never be set to a 1.

// Pull the WP# and HOLD# pin of SPI Flash as a high level to prevent hold state

ConfigGP23AsGpioOutputForPullHighHoldPin(); // added by Roger

ConfigGP4AsGpioOutputForPullHighWPPin(); // added by Roger

#if 1

//

// Reset the Fudan FM25Q128. using the existing api

//

if (AM_HAL_STATUS_SUCCESS != am_devices_mspi_flash_reset())

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

// software reset code

#else

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_ENABLE_RESET, false, 0, g_PIOBuffer, 0); // Enable reset

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_RESET, false, 0, g_PIOBuffer, 0); // Reset

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

#endif

am_util_delay_us(1000); // for stable concern, delay 1000us after software reset

g_ui32SR1 = 0;

g_ui32SR2 = 0;

g_ui32SR3 = 0;

am_util_stdio_printf("Dump out the STATUS REGISTER 1 - 3 before configurating:\n\r");

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER1, false, 0, (uint32_t *)&g_ui32SR1, 1);

am_util_stdio_printf("STATUS REGISTER 1 is 0x%02X\n", (uint8_t)g_ui32SR1);

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER2, false, 0, (uint32_t *)&g_ui32SR2, 1);

am_util_stdio_printf("STATUS REGISTER 2 is 0x%02X\n", (uint8_t)g_ui32SR2);

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER3, false, 0, (uint32_t *)&g_ui32SR3, 1);

am_util_stdio_printf("STATUS REGISTER 3 is 0x%02X\n", (uint8_t)g_ui32SR3);

//

// Enable writing to the Status/Configuration register.

//

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE, false, 0, g_PIOBuffer, 0); // Non-Volatile

//ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE_VOLATILE, false, 0, g_PIOBuffer, 0); // Volatile

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Configure the Fudan FM25Q128 Status Register-1.

//

g_PIOBuffer[0] = AM_DEVICES_MSPI_CLEAR_STATUS_REGISTER1 ; // Write status register + Data (0x00) --> Clear

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER1, false, 0, g_PIOBuffer, 1); // SR1

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Enable writing to the Status/Configuration register.

//

//ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE, false, 0, g_PIOBuffer, 0); // Non-Volatile

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE_VOLATILE, false, 0, g_PIOBuffer, 0); // Volatile

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Configure the Fudan FM25Q128 Status Register-3.

//

g_PIOBuffer[0] = g_ui32SR3 & ~AM_DEVICES_MSPI_CLEAR_STATUS_REGISTER3;

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER3, false, 0, g_PIOBuffer, 1);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

// SPI mode does not need to config the QE bit, move the QE setting to the quad SPI initial code

#if 0

//

// Enable writing to the Status/Configuration register.

//

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE, false, 0, g_PIOBuffer, 0); // Non-Volatile

//ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE_VOLATILE, false, 0, g_PIOBuffer, 0); // Volatile

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Configure the Fudan FM25Q128 Status Register-2.

//

g_PIOBuffer[0] = (uint8_t)g_ui32SR2 | AM_DEVICES_MSPI_ENABLE_QUAD_STATUS_REGISTER2; // Setting LC and Enable QE(QUAD ENABLE)

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER2, false, 0, g_PIOBuffer, 1);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

#endif

am_util_stdio_printf("Dump out the STATUS REGISTER 1 & 3 after having been overwritten:\n\r");

g_ui32SR1 = 0;

g_ui32SR2 = 0;

g_ui32SR3 = 0;

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER1, false, 0, (uint32_t *)&g_ui32SR1, 1);

am_util_stdio_printf("STATUS REGISTER 1 is 0x%02X\n", (uint8_t)g_ui32SR1);

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER2, false, 0, (uint32_t *)&g_ui32SR2, 1);

am_util_stdio_printf("STATUS REGISTER 2 is 0x%02X\n", (uint8_t)g_ui32SR2);

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER3, false, 0, (uint32_t *)&g_ui32SR3, 1);

am_util_stdio_printf("STATUS REGISTER 3 is 0x%02X\n", (uint8_t)g_ui32SR3);

switch (psMSPISettings->eDeviceConfig)

{

case AM_HAL_MSPI_FLASH_SERIAL_CE0:

case AM_HAL_MSPI_FLASH_SERIAL_CE1:

// Nothing to do. Device defaults to SPI mode for initializing SPI flash device. Disable QPI mode

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_DISABLE_QPI_MODE, false, 0, g_PIOBuffer, 0); // Disable QPI, return to SPI

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

break;

case AM_HAL_MSPI_FLASH_DUAL_CE0:

case AM_HAL_MSPI_FLASH_DUAL_CE1:

// Device does not support Dual mode.

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

//break;

case AM_HAL_MSPI_FLASH_QUAD_CE0:

case AM_HAL_MSPI_FLASH_QUAD_CE1:

case AM_HAL_MSPI_FLASH_QUADPAIRED:

case AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL:

am_util_stdio_printf("Check the QE bit in STATUS REGISTER 2.\n");

// check the QE bit in SR2

if ( ((uint8_t)g_ui32SR2 & (1<<1)) == 0)

{

am_util_stdio_printf("Config the STATUS REGISTER 2 for Quad SPI mode.\n");

//

// Enable writing to the Status/Configuration register.

//

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE, false, 0, g_PIOBuffer, 0); // Non-Volatile

//ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE_VOLATILE, false, 0, g_PIOBuffer, 0); // Volatile

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Configure the Fudan FM25Q128 Status Register-2.

//

g_PIOBuffer[0] = (uint8_t)g_ui32SR2 | AM_DEVICES_MSPI_ENABLE_QUAD_STATUS_REGISTER2; // default LC Setting and Enable QE(QUAD ENABLE)

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_STATUS_REGISTER2, false, 0, g_PIOBuffer, 1);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

}

else

{

am_util_stdio_printf("QE bit in the STATUS REGISTER 2 has already been enabled.\n");

}

am_util_stdio_printf("Get the value of STATUS REGISTER 2:\n");

ui32Status = am_device_command_read(AM_DEVICES_MSPI_FLASH_READ_STATUS_REGISTER2, false, 0, (uint32_t *)&g_ui32SR2, 1);

am_util_stdio_printf("STATUS REGISTER 2 is 0x%02X\n", (uint8_t)g_ui32SR2);

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_ENABLE_QPI_MODE, false, 0, g_PIOBuffer, 0); // Enable QPI

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

break;

case AM_HAL_MSPI_FLASH_OCTAL_CE0:

case AM_HAL_MSPI_FLASH_OCTAL_CE1:

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

//break;

}

return AM_DEVICES_MSPI_FLASH_STATUS_SUCCESS;

}

//

// Device specific de-initialization function.

//

uint32_t am_device_deinit_flash(am_hal_mspi_dev_config_t *psMSPISettings)

{

uint32_t ui32Status;

//

// Reset the Fudan FM25Q128

//

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_ENABLE_RESET, false, 0, g_PIOBuffer, 0); // Enable reset

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_RESET, false, 0, g_PIOBuffer, 0); // Reset

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

// added by Roger

am_util_delay_us(1000); // delay 1000us after software reset

//

// Configure the Fudan FM25Q128 Device mode.

//

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_WRITE_ENABLE, false, 0, g_PIOBuffer, 0);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

switch (psMSPISettings->eDeviceConfig)

{

case AM_HAL_MSPI_FLASH_SERIAL_CE0:

case AM_HAL_MSPI_FLASH_SERIAL_CE1:

// Nothing to do. Device defaults to SPI mode.

break;

case AM_HAL_MSPI_FLASH_DUAL_CE0:

case AM_HAL_MSPI_FLASH_DUAL_CE1:

// Device does not support Dual mode.

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

//break;

case AM_HAL_MSPI_FLASH_QUAD_CE0:

case AM_HAL_MSPI_FLASH_QUAD_CE1:

case AM_HAL_MSPI_FLASH_QUADPAIRED:

case AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL:

ui32Status = am_device_command_write(AM_DEVICES_MSPI_FLASH_DISABLE_QPI_MODE, false, 0, g_PIOBuffer, 0);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

break;

case AM_HAL_MSPI_FLASH_OCTAL_CE0:

case AM_HAL_MSPI_FLASH_OCTAL_CE1:

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

//break;

}

return AM_DEVICES_MSPI_FLASH_STATUS_SUCCESS;

}

#endif

uint32_t

am_devices_mspi_flash_init(am_hal_mspi_dev_config_t *psMSPISettings, void **pHandle)

{

uint32_t ui32Status;

//

// Enable fault detection.

//

#if AM_APOLLO3_MCUCTRL

am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_FAULT_CAPTURE_ENABLE, 0);

#else

am_hal_mcuctrl_fault_capture_enable();

#endif

//

// Configure the MSPI for Serial or Quad-Paired Serial operation during initialization.

//

switch (psMSPISettings->eDeviceConfig)

{

case AM_HAL_MSPI_FLASH_SERIAL_CE0: // Select CE0 SPI mode

case AM_HAL_MSPI_FLASH_DUAL_CE0:

case AM_HAL_MSPI_FLASH_QUAD_CE0: // Select CE0 Quad mode

case AM_HAL_MSPI_FLASH_OCTAL_CE0:

g_psMSPISettings = SerialCE0MSPIConfig; // Configure the MSPI for Serial operation during initialization

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_initialize(AM_DEVICES_MSPI_FLASH_MSPI_INSTANCE, &g_pMSPIHandle))

{

am_util_stdio_printf("Error - Failed to initialize MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_power_control(g_pMSPIHandle, AM_HAL_SYSCTRL_WAKE, false))

{

am_util_stdio_printf("Error - Failed to power on MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_device_configure(g_pMSPIHandle, &SerialCE0MSPIConfig))

{

am_util_stdio_printf("Error - Failed to configure MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_enable(g_pMSPIHandle))

{

am_util_stdio_printf("Error - Failed to enable MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

am_bsp_mspi_pins_enable(SerialCE0MSPIConfig.eDeviceConfig); // Set up the MSPI pins for CE0

break;

case AM_HAL_MSPI_FLASH_SERIAL_CE1:

case AM_HAL_MSPI_FLASH_DUAL_CE1:

case AM_HAL_MSPI_FLASH_QUAD_CE1:

case AM_HAL_MSPI_FLASH_OCTAL_CE1:

g_psMSPISettings = SerialCE1MSPIConfig;

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_initialize(AM_DEVICES_MSPI_FLASH_MSPI_INSTANCE, &g_pMSPIHandle))

{

am_util_stdio_printf("Error - Failed to initialize MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_power_control(g_pMSPIHandle, AM_HAL_SYSCTRL_WAKE, false))

{

am_util_stdio_printf("Error - Failed to power on MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_device_configure(g_pMSPIHandle, &SerialCE1MSPIConfig))

{

am_util_stdio_printf("Error - Failed to configure MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_enable(g_pMSPIHandle))

{

am_util_stdio_printf("Error - Failed to enable MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

am_bsp_mspi_pins_enable(SerialCE1MSPIConfig.eDeviceConfig); // Set up the MSPI pins for CE1

break;

case AM_HAL_MSPI_FLASH_QUADPAIRED:

g_psMSPISettings = QuadPairedSerialMSPIConfig;

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_initialize(AM_DEVICES_MSPI_FLASH_MSPI_INSTANCE, &g_pMSPIHandle))

{

am_util_stdio_printf("Error - Failed to initialize MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_power_control(g_pMSPIHandle, AM_HAL_SYSCTRL_WAKE, false))

{

am_util_stdio_printf("Error - Failed to power on MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_device_configure(g_pMSPIHandle, &QuadPairedSerialMSPIConfig))

{

am_util_stdio_printf("Error - Failed to configure MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

if (AM_HAL_STATUS_SUCCESS != am_hal_mspi_enable(g_pMSPIHandle))

{

am_util_stdio_printf("Error - Failed to enable MSPI.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

am_bsp_mspi_pins_enable(QuadPairedSerialMSPIConfig.eDeviceConfig); // Set up the MSPI pins

break;

case AM_HAL_MSPI_FLASH_QUADPAIRED_SERIAL:

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

//break;

}

if (AM_HAL_STATUS_SUCCESS != am_devices_mspi_flash_reset()) // software reset the external flash device

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

// added by Roger

am_util_delay_us(1000); // for stable concern, delay 1000us after software reset

//

// Device specific MSPI Flash initialization.

// Added by Roger

//

ui32Status = am_device_init_flash(psMSPISettings);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

am_util_stdio_printf("Error - Failed to initial device specific MSPI Flash.\n");

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Initialize the MSPI settings for the SPI FLASH.

//

g_psMSPISettings = *psMSPISettings;

// Disable MSPI before re-configuring it

ui32Status = am_hal_mspi_disable(g_pMSPIHandle);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

// added by Roger

#if defined (FUDAN_FM25Q128)

am_util_stdio_printf("Status Register 2 is 0x%02X.\n",(uint8_t)g_ui32SR2);

if ((g_psMSPISettings.eDeviceConfig == AM_HAL_MSPI_FLASH_QUAD_CE0) || (g_psMSPISettings.eDeviceConfig == AM_HAL_MSPI_FLASH_QUAD_CE1))

{

am_util_stdio_printf("MSPI operation with Quad SPI mode.\n");

// added by Roger, for updating the dummy clocks according to the LC setting under QPI mode

switch (((uint8_t)g_ui32SR2 & 0xC0) >> 6)

{

case 0: // LC = 00

g_psMSPISettings.ui8TurnAround = 6;

break;

case 1: // LC = 01

g_psMSPISettings.ui8TurnAround = 8;

break;

case 2: // LC = 10

g_psMSPISettings.ui8TurnAround = 10;

break;

case 3: // LC = 11

g_psMSPISettings.ui8TurnAround = 4;

break;

default:

g_psMSPISettings.ui8TurnAround = 6;

break;

}

}

if ((g_psMSPISettings.eDeviceConfig == AM_HAL_MSPI_FLASH_SERIAL_CE0) || (g_psMSPISettings.eDeviceConfig == AM_HAL_MSPI_FLASH_SERIAL_CE1))

{

am_util_stdio_printf("MSPI operation with SPI mode.\n");

// added by Roger, for updating the dummy clocks according to the LC setting under SPI mode

switch (((uint8_t)g_ui32SR2 & 0xC0) >>6)

{

case 0: // LC = 00

case 1: // LC = 01

case 2: // LC = 10

g_psMSPISettings.ui8TurnAround = 8;

break;

case 3: // LC = 11

g_psMSPISettings.ui8TurnAround = 0;

break;

default:

g_psMSPISettings.ui8TurnAround = 8;

break;

}

}

am_util_stdio_printf("g_psMSPISettings.ui8TurnAround = 0x%02X.\n", g_psMSPISettings.ui8TurnAround);

#endif

//

// Re-Configure the MSPI for the requested operation mode.

//

//ui32Status = am_hal_mspi_device_configure(g_pMSPIHandle, psMSPISettings);

ui32Status = am_hal_mspi_device_configure(g_pMSPIHandle, &g_psMSPISettings); // modified by Roger

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

// Re-Enable MSPI

ui32Status = am_hal_mspi_enable(g_pMSPIHandle);

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

//

// Configure the MSPI pins.

//

am_bsp_mspi_pins_enable(g_psMSPISettings.eDeviceConfig); // Set up the MSPI pins

//

// Enable MSPI interrupts.

//

#if MSPI_USE_CQ

ui32Status = am_hal_mspi_interrupt_clear(g_pMSPIHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR );

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

ui32Status = am_hal_mspi_interrupt_enable(g_pMSPIHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR );

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

#else

ui32Status = am_hal_mspi_interrupt_clear(g_pMSPIHandle, AM_HAL_MSPI_INT_ERR | AM_HAL_MSPI_INT_DMACMP | AM_HAL_MSPI_INT_CMDCMP );

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

ui32Status = am_hal_mspi_interrupt_enable(g_pMSPIHandle, AM_HAL_MSPI_INT_ERR | AM_HAL_MSPI_INT_DMACMP | AM_HAL_MSPI_INT_CMDCMP );

if (AM_HAL_STATUS_SUCCESS != ui32Status)

{

return AM_DEVICES_MSPI_FLASH_STATUS_ERROR;

}

#endif

#if AM_CMSIS_REGS

NVIC_EnableIRQ(MSPI_IRQn);

#else // AM_CMSIS_REGS

am_hal_interrupt_enable(AM_HAL_INTERRUPT_MSPI);

#endif // AM_CMSIS_REGS

am_hal_interrupt_master_enable();

//

// Return the handle.

//

*pHandle = g_pMSPIHandle;

//

// Return the status.

//

return AM_DEVICES_MSPI_FLASH_STATUS_SUCCESS;

}

至此,FM25Q128的底层驱动代码与SDK中的MSPI外设API已经对接完成,我们可以操作以下的APIFlash进行擦除扇区,擦除块,擦除全片,读,写等测试。

//SPI Flash初始化

uint32_t

am_devices_mspi_flash_init(am_hal_mspi_dev_config_t *psMSPISettings, void **pHandle);

// 获取SPI Flash的器件ID

uint32_t

am_devices_mspi_flash_id(void);

// SPI Flash扇区擦除。注意:实际上是调用的Block块擦除命令0xD8,擦除单位为64KB

uint32_t

am_devices_mspi_flash_sector_erase(uint32_t ui32SectorAddress);

// SPI Flash全片擦除

uint32_t am_devices_mspi_flash_mass_erase(void);

// 读取SPI Flash内容

uint32_t

am_devices_mspi_flash_read(uint8_t *pui8RxBuffer,

uint32_t ui32ReadAddress,

uint32_t ui32NumBytes,

bool bWaitForCompletion);

// SPI Flash写入内容

uint32_t

am_devices_mspi_flash_write(uint8_t *pui8TxBuffer,

uint32_t ui32WriteAddress,

uint32_t ui32NumBytes);

SPI Flash的相关API操作Demo详见mspi_quad_example工程下的mspi_quad_example.c文件。注意:开启宏定义#define TEST_QUAD_SPI,即为测试Quad SPI模式读写SPI Flash;如果注释掉该宏,则为单线SPI模式读写SPI FlashSPI Flash操作成功后,通过J-LinkSWO输出log信息显示操作结果,截图如下:

o4YBAFyJ44eAXPtqAAB7e_gAFYU601.jpg

o4YBAFyJ44-AYoMMAABoTbs9_LY333.jpg

o4YBAFyJ45aAXv2VAABn2JuiycM846.jpg

后记:

整理一下调试过程中遇到的一些坑:

1SDK v2.0v1.2.12启动代码startup_keil.s作了改动,直接将SDK v1.2.12中调试好的驱动代码放到v2.0中进行编译,导致无法进入MSPI中断服务程序,读取Flash内容时卡死,原因是SDK v2.0中把MSPI中断服务函数名称修改了:void am_mspi0_isr(void)

o4YBAFyJ452ASpnyAABy4WCfkGc168.jpg

2、新的片子FM25Q128在初始化过程中无法正常读取和修改状态寄存器,这是因为芯片默认QE=0,芯片处于单线SPI模式,Pin3WP#脚,Pin7Hold#/RESET#脚,由于Pin7电压不稳定,或者处于低电平状态,导致芯片进入RESET状态,MSPI无法正确访问Flash状态寄存器,导致读写失败!初始化为SPI后,将MCU连接到SPI FlashPin3Pin7IO设置为GPIO输出并使能内部上拉,输出高电平,初始化SPI Flash操作过程中,拉高WP#HOLD#/RESET#管脚,让Flash芯片处于非写保护和RESET/HOLD状态。代码片段示例如下:

pIYBAFyJ47SAVDISAABaNYXb8gU168.jpg

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SPI Flash
    +关注

    关注

    1

    文章

    13

    浏览量

    10272
收藏 人收藏

    评论

    相关推荐

    ESP32外部flashspi外设冲突怎么解决?

    硬件: ESP32 ,W25Q128 SPI显示器 库:IDF4.0.1 使用hspi挂载了外部16MB的W25Q128,并同时挂载了SPI的显示器,使用两不同IO口进行分时复用。 问
    发表于 06-25 06:19

    【GD32H757Z海棠派开发板使用手册】第十一讲 SPI-SPI NOR FLASH读写实验

    通过本实验主要学习以下内容: •SPI简介 •GD32H7 SPI简介 •SPI NOR FLASH——GD25Q128ESIGR简介 •使
    的头像 发表于 06-04 11:42 202次阅读
    【GD32H757Z海棠派开发板使用手册】第十一讲 <b class='flag-5'>SPI-SPI</b> NOR <b class='flag-5'>FLASH</b>读写实验

    【GD32F470紫藤派开发板使用手册】第十一讲 SPI-SPI NOR FLASH读写实验

    通过本实验主要学习以下内容: •SPI简介 •GD32F470 SPI简介 •SPI NOR FLASH——GD25Q32ESIGR简介 •
    的头像 发表于 05-17 09:57 956次阅读
    【GD32F470紫藤派开发板使用手册】第十一讲 <b class='flag-5'>SPI-SPI</b> NOR <b class='flag-5'>FLASH</b>读写实验

    具有双/四SPI和QPI的串行闪存W25Q128FV数据手册

    电子发烧友网站提供《具有双/四SPI和QPI的串行闪存W25Q128FV数据手册.pdf》资料免费下载
    发表于 04-25 17:11 0次下载

    全志R128 SDK HAL 模块开发指南——Flash Controller

    Model 0/1/2/3 可灵活配置 4 段虚拟地址区间,支持 DMA 读写、Nor Flash XIP 操作 最大 2ˆ32Bytes 容量的 Nor Flash,常见有 64M
    发表于 03-25 10:11

    CX3开发平台是否能在SPI FLASH内放入User Data ?

    SPI FLASH,希望有2K~4K Byte的空间可以存放User Data, 开机方式:boot from SPI FLASH 开发平台
    发表于 02-28 08:13

    用S25FS128S无法从SPI Flash启动FX3是什么原因?怎么查?

    您好, 我们根据官方推荐使用了S25FS128S作为FX3SPI Flash,将固件下载到Flash内以后,重新上电,设备仍然显示为boo
    发表于 02-28 08:02

    复旦FM33LG048软件I2C驱动OLED的demo 帮助新手快速从STM32上手FM33

    demo任务:利用复旦FM33LG048外设I2C驱动OLED显示demo目的:通过demo熟悉复旦的I2C、GPIO外设,帮助
    的头像 发表于 11-11 08:27 411次阅读
    <b class='flag-5'>复旦</b><b class='flag-5'>微</b><b class='flag-5'>FM</b>33LG048软件I2C驱动OLED的demo 帮助新手快速从STM32上手<b class='flag-5'>FM</b>33

    复旦FM3316/3313/3312低功耗MCU芯片技术手册

    电子发烧友网站提供《复旦FM3316/3313/3312低功耗MCU芯片技术手册.pdf》资料免费下载
    发表于 09-20 14:49 2次下载
    <b class='flag-5'>复旦</b><b class='flag-5'>微</b><b class='flag-5'>FM</b>3316/3313/3312低功耗MCU芯片<b class='flag-5'>技术</b>手册

    CW25Q128A_DS_EN_V1.0数据手册

    标准的串行外设接口(SPI)、双/四I/O SPI:串行时钟、芯片选择、串行数据I/O0(DI)、I/O1(DO)、I/O2和I/03。 支持高达104 MHz的CW25Q128A单
    发表于 09-15 06:00

    如何使用SPI和PDMA访问外部SPI Flash W25Q32

    : NuMaker-M252SD V1.1, SPI Flash W25Q32 本样本代码使用 SPI 和 PDMA 访问外部 SPI
    发表于 08-29 08:10

    使用NAU88L25播放存储在外部SPI Flash W25Q32中的WAV文件

    应用程序: 本样本代码使用外部编码 NAU88L25 播放存储在外部 SPI Flash W25Q32 中的 WAV 文件 。 BSP 版本: M031 BSP CMSIS
    发表于 08-22 07:17

    M031SE使用SPI去读取W25Q128失败怎么解决?

    请大佬帮忙看一下,硬件连接肯定没有问题,已经核对多次了,现在的目的是写入命令,读取出来Flash W25Q128的型号 命令:{0x90,0x00,0x00,0x00,0xFF,0xFF} 返回
    发表于 08-21 07:44

    GD32F303固件库开发(16)----移植兆易创新SPI Nor Flash之GD25Q64Flash

    64Mbit,相当于8M字节。W25Q64可以支持 SPI 的模式 0 和模式 3,也就是 CPOL=0/CPHA=0 和CPOL=1/CPHA=1 这两种模式。
    的头像 发表于 07-26 16:14 1143次阅读
    GD32F303固件库开发(16)----移植兆易创新<b class='flag-5'>SPI</b> Nor <b class='flag-5'>Flash</b>之GD<b class='flag-5'>25Q64Flash</b>

    STM32 SPI读写W25Q64(三)

    GPIO口模拟SPI读写W25Q64的基本内容已经跟大家介绍完了,今天跟大家介绍下如何通过串口接收文件并保存到W25Q64中。
    发表于 07-22 11:11 1006次阅读
    STM32 <b class='flag-5'>SPI</b>读写W<b class='flag-5'>25Q</b>64(三)