STM32 SPI W25X16驱动

发布者:SparklingRiver最新更新时间:2015-10-30 来源: eefocus关键字:STM32  SPI  W25X16驱动 手机看文章 扫描二维码
随时随地手机看文章
    前面说了STM32的I2C,作为STM32的另外一个串行接口就不得不提到了——SPI。与I2C差不多,同样有硬件接口,有库函数支持,我们要做的就是结合SPI接口芯片调用库函数,就能实现SPI驱动了。一切看代码,你会懂的,注释非常详细的,很适合初学者。代码能够直接用到实际项目工程里面去的。SPI芯片选用W25X系列。。。

    演示效果使用超级终端或者SecureCRT 5.5(这货真的不错)

    工程结构图:

  STM32 <wbr>SPI <wbr>W25X16驱动

    1、工程里面的beep.c led.c usart1.c 与《STM32 基于库函数控制按键&nb… 》《STM32 串口例程之查询收》里面完全一样,这里就不在上代码。

    2、main.c

//程序功能:主要用于测试SPI W25X16驱动是否正常


#include"stm32f10x.h"
#include"user_usart1.h"
#include"user_led.h"
#include"user_beep.h"
#include"user_spi_w25x16.h"
#include


#define  FLASH_ID1              0xef3015
#define  FLASH_ID2              0xef4015
#define  FLASH_WriteAddress     0x000000
#define  FLASH_ReadAddress      FLASH_WriteAddress
#define  FLASH_SectorErase      FLASH_WriteAddress

#define CountOf(a)          (sizeof(a)/sizeof(*(a)))
#define DataSize    (CountOf(TxDataTable)-1)

u8 TxDataTable[]=" Hello,I am wgchnln,我 爱 ARM,I will persist in learning ARM,坚决不放弃 ";
u8 RxDataTable[DataSize];


//=============================================
#ifdef __GNUC__
 
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
//=============================================



TestStatus User_SPI_DataCompare(u8 *TxData,u8 *RxData,u8 Num)
{
  while(Num--)
  {
   if(*TxData!=*RxData)
   {
    return Failed;
   }
   RxData++;
   TxData++;
  }

  return Successed;
}


void User_SPI_Test(void)
{
  vu32 ID,DeviceID;
  u8 Buffer;
  volatile TestStatus Test1=Failed;
  volatile TestStatus Test2=Successed;        //存放两次测试的结果
 
 
  printf(" 正在努力读取ID号.....");
  User_LedSpark(Led1,2);
  ID=User_SPI_W25X16_ReadID();
  printf("flashID:%x ",ID);

  printf(" 正在努力读取DeviceID号......");
  User_LedSpark(Led1,2);
  DeviceID=User_SPI_W25X16_ReadDeviceID();
  printf("flashDeviceID:%x ",DeviceID);
 
 
 
  if((ID==FLASH_ID1)||(ID==FLASH_ID2))
  {
 
   printf(" ARM在芯片擦除......");
 User_LedSpark(Led1,2);
 User_SPI_W25X16_SectorErase(FLASH_SectorErase);
 printf("完成 ");

 
 printf(" 你要写入的数据:%s ",TxDataTable);
 printf(" 努力为你芯片写入中......");
 User_LedSpark(Led1,2);
 User_SPI_W25X16_ChipWrite(TxDataTable,FLASH_WriteAddress,DataSize);
 printf("完成 ");

 
 printf(" 芯片数据读取......");
 User_LedSpark(Led1,2);
 User_SPI_W25X16_ChipRead(RxDataTable,FLASH_ReadAddress,DataSize);
 printf("完成 ");
 User_LedSpark(Led1,2);
 printf(" 为您读取的数据:%s ",RxDataTable);

 
 printf(" 为您做数据比较中......");
 User_LedSpark(Led1,2);
 Test1=User_SPI_DataCompare(RxDataTable,TxDataTable,DataSize);
 if(Test1==Successed)
 {
   printf("数据相同 ");
 }
 else
 {
   printf("数据不相同 ");
   User_LedSpark(Led2,2);
   printf("为您分析可能原因:数据未写入、读取错误、或者两者同时存在 ");
 }

 
 printf(" 再一次芯片擦除......");
 User_LedSpark(Led1,2);
 User_SPI_W25X16_SectorErase(FLASH_SectorErase);
 printf("完成 ");

 
 printf(" 又一次芯片读取......");
 User_LedSpark(Led1,2);
 User_SPI_W25X16_ChipRead(RxDataTable,FLASH_ReadAddress,DataSize);
 printf("完成 ");

 
 printf(" 判断是否擦除掉......");
 User_LedSpark(Led1,1);
 for(Buffer=0;Buffer
 {
   if(RxDataTable[Buffer]!=0xff)
   {
    Test2=Failed;
   }
 }
 if(Test2==Failed)
 {
   printf("失败 ");
   printf("为您分析的可能原因:读取错误、擦除失败、或者两者同时存在 ");
 }
 else
 {
   printf("擦除OK ");
 }

 
 printf(" ------------为您展示此次测试结果------------ ");
 if((Test1==Successed)&&((Test2==Successed)))
 {
   User_LedSpark(Led1,2);
   printf(" 恭喜你,SPI W25X16驱动测试通过啦 ");
 }
 else
 {
   User_LedSpark(Led2,2);
   printf(" 糟糕,SPI功能演示失败了......原因可能是读写数据不一致、软件擦除失败 ");
 }
  }
 
 
  else
  {
   User_LedSpark(Led2,2);
 printf(" 悲剧了,SPI功能演示失败啦.....原因是芯片ID号码读取出错哦 ");
  }
}


int main(void)
{
  User_USART1Config();
  printf(" 串口1配置......");
  printf("完成 ");

  printf(" 蜂鸣器初始化...");
  User_BeepConfig();
  printf(" 蜂鸣器测试......");
  User_BeepStatus(BeepStatus_TurnOn);
  printf("完成 ");

  printf(" LED初始化...");
  User_LedConfig();
  printf(" LED测试......");
  User_LedSpark(Led0,2);
  printf("完成 ");

  printf(" SPI初始化...");
  User_SPI_Config();
  User_LedSpark(Led0,2);
  printf("完成 ");

  User_SPI_Test();

  while(1);
}

//==================================================
PUTCHAR_PROTOTYPE
{
 
 
  USART_SendData(USART1, (uint8_t) ch);

 
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
  {}

  return ch;
}
//==================================================

  3、user_spi_w25x16.c

//program function:SPI1 Init &&  FLASF Chip W25X16 driver


#include"stm32f10x.h"
#include"user_spi_w25x16.h"
#include



#define WriteEnable    0x06
#define WriteDisable   0x04
#define ReadStatusRegister  0x05
#define WriteStatusRegister  0x01
#define ReadData    0x03
#define FastRead    0x0b
#define FsatReadDualOutput  0x3b
#define PageProgram    0x02
#define BlukErase    0xd8
#define SectorErase    0x20
#define ChipErase    0xc7
#define PowerDown    0xb9
#define WakeUp     0xab
#define DeviceID    0xab
#define ManufatureID   0x90
#define JedecID     0x9f

#define JudgeCode    0x01           //用于判断通讯是否结束用
#define NoneCode    0xa5           //无意义的指令,用于:接收数据时,发送这个质量来产生接收时候的时钟



void User_SPI_Config(void)
{
 
 
  SPI_InitTypeDef           SPI_InitStructure;
 
  GPIO_InitTypeDef           GPIO_InitStructure;

 
 
  RCC_APB2PeriphClockCmd(SPI_24G_CS_Clock,ENABLE);
  GPIO_InitStructure.GPIO_Pin        =SPI_24G_CS_Pin;
  GPIO_InitStructure.GPIO_Mode        =GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed        =GPIO_Speed_50MHz;
  GPIO_Init(SPI_24G_CS_Port,&GPIO_InitStructure);
  GPIO_SetBits(SPI_24G_CS_Port,SPI_24G_CS_Pin);

 
  RCC_APB2PeriphClockCmd(SPI_VS1003B_CS_Clock,ENABLE);
  GPIO_InitStructure.GPIO_Pin        =SPI_VS1003B_CS_Pin;
  GPIO_InitStructure.GPIO_Mode        =GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed        =GPIO_Speed_50MHz;
  GPIO_Init(SPI_VS1003B_CS_Port,&GPIO_InitStructure);
  GPIO_SetBits(SPI_VS1003B_CS_Port,SPI_VS1003B_CS_Pin);

 
 
  RCC_APB2PeriphClockCmd(SPI_W25X16_Clock,ENABLE);
 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

 
 
  RCC_APB2PeriphClockCmd(SPI_W25X16_CS_Clock,ENABLE);
  GPIO_InitStructure.GPIO_Pin        =SPI_W25X16_CS_Pin;
  GPIO_InitStructure.GPIO_Mode        =GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed        =GPIO_Speed_50MHz;
  GPIO_Init(SPI_W25X16_CS_Port,&GPIO_InitStructure);
  SPI_W25X16_CS_DisSelect;

 
  RCC_APB2PeriphClockCmd(SPI_W25X16_SCK_Clock,ENABLE);
  GPIO_InitStructure.GPIO_Pin        =SPI_W25X16_SCK_Pin;
  GPIO_InitStructure.GPIO_Mode        =GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed        =GPIO_Speed_50MHz;
  GPIO_Init(SPI_W25X16_SCK_Port,&GPIO_InitStructure);

 
  RCC_APB2PeriphClockCmd(SPI_W25X16_MISO_Clock,ENABLE);
  GPIO_InitStructure.GPIO_Pin        =SPI_W25X16_MISO_Pin;
  GPIO_Init(SPI_W25X16_MISO_Port,&GPIO_InitStructure);

 
  RCC_APB2PeriphClockCmd(SPI_W25X16_MOSI_Clock,ENABLE);
  GPIO_InitStructure.GPIO_Pin        =SPI_W25X16_MOSI_Pin;
  GPIO_Init(SPI_W25X16_MOSI_Port,&GPIO_InitStructure);

 
 
  SPI_InitStructure.SPI_Direction       =SPI_Direction_2Lines_FullDuplex;      //通讯模式:双向全双工模式
  SPI_InitStructure.SPI_Mode        =SPI_Mode_Master;       //主从:主模式
  SPI_InitStructure.SPI_DataSize       =SPI_DataSize_8b;       //数据帧长度:8bits
  SPI_InitStructure.SPI_CPOL        =SPI_CPOL_High;        //空闲时置高
  SPI_InitStructure.SPI_CPHA        =SPI_CPHA_2Edge;        //第二个时钟采样
  SPI_InitStructure.SPI_NSS         =SPI_NSS_Soft;        //NSS控制选择:软件控制
  SPI_InitStructure.SPI_BaudRatePrescaler     =SPI_BaudRatePrescaler_2;     //波特率分配系数:2分频
  SPI_InitStructure.SPI_FirstBit       =SPI_FirstBit_MSB;       //数据帧格式:MSB在前
  SPI_InitStructure.SPI_CRCPolynomial      =7;           //CRC效验多项式
 
  SPI_Init(SPI1,&SPI_InitStructure);
 
  SPI_Cmd(SPI1,ENABLE);
}


u8 User_SPI_W25X16_SendByte(u8 SendByteData)
{
  u8 ReceiveData;
 
 
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);
 
  SPI_I2S_SendData(SPI1,SendByteData);

 
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);
 
  ReceiveData=SPI_I2S_ReceiveData(SPI1);

  return ReceiveData;
}

         
u8 User_SPI_W25X16_ReadByte(void)
{
  u8 ReceiveData;
 
  ReceiveData=User_SPI_W25X16_SendByte(NoneCode);

  return ReceiveData;
}

                       
vu16 User_SPI_W25X16_SendHalfWord(u16 HalfWord)
{
  vu16 ReceiveData;

 
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);
 
  SPI_I2S_SendData(SPI1,HalfWord);

 
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);
 
  ReceiveData=SPI_I2S_ReceiveData(SPI1);
 
  return ReceiveData;
}

        
void User_SPI_W25X16_WriteEnable(void)
{
 
  SPI_W25X16_CS_Select;

 
  User_SPI_W25X16_SendByte(WriteEnable);

 
  SPI_W25X16_CS_DisSelect;
}

[page]            
void User_SPI_W25X16_WaitForWriteEnd(void)
{
  u8 ReceiveStatus;                     //用于存放W25X16返回的状态非零就是操作结束
 
  SPI_W25X16_CS_Select;                    
 
  User_SPI_W25X16_SendByte(ReadStatusRegister);
 
  do
  {
   ReceiveStatus=User_SPI_W25X16_SendByte(NoneCode);
  }
  while(ReceiveStatus & JudgeCode==SET);
 
  SPI_W25X16_CS_DisSelect;
        

                       
void User_SPI_W25X16_SectorErase(vu32 SectorAddress)
{
 
  User_SPI_W25X16_WriteEnable();
 
  SPI_W25X16_CS_Select;

 
  User_SPI_W25X16_SendByte(SectorErase);
 
  User_SPI_W25X16_SendByte((SectorAddress & 0xff0000)>>16);       //发送最高8位
  User_SPI_W25X16_SendByte((SectorAddress & 0xff00)>>8);       // 中间8位
  User_SPI_W25X16_SendByte(SectorAddress & 0xff);         //发送最低8位
 

 
  SPI_W25X16_CS_DisSelect;

 
  User_SPI_W25X16_WaitForWriteEnd();
}


void User_SPI_W25X16_BulkErase(void)
{
 
  User_SPI_W25X16_WriteEnable();
 
  SPI_W25X16_CS_Select;

 
  User_SPI_W25X16_SendByte(ChipErase);

 
  SPI_W25X16_CS_DisSelect;

 
  User_SPI_W25X16_WaitForWriteEnd();
}


void User_SPI_W25X16_PageWrite(u8 *DataTable,vu32 WriteAddress,vu16 NumberOfWrite)
{
 
  User_SPI_W25X16_WriteEnable();
 
  SPI_W25X16_CS_Select;

 
  User_SPI_W25X16_SendByte(PageProgram);

 
  User_SPI_W25X16_SendByte((WriteAddress & 0xff0000)>>16);     //最高8位地址
  User_SPI_W25X16_SendByte((WriteAddress & 0xff00)>>8);      //中间8位地址
  User_SPI_W25X16_SendByte(WriteAddress & 0xff);       //最低8位地址

 
  if(NumberOfWrite > SPI_W25X16_PerPageWriteSize)       //W25X16采用的是页写入方式,最多一次性写入256个数据,然后内部地址指针归零
  {
   NumberOfWrite=SPI_W25X16_PerPageWriteSize;
 printf(" 哦偶,一次性写入的数据太多,不能超过256的啦,ARM将为你写入前256个数据 ");
  }

 
  while(NumberOfWrite--)
  {
   User_SPI_W25X16_SendByte(*DataTable);
 DataTable++;               //数组指针 +1
  }

  SPI_W25X16_CS_DisSelect;

 
  User_SPI_W25X16_WaitForWriteEnd();
}


void User_SPI_W25X16_ChipWrite(u8 *DataTable,vu32 WriteAddress,vu16 NumberOfWrite)
{
  u8 AddressRemainder    =0;
  u8 NumberOfPage     =0;
  u8 Count       =0;                        //存放地址所在页需要写入的最多数据
  u8 NumberOfSingle     =0;                        //写入数据的最后一些需要写入的数据个数
  u8 Buffer       =0;            //保留

  AddressRemainder     =WriteAddress % SPI_W25X16_PageSize;
  Count        =SPI_W25X16_PageSize - AddressRemainder;
  NumberOfPage      =NumberOfWrite / SPI_W25X16_PageSize;
  NumberOfSingle     =NumberOfWrite % SPI_W25X16_PageSize;

 
  if(AddressRemainder==0)
  {
   
 if(NumberOfPage==0)                //NumberOfWrite < SPI_W25X16_PageSize
 {
   User_SPI_W25X16_PageWrite(DataTable,WriteAddress,NumberOfWrite);
 }
 
 else
 {
  
   while(NumberOfPage--)
   {
     User_SPI_W25X16_PageWrite(DataTable,WriteAddress,SPI_W25X16_PageSize);  //一次性写入256个
  DataTable+=SPI_W25X16_PageSize;          //接着写下一个256数据
  WriteAddress+=SPI_W25X16_PageSize;          //地址就移到下一页(256为单位)
   }
  
   User_SPI_W25X16_PageWrite(DataTable,WriteAddress,NumberOfSingle);
 }
  }
 
  else
  {
   
 if(NumberOfPage==0)
 {
  
   if(NumberOfWrite < Count)
   {
     User_SPI_W25X16_PageWrite(DataTable,WriteAddress,NumberOfWrite);
   }
  
   else
   {
  
  User_SPI_W25X16_PageWrite(DataTable,WriteAddress,Count);     //起始地址所在页只需要写入Count个
  Buffer=NumberOfWrite-Count;          //计算出下一页要写入的数据数量
  DataTable+=Count;
  WriteAddress+=Count;

  
  User_SPI_W25X16_PageWrite(DataTable,WriteAddress,Buffer);
   }
 }
 
 else
 {
  
   User_SPI_W25X16_PageWrite(DataTable,WriteAddress,Count);

   //之后需要重新计算以下参数  原因:数据量超过一页分两种情况:1、数据量不会覆盖完起始地址下一页;2、数据量会完全覆盖起始地址下一页
   //重新计算就是看是否会覆盖掉下一页,如果会就进入while()循环,否则就不进入
   DataTable+=Count;
   WriteAddress+=Count;
   NumberOfWrite-=Count;
   NumberOfPage=NumberOfWrite / SPI_W25X16_PageSize;
   NumberOfSingle=NumberOfWrite % SPI_W25X16_PageSize;

  
   while(NumberOfPage--)
   {
    User_SPI_W25X16_PageWrite(DataTable,WriteAddress,SPI_W25X16_PageSize);
  DataTable+=SPI_W25X16_PageSize;
  WriteAddress+=SPI_W25X16_PageSize;
   }

  
   if(NumberOfSingle != 0)
   {
    User_SPI_W25X16_PageWrite(DataTable,WriteAddress,NumberOfSingle);
   }
 }
  }
}


void User_SPI_W25X16_ChipRead(u8 *DataTable,vu32 ReadAddress,vu16 NumberOfRead)
{
                   //虽然要发送地址,但是不需要说明有个写操作(I2C才是这样的时序)
  SPI_W25X16_CS_Select;

 
  User_SPI_W25X16_SendByte(ReadData);

 
  User_SPI_W25X16_SendByte((ReadAddress & 0xff0000) >> 16);       //最高8位地址
  User_SPI_W25X16_SendByte((ReadAddress & 0xff00) >> 8);       //中间8位
  User_SPI_W25X16_SendByte(ReadAddress & 0xff);                   //最低8位

 
  while(NumberOfRead--)
  {
   *DataTable = User_SPI_W25X16_SendByte(NoneCode);
 DataTable++;
  }

 
  SPI_W25X16_CS_DisSelect;
}


vu32 User_SPI_W25X16_ReadID(void)
{
  vu32 ID      =0;
  vu32 IDBuffer1 =0;
  vu32 IDBuffer2 =0;
  vu32 IDBuffer3 =0;
                  
  SPI_W25X16_CS_Select;
 
  User_SPI_W25X16_SendByte(JedecID);

 
  IDBuffer1   =User_SPI_W25X16_SendByte(NoneCode);     //读取高位
  IDBuffer2   =User_SPI_W25X16_SendByte(NoneCode);     //读取中位
  IDBuffer3   =User_SPI_W25X16_SendByte(NoneCode);     //读取低位

  SPI_W25X16_CS_DisSelect;

  ID=(IDBuffer1<<16)|(IDBuffer2<<8)|IDBuffer3;
 
  return ID;
}


vu32 User_SPI_W25X16_ReadDeviceID(void)
{
  vu32 ID      =0;
  vu32 IDBuffer1 =0;
  vu32 IDBuffer2 =0;
  vu32 IDBuffer3 =0;
                  
  SPI_W25X16_CS_Select;
 
  User_SPI_W25X16_SendByte(ManufatureID);

 
  IDBuffer1   =User_SPI_W25X16_SendByte(NoneCode);     //读取高位
  IDBuffer2   =User_SPI_W25X16_SendByte(NoneCode);     //读取中位
  IDBuffer3   =User_SPI_W25X16_SendByte(NoneCode);     //读取低位

  SPI_W25X16_CS_DisSelect;

  ID=(IDBuffer1<<16)|(IDBuffer2<<8)|IDBuffer3;
 
  return ID;
}


void User_SPI_W25X16_StartReadSequence(vu32 ReadAddress)
{
  SPI_W25X16_CS_Select;

  User_SPI_W25X16_SendByte(ReadData);

  User_SPI_W25X16_SendByte((ReadAddress & 0xff0000) >> 16);       //最高8位地址
  User_SPI_W25X16_SendByte((ReadAddress & 0xff00) >> 8);       //中间8位
  User_SPI_W25X16_SendByte(ReadAddress & 0xff);                   //最低8位

  //SPI_W25X16_DisSelect;
}


void User_SPI_W25X16_PowerDown(void)
{
  SPI_W25X16_CS_Select;

  User_SPI_W25X16_SendByte(PowerDown);

  SPI_W25X16_CS_DisSelect;
}


void User_SPI_W25X16_WakeUp(void)
{
  SPI_W25X16_CS_Select;

  User_SPI_W25X16_SendByte(WakeUp);

  SPI_W25X16_CS_DisSelect;
}

user_spi_w25x16.h

//SPI FLASH chip W25X16 头文件

#ifndef _USER_SPI_W25X16_H
#define _USER_SPI_W25X16_H

#include"stm32f10x.h"

typedef enum{Failed=0,Successed=!Failed}TestStatus;                         //声明定义枚举型变量 用于表示测试失败与成功

#define SPI_W25X16_SectorSize      4096
#define SPI_W25X16_PageSize       256      //W25X16每页数据长度
#define SPI_W25X16_PerPageWriteSize     256      //每页最多写入的数据个数


#define SPI_W25X16         SPI1
#define SPI_W25X16_Clock       RCC_APB2Periph_SPI1


#define SPI_W25X16_CS_Clock       RCC_APB2Periph_GPIOC
#define SPI_W25X16_CS_Port       GPIOC
#define SPI_W25X16_CS_Pin       GPIO_Pin_4


#define SPI_W25X16_SCK_Clock      RCC_APB2Periph_GPIOA
#define SPI_W25X16_SCK_Port       GPIOA
#define SPI_W25X16_SCK_Pin       GPIO_Pin_5


#define SPI_W25X16_MISO_Clock         RCC_APB2Periph_GPIOA
#define SPI_W25X16_MISO_Port      GPIOA
#define SPI_W25X16_MISO_Pin       GPIO_Pin_6


#define SPI_W25X16_MOSI_Clock      RCC_APB2Periph_GPIOA
#define SPI_W25X16_MOSI_Port      GPIOA
#define SPI_W25X16_MOSI_Pin       GPIO_Pin_7


#define SPI_24G_CS_Clock       RCC_APB2Periph_GPIOB
#define SPI_24G_CS_Port        GPIOB
#define SPI_24G_CS_Pin        GPIO_Pin_2


#define SPI_VS1003B_CS_Clock      RCC_APB2Periph_GPIOB
#define SPI_VS1003B_CS_Port       GPIOB
#define SPI_VS1003B_CS_Pin       GPIO_Pin_0


#define SPI_W25X16_CS_Select      GPIO_ResetBits(SPI_W25X16_CS_Port,SPI_W25X16_CS_Pin)

#define SPI_W25X16_CS_DisSelect      GPIO_SetBits(SPI_W25X16_CS_Port,SPI_W25X16_CS_Pin)



u8   User_SPI_W25X16_SendByte(u8 SendByteData)         //send data that is byte
u8   User_SPI_W25X16_ReadByte(void);                        //Read ByteData from chip W25X16
vu16  User_SPI_W25X16_SendHalfWord(u16 HalfWord) ;         //send data ,is halfword
void User_SPI_W25X16_WriteEnable(void);                     //write enable for W25X16
void User_SPI_W25X16_WaitForWriteEnd(void);                 //wait the end about write for chip W25X16


void User_SPI_Config(void);                         //SPI1 init configuration
void User_SPI_W25X16_SectorErase(vu32 SectorAddress);       
void User_SPI_W25X16_BulkErase(void);            //erase the W25X16
void User_SPI_W25X16_PageWrite(u8 *DataTable,vu32 WriteAddress,vu16 NumberOfWrite);
void User_SPI_W25X16_ChipWrite(u8 *DataTable,vu32 WriteAddress,vu16 NumberOfWrite);
void User_SPI_W25X16_ChipRead(u8 *DataTable,vu32 ReadAddress,vu16 NumberOfRead);
vu32 User_SPI_W25X16_ReadID(void);             //read chip ID
vu32 User_SPI_W25X16_ReadDeviceID(void);           //read manufacture device ID
void User_SPI_W25X16_StartReadSequence(vu32 ReadAddress);
void User_SPI_W25X16_PowerDown(void);
void User_SPI_W25X16_WakeUp(void);

 


#endif

 

以上,结束。

关键字:STM32  SPI  W25X16驱动 引用地址:STM32 SPI W25X16驱动

上一篇:STM32 通用定时器的几种配置方式
下一篇:STM32 I2C AT24C02驱动

推荐阅读最新更新时间:2024-03-16 14:38

通过STM32外部中断触发DMA传输
目前STM32家族中的很多系列,比如STM32G0/STM32G4/STM32L4+/STM32H7等都内置了DMAMUX模块。有了它一方面使得DMA请求与DMA控制器之间的映射关系更为灵活方便,另一方面也大大拓展了DMA请求事件,不再局限于外设事件,比方基于GPIO的外部中断事件、或者DMA事件本身来触发DMA传输。 关于DMAMUX的基本结构及功能原理,这里就不说了,这里重点介绍基于STM32G4芯片,使用GPIO的外部中断事件触发DMA传输,通过DMA将内存数据传输到GPIO端口的实现过程,包括基于CubeMx的配置、关键代码及注意点。 本演示例程基于STM32G4系列的Nucleo板进行,按键【PC.13】用来触发
[单片机]
ADIS16203角度传感器的stm32驱动实现要点
一、前言 ADIS16203是一款完整的倾斜角测量系统,采用ADI公司的 iSensor™集成技术制造,全部功能均集成于一个紧凑的封装中。该器件采用嵌入式信号处理解决方案来增强ADI公司的 iMEMS®传感器技术,可提供适当格式的工厂校准、传感器数字倾斜角数据,从而利用串行外设接口(SPI)即可方便地访问数据。通过SPI接口可以访问多个测量结果:360°线性倾斜角、±180°线性倾斜角、温度、电源和一个辅助模拟输入。由于可以轻松访问校准的数字传感器数据,因此开发者能够获得可立即供系统使用的器件,使开发时间、成本和编程风险得以减少。 通过数个内置特性,如单命令失调校准等,以及方便的采样速率控制和带宽控制,该器件很容易适应终端系统
[单片机]
ADIS16203角度传感器的<font color='red'>stm32</font><font color='red'>驱动</font>实现要点
基于STM32和CPLD可编程逻辑器件的等精度测频技术
在电子工程、资源勘探、仪器仪表等相关应用中,频率测量是电子测量技术中最基本最常见的测量之一,频率计也是工程技术人员必不可少的测量工具。但是,传统的频率测量方法在实际应用中有较大的局限性,基于传统测频原理的频率计的测量精度将随被测信号频率的变化而变化,传统的直接测频法其测量精度将随被测信号频率的降低而降低,测周法的测量精度将随被测信号频率的升高而降低。本文中提出一种基于ARM与CPLD宽频带的数字频率计的设计,以微控器STM32作为核心控制芯片,利用CPLD可编程逻辑器件,实现闸门测量技术的等精度测频。 本设计的技术指标: 测频范围:1Hz~200MHz,分辨率为0.1Hz,测频相对误差百万分之一。 周期测量:信号测量范围与精度要求
[单片机]
基于<font color='red'>STM32</font>和CPLD可编程逻辑器件的等精度测频技术
stm32通过电调带动电机
这几天在做32通过电调带动电机的实验,上网一查,发现这方面的资料很少,经过自己的亲自实践,总结出以下经验,供大家参考。 论坛上也有很多人说自己在做,但是都遇到了同样的瓶颈。我想他们大多是pwm的频率和占空比没有调到合适的值吧。 首先,我在网上只找到一片很好的文章,是瑞生大神写的:http://www.rationmcu.com/lpc1114/1126.html 我的电机是银燕2212/1400kv经典电机 ,电调也是银燕40A无刷电调。 通过它知道,当pwm设置为500hz的 时候电调才能正常的工作,刚开始时高电平时间要控制在0.7-1.9左右,让电机带电自检。 通过按键控制占空比可以很好地 实现这一点。 好了,下面上我的代码。
[单片机]
lpc1788移植u-boot-2010.03之spi flash移植
开发环境: MCU: NXP LPC1788 u-boot: u-boot-2010.03 SPI Flash: AT45DB321D 由于ATMEL的spi flash在u-boot中已经实现,我们就不要去写AT45DB321D的驱动了,现在考虑SPI总线的问题(u-boot中的spi驱动在driver/spi目录中),在driver/spi目录中可以看到各种芯片的spi总线实现,不过lpc1788是没有的,别动别动看到了一个soft_spi.c,好了现在spi总线的驱动也不用写了,直接用soft spi。 在lpc1788的配置文件中加入以下内容: #define CONFIG_CMD_SF //加入cmd_sf.
[单片机]
stm32 移植uip
1 stm32 定义常量不要code 关键字 // 定义全1 地址常量 static const uip_ipaddr_t code all_ones_addr = #if UIP_CONF_IPV6 {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; #else /* UIP_CONF_IPV6 */ {0xffff,0xffff}; #endif /* UIP_CONF_IPV6 */ //定义全0地址常量 static const uip_ipaddr_t code all_zeroes_addr = #if UIP_CONF_IP
[单片机]
STM32启动过程相关代码分析
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO路径下的文件进行分析。对了,我用的库是3.5的。 system_stm32f10x.c SystemInit(): 在 startup_stm32f10x_xx.s 文件中被调用,功能是设置系统时钟(包括时钟源,PLL系数,AHB/APBx的预分频系数还有 flash的设定),这个函数 会在系统复位之后首先被执行。文件中默认的一些设置:允许HSE(外部时钟),FLASH(允许预取缓冲区,设置2个等待周 期),PLL系数为9,开启PLL并选择
[单片机]
STM32系统架构
在小容量、中容量和 大容量产品中,主系统由以下部分构成: ● 四个驱动单元: ─ Cortex-M3内核DCode总线(D-bus),和系统总线(S-bus) ─ 通用DMA1和通用DMA2 ● 四个被动单元 ─ 内部SRAM ─ 内部闪存存储器 ─ FSMC ─ AHB到APB的桥(AHB2APBx),它连接所有的APB设备 这些都是通过一个多级的AHB总线构架相互连接的,如下图所示: 在互联型产品中,主系统由以下部分构成: ● 五个驱动单元: ─ Cortex-M3内核DCode总线(D-bus),和系统总线(S-bus) ─ 通用DMA1和通用DMA2 ─ 以太网DMA ● 三个被动单元 ─ 内部SRAM ─ 内部闪存
[单片机]
<font color='red'>STM32</font>系统架构
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved