这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 学习AI8051开发板例程:19AI8051的硬件SPI读取FLASH芯片

共1条 1/1 1 跳转至

学习AI8051开发板例程:19AI8051的硬件SPI读取FLASH芯片

高工
2026-01-05 20:00:34   被打赏 35 分(兑奖)     打赏

一:W25Q128芯片介绍

    W25Q128FV(128M位)串行闪存为空间、引脚和功率有限的系统提供了存储解决方案。25Q系列提供的灵活性和性能远远超过普通的串行闪存设备。它们是将代码隐藏到RAM、直接从双/四 SPI(XIP)执行代码以及存储语音、文本和数据的理想选择。该设备使用单一2.7V至3.6V电源,电流消耗为4mA交流电和1uA电源。所有设备都采用节省空间的包装。

    W25Q128FV阵列被划分为65,536个可编程页面,每个页面大小为256字节。最多可同时编程256字节。页面可以以16个一组(4KB扇区擦除)、128个一组(32KB块擦除)、256个一组(64KB块擦除)或整个芯片(芯片擦除)的方式进行擦除。W25Q128FV分别拥有4,096个可擦除扇区和256个可擦除块。较小的4KB扇区使得在需要存储数据和参数的应用中具备更大的灵活性。(参见图2。)W25Q128FV支持标准的串行外围接口(SPI)、双/四路I/O SPI以及2周期指令循环的四路外围接口(QPI):串行时钟、芯片选择、串行数据I/O0(DI)、1/O1(DO)、1/O2(WP)以及I/O3(/HOLD)。SPI频率最高可支持104MHz,从而在采用快速读取双/四路V/O及QPI指令时,可实现相当于208MHz(104MHz 2)的双路I/O和416MHz(104MHzx4)的四路I/O的时钟速率。这些传输速率的表现优于标准的异步8位和 16位并行闪存存储器。连续读取模式可实现高效的内存访问,仅需最多8个时钟指令开销即可读取一个24位地址,从而支持真正的XIP(就地执行)操作。

    一个保持位、写保护位以及可编程的写保护功能,同时具备顶部或底部阵列控制功能,进一步增强了控制灵活性。此外,该设备还支持JEDEC标准制造商及设备标识符以及SFDP寄存器、一个64位唯一序列号以及三个256字节安全寄存器。

二:特点:

新型SpiFlash存储器系列

W25Q128FV:128兆位/16兆字节-标准SPI:CLK、/CS、DI、DO、MP、/Hold-双SPI:CLK、/CS、I0o、I01、MWP、/Hold四通道SPI:CLK、/CS、100、I01、102、103-QPI:CLK./CS,1O0,1O1,1O2,1O3软件与硬件重置

最高性能串行闪存-104MHz单通道、双通道/四通道SPI时钟等效于208/416MHz的双/四线SPI-50MB/s 连续数据传输速率超过10万次擦除/编程循环

超过20年数据保留

高效的"连续读取"和OPI模式支持8/16/32/64字节循环的连续读取最少仅需8个时钟周期即可访问内存-四通道外设接口(QP)减少指令开销

允许真正的xIP(原地执行)操作性能优于x16并行闪存

三:硬件设计:

19-1.png

四:软件代码:

4.1 : SPI初始化:

void SPI_init(void)
{
    SSIG = 1; //忽略 SS 引脚功能,使用 MSTR 确定器件是主机还是从机
    SPEN = 1; //使能 SPI 功能
    DORD = 0; //先发送/接收数据的高位( MSB)
    MSTR = 1; //设置主机模式
    CPOL = 1; //SCLK 空闲时为高电平,SCLK 的前时钟沿为下降沿,后时钟沿为上升沿
    CPHA = 1; //数据在 SCLK 前时钟沿驱动,后时钟沿采样
    //采用漏极开路+上拉电阻方式驱动,需要调低SPI频率才能正常与Flash通信
    SPCTL = (SPCTL & ~3) | 2;   //SPI 时钟频率选择, 0: 4T, 1: 8T,  2: 16T,  3: 2T
    SPI_S1 = 1;     //00: P1.4 P1.5 P1.6 P1.7, 01: P2.4 P2.5 P2.6 P2.7, 10: P4.0 P4.1 P4.2 P4.3, 11: P3.5 P3.4 P3.3 P3.2
    SPI_S0 = 0;

    HSCLKDIV = 0x01;    //高速时钟1分频,默认2分频
    
    SPI_SCK = 0;    // set clock to low initial state
    SPI_SI = 1;
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
}

4.2  SPI发送字节

void SPI_WriteByte(u8 out)
{
    SPDAT = out;
    while(SPIF == 0) ;
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
}

4.3 SPI读取字节:

u8 SPI_ReadByte(void)
{
    SPDAT = 0xff;
    while(SPIF == 0) ;
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
    return (SPDAT);
}

4.4 检测芯片是否存在:

void FlashCheckID(void)
{
    SPI_CE_Low();
    SPI_WriteByte(SFC_RDID);        //发送读取ID命令
    SPI_WriteByte(0x00);            //空读3个字节
    SPI_WriteByte(0x00);
    SPI_WriteByte(0x00);
    PM25LV040_ID1 = SPI_ReadByte();         //读取制造商ID1
    PM25LV040_ID  = SPI_ReadByte();         //读取设备ID
    PM25LV040_ID2 = SPI_ReadByte();         //读取制造商ID2
    SPI_CE_High();

//    printf("ID1=0x%02x,ID=0x%02x,ID2=0x%02x\r\n",PM25LV040_ID1,PM25LV040_ID,PM25LV040_ID2);

    if((PM25LV040_ID1 == 0x9d) && (PM25LV040_ID2 == 0x7f))  B_FlashOK = 1;  //检测是否为PM25LVxx系列的Flash
    else if(PM25LV040_ID == 0x12)  B_FlashOK = 2;                           //检测是否为W25X4x系列的Flash
    else if(PM25LV040_ID == 0x13)  B_FlashOK = 3;                           //检测是否为W25X8x系列的Flash
    else if(PM25LV040_ID == 0x17)  B_FlashOK = 4;                           //检测是否为W25X128系列的Flash
    else                                                    B_FlashOK = 0;
}

4.5  读取N个字节

void SPI_Read_Nbytes(u32 addr, u8 *buffer, u16 size)
{
    if(size == 0)   return;
    if(!B_FlashOK)  return;
    while(CheckFlashBusy() > 0);        //Flash忙检测

    SPI_CE_Low();                       //enable device
    SPI_WriteByte(SFC_READ);            //read command

    SPI_WriteByte(((u8 *)&addr)[1]);    //设置起始地址
    SPI_WriteByte(((u8 *)&addr)[2]);
    SPI_WriteByte(((u8 *)&addr)[3]);

    do{
        *buffer = SPI_ReadByte();       //receive byte and store at buffer
        buffer++;
    }while(--size);                     //read until no_bytes is reached
    SPI_CE_High();                      //disable device
}

4.6 写入多个字节

void SPI_Write_Nbytes(u32 addr, u8 *buffer, u8 size)
{
    if(size == 0)   return;
    if(!B_FlashOK)  return;
    while(CheckFlashBusy() > 0);        //Flash忙检测


    FlashWriteEnable();                 //使能Flash写命令

    SPI_CE_Low();                       // enable device
    SPI_WriteByte(SFC_PAGEPROG);        // 发送页编程命令
    SPI_WriteByte(((u8 *)&addr)[1]);    //设置起始地址
    SPI_WriteByte(((u8 *)&addr)[2]);
    SPI_WriteByte(((u8 *)&addr)[3]);
    do{
        SPI_WriteByte(*buffer++);       //连续页内写
        addr++;
        if ((addr & 0xff) == 0) break;
    }while(--size);
    SPI_CE_High();                      // disable device
}





关键词: AI8051     FLASH    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]