查看: 6634|回复: 5

[分享] 【YL-KL26Z开发】+ SPI读写W25Q32

[复制链接]

该用户从未签到

42

主题

340

帖子

0

高级会员

Rank: 4

积分
722
最后登录
2016-1-9
发表于 2015-7-27 22:53:31 | 显示全部楼层 |阅读模式
本帖最后由 LokTarOgar 于 2015-7-27 22:57 编辑

接上次IIC的实验:https://www.nxpic.org.cn/module/forum/thread-600294-1-1.html

本次所做实验为SPI读写开发板上的spiflash器件(W25Q32),可以实现SPI主机的简单应用,更复杂的论坛里面已经有大神发过了。

本次实验实现功能为:
1.通过SPI擦除W25Q32上的数据。程序只实现的简单的擦出,还有许多擦除指令不一一再试,有兴趣的可以调试一下;
2.通过SPI向W25Q32写入一个数组的数据,即从00地址开始的20给数据。
3.通过SPI读取W25Q32中从00地址开始的20给数据
4.读写的数据会通过串口显示,并且在成功读写后会使LED点亮。

程序如下:

主程序:


int  main (void)
{

    INT8U spiid,i = 0;

    SystemCoreClockUpdate();                                            /* 时钟配置                     */
    uart0Init(9600,0,0,8,1);
    printf("SPI Test Star...\r\n");
    gpioInit();                                                                   /* 管脚初始化                   */

    spiInit(SPI0_BASE_PTR , Master);                                    /* SPI0主机模式初始化           */

    spiid = flash_read_id();                                            //读ID
    printf("ID=0x%x08\r\n",spiid);

    printf("Start to erase sector 0...\r\n");
    flash_sector_erase (0x000000);                            //擦除W25Q32



    myDelay(300);                                                                   /* 延时                         */
    ledSet(0);
    printf("Start to write sector 0...\r\n");
    flash_write_sector(0x000000, SNDBUFPT, 20);                          /* 以0x0为起始地址,将WrBuf 写入 */
    myDelay(30);

    printf("Start to read sector 0...\r\n");                                                                    /* 数组里的20个数据写入芯片     */
    flash_read_data(0x000000,  RCVBUFPT,20);                            /* 以0x0为起始地址,读20个   */

    for (i = 0;i < 19;i++) {
        if (GucRdBuf != GucWrBuf ) {                              /* 若SPI读写不正确则程序D3常亮 */
           ledSet(1);
           printf("SPI ERR...\r\n");
            while (1);
        }
    }
    ledSet(2);                                                         /*  若SPI读写正确,D4常亮 */
    printf("Verify ok...\r");
    while(1) {
    };
}

SPI初始化:

void spiInit (SPI_MemMapPtr SPI,BOOLEAN bMode)
{
    SIM_SCGC4 |= SIM_SCGC4_SPI0_MASK;                                   /* 开启SPI0                     */
                                                                        /* CPOL = 0, SCK 为低有效       */
                                                                        /* MSTR = 1, SPI 处于主模式     */
                                                                        /* LSBF = 0, MSB (位7)在先      */
                                                                        /* SPIE = 0, SPI 中断被禁止     */
                                                                        /* CPHA = 0, SCK第一个时钟沿采样*/
    SPI->C1 |= SPI_C1_SPE_MASK ;                                        /* SPI使能                      */
    SPI->C1 &= ~(1 << SPI_C1_CPHA_SHIFT);
    if(bMode == Master) {                                               /* 主模式                       */
        SPI->C1 |= SPI_C1_MSTR_MASK;
    } else {                                                            /* 从模式                       */
        SPI->C1 &= ~(1 << SPI_C1_MSTR_SHIFT);
    }
    SPI->BR |= SPI_BR_SPPR(0) ;                                         /* 时钟分频                     */
}


SPI发送一字节数据:

INT8U Send_Byte (INT8U ucdata)
{
    INT8U ucTemp;
    while((SPI0_S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK);             /* 发送前要先判断寄存器         */
    SPI0_DL = ucdata;

    while((SPI0_S & SPI_S_SPRF_MASK) != SPI_S_SPRF_MASK);               /* 接收数据有效                 */
    ucTemp = SPI0_DL;                                                    /* 清空接收标记寄存器           */
    ucTemp = ucTemp;
        return ucTemp;
}


读W25Q32状态:

uint8_t flash_read_status ( void )
{
        uint8_t status;

        SPI_FLASH_CS_LOW();                                                                                                     /* 选中SPI Flash                */
        Send_Byte(0x05);                                               
        status = Send_Byte(0xff);                                       
        SPI_FLASH_CS_HIGH();                                                                                        /* P0.2--1,CS = 1 释放SPI Flash */
        return status;                                                                                            /* Return Reg 1's Content                */
}


读W25Q32地址:

INT16U flash_read_id (void)
{
        INT16U IDcode;

        SPI_FLASH_CS_LOW();                                                                                                             /* P0.2--0,CS = 0 选中SPI Flash */
        Send_Byte(0x4b);
        Send_Byte(0x00);
        Send_Byte(0x00);
        Send_Byte(0x00);
        Send_Byte(0x00);
        IDcode = Send_Byte(0xff);
        SPI_FLASH_CS_HIGH();                                                                                                            /* P0.2--1,CS = 1 释放SPI Flash */

        return IDcode;                                                                                                   
}


读W25Q32数据:

uint8_t flash_read_data (uint32_t RAddr, uint8_t *buf, uint32_t RLength)
{
        uint8_t Temp;
        uint32_t i;

        if (RLength == 0)
        {
                return 0;
        }

        /*
         *        Check the state register. If it's busy , wait until it's free
         */
        while(1)                                                                                                               
        {                                                                                                               
                Temp = flash_read_status( );                                                               
                Temp &= 0x01;                                                                                       
                if(Temp == 0x00)                                                                        
                        break;                                                                        
                for(i=0; i<10; i++);                                                
        }

        SPI_FLASH_CS_LOW();                                                                                                             /* P0.2--0,CS = 0 选中SPI Flash */
        Send_Byte(0x03);
        Send_Byte((RAddr & 0xFF0000) >> 16);
        Send_Byte((RAddr & 0x00FF00) >> 8);
        Send_Byte((RAddr & 0x0000FF));
        for (i=0; i<RLength; i++)
        {
                buf = Send_Byte(0xff);
                printf("Read Data = %d\r\n",buf);
        }
        SPI_FLASH_CS_HIGH();                                                                                                            /* P0.2--1,CS = 1 释放SPI Flash */

        return 1;
}


W25Q32区域擦除:

uint8_t flash_sector_erase (uint32_t addr)
{
        flash_write_enable();                                                                                                    /* Write enable                 */
        
        SPI_FLASH_CS_LOW();                                                                                                             /* P0.2--0,CS = 0 选中SPI Flash */
        Send_Byte(0x20);
        Send_Byte((addr & 0xFF0000) >> 16);
        Send_Byte((addr & 0x00FF00) >> 8);
        Send_Byte(addr & 0x0000FF);
         SPI_FLASH_CS_HIGH();                                                                                                            /* P0.2--1,CS = 1 释放SPI Flash */

        while (flash_read_status() & 0x01 != 0x00);                                                        /* Wait for the flash free      */

        return 1;
}


W25Q32区域写:

uint8_t flash_write_sector (uint32_t WAddr, uint8_t *buf, uint32_t WLength)
{
        uint32_t i;

        if (WLength == 0)
        {
                return 0;
        }

        flash_write_enable();                                                                                                    /* Write enable                 */


        SPI_FLASH_CS_LOW();                                                                                                             /* P0.2--0,CS = 0 选中SPI Flash */
        Send_Byte(0x02);
        Send_Byte((WAddr & 0xFF0000) >> 16);
        Send_Byte((WAddr & 0x00FF00) >> 8);
        Send_Byte((WAddr & 0x0000FF));
        for (i=0; i<WLength; i++)
        {
                Send_Byte(buf);        
                printf("Send Data = %d\r\n",buf);
        }
        SPI_FLASH_CS_HIGH();                                                                                                            /* P0.2--1,CS = 1 释放SPI Flash */

        while ((flash_read_status() & 0x01) != 0x00);

        return 1;
}


主程序就不多说了,很好理解,就是将要实现的功能整合到一起。还是惯例红色的部分比较重要。

在这里重点说一下SPI写程序:


起初从主函数按照一步步调试观察的时候,发现程序只用到了SPI的写操作(程序上的说明是写操作),而没有用到读操作(同左),非常费解。

后来发现其实它的写操作里面是包含读操作的。

当需要写数据时就将数据给SPI,函数返回值不去理会,将标志位清零即可。
当需要读数据时就发送一帧0xff,然后将函数返回值读出来。

在这里需要说明为什么要发送0xff,我个人的认为是由于W25Q32器件的指令问题,如下图:
QQ截图20150727224251.png    
我姑且这么认为,如果有大神知道原因,请告知,谢谢。


再就是读写W25Q32的函数:

起始函数很好理解,首先是片选,然后发送指令(芯片手册很全面),最后向SPI写数据或读数据即可。

在读写程序是要注意一点,清除读标志位和写标志位时,需要做相应的对SPI_D的操作,见下图:
QQ截图20150727224958.png
QQ截图20150727225049.png

在这里要注意。

这里是源工程: SPI_Master.zip (1.25 MB, 下载次数: 60)

评分

参与人数 1NXP金币 +30 收起 理由
小七 + 30 打赏!

查看全部评分

回复

使用道具 举报

  • TA的每日心情
    开心
    2018-7-23 21:04
  • 签到天数: 103 天

    连续签到: 1 天

    [LV.6]常住居民II

    228

    主题

    5379

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    16706
    最后登录
    1970-1-1
    发表于 2015-7-28 08:34:22 | 显示全部楼层
    多谢分享!
    回复

    使用道具 举报

    该用户从未签到

    5

    主题

    32

    帖子

    0

    注册会员

    Rank: 2

    积分
    73
    最后登录
    2018-5-3
    发表于 2015-7-28 10:36:02 | 显示全部楼层
    谢谢楼主
    回复

    使用道具 举报

    该用户从未签到

    29

    主题

    439

    帖子

    0

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    720
    最后登录
    2015-12-29
    发表于 2015-7-28 15:16:52 | 显示全部楼层
    可以参考一下
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    29

    主题

    439

    帖子

    0

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    720
    最后登录
    2015-12-29
    发表于 2015-7-28 15:51:36 | 显示全部楼层
    这个spi还算不难的
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-10-18 11:35
  • 签到天数: 9 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    21

    主题

    945

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2001
    最后登录
    2020-6-8
    发表于 2015-7-29 10:23:50 | 显示全部楼层
    谢谢楼主分亨,顶一下。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-23 14:27 , Processed in 0.099270 second(s), 28 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表