第一次接触SPI Flash,参考别人的程序理解,主要参考的是Swallow的“HOT大叔NUC120助学板第十贴----SPI(查询方式)”
英文驱动手册版本:V1.05.001
中文驱动手册版本:V1.00.001
Keil版本:V4.00
Source Insight版本:V3.50.0064
学习总结:
1、有关W25Q16BV
助学板上与M0相连的是以下四个管脚:
CS:低电平有效
DO:在Clk下降沿“read device”
DI:在Clk上升沿“write device”
Clk:Modes0模式下,空闲时为0
Modes1模式下,空闲时为1
在初始化SPI时需要用到
2、SPI初始化流程
(1)DrvSPI_Open()
打开SPI,要参考Flash芯片手册
(2)DrvSPI_SetEndian()
设置传输位顺序,MSB or LSB,要参考Flash芯片手册
(3)DrvSPI_DisableAutoSS()
关闭自动片选功能
(4)DrvSPI_SetSlaveSelectActiveLevel()
从机激活方式
(5)DrvSPI_Set2BitTransforMode()
2位传输模式
(6)DrvSPI_SetClockFreq()
SPI时钟
(7)DrvGPIO_InitFunction()
设置对应GPIO的SPI功能
(8)DrvGPIO_SetBit(E_PGA,14)
不选中Flash,防止误操作
3、看到很多程序(包括官方例程)都使用宏定义UNLOCKREG()和LOCKREG()对寄存器解锁加锁,后来翻驱动手册,找到了对应的函数DrvSYS_UnlockProtectedReg()和DrvSYS_LockProtectedReg()。疑惑,为什么大家不使用手册里的函数?
4、关于片选引脚
看到别人程序里片选都通过自定义宏来实现(#define Enable_SPI_CS DrvGPIO_ClrBit(SPI_CS_PORT,SPI_CS_PORT_NUM) 和#define DISABLE_SPI_CS DrvGPIO_SetBit(SPI_CS_PORT,SPI_CS_PORT_NUM) ),但驱动手册里有片选函数DrvSPI_ClrSS()和DrvSPI_SetSS(),改用手册里的函数后发现收到的数据都是0xffffffff,疑惑。测量电压,函数对SS10(PC8)引脚是起作用的,查看助学板原理图发现SPI Flash的片选并没有使用SS10(PC8)引脚而是用的PA14,明白了。后看到这两个引脚在外引的插针上挨着,就将插针焊上,拿跳针帽将其连上。问题解决。
疑问:
1、为什么不使用手册里的寄存器解锁加锁函数?
2、关于读取W25Q16BV的ID。看芯片手册,先发送命令0x90,然后发送地址0x000000,就可以接收到16位的设备ID。但程序里为什么要在发送地址后再发送16位的数据0x0000,否则收到错误ID?不知道在手册什么地方有要求,找不到……
3、对2比特串行数据IO模式不太明白,没找到相关资料,求教
<
#include <stdio.h>
#include "NUC1xx.h"
#include "DrvGPIO.h"
#include "DrvUART.h"
#include "DrvSYS.h"
#include "DrvSPI.h"
#define SPI_CS_PORT E_GPA
#define SPI_CS_PORT_NUM 14
#define Enable_SPI_CS DrvGPIO_ClrBit(SPI_CS_PORT,SPI_CS_PORT_NUM)
#define DISABLE_SPI_CS DrvGPIO_SetBit(SPI_CS_PORT,SPI_CS_PORT_NUM)
/*W25Q16BV命令宏定义*/
#define ReadID 0x90
/*函数声明*/
void InitSystem(void);
void InitSPI(void);
void InitUART(void);
void InitGPIO(void);
uint32_t SPIReadID(void);
/*---------------------------------------------------------------------------------------------------------*/
/* MAIN function */
/*---------------------------------------------------------------------------------------------------------*/
int main (void)
{
uint32_t SPIID;
InitSystem();
InitSPI();
InitUART();
InitGPIO();
while(1)
{
//如果Key2按下
if(DrvGPIO_GetBit(E_GPB,14)==0)
{
SPIID=SPIReadID();
printf("W25Q16BV制造商ID及设备ID为:0x%X\n",SPIID);
}
}
}
void InitSystem(void)
{
//相当于UNLOCKREG();
DrvSYS_UnlockProtectedReg();
SYSCLK->PWRCON.XTL12M_EN=1;
//相当于LOCKREG();
DrvSYS_LockProtectedReg();
}
void InitSPI(void)
{
//初始化SPI,注意传输模式(eDRVSPI_TYPE)的选择
//函数参数与手册有出入
DrvSPI_Open(eDRVSPI_PORT1,eDRVSPI_MASTER,eDRVSPI_TYPE1,32,FALSE);
//设置传输位顺序为MSB
DrvSPI_SetEndian(eDRVSPI_PORT1,eDRVSPI_MSB_FIRST);
//关闭自动片选功能
DrvSPI_DisableAutoSS(eDRVSPI_PORT1);
//设置从机激活方式
DrvSPI_SetSlaveSelectActiveLevel(eDRVSPI_PORT1,eDRVSPI_ACTIVE_LOW_FALLING);
//设置两比特传输模式
DrvSPI_Set2BitTransferMode(eDRVSPI_PORT1,TRUE);
//设置SPI时钟频率
DrvSPI_SetClockFreq(eDRVSPI_PORT1,1000000,0);
//设置GPIO引脚的SPI功能
DrvGPIO_InitFunction(E_FUNC_SPI1);
//关闭SPI的片选
//一般使用为DISABLE_SPI_CS;
DrvSPI_ClrSS(eDRVSPI_PORT1,eDRVSPI_SS0);
}
void InitUART(void)
{
STR_UART_T Param;
Param.u32BaudRate=115200;
Param.u8cDataBits=DRVUART_DATABITS_8;
Param.u8cStopBits=DRVUART_STOPBITS_1;
Param.u8cParity=DRVUART_PARITY_NONE;
Param.u8cRxTriggerLevel=DRVUART_FIFO_1BYTES;
Param.u8TimeOut=0;
DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC,0);
DrvGPIO_InitFunction(E_FUNC_UART0);
DrvUART_Open(UART_PORT0,&Param);
}
void InitGPIO(void)
{
DrvGPIO_Open(E_GPB,14,E_IO_INPUT);
DrvGPIO_Open(E_GPB,15,E_IO_INPUT);
}
uint32_t SPIReadID(void)
{
uint32_t DataTemp;
//使能CS
//一般使用Enable_SPI_CS;
DrvSPI_SetSS(eDRVSPI_PORT1,eDRVSPI_SS0);
//根据Flash芯片手册,先发送八位读取ID命令(0x90)
//然后发送二十四位地址(0x000000)
//定义SPI传输的比特长度
//设置传输长度为八位
DrvSPI_SetBitLength(eDRVSPI_PORT1,8);
//装载读ID命令
DataTemp=ReadID;
//向设备写命令
DrvSPI_SingleWrite(eDRVSPI_PORT1,&DataTemp);
//等待设备接收完毕
while(DrvSPI_IsBusy(eDRVSPI_PORT1));
//设置传输长度为二十四位
DrvSPI_SetBitLength(eDRVSPI_PORT1,24);
//装载24位地址
DataTemp=0x000000;
//向设备写地址
DrvSPI_SingleWrite(eDRVSPI_PORT1,&DataTemp);
//等待设备接收完毕
while(DrvSPI_IsBusy(eDRVSPI_PORT1));
//命令和地址发送完毕
//准备接受设备返回的ID
//不明白为什么要传输一次0x0000
//设置传输长度为十六位
DrvSPI_SetBitLength(eDRVSPI_PORT1,16);
DataTemp=0x0000;
DrvSPI_SingleWrite(eDRVSPI_PORT1,&DataTemp);
while(DrvSPI_IsBusy(eDRVSPI_PORT1));
//取消片选
//一般使用DISABLE_SPI_CS;
DrvSPI_ClrSS(eDRVSPI_PORT1,eDRVSPI_SS0);
//接受数据
//注意,因为SPI不继续传输,所以不使用DrvSPI_SingleRead函数
DrvSPI_DumpRxRegister(eDRVSPI_PORT1,&DataTemp,1);
//返回ID
return(DataTemp);
}
>
按键返回FlashID.rar
(325.91 KB)
|