打印

关于stm32 spi读写M25P16的问题

[复制链接]
9410|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
610095871|  楼主 | 2011-6-15 21:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位好 我最近在自学stm32现在在做spi读写M25P16的程序 但是现在遇到了问题现在不知道该怎么办了 希望有经验的朋友帮忙指点下
以下是我的程序
#include <stm32f10x_lib.h>
#include "mysysinit.h"
#include "delay.h"

GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构变量
SPI_InitTypeDef  SPI_InitStructure;//设置一个spi的结构变量
////////GPIO的设置/////////
void gpioinit()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void spi_init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 ,ENABLE);
SPI_Cmd(SPI1,DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
   SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
   SPI_InitStructure.SPI_CRCPolynomial = 7;
   SPI_Init(SPI1, &SPI_InitStructure);
   SPI_Cmd(SPI1, ENABLE);   
}
static u8 sendrecieve(u8 byte)
{
while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE))==RESET);
SPI_I2S_SendData(SPI1,byte);
while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE ))==RESET);
return SPI_I2S_ReceiveData(SPI1);
//SPI_I2S_ClearFlag(SPI1,SPI_FLAG_RXNE);
}
int main()
{
u8 aa;
my_systeminit();
gpioinit();
spi_init();
delayinit(72);
while(1)
{
  sendrecieve(0x50);
  delay_ms(10000);
  aa=sendrecieve(0x50);
  if(aa==0x50)GPIO_SetBits(GPIOC,GPIO_Pin_6);
  delay_ms(10000);
}
}
沙发
610095871|  楼主 | 2011-6-16 11:35 | 只看该作者
知道的希望大家给点建议啊

使用特权

评论回复
板凳
香水城| | 2011-6-16 12:13 | 只看该作者
你自己都不知道遇到了什么问题,谁能给你建议?

使用特权

评论回复
地板
txcy| | 2011-6-16 13:09 | 只看该作者
楼主遇到了什么问题??

使用特权

评论回复
5
610095871|  楼主 | 2011-6-16 15:53 | 只看该作者
4# txcy
配置好spi后 后面不知道该怎么写了,没有人指导,现在停在这里了。带的例程写的又很多很繁琐,希望能给个简单的例子,只要能实现spi对flash的简单读写就行

使用特权

评论回复
6
610095871|  楼主 | 2011-6-16 15:56 | 只看该作者
编写flash的读写程序,static u8 sendrecieve(u8 byte)
{
while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE))==RESET);
SPI_I2S_SendData(SPI1,byte);
while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE ))==RESET);
return SPI_I2S_ReceiveData(SPI1);
//SPI_I2S_ClearFlag(SPI1,SPI_FLAG_RXNE);
}

这个程序不是通过spi对flah进行读写吗? 而且单片机既然带了spi协议,那应该就不需要进行时序的模拟了,但是我看的很多例子上都有很多的flash的读写程序,求教

使用特权

评论回复
7
mxh0506| | 2011-6-16 21:30 | 只看该作者
可以参考STM32库里的sFlash范例

使用特权

评论回复
8
610095871|  楼主 | 2011-6-16 22:37 | 只看该作者
7# mxh0506
我看了下flash的固件库函数,但是不管用,比如忙检测什么都没有 ,如果阁下有比较简单的例程能共享下,感激不尽

使用特权

评论回复
9
610095871|  楼主 | 2011-6-16 22:38 | 只看该作者
3# 香水城
香主共享个例程呗 谢谢了

使用特权

评论回复
10
趴趴熊| | 2011-6-17 09:15 | 只看该作者
感觉你好笨。看手册就知道怎么操作了。

读数据是先定位数据指针,写入24位地址

CS_HIGH();   
..........
CS_LOW();       //高变低会使上次命令失效
SPI_SendByte(0x03);   //读数据命令
SPI_SendByte(High_Word_Low_Byte);   //24位地址
SPI_SendByte(Low_Word_High_Byte);
SPI_SendByte(Low_Word_Low_Byte);

然后发送dummy字节,让flash返回当前地址的数据,flash会自动累加数据指针,下次发送dummy字节,就能取到下一个地址的数
while (....)
{
   ....
dat = SPI_SendByte(0xFF);     // 可以一直保持CS_LOW
  ....
}

使用特权

评论回复
11
香水城| | 2011-6-17 09:50 | 只看该作者
3# 香水城  
香主共享个例程呗 谢谢了
610095871 发表于 2011-6-16 22:38


固件库中的例程已经足够了。

使用特权

评论回复
12
610095871|  楼主 | 2011-6-17 09:55 | 只看该作者
#include <stm32f10x_lib.h>
#include "mysysinit.h"
#include "delay.h"
#include "stm32f10x_spi.h"
#define FLASH_CHREAD 0x0B
#define FLASH_CLREAD 0x03
#define FLASH_PREAD        0xD2

#define FLASH_BUFWRITE1 0x84  // 写入第一缓冲区
#define FLASH_IDREAD 0x9F
#define FLASH_STATUS 0xD7          // 读取状态寄存器
#define PAGE_ERASE 0x81
#define PAGE_READ 0xD2
#define MM_PAGE_TO_B1_XFER 0x53                                // 将主存储器的指定页数据加载到第一缓冲区
#define BUFFER_2_WRITE 0x87                                        // 写入第二缓冲区
#define B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86        // 将第二缓冲区的数据写入主存储器(擦除模式)

#define BUFFER_1_WRITE 0x84 // 写入第一缓冲区
#define BUFFER_2_WRITE 0x87 // 写入第二缓冲区
#define BUFFER_1_READ 0xD4 // 读取第一缓冲区
#define BUFFER_2_READ 0xD6 // 读取第二缓冲区
#define B1_TO_MM_PAGE_PROG_WITH_ERASE 0x83 // 将第一缓冲区的数据写入主存储器(擦除模式)
#define B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86 // 将第二缓冲区的数据写入主存储器(擦除模式)
#define MM_PAGE_TO_B1_XFER 0x53 // 将主存储器的指定页数据加载到第一缓冲区
#define MM_PAGE_TO_B2_XFER 0x55 // 将主存储器的指定页数据加载到第二缓冲区
#define PAGE_ERASE 0x81 // 页删除(每页512/528字节)
#define SECTOR_ERASE 0x7C // 扇区擦除(每扇区128K字节)
#define READ_STATE_REGISTER 0xD7 // 读取状态寄存器


/* Private typedef -----------------------------------------------------------*/
#define SPI_FLASH_PageSize    0x100

/* Private define ------------------------------------------------------------*/
#define WRITE      0x02  /* Write to Memory instruction */
#define WRSR       0x01  /* Write Status Register instruction */
#define WREN       0x06  /* Write enable instruction */

#define READ       0x03  /* Read from Memory instruction */
#define RDSR       0x05  /* Read Status Register instruction  */
#define RDID       0x9F  /* Read identification */
#define SE         0xD8  /* Sector Erase instruction */
#define BE         0xC7  /* Bulk Erase instruction */

#define WIP_Flag   0x01  /* Write In Progress (WIP) flag */

#define Dummy_Byte 0xA5

#define Select_Flash()     GPIO_ResetBits(GPIOA, GPIO_Pin_4)
/* Deselect SPI FLASH: ChipSelect pin high */
#define NotSelect_Flash()    GPIO_SetBits(GPIOA, GPIO_Pin_4)

u8 aa=0xaa;

GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构变量
SPI_InitTypeDef  SPI_InitStructure;//设置一个spi的结构变量
////////GPIO的设置/////////
void gpioinit()
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
          GPIO_Init(GPIOA, &GPIO_InitStructure);

          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
          GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
          GPIO_Init(GPIOC, &GPIO_InitStructure);
}

void spi_init()
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 ,ENABLE);
        SPI_Cmd(SPI1,DISABLE);
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
          SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
          SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
          SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
          SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
          SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
          SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
          SPI_InitStructure.SPI_CRCPolynomial = 7;
          SPI_Init(SPI1, &SPI_InitStructure);
          SPI_Cmd(SPI1, ENABLE);          
}

static u8 sendrecieve(u8 byte)
{

        while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE))==RESET);
        SPI_I2S_SendData(SPI1,byte);
        while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE ))==RESET);
        return SPI_I2S_ReceiveData(SPI1);
        //SPI_I2S_ClearFlag(SPI1,SPI_FLAG_RXNE);
}
void FlashWaitBusy(void)//Flash忙检测
{
          u8 FLASH_Status = 0;
          Select_Flash();       
          sendrecieve(RDSR);//读状态
          do
          {
            FLASH_Status = sendrecieve(Dummy_Byte);
          }
          while ((FLASH_Status & WIP_Flag) == SET);
          NotSelect_Flash();          

}
void FlashPageEarse(u16 page) //擦除指定的页,页范围0-4095
{       

  FlashWaitBusy();//Flash忙检测
  Select_Flash(); //CS置"0"
  sendrecieve(0X06);        //写使能
  NotSelect_Flash(); //CS置"1"

  FlashWaitBusy();//Flash忙检测
  Select_Flash(); //CS置"0"
  sendrecieve(SE);  //块擦除
  sendrecieve((page & 0xFF0000) >> 16);
  sendrecieve((page & 0xFF00) >> 8);
  sendrecieve(page & 0xFF);
  NotSelect_Flash(); //CS置"1"

}
unsigned char M25P16_RamTo_buf(unsigned int start_address)
{
          unsigned int i;
          FlashPageEarse(0X01); //擦除指定的页,页范围0-4095

          FlashWaitBusy();//Flash忙检测
          Select_Flash(); //CS置"0"
          sendrecieve(0X06);        //写使能
          NotSelect_Flash(); //CS置"1"

          FlashWaitBusy();//Flash忙检测
          Select_Flash(); //CS置"0"
          sendrecieve(0X02);        //页写
          sendrecieve((start_address & 0xFF0000) >> 16);
          sendrecieve((start_address & 0xFF00) >> 8);
          sendrecieve(start_address & 0xFF);
          sendrecieve(0xa4);
          NotSelect_Flash();
}


unsigned char M25P16_buf_ToRam(unsigned int start_address)
{
        FlashWaitBusy(); //Flash忙检测

        Select_Flash();//CS置"0"                
    sendrecieve(0X03);//        读数据
    sendrecieve((start_address & 0xFF0000) >> 16);
    sendrecieve((start_address & 0xFF00) >> 8);
    sendrecieve(start_address & 0xFF);
        aa=sendrecieve(0xa5);
        NotSelect_Flash();//CS置"1"
}


int main()
{

        my_systeminit();
        gpioinit();
        spi_init();
        delayinit(72);
        M25P16_RamTo_buf(1000);
        while(1)
        {
                M25P16_buf_ToRam(1000);       
                delay_ms(100);
                if(aa==0xa4)
                GPIO_SetBits(GPIOC,GPIO_Pin_7);
        }
}
哈哈 终于做出来 发一个数据 接收到后 让灯亮 现在放上面 和大家交流

使用特权

评论回复
13
香水城| | 2011-6-17 10:03 | 只看该作者
哈哈,LZ自己有能力,但就是想偷懒走捷径,还是静下心,努力地钻研钻研比较好,:lol

使用特权

评论回复
14
pkat| | 2011-6-17 10:11 | 只看该作者
做科研得静下心来:lol

使用特权

评论回复
15
香水城| | 2011-6-17 10:12 | 只看该作者
呵呵,可以学学熊猫阿宝~~~~~~

使用特权

评论回复
16
610095871|  楼主 | 2011-6-17 15:59 | 只看该作者
谢谢各位,学到了很多东西。

使用特权

评论回复
17
岁月如割| | 2013-12-18 19:39 | 只看该作者
楼主你有遇到以数组形式写多个数进去然后都读出来出现错误这样的情况么,,一个个写一个一个读却没问题,,还有就是为什么每次要判断flash忙不忙呢

使用特权

评论回复
18
q913794286| | 2014-1-19 14:18 | 只看该作者
610095871 发表于 2011-6-17 09:55
#include
#include "mysysinit.h"
#include "delay.h"

这个很简单啊,困难的是能在m25p16的任意地址写任意字长的数据,还要能读的出来。。。。。
这个我纠结了多天。数字字符的存储没有问题,可是汉字的字长为2B=16位了,(void*)转换后存进去,,,读不出数据来。。。。

使用特权

评论回复
19
yzzly| | 2014-1-20 13:39 | 只看该作者
本帖最后由 yzzly 于 2014-1-20 13:44 编辑

本人用了几年的STM32F103VE操作M25P40的函数,系统时钟72M
void SPI2_Wbyte(Uint16 Dat)
{
        while((SPI2->SR & 0x02)!=0x02);                                                                //·¢ËÍ»º³åÆ÷²»¿Õ
        SPI2->DR=Dat;
}

Uint16 SPI2_Rbyte(void)
{
        while((SPI2->SR & 0x01)!=0x01);                                                                 //½ÓÊÕ»º³åÆ÷²»¿Õ
        return(SPI2->DR);
}
Uint16 ReadM25p40StaReg(void)
{
        Uint16 Sta=0;
        ENM25P40;
        SPI2_Wbyte(RDSR);               SPI2_Rbyte();
        SPI2_Wbyte(0x00);                Sta=SPI2_Rbyte();
        DIM25P40;
        return(Sta);
}

void WriteM25p40En(void)
{
        ENM25P40;
        SPI2_Wbyte(WREN);                        SPI2_Rbyte();
        DIM25P40;
        while((ReadM25p40StaReg() & 0x02)==0)Flags.Wdog=1;
}

void WriteM25p40Di(void)
{
        ENM25P40;
        SPI2_Wbyte(WRDI);                        SPI2_Rbyte();
        DIM25P40;
        while(ReadM25p40StaReg() & 0x02)Flags.Wdog=1;
}

void WriteM25p40StaReg(Uint16 sta)
{
        WriteM25p40En();
        ENM25P40;
        SPI2_Wbyte(WRSR);                  SPI2_Rbyte();
        SPI2_Wbyte(sta);                        SPI2_Rbyte();
        DIM25P40;
        while((ReadM25p40StaReg() & 0x01)==0)Flags.Wdog=1;
        while(ReadM25p40StaReg() & 0x01)Flags.Wdog=1;
        WriteM25p40Di();
        __nop();
}

void WriteM25p40Addr(Uint32 addr)
{
        SPI2_Wbyte((addr>>16) & 0x00000007);                                                       //23~16λµØÖ·
        SPI2_Rbyte();
        SPI2_Wbyte((addr>>8) & 0x000000FF);                                                            //15~8λµØÖ·
        SPI2_Rbyte();
        SPI2_Wbyte((addr>>0) & 0x000000FF);                                                            //7~0λµØÖ·
        SPI2_Rbyte();
}

Uint32 ReadM25p40ID(void)                                                                                         //IDÖ»ÓÐÔÚоƬ¼Ó¹¤¹ý³ÌÖвÅÄܶÁ³ö¡£
{
        Uint32 id1=0,id2=0,id=0;
        ENM25P40;
        SPI2_Wbyte(RDID);                        SPI2_Rbyte();        
        SPI2_Wbyte(0x55);                        id1=SPI2_Rbyte();                                       //³§ÉÌID
        SPI2_Wbyte(0x55);                        id2=SPI2_Rbyte()<<8;                                //Æ÷¼þID
        SPI2_Wbyte(0x55);                        id=SPI2_Rbyte();                                            //´æ´¢Æ÷ÈÝÁ¿(2^id)
        DIM25P40;
        id=id+(id1<<16)+id2;
        return(id);
}

void M25p40PageRead(Uint32 volatile *Dest,Uint16 SectorNum,Uint16 PageNum,Uint16 DataLen,Uint16 ByteNum)
{
        Uint16 Cnt;
        SectorNum-- ; PageNum--;
        ENM25P40;
        SPI2_Wbyte(READ);                        SPI2_Rbyte();
        WriteM25p40Addr(SectorNum*65536+PageNum*256);
        if(ByteNum==2)                                                                                                                  //¶Á2¸ö×Ö½Ú
        {
                for(Cnt=0;Cnt<DataLen;Cnt++)
                {
                        SPI2_Wbyte(0x00);        *(Dest+Cnt)=SPI2_Rbyte();                                          //¶ÁµÍ8λ
                        SPI2_Wbyte(0x00);        *(Dest+Cnt)=*(Dest+Cnt)+(SPI2_Rbyte()<<8);            //¶Á¸ß8λ
                }
        }
        else                                                                                                                                          //¶Á4¸ö×Ö½Ú
        {
                for(Cnt=0;Cnt<DataLen;Cnt++)
                {
                        SPI2_Wbyte(0x00);        *(Dest+Cnt)=SPI2_Rbyte();
                        SPI2_Wbyte(0x00);        *(Dest+Cnt)=*(Dest+Cnt)+(SPI2_Rbyte()<<8);
                        SPI2_Wbyte(0x00);        *(Dest+Cnt)=*(Dest+Cnt)+(SPI2_Rbyte()<<16);
                        SPI2_Wbyte(0x00);        *(Dest+Cnt)=*(Dest+Cnt)+(SPI2_Rbyte()<<24);
                }
        }
        DIM25P40;
}

void M25p40PageProgram(Uint32 volatile *Buf,Uint16 SectorNum,Uint16 PageNum,Uint16 DataLen,Uint16 ByteNum)
{
        Uint16 Cnt;
        SectorNum-- ; PageNum--;
        WriteM25p40En();
        ENM25P40;
        SPI2_Wbyte(PP);     SPI2_Rbyte();
        WriteM25p40Addr(SectorNum*65536+PageNum*256);
        if(ByteNum==2)                                                                                               //Ò»´Îд2¸ö×Ö½Ú
        {
                for(Cnt=0;Cnt<DataLen;Cnt++)
                {
                        SPI2_Wbyte(*(Buf+Cnt)&0xFF);                SPI2_Rbyte();                   //дµÍ8λ
                        SPI2_Wbyte(*(Buf+Cnt)>>8);                   SPI2_Rbyte();               //д¸ß8λ
                }
        }
        else                                                                                                                        //Ò»´Îд4¸ö×Ö½Ú
        {
                for(Cnt=0;Cnt<DataLen;Cnt++)
                {
                        SPI2_Wbyte(*(Buf+Cnt)&0xFF);                SPI2_Rbyte();
                        SPI2_Wbyte((*(Buf+Cnt)>>8)&0xFF);        SPI2_Rbyte();
                        SPI2_Wbyte((*(Buf+Cnt)>>16)&0xFF);        SPI2_Rbyte();
                        SPI2_Wbyte((*(Buf+Cnt)>>24)&0xFF);        SPI2_Rbyte();
                }
        }
        DIM25P40;
        __nop();
        while(ReadM25p40StaReg() & 0x01)Flags.Wdog=1;               
        WriteM25p40Di();
}

Uint16 M25p40SectorErase(Uint16 SectorNum)                                                   //M25P40ÉÈÇø²Á³ý
{
        Uint16 Temp;
        SectorNum--;
        WriteM25p40En();
        ENM25P40;
        SPI2_Wbyte(SE);   SPI2_Rbyte();                                    //дÉÈÇø²Á³ýÃüÁî
        WriteM25p40Addr(SectorNum*65536);                                                        //ÉÈÇøºÅ*ÿÉÈÇø×Ö½ÚÊý=ÿ¸öÉÈÇøµÄÆðʼµØÖ·
        DIM25P40;
        Temp=1;
        while(ReadM25p40StaReg() & 0x01)
        {
                Flags.Wdog=1;
        }
        WriteM25p40Di();
        return(Temp);
}

使用特权

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

本版积分规则

27

主题

323

帖子

10

粉丝