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

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

3天内不再提示

RA MCU众测宝典 | 在瑞萨CPKCOR-RA8D1B核心板上实现QSPI读取外部Flash

RA生态工作室 2026-02-06 18:02 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

RA MCU众测宝典”中I2C/SPI通信与显示驱动专题更新了。这次我们聚焦瑞萨CPKCOR-RA8D1B核心板】开发板,一步步实现QSPI读取外部Flash。


开启宝典

QSPI是Queued SPI的简写,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛。在SPI协议的基础上,Motorola公司对其功能进行了增强,增加了队列传输机制,推出了队列串行外围接口协议(即QSPI协议)。


QSPI是一种专用的通信接口,连接单、双或四(条数据线)SPI Flash存储介质。QSPI是一个内存控制器,用于连接具有SPI兼容接口的串行ROM(非易失性存储器)。


我们看一下核心板上的外扩Flash:


e5af7e36-0342-11f1-96ea-92fbcf53809c.png

外扩的Flash的型号是AT25SF128B。


QSPI使用6个信号连接Flash,分别是四个数据线QIO0~QIO3,一个时钟输出CLK,一个片选输出(低电平有效)QSSL,它们的作用介绍如下:

QSSL:片选输出(低电平有效),适用于FLASH 1。如果QSPI始终在双闪存模式下工作,则其也可用于FLASH 2从设备选择信号线。QSPI通讯以QSSL线置低电平为开始信号,以QSSL线被拉高作为结束信号。

CLK:时钟输出,适用于两个存储器,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,两个设备之间通讯时,通讯速率受限于低速设备。

QIO0QIO0~QIO3:四线模式中为双向IO。


接下来进行软件配置:


添加OSPI功能模块:

e5bffe28-0342-11f1-96ea-92fbcf53809c.png


接下来我们配置一下引脚:

e5d42b5a-0342-11f1-96ea-92fbcf53809c.png


一共是6个引脚,接下来配置模块信息:

e5e6d1d8-0342-11f1-96ea-92fbcf53809c.png


下面是部分Flash的命令,我们可以初始化这些内容:

e5fe48ae-0342-11f1-96ea-92fbcf53809c.png


接下来我们代码测试一下QSPI的功能。


我们定义了一些基础功能测试:

左右滑动查看完整内容

uint8_tg_read_data [OSPI_B_APP_DATA_SIZE] = {RESET_VALUE};
uint8_tg_write_data [OSPI_B_APP_DATA_SIZE] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,};spi_flash_direct_transfer_tg_ospi_b_direct_transfer [OSPI_B_TRANSFER_MAX] ={/* Transfer structure for SPI mode */ [OSPI_B_TRANSFER_WRITE_ENABLE_SPI] = { .command = OSPI_B_COMMAND_WRITE_ENABLE_SPI, .address = OSPI_B_ADDRESS_DUMMY, .data = OSPI_B_DATA_DUMMY, .command_length = OSPI_B_COMMAND_LENGTH_SPI, .address_length = OSPI_B_ADDRESS_LENGTH_ZERO, .data_length = OSPI_B_DATA_LENGTH_ZERO, .dummy_cycles = OSPI_B_DUMMY_CYCLE_WRITE_SPI }, [OSPI_B_TRANSFER_READ_STATUS_SPI] = { .command = OSPI_B_COMMAND_READ_STATUS_SPI, .address = OSPI_B_ADDRESS_DUMMY, .data = OSPI_B_DATA_DUMMY, .command_length = OSPI_B_COMMAND_LENGTH_SPI, .address_length = OSPI_B_ADDRESS_LENGTH_ZERO, .data_length = OSPI_B_DATA_LENGTH_ONE, .dummy_cycles = OSPI_B_DUMMY_CYCLE_READ_STATUS_SPI }, [OSPI_B_TRANSFER_READ_DEVICE_ID_SPI] = { .command = OSPI_B_COMMAND_READ_DEVICE_ID_SPI, //0x9f .address = OSPI_B_ADDRESS_DUMMY, //0 .data = OSPI_B_DATA_DUMMY, //0 .command_length = OSPI_B_COMMAND_LENGTH_SPI, //1 .address_length = OSPI_B_ADDRESS_LENGTH_ZERO, //0 .data_length = OSPI_B_DATA_LENGTH_FOUR, //4 .dummy_cycles = OSPI_B_DUMMY_CYCLE_READ_STATUS_SPI //0 }};fsp_err_tospi_b_read_device_id(uint32_t*constp_id){fsp_err_t err = FSP_SUCCESS;spi_flash_direct_transfer_ttransfer = {RESET_VALUE};/* Read and check flash device ID */ transfer = g_ospi_b_direct_transfer[OSPI_B_TRANSFER_READ_DEVICE_ID_SPI]; err =R_OSPI_B_DirectTransfer(&g_qspi0_flash_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);if(err!=FSP_SUCCESS) {printf("R_OSPI_B_DirectTransfer API FAILED \r\n"); }/* Get flash device ID */ *p_id = transfer.data;returnerr;}staticfsp_err_tospi_b_write_enable(void){fsp_err_t err = FSP_SUCCESS;spi_flash_direct_transfer_ttransfer = {RESET_VALUE};/* Transfer write enable command */ transfer = g_ospi_b_direct_transfer[OSPI_B_TRANSFER_WRITE_ENABLE_SPI]; err =R_OSPI_B_DirectTransfer(&g_qspi0_flash_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); assert(FSP_SUCCESS == err);/* Read Status Register */ transfer = g_ospi_b_direct_transfer[OSPI_B_TRANSFER_READ_STATUS_SPI]; err =R_OSPI_B_DirectTransfer(&g_qspi0_flash_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ); assert(FSP_SUCCESS == err);/* Check Write Enable bit in Status Register */if(OSPI_B_WEN_BIT_MASK != (transfer.data & OSPI_B_WEN_BIT_MASK)) {printf("Write enable FAILED\r\n"); }returnerr;}staticfsp_err_tospi_b_wait_operation(uint32_ttimeout){fsp_err_t err = FSP_SUCCESS;spi_flash_status_tstatus = {RESET_VALUE}; status.write_in_progress =true;while(status.write_in_progress) {/* Get device status */ R_OSPI_B_StatusGet(&g_qspi0_flash_ctrl, &status);if(RESET_VALUE == timeout) {printf("OSPI time out occurred\r\n"); } R_BSP_SoftwareDelay(1, OSPI_B_TIME_UNIT); timeout --; }returnerr;}staticfsp_err_tospi_b_erase_operation(uint8_t*constp_address){fsp_err_t err = FSP_SUCCESS;uint32_t sector_size = RESET_VALUE;uint32_t erase_timeout = RESET_VALUE;/* Check sector size according to input address pointer, described in S28HS512T data sheet */if(OSPI_B_SECTOR_4K_END_ADDRESS < (uint32_t)p_address)    {        sector_size = OSPI_B_SECTOR_SIZE_256K;        erase_timeout = OSPI_B_TIME_ERASE_256K;    }else    {        sector_size = OSPI_B_SECTOR_SIZE_4K;        erase_timeout = OSPI_B_TIME_ERASE_4K;    }/* Performs erase sector */    err = R_OSPI_B_Erase(&g_qspi0_flash_ctrl, p_address, sector_size);/* Wait till operation completes */    err = ospi_b_wait_operation(erase_timeout);return err;}staticfsp_err_tospi_b_write_operation(uint8_t * const p_address,uint8_t *pdata, uint16_t len){fsp_err_t   err         = FSP_SUCCESS;/* Erase sector before write data to flash device */    err = ospi_b_erase_operation(p_address);/* Write data to flash device */    err = R_OSPI_B_Write(&g_qspi0_flash_ctrl, pdata, p_address, len);/* Wait until write operation completes */    err = ospi_b_wait_operation(OSPI_B_TIME_WRITE);return err;}staticfsp_err_tospi_b_read_operation(uint8_t * const p_address,uint8_t *pdata, uint16_t len){fsp_err_t err = FSP_SUCCESS;/* Clean read buffer */memset(pdata, RESET_VALUE, len);/* Read data from flash device */memcpy(pdata, p_address, len);return err;
}


在main中我们需要先初始化:

左右滑动查看完整内容

voidqspi_FlashInit(void){
/* Open the OSPI instance. */ fsp_err_terr=R_OSPI_B_Open(&g_qspi0_flash_ctrl, &g_qspi0_flash_cfg); assert(FSP_SUCCESS == err); /* Switch OSPI module to 1S-1S-1S mode to configure flash device */ err = R_OSPI_B_SpiProtocolSet(&g_qspi0_flash_ctrl, SPI_FLASH_PROTOCOL_EXTENDED_SPI); assert(FSP_SUCCESS == err); /* Reset flash device by driving OM_RESET pin */ R_XSPI->LIOCTL_b.RSTCS0 =0; R_BSP_SoftwareDelay(OSPI_B_TIME_RESET_PULSE, OSPI_B_TIME_UNIT); R_XSPI->LIOCTL_b.RSTCS1 =1; R_BSP_SoftwareDelay(OSPI_B_TIME_RESET_SETUP, OSPI_B_TIME_UNIT); ospi_b_write_enable();
}


然后直接初始化阶段测试QSPI,我们写入一页数据,但是之读取其中的16个,并通过串口打印:

左右滑动查看完整内容

fsp_err_tospi_b_Testoperation(uint8_t*p_address){
fsp_err_t err =FSP_SUCCESS; uint16_t i=0; err=ospi_b_erase_operation(p_address); err=ospi_b_write_operation (p_address,g_write_data,OSPI_B_APP_DATA_SIZE); if(err==FSP_SUCCESS) { /* Print execution time */ printf("Write %d bytes completed successfully\r\n", (int)(OSPI_B_APP_DATA_SIZE)); } else { printf("Write operation failure\r\n"); } printf("Write Data:\r\n"); for(i=0;i<=OSPI_B_APP_DATA_SIZE-1;i++)    {        printf("%d ",g_write_data[i]);    }    err = ospi_b_read_operation (p_address,g_read_data,16);    if(err==FSP_SUCCESS)    {        /* Print execution time */        printf("\r\nRead %d bytes completed successfully\r\n", (int)(OSPI_B_APP_DATA_SIZE));    }    else    {        printf("\r\nRead operation failure\r\n");    }    printf("Read Data:\r\n");    for(i=0;i<=sizeof(g_read_data)-1;i++)    {        printf("%d ",g_read_data[i]);    }    /* Compare data read and date written */    if(RESET_VALUE == memcmp(&g_read_data, &g_write_data, (size_t)16))    {        printf("\r\nData read matched data written\r\n");        printf("flash读写数据成功\r\n");    }    else    {        printf("\r\nData read does not match data written\r\n");        printf("flash读写数据失败\r\n");    }    /* Performs OSPI erase operation */    err = ospi_b_erase_operation(p_address);    if(err==FSP_SUCCESS)    {        /* Print execution time */        printf("Erase sector completed successfully\r\n");    }    else    {        printf("erase operation failure\r\n");    }    return err;
}


串口打印结果如下:

e615251a-0342-11f1-96ea-92fbcf53809c.png


从QSPI的六引脚配置、OSPI功能模块添加,到命令集定义、Flash读写擦除的代码实现,再到串口打印验证数据匹配。我们不仅掌握了不同通信协议的配置逻辑,还摸清了它们在存储外设交互中的核心应用——这次通过QSPI实现Flash的读写擦除与数据验证,正是高速通信在存储场景的典型落地。

I2C/SPI通信与显示驱动专题的技能专题还在持续拓展!如果你在实操中对QSPI的协议时序、Flash命令配置有新的感悟,或是想分享更多通信驱动的实战场景,欢迎在评论区交流。


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

    关注

    147

    文章

    19232

    浏览量

    405177
  • RA
    RA
    +关注

    关注

    0

    文章

    40

    浏览量

    25393
  • 瑞萨电子
    +关注

    关注

    39

    文章

    2987

    浏览量

    74600
  • 核心板
    +关注

    关注

    6

    文章

    1432

    浏览量

    32200
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    CPKCOR-RA8D1B核心板实现QSPI读取外部Flash

    QSPI是Queued SPI的简写,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛。SPI协议的基础,Motorola公司对其功能进行了增强,增加了队列传输机制,推出了队列串行外围接口协议(即
    的头像 发表于 01-28 17:27 4391次阅读
    <b class='flag-5'>在</b><b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>CPKCOR-RA8D1B</b><b class='flag-5'>核心板</b><b class='flag-5'>上</b><b class='flag-5'>实现</b><b class='flag-5'>QSPI</b><b class='flag-5'>读取</b><b class='flag-5'>外部</b><b class='flag-5'>Flash</b>

    RA8D1单片机IO中断配置实现方法

    本文为结合e2 studio工具,以及CPKCOR_RA8D1B评估,给大家讲述
    的头像 发表于 04-09 15:05 2223次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA8D1</b>单片机IO中断配置<b class='flag-5'>实现</b>方法

    RA MCU宝典 | I²C读取EEPROM

    “RAMCU宝典”IIC专题继续深耕!一期我们用【RA-Eco-RA2E1】开发板实现了IIC通信的OLED显示。这次我们把目光转向实
    的头像 发表于 01-13 18:05 8783次阅读
    <b class='flag-5'>RA</b> <b class='flag-5'>MCU</b><b class='flag-5'>众</b>测<b class='flag-5'>宝典</b> | I²C<b class='flag-5'>读取</b>EEPROM

    RA MCU宝典 | 环境搭建之【RA-Eco-RA4M2】搭建Keil开发环境

    “RAMCU宝典”环境搭建专题再添硬核实操!开启宝典概览
    的头像 发表于 04-03 17:59 7290次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> <b class='flag-5'>MCU</b><b class='flag-5'>众</b>测<b class='flag-5'>宝典</b> | 环境搭建之【<b class='flag-5'>RA-Eco-RA</b>4M2】搭建Keil开发环境

    RA MCU宝典 | 环境搭建之【RA-Eco-RA4M2】QE工具使用

    “RAMCU宝典”环境搭建专题再添硬核实操!开启宝典01简介RA-Eco-RA4M2-1
    的头像 发表于 04-10 18:26 6170次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> <b class='flag-5'>MCU</b><b class='flag-5'>众</b>测<b class='flag-5'>宝典</b> | 环境搭建之【<b class='flag-5'>RA-Eco-RA</b>4M2】QE工具使用

    RA MCU宝典 | 串口之【RA-Eco-RA2L1】RTC日历及串口设置时间

    “RAMCU宝典”串口专题添硬核实操!开启宝典前言RAMCU
    的头像 发表于 04-21 18:07 7234次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> <b class='flag-5'>MCU</b><b class='flag-5'>众</b>测<b class='flag-5'>宝典</b> | 串口之【<b class='flag-5'>RA-Eco-RA2L1</b>】RTC日历及串口设置时间

    RA8D1 CPK开发RA8D1移植ThreadX操作系统

    CPKCOR-RA8D1B核心板电子为中国市场设计的模块化开发, 使用
    发表于 10-20 20:22

    CPKCOR-RA8D1】+ 1.RA8D1开箱点灯

    很荣幸收到了电子发放的CPKCOR-RA8D1B开发,之前的直播间讲过这款板子,但是没
    发表于 09-24 18:55

    CPKCOR-RA8D1RA8D1开箱测试报告

    1.RA8D1核心板 CPKCOR-RA8D1B使用224BGA封装的RA8D1
    发表于 10-02 17:25

    CPKCOR-RA8D1】介绍、环境搭建、工程测试

    官方 Demo 例程,实现核心板、底板、摄像头模块、显示屏模块的工程测试 介绍 RA8D1 套件包括
    发表于 10-06 19:35

    CPKCOR-RA8D1】开发套件全攻略:从硬件解析到摄像头显示Demo实战

    本文将全面解析电子高性能的CPKCOR-RA8D1开发套件。内容涵盖核心板与扩展板的硬件资源详解、原理图分析、Flexible Software Package (FSP)开发环境
    发表于 10-30 09:34

    CPKCOR-RA8D1】开发套件全攻略:从硬件解析到摄像头显示Demo实战

    | 本文将全面解析电子高性能的CPKCOR-RA8D1开发套件。内容涵盖核心板与扩展板的硬件资源详解、原理图分析、Flexible Software Package (FSP)开发
    发表于 10-30 15:13

    CPKCOR-RA8D1】基于G.729A算法研究

    Renesas RA8D1 核心板CPKCOR-RA8D1B; CPKEXP-EKRA8X1 扩展板; 软件 开发环境搭建:包括 FSP软件包和 e2 studio 工具链的安装和
    发表于 10-31 00:50

    RA8D1试用活动】RA8D1B-CPKCOR开发移植linux

    RA8D1试用活动】RA8D1B-CPKCOR开发移植linux
    的头像 发表于 11-16 01:02 1983次阅读
    【<b class='flag-5'>RA8D1</b>试用活动】<b class='flag-5'>RA8D1B-CPKCOR</b>开发<b class='flag-5'>板</b>移植linux

    RA MCU宝典 | OLED之【RA-Eco-RA2L1】I²C驱动OLED屏幕 BME280传感器

    “RAMCU宝典”全新专题——OLED显示驱动正式开篇!开启宝典前言RAMCU
    的头像 发表于 05-08 16:08 1055次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> <b class='flag-5'>MCU</b><b class='flag-5'>众</b>测<b class='flag-5'>宝典</b> | OLED之【<b class='flag-5'>RA-Eco-RA2L1</b>】I²C驱动OLED屏幕 BME280传感器