[技术问答]

N76E003里的SPI+FLASH指令问题

[复制链接]
3315|15
手机看帖
扫描二维码
随时随地手机跟帖
hk386|  楼主 | 2018-4-17 10:28 | 显示全部楼层 |阅读模式

#include "N76E003.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "Common.h"
#include "Delay.h"


#define SPI_CLOCK       0

#define SS_PIN          P15
#define WRITE_ENABLE    0x06
#define WRITE_DISABLE   0x04
#define READ_DATA       0x03
#define PAGE_PROGRAM    0x02
#define CHIP_ERASE      0xC7
#define READ_STATUS1    0x05

//-----------------------------------------------------------------------------------------------------------
void SPI_Error(void)
{
    printf ("\n*  SPI Error, please check the connection between MCU and SPI Flash");
    while(1);
}
//-----------------------------------------------------------------------------------------------------------
void SPI_Initial(void)
{
    #if   SPI_CLOCK == 0
            clr_SPR1;
            clr_SPR0; //时钟除频
    #elif SPI_CLOCK == 1
            clr_SPR1;
            set_SPR0;
    #elif SPI_CLOCK == 2
            set_SPR1;  
            clr_SPR0;
    #elif SPI_CLOCK == 3
            set_SPR1;
            set_SPR0;
    #endif

    /* /SS General purpose I/O ( No Mode Fault ) */
    set_DISMODF;
    clr_SSOE;

    /* SPI in Master mode */
    set_MSTR;

    /* MSB first */
    clr_LSBFE;

    clr_CPOL;
    clr_CPHA;
   
    /* Enable SPI function */
    set_SPIEN;
}
//-----------------------------------------------------------------------------------------------------------
void Read_MID_DID(UINT8 *pu8MID,UINT8 *pu8DID)
{
    SS_PIN = 0;
    SPDR = 0x90;
    while((SPSR&0x80)==0x00); //前面发的应该是指令,打开的是MID/DID的指令 ,90h         指令以/CS 拉低开始,然后通过DI传输指令代码90H和24位的地址(全为000000H)。这之后,WINBOND 的ID
  // (EFH)和芯片ID将在时钟的下降沿以高位在前的方式传出。关于W25Q128BV 的芯片和制造商ID,在图29中列出。如果24位地址传输的是000001H,那么芯片ID将首先被传出,然后紧接着的是制造商ID。这两个是连续读出来的。该指令以/CS拉高结束。
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);         //24位地址(0x00,0x00,0x00)
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;
                                                                 
    SPDR = 0xFF;  //连续读数据
    while((SPSR&0x80)==0x00);
    *pu8MID = SPDR;//把SPDR的值发给pu8MID
    clr_SPIF;

    SPDR = 0xFF; //连续读数据
    while((SPSR&0x80)==0x00);
    *pu8DID = SPDR;        //把SPDR的值发给pu8DID
    clr_SPIF;
    SS_PIN = 1;   
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Write_Enable(void)         //写使能,06H
{
    SS_PIN = 0;
    SPDR = WRITE_ENABLE; //06
    while((SPSR&0x80)==0x00);
    clr_SPIF;
    SS_PIN = 1;   
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Write_Disable(void)        //禁止写,04H
{
    SS_PIN = 0;
    SPDR = WRITE_DISABLE; //04
    while((SPSR&0x80)==0x00);
    clr_SPIF;
    SS_PIN = 1;   
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Chip_Erase(void)         //全片擦除,C7H/60H
{
    SS_PIN = 0;
    SPDR = CHIP_ERASE;        //0xC7
    while((SPSR&0x80)==0x00);
    clr_SPIF;
    SS_PIN = 1;   
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Read_Status(void) //读状态寄存器1,05H
{
    UINT8 u8Status;

    SS_PIN = 0;
    do{
        SPDR = READ_STATUS1; //        0x05,开始读状态寄存器1
        while((SPSR&0x80)==0x00);
        clr_SPIF;
   
        SPDR = 0xFF; //连续写数据,把数据写入到SPDR,读到的数据为状态寄存器1
        while((SPSR&0x80)==0x00);
        u8Status = SPDR;//01h为写状态寄存器
        clr_SPIF;
    }while((u8Status&0x01)==0x01);
    SS_PIN = 1;   
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Erase_Verify(void)  //        flash 擦除证明
{
    UINT16 u16CNT;   
    UINT8  u8Data;

    SS_PIN = 0;
    SPDR = READ_DATA;//        0x03  ,读数据
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    /* 24-bit Address */
    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    for(u16CNT=0;u16CNT<256;u16CNT++)
    {
        SPDR = 0x00; //        ???
        while((SPSR&0x80)==0x00);
        u8Data = SPDR;
        clr_SPIF;
        if(u8Data != 0xFF)
        {
            SPI_Error();
        }
    }

    SS_PIN = 1;
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Program(void)
{
    UINT16 u16CNT;
   
    SS_PIN = 0;

    SPDR = PAGE_PROGRAM; //        0x02
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    /* 24-bit Address */
    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    /* Send the data to SPI_Flash buffer */
    for(u16CNT=0;u16CNT<256;u16CNT++)
    {
        SPDR = (UINT8)u16CNT;
        while((SPSR&0x80)==0x00);
        clr_SPIF;
    }
   
    SS_PIN = 1;   
}
//-----------------------------------------------------------------------------------------------------------
void Flash_Program_Verify(void)
{
    UINT16 u16CNT;   
    UINT8  u8Data;

    SS_PIN = 0;

    SPDR = READ_DATA;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    /* 24-bit Address */
    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    SPDR = 0x00;
    while((SPSR&0x80)==0x00);
    clr_SPIF;

    for(u16CNT=0;u16CNT<256;u16CNT++)
    {
        SPDR = 0x00; //???
        while((SPSR&0x80)==0x00);
        u8Data = SPDR;
        clr_SPIF;
        if(u8Data != (UINT8)u16CNT)
        {
            SPI_Error();
        }
    }

    SS_PIN = 1;
}
//-----------------------------------------------------------------------------------------------------------
void main(void)
{      
    UINT8 u8MID,u8DID;

    /* Note
       MCU power on system clock is HIRC (22.1184MHz), so Fsys = 22.1184MHz
    */
   
    Set_All_GPIO_Quasi_Mode;
    InitialUART0_Timer3(115200);             /* 9600 Baud Rate*/
    SPI_Initial();

    Read_MID_DID(&u8MID,&u8DID);

    if((u8MID != 0xEF)&&(u8DID != 0x14))  //manufacturer id=MID ,Device ID=DID
    {
        SPI_Error();
    }

    /* The procedure of SPI Flash at erase mode */
    Flash_Write_Enable();
    Flash_Chip_Erase();
    Flash_Read_Status();
    Flash_Write_Disable();   
    Flash_Erase_Verify();
    /* The procedure of SPI Flash at program mode */
    Flash_Write_Enable();
    Flash_Program();
    Flash_Read_Status();
    Flash_Write_Disable();

    /* Program verify */
    Flash_Program_Verify();

    printf("\nFinished the SPI Demo Code and test pass!!!\n");
    while(1);
}
//-----------------------------------------------------------------------------------------------------------
  问题我在程序中用红色标出来了,SPDR=0X00,这个应该是指令,可是代表什么指令我查了半天资料还是不懂,麻烦大神帮忙给我解释一下吗,谢谢。
xinxianshi| | 2018-4-17 17:02 | 显示全部楼层
SPDR是SPI的数据寄存器,你可以手册搜索到。
应该是接手SPI数据用的。
先清空,然后等待数据接收,接收后,那个就会被置位了,这样跳过while,读出来数据,清理标志位。

使用特权

评论回复
xinxianshi| | 2018-4-17 17:03 | 显示全部楼层
在手册的第81页有详细说明,你看了就明白了。

使用特权

评论回复
xinxianshi| | 2018-4-17 17:04 | 显示全部楼层
另外在82页有对这个寄存器的介绍,81页那个SPSR以及SPIF的介绍配合就明白这一段函数怎么回事了。

使用特权

评论回复
dongnanxibei| | 2018-4-17 19:16 | 显示全部楼层
楼上高手都说清除了,确实是这样,那个应该是发送接收寄存器。

使用特权

评论回复
捉虫天师| | 2018-4-17 22:46 | 显示全部楼层
很好懂啊,楼主难道不知道寄存器对应的作用

使用特权

评论回复
hk386|  楼主 | 2018-4-18 10:15 | 显示全部楼层
xinxianshi 发表于 2018-4-17 17:02
SPDR是SPI的数据寄存器,你可以手册搜索到。
应该是接手SPI数据用的。
先清空,然后等待数据接收,接收后, ...

大哥,你搞错了,不是接收,是发送,SPI接了W25Q16BV(flash),SPDR=xxh,跟着是指令,不是数据,接数据应该是相反是,比如看下面的u8Data=SPDR这样才是接收数据。

使用特权

评论回复
hk386|  楼主 | 2018-4-18 10:16 | 显示全部楼层
dongnanxibei 发表于 2018-4-17 19:16
楼上高手都说清除了,确实是这样,那个应该是发送接收寄存器。

大哥,你搞错了,不是接收,是发送,SPI接了W25Q16BV(flash),SPDR=xxh,跟着是指令,不是数据,接数据应该是相反是,比如看下面的u8Data=SPDR这样才是接收数据。

使用特权

评论回复
hk386|  楼主 | 2018-4-18 10:16 | 显示全部楼层
捉虫天师 发表于 2018-4-17 22:46
很好懂啊,楼主难道不知道寄存器对应的作用

大哥,你搞错了,不是接收,是发送,SPI接了W25Q16BV(flash),SPDR=xxh,跟着是指令,不是数据,接数据应该是相反是,比如看下面的u8Data=SPDR这样才是接收数据。

使用特权

评论回复
捉虫天师| | 2018-4-18 10:21 | 显示全部楼层
hk386 发表于 2018-4-18 10:16
大哥,你搞错了,不是接收,是发送,SPI接了W25Q16BV(flash),SPDR=xxh,跟着是指令,不是数据,接数据应 ...

那就是发送了,发送和接收是一样的操作逻辑,只不过一个往里面写,一个往外读。

使用特权

评论回复
hk386|  楼主 | 2018-4-18 13:50 | 显示全部楼层
捉虫天师 发表于 2018-4-18 10:21
那就是发送了,发送和接收是一样的操作逻辑,只不过一个往里面写,一个往外读。 ...

大哥,我怎么感觉你好像是消遣我的啊,没错,那个是发数据,可是发数据有不同的意思的,跟这个FLASH连接,如果你有好好细看我发的这个程序的话,我在一些程序的后面加了注释,那个是代表每当SPDR发什么数据的时候,会对FLASH进行什么操作,程序一开始就已经有所说明了。然后再比对下FLASH规格书再补点东西,这个基本就看明白了,现在就差我标的那个红色的是什么意思,我感觉你们好像都没仔细了解这个程序是什么意思

使用特权

评论回复
捉虫天师| | 2018-4-18 15:19 | 显示全部楼层
我今天空闲,好心帮你看看,你说我没看,你应该是没懂我的意思。你不就是问那个为什么写0吗,当然是要发送出去个0了,或者就是个握手信息呢?
请参考例子N76E003_BSP_Keil_C51_V1.0.5\Sample_Code\SPI_Master-Slave\SPI_Polling
这个里面有两个例子,一个主机代码,一个从机代码,他们约定了一套顺序相反的字符作为握手信息,比如甲方发送1,一方确认是否收到1.就这么简单,你有啥好纠结的。

使用特权

评论回复
hk386|  楼主 | 2018-4-18 17:34 | 显示全部楼层
捉虫天师 发表于 2018-4-18 15:19
我今天空闲,好心帮你看看,你说我没看,你应该是没懂我的意思。你不就是问那个为什么写0吗,当然是要发送 ...

晕啊,我这个例子不是双机通信啊,是SPI+FLASH,不一样的好吗,比如说,SPDR=0X90,是主机给FLASH发0X90,看起来是发数据,可是根据FLASH的规格书,0X90代表读取制造商/芯片ID,这个就相当打开FLASH的某个窗口,然后后面加24位地址,24个0,在加上SPDF(X0FF)连续读操作,然后你就可以看到*pu8MID = SPDR,*pu8DID = SPDR,把SPDR的值分别写到*pu8MID,*pu8DID,是这样理解的,不是说单纯就能直接操作,规格书里把这个叫做指令操作,所以我问题一开始就问,SPDR=0X00是代表什么操作,而不是问发了什么数据,不过几天又翻了一下这个规格书,上面有一句话大概是这样说的(快速读指令)只是在传输完24位地址后,外加8位无关的数据。在传输8位无关的数据时间内,芯片用来建立初始地址,我觉得这个0X00放在是拿来延时用的。

使用特权

评论回复
hk386|  楼主 | 2018-4-18 17:44 | 显示全部楼层
捉虫天师 发表于 2018-4-18 15:19
我今天空闲,好心帮你看看,你说我没看,你应该是没懂我的意思。你不就是问那个为什么写0吗,当然是要发送 ...

而且想往FLASH写数据那里那么容易,它一开始就定义了很多的函数,往里写数据要很多操作才能完成的

使用特权

评论回复
捉虫天师| | 2018-4-18 19:16 | 显示全部楼层
hk386 发表于 2018-4-18 17:44
而且想往FLASH写数据那里那么容易,它一开始就定义了很多的函数,往里写数据要很多操作才能完成的 ...

懂你意思了,是单片机跟存储芯片的通信,SPI接口。所以这里可能这个芯片有这个要求写0,写一次0,读出来一次数据,应该是这样,根据你的程序应该是。
其实你这种个问题,最好连带那个SPI的存储芯片手册一并提供了,大家才好给你分析。哈哈,要不然跟我一眼样,一直在猜你的程序要干啥。

使用特权

评论回复
ylslib| | 2018-4-30 14:17 | 显示全部楼层
SPDR是SPI的数据寄存器。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

593

帖子

0

粉丝