6.工程&资料
https://mbb.eet-china.com/forum/topic/76292_1_1.html
4.移植FatFs
将FatFs源文件ff14文件夹复制到工程的Utilities文件夹下,并刷新工程,即可显示出目录结构及对应的源文件了。在SPIFlash上实现FatFs文件系统主要是对diskio.c接口文件和ffconf.h配置文件的修改。
diskio.c接口文件源码如下所示:
<div><div><div>/*-----------------------------------------------------------------------*/
/*LowleveldiskI/OmoduleskeletonforFatFs(C)ChaN,2019*/
/*-----------------------------------------------------------------------*/
/*Ifaworkingstoragecontrolmoduleisavailable,itshouldbe*/
/*attachedtotheFatFsviaagluefunctionratherthanmodifyingit.*/
/*Thisisanexampleofgluefunctionstoattachvariousexsisting*/
/*storagecontrolmodulestotheFatFsmodulewithadefinedAPI.*/
/*-----------------------------------------------------------------------*/
#include"ff.h"/*Obtainsintegertypes*/
#include"diskio.h"/*Declarationsofdiskfunctions*/
#include"gd32vf103v_spi_flash_eval.h"
/*Definitionsofphysicaldrivenumberforeachdrive*/
#defineDEV_SPI_FLASH0
/*-----------------------------------------------------------------------*/
/*GetDriveStatus*/
/*-----------------------------------------------------------------------*/
DSTATUSdisk_status(
BYTEpdrv/*Physicaldrivenmubertoidentifythedrive*/
)
{
DSTATUSstat;
intresult;
switch(pdrv)
{
caseDEV_SPI_FLASH:returnRES_OK;
}
returnSTA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/*InidializeaDrive*/
/*-----------------------------------------------------------------------*/
DSTATUSdisk_initialize(
BYTEpdrv/*Physicaldrivenmubertoidentifythedrive*/
)
{
DSTATUSstat;
intresult;
switch(pdrv)
{
caseDEV_SPI_FLASH:returnRES_OK;
}
returnSTA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/*ReadSector(s)*/
/*-----------------------------------------------------------------------*/
DRESULTdisk_read(
BYTEpdrv,/*Physicaldrivenmubertoidentifythedrive*/
BYTE*buff,/*Databuffertostorereaddata*/
LBA_tsector,/*StartsectorinLBA*/
UINTcount/*Numberofsectorstoread*/
)
{
DRESULTres;
intresult;
//xUserPrintf("\r\ndrpdrv=%d,sector=%d,count=%d\r\n",pdrv,sector,count);
switch(pdrv)
{
caseDEV_SPI_FLASH:
for(;count>0;count--)
{
spi_flash_read(sector*SECTOR_SIZE,buff,SECTOR_SIZE);
sector+=1;
buff+=SECTOR_SIZE;
}
returnRES_OK;
}
returnRES_PARERR;
}
/*-----------------------------------------------------------------------*/
/*WriteSector(s)*/
/*-----------------------------------------------------------------------*/
#ifFF_FS_READONLY==0
DRESULTdisk_write(
BYTEpdrv,/*Physicaldrivenmubertoidentifythedrive*/
constBYTE*buff,/*Datatobewritten*/
LBA_tsector,/*StartsectorinLBA*/
UINTcount/*Numberofsectorstowrite*/
)
{
DRESULTres;
intresult;
//xUserPrintf("\r\ndwpdrv=%d,sector=%d,count=%d\r\n",pdrv,sector,count);
switch(pdrv)
{
caseDEV_SPI_FLASH:
for(;count>0;count--)
{
spi_flash_erase_sector(sector*SECTOR_SIZE);
spi_flash_write(sector*SECTOR_SIZE,(uint8_t*)buff,SECTOR_SIZE);
sector+=1;
buff+=SECTOR_SIZE;
}
returnRES_OK;
}
returnRES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/
/*MiscellaneousFunctions*/
/*-----------------------------------------------------------------------*/
DRESULTdisk_ioctl(
BYTEpdrv,/*Physicaldrivenmuber(0..)*/
BYTEcmd,/*Controlcode*/
void*buff/*Buffertosend/receivecontroldata*/
)
{
DRESULTres;
intresult;
switch(pdrv)
{
caseDEV_SPI_FLASH:
switch(cmd)
{
caseCTRL_SYNC:
res=RES_OK;
break;
caseGET_SECTOR_SIZE:
*(WORD*)buff=SECTOR_SIZE;
res=RES_OK;
break;
caseGET_BLOCK_SIZE:
*(DWORD*)buff=1;
res=RES_OK;
break;
caseGET_SECTOR_COUNT:
*(DWORD*)buff=SECTOR_COUNT;
res=RES_OK;
break;
default:
res=RES_PARERR;
break;
}
break;
default:res=RES_PARERR;break;
}
returnres;
}
DWORDget_fattime(void)
{
return0;
}
ffconf.h配置文件源码如下所示:
<div><div><div>/*---------------------------------------------------------------------------/
/FatFsFunctionalConfigurations
/---------------------------------------------------------------------------*/
#defineFFCONF_DEF86606/*RevisionID*/
/*---------------------------------------------------------------------------/
/FunctionConfigurations
/---------------------------------------------------------------------------*/
#defineFF_FS_READONLY0
/*Thisoptionswitchesread-onlyconfiguration.(0:Read/Writeor1:Read-only)
/Read-onlyconfigurationremoveswritingAPIfunctions,f_write(),f_sync(),
/f_unlink(),f_mkdir(),f_chmod(),f_rename(),f_truncate(),f_getfree()
/andoptionalwritingfunctionsaswell.*/
#defineFF_FS_MINIMIZE0
/*ThisoptiondefinesminimizationleveltoremovesomebasicAPIfunctions.
/
/0:Basicfunctionsarefullyenabled.
/1:f_stat(),f_getfree(),f_unlink(),f_mkdir(),f_truncate()andf_rename()
/areremoved.
/2:f_opendir(),f_readdir()andf_closedir()areremovedinadditionto1.
/3:f_lseek()functionisremovedinadditionto2.*/
#defineFF_USE_STRFUNC0
/*Thisoptionswitchesstringfunctions,f_gets(),f_putc(),f_puts()andf_printf().
/
/0:Disablestringfunctions.
/1:EnablewithoutLF-CRLFconversion.
/2:EnablewithLF-CRLFconversion.*/
#defineFF_USE_FIND0
/*Thisoptionswitchesfiltereddirectoryreadfunctions,f_findfirst()and
/f_findnext().(0:Disable,1:Enable2:Enablewithmatchingaltname[]too)*/
#defineFF_USE_MKFS1
/*Thisoptionswitchesf_mkfs()function.(0:Disableor1:Enable)*/
#defineFF_USE_FASTSEEK0
/*Thisoptionswitchesfastseekfunction.(0:Disableor1:Enable)*/
#defineFF_USE_EXPAND0
/*Thisoptionswitchesf_expandfunction.(0:Disableor1:Enable)*/
#defineFF_USE_CHMOD0
/*Thisoptionswitchesattributemanipulationfunctions,f_chmod()andf_utime().
/(0:Disableor1:Enable)AlsoFF_FS_READONLYneedstobe0toenablethisoption.*/
#defineFF_USE_LABEL0
/*Thisoptionswitchesvolumelabelfunctions,f_getlabel()andf_setlabel().
/(0:Disableor1:Enable)*/
#defineFF_USE_FORWARD0
/*Thisoptionswitchesf_forward()function.(0:Disableor1:Enable)*/
/*---------------------------------------------------------------------------/
/LocaleandNamespaceConfigurations
/---------------------------------------------------------------------------*/
#defineFF_CODE_PAGE936
/*ThisoptionspecifiestheOEMcodepagetobeusedonthetargetsystem.
/Incorrectcodepagesettingcancauseafileopenfailure.
/
/437-U.S.
/720-Arabic
/737-Greek
/771-KBL
/775-Baltic
/850-Latin1
/852-Latin2
/855-Cyrillic
/857-Turkish
/860-Portuguese
/861-Icelandic
/862-Hebrew
/863-CanadianFrench
/864-Arabic
/865-Nordic
/866-Russian
/869-Greek2
/932-Japanese(DBCS)
/936-SimplifiedChinese(DBCS)
/949-Korean(DBCS)
/950-TraditionalChinese(DBCS)
/0-Includeallcodepagesaboveandconfiguredbyf_setcp()
*/
#defineFF_USE_LFN0
#defineFF_MAX_LFN255
/*TheFF_USE_LFNswitchesthesupportforLFN(longfilename).
/
/0:DisableLFN.FF_MAX_LFNhasnoeffect.
/1:EnableLFNwithstaticworkingbufferontheBSS.AlwaysNOTthread-safe.
/2:EnableLFNwithdynamicworkingbufferontheSTACK.
/3:EnableLFNwithdynamicworkingbufferontheHEAP.
/
/ToenabletheLFN,ffunicode.cneedstobeaddedtotheproject.TheLFNfunction
/requierscertaininternalworkingbufferoccupies(FF_MAX_LFN+1)*2bytesand
/additional(FF_MAX_LFN+44)/15*32byteswhenexFATisenabled.
/TheFF_MAX_LFNdefinessizeoftheworkingbufferinUTF-16codeunitanditcan
/beinrangeof12to255.Itisrecommendedtobesetit255tofullysupportLFN
/specification.
/Whenusestackfortheworkingbuffer,takecareonstackoverflow.Whenuseheap
/memoryfortheworkingbuffer,memorymanagementfunctions,ff_memalloc()and
/ff_memfree()exemplifiedinffsystem.c,needtobeaddedtotheproject.*/
#defineFF_LFN_UNICODE0
/*ThisoptionswitchesthecharacterencodingontheAPIwhenLFNisenabled.
/
/0:ANSI/OEMincurrentCP(TCHAR=char)
/1:UnicodeinUTF-16(TCHAR=WCHAR)
/2:UnicodeinUTF-8(TCHAR=char)
/3:UnicodeinUTF-32(TCHAR=DWORD)
/
/AlsobehaviorofstringI/Ofunctionswillbeaffectedbythisoption.
/WhenLFNisnotenabled,thisoptionhasnoeffect.*/
#defineFF_LFN_BUF255
#defineFF_SFN_BUF12
/*ThissetofoptionsdefinessizeoffilenamemembersintheFILINFOstructure
/whichisusedtoreadoutdirectoryitems.Thesevaluesshouldbesuffcientfor
/thefilenamestoread.Themaximumpossiblelengthofthereadfilenamedepends
/oncharacterencoding.WhenLFNisnotenabled,theseoptionshavenoeffect.*/
#defineFF_STRF_ENCODE3
/*WhenFF_LFN_UNICODE>=1withLFNenabled,stringI/Ofunctions,f_gets(),
/f_putc(),f_putsandf_printf()convertthecharacterencodinginit.
/ThisoptionselectsassumptionofcharacterencodingONTHEFILEtobe
/read/writtenviathosefunctions.
/
/0:ANSI/OEMincurrentCP
/1:UnicodeinUTF-16LE
/2:UnicodeinUTF-16BE
/3:UnicodeinUTF-8
*/
#defineFF_FS_RPATH0
/*Thisoptionconfiguressupportforrelativepath.
/
/0:Disablerelativepathandremoverelatedfunctions.
/1:Enablerelativepath.f_chdir()andf_chdrive()areavailable.
/2:f_getcwd()functionisavailableinadditionto1.
*/
/*---------------------------------------------------------------------------/
/Drive/VolumeConfigurations
/---------------------------------------------------------------------------*/
#defineFF_VOLUMES1
/*Numberofvolumes(logicaldrives)tobeused.(1-10)*/
#defineFF_STR_VOLUME_ID0
#defineFF_VOLUME_STRS"RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/*FF_STR_VOLUME_IDswitchessupportforvolumeIDinarbitrarystrings.
/WhenFF_STR_VOLUME_IDissetto1or2,arbitrarystringscanbeusedasdrive
/numberinthepathname.FF_VOLUME_STRSdefinesthevolumeIDstringsforeach
/logicaldrives.NumberofitemsmustnotbelessthanFF_VOLUMES.Valid
/charactersforthevolumeIDstringsareA-Z,a-zand0-9,however,theyare
/comparedincase-insensitive.IfFF_STR_VOLUME_ID>=1andFF_VOLUME_STRSis
/notdefined,auserdefinedvolumestringtableneedstobedefinedas:
/
/constchar*VolumeStr[FF_VOLUMES]={"ram","flash","sd","usb",...
*/
#defineFF_MULTI_PARTITION0
/*Thisoptionswitchessupportformultiplevolumesonthephysicaldrive.
/Bydefault(0),eachlogicaldrivenumberisboundtothesamephysicaldrive
/numberandonlyanFATvolumefoundonthephysicaldrivewillbemounted.
/Whenthisfunctionisenabled(1),eachlogicaldrivenumbercanbeboundto
/arbitraryphysicaldriveandpartitionlistedintheVolToPart[].Alsof_fdisk()
/funcitonwillbeavailable.*/
#defineFF_MIN_SS512
#defineFF_MAX_SS4096
/*Thissetofoptionsconfigurestherangeofsectorsizetobesupported.(512,
/1024,2048or4096)Alwayssetboth512formostsystems,genericmemorycardand
/harddisk.Butalargervaluemayberequiredforon-boardflashmemoryandsome
/typeofopticalmedia.WhenFF_MAX_SSislargerthanFF_MIN_SS,FatFsisconfigured
/forvariablesectorsizemodeanddisk_ioctl()functionneedstoimplement
/GET_SECTOR_SIZEcommand.*/
#defineFF_LBA640
/*Thisoptionswitchessupportfor64-bitLBA.(0:Disableor1:Enable)
/Toenablethe64-bitLBA,alsoexFATneedstobeenabled.(FF_FS_EXFAT==1)*/
#defineFF_MIN_GPT0x100000000
/*MinimumnumberofsectorstoswitchGPTformattocreatepartitioninf_mkfsand
/f_fdiskfunction.0x100000000max.ThisoptionhasnoeffectwhenFF_LBA64==0.*/
#defineFF_USE_TRIM0
/*ThisoptionswitchessupportforATA-TRIM.(0:Disableor1:Enable)
/ToenableTrimfunction,alsoCTRL_TRIMcommandshouldbeimplementedtothe
/disk_ioctl()function.*/
/*---------------------------------------------------------------------------/
/SystemConfigurations
/---------------------------------------------------------------------------*/
#defineFF_FS_TINY0
/*Thisoptionswitchestinybufferconfiguration.(0:Normalor1:Tiny)
/Atthetinyconfiguration,sizeoffileobject(FIL)isshrinkedFF_MAX_SSbytes.
/Insteadofprivatesectorbuffereliminatedfromthefileobject,commonsector
/bufferinthefilesystemobject(FATFS)isusedforthefiledatatransfer.*/
#defineFF_FS_EXFAT0
/*ThisoptionswitchessupportforexFATfilesystem.(0:Disableor1:Enable)
/ToenableexFAT,alsoLFNneedstobeenabled.(FF_USE_LFN>=1)
/NotethatenablingexFATdiscardsANSIC(C89)compatibility.*/
#defineFF_FS_NORTC0
#defineFF_NORTC_MON1
#defineFF_NORTC_MDAY1
#defineFF_NORTC_YEAR2019
/*TheoptionFF_FS_NORTCswitchestimestampfunctiton.Ifthesystemdoesnothave
/anyRTCfunctionorvalidtimestampisnotneeded,setFF_FS_NORTC=1todisable
/thetimestampfunction.EveryobjectmodifiedbyFatFswillhaveafixedtimestamp
/definedbyFF_NORTC_MON,FF_NORTC_MDAYandFF_NORTC_YEARinlocaltime.
/Toenabletimestampfunction(FF_FS_NORTC=0),get_fattime()functionneedtobe
/addedtotheprojecttoreadcurrenttimeformreal-timeclock.FF_NORTC_MON,
/FF_NORTC_MDAYandFF_NORTC_YEARhavenoeffect.
/Theseoptionshavenoeffectinread-onlyconfiguration(FF_FS_READONLY=1).*/
#defineFF_FS_NOFSINFO0
/*IfyouneedtoknowcorrectfreespaceontheFAT32volume,setbit0ofthis
/option,andf_getfree()functionatfirsttimeaftervolumemountwillforce
/afullFATscan.Bit1controlstheuseoflastallocatedclusternumber.
/
/bit0=0:UsefreeclustercountintheFSINFOifavailable.
/bit0=1:DonottrustfreeclustercountintheFSINFO.
/bit1=0:UselastallocatedclusternumberintheFSINFOifavailable.
/bit1=1:DonottrustlastallocatedclusternumberintheFSINFO.
*/
#defineFF_FS_LOCK0
/*TheoptionFF_FS_LOCKswitchesfilelockfunctiontocontrolduplicatedfileopen
/andillegaloperationtoopenobjects.Thisoptionmustbe0whenFF_FS_READONLY
/is1.
/
/0:Disablefilelockfunction.Toavoidvolumecorruption,applicationprogram
/shouldavoidillegalopen,removeandrenametotheopenobjects.
/>0:Enablefilelockfunction.Thevaluedefineshowmanyfiles/sub-directories
/canbeopenedsimultaneouslyunderfilelockcontrol.Notethatthefile
/lockcontrolisindependentofre-entrancy.*/
/*#include<somertos.h>//O/Sdefinitions*/
#defineFF_FS_REENTRANT0
#defineFF_FS_TIMEOUT1000
#defineFF_SYNC_tHANDLE
/*TheoptionFF_FS_REENTRANTswitchesthere-entrancy(threadsafe)oftheFatFs
/moduleitself.Notethatregardlessofthisoption,fileaccesstodifferent
/volumeisalwaysre-entrantandvolumecontrolfunctions,f_mount(),f_mkfs()
/andf_fdisk()function,arealwaysnotre-entrant.Onlyfile/directoryaccess
/tothesamevolumeisundercontrolofthisfunction.
/
/0:Disablere-entrancy.FF_FS_TIMEOUTandFF_SYNC_thavenoeffect.
/1:Enablere-entrancy.Alsouserprovidedsynchronizationhandlers,
/ff_req_grant(),ff_rel_grant(),ff_del_syncobj()andff_cre_syncobj()
/function,mustbeaddedtotheproject.Samplesareavailablein
/option/syscall.c.
/
/TheFF_FS_TIMEOUTdefinestimeoutperiodinunitoftimetick.
/TheFF_SYNC_tdefinesO/Sdependentsyncobjecttype.e.g.HANDLE,ID,OS_EVENT*,
/SemaphoreHandle_tandetc.AheaderfileforO/Sdefinitionsneedstobe
/includedsomewhereinthescopeofff.h.*/
/*---Endofconfigurationoptions---*/
5.FatFs演示示例
在FatFs接口文件和配置文件移植完成后,,我们在main.c中对文件系统进行初始化,主要是对磁盘的初始化和挂载操作,便于后面的文件操作:
<div><div><div>FATFSfs;
BYTEwork[FF_MAX_SS];
uint8_tfsFlag=0;
uint8_tfsTest=0;
voidxInitFileSystem(void)
{
FRESULTres;
res=f_mount(&fs,"0:",1);
if(res==FR_NO_FILESYSTEM)
{
res=f_mkfs("0:",0,work,sizeof(work));
if(res==FR_OK)
{
xUserPrintf("\r\nCreateanFAT/exFATvolumeonthelogicaldrive\r\n");
res=f_mount(&fs,"0:",1);
if(res==FR_OK)fsFlag=1;
}
}
else
{
fsFlag=1;
}
if(fsFlag)
{
xUserPrintf("\r\nRegistertheworkareaofthevolumesuccess\r\n");
}
}
然后我们添加一个简单的测试DEMO程序,主要功能是在hello.txt文件的尾部不断的插入新数据,然后再把hello.txt的内容读取出来并打印出来;为了方便测试,将这个函数添加到shell命令中了:
<div><div><div>voidxTestFileSystem(void)
{
FILfil;
UINTbw;
FRESULTres;
if(fsFlag)
{
charbuffer[200];
res=f_open(&fil,"0:hello.txt",FA_OPEN_APPEND|FA_WRITE);
if(res==FR_OK)
{
memset(buffer,0,sizeof(buffer));
sprintf(buffer,"%d",fsTest++%100);
res=f_write(&fil,buffer,1,&bw);
f_close(&fil);
}
res=f_open(&fil,"0:hello.txt",FA_OPEN_EXISTING|FA_READ);
if(res==FR_OK)
{
memset(buffer,0,sizeof(buffer));
res=f_read(&fil,buffer,200,&bw);
xUserPrintf("\r\nread:%d|%d=>>%s\r\n",res,bw,buffer);
f_close(&fil);
}
}
else
{
xUserPrintf("\r\nFileSystemInitFailed!\r\n");
}
}
如下图所示是测试过程和结果:
FatFs是一个应用在小型嵌入式系统中的通用文件系统(FAT/exFAT)模块。FatFs模块是遵循ANSIC(C89)编写的,与磁盘I/O层是完全分离的。因此,它是独立于平台的。它可以被整合到资源有限的小型微控制器中,如8051、PIC、AVR、ARM、Z80、RX等等;
本文中使用的是FatFs_R0.14版本,结合GD32RISV-V开发平台板载的SPIFLASH来实现文件系统的功能。FatFs官网及下载地址:
,当然也可以到面包板下载中心下载:
https://mbb.eet-china.com/download/36035.html
2.硬件原理图
从原理图上我们可以看到,SPIFlash使用的GD25Q16这颗芯片,其存储容量为2M字节;与MCU连接的接口使用的是硬件SPI0,另外CS操作引脚使用的是PE3。需要注意的是有一个JP12的跳线设置,需要将PA5与SPI0_SCK进行短接。
3.移植前准备
实现FatFs的移植是基于《【兆易创新RISC-V开发板评测】03.实现uGUI移植到GD32RISC-V开发平台》的工程上实现的。通过NucleiStudioIDE打开工程,在gd32vf103_eval.c文件中对硬件SPI接口进行配置初始化:
<div><div><div>/*!
\briefconfigspi0forspiflash
\param[in]none
\param[out]none
\retvalnone
*/
voidgd_eval_spi_init(void)
{
spi_parameter_structspi_init_struct;
spi_struct_para_init(&spi_init_struct);
/*peripheralclockenable*/
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_SPI0);
/*SPI0GPIOconfig:SCK/PA5,MISO/PA6,MOSI/PA7*/
gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_5|GPIO_PIN_7);
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_6);
/*SPIflashCSpinconfig:SPIFlashCS/PE3*/
gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_3);
/*deinitilizeSPIandtheparameters*/
spi_i2s_deinit(SPI0);
/*SPI0parameterconfig*/
spi_init_struct.trans_mode=SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode=SPI_MASTER;
spi_init_struct.frame_size=SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase=SPI_CK_PL_HIGH_PH_2EDGE;
spi_init_struct.nss=SPI_NSS_SOFT;
spi_init_struct.prescale=SPI_PSC_8;
spi_init_struct.endian=SPI_ENDIAN_MSB;
spi_init(SPI0,&spi_init_struct);
/*SPIenable*/
spi_enable(SPI0);
}
/*!
\briefreadandwritespiflashbyspi0
\param[in]data:writetospiflash
\param[out]data:readfromspiflash
\retvalnone
*/
uint16_tgd_eval_spi_rw(uint16_tdata)
{
while(RESET==spi_i2s_flag_get(SPI0,SPI_FLAG_TBE));
spi_i2s_data_transmit(SPI0,data);
while(RESET==spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE));
returnspi_i2s_data_receive(SPI0);
}
新建gd32vf103v_spi_flash_eval.c和gd32vf103v_spi_flash_eval.h两个文件,在这个文件中实现对SPIFlash的操作函数:
<div><div>#include"gd32vf103v_eval.h"
#include"gd32vf103v_spi_flash_eval.h"
#include<stdarg.h>
#include<string.h>
unsignedlongxUserPow(intx,inty)
{
unsignedlongsum=1;
while(y--)
{
sum*=x;
}
returnsum;
}
voidxUserPutChar(constcharch)
{
usart_data_transmit(USART0,(uint8_t)ch);
while(usart_flag_get(USART0,USART_FLAG_TBE)==RESET){
}
}
voidxUserPutString(constchar*str)
{
while(*str)
{
xUserPutChar(*str++);
}
}
voidxUserPrintNum(constintvalue,constintpow)
{
inttemp,count=0,data;
temp=value;
if(temp==0)
{
xUserPutChar(’0’);
}
else
{
while(temp)
{
count++;temp/=pow;
}
temp=value;
while(count)
{
data=temp/xUserPow(pow,count-1);
temp=temp%xUserPow(pow,count-1);
if(data<=9)xUserPutChar(data+’0’);
elsexUserPutChar(data+’a’-10);
count--;
}
}
}
voidxUserPrintf(constchar*str,...)
{
va_listap;
intval,r_val;
charcount,ch;
va_start(ap,str);
while(*str)
{
switch(*str)
{
case’%’:
str++;
switch(*str)
{
case’d’:
xUserPrintNum(va_arg(ap,int),10);
break;
case’x’:
xUserPrintNum(va_arg(ap,int),16);
break;
case’s’:
xUserPutString(va_arg(ap,char*));
break;
case’c’:
xUserPutChar((char)va_arg(ap,int));
break;
default:break;
}
break;
case’\n’:xUserPutChar(’\n’);break;
case’\r’:xUserPutChar(’\r’);break;
default:xUserPutChar(*str);break;
}
str++;
}
va_end(ap);
}
voidspi_flash_write_enable(void)
{
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_WREN);
SPIFlashCS_H();
}
voidspi_flash_write_disable(void)
{
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_WRDI);
SPIFlashCS_H();
}
voidspi_flash_wait_for_write_end(void)
{
uint8_tflag=0;
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_RDSR);
do
{
flag=gd_eval_spi_rw(SPI_FLASH_DUMMY);
}while(flag&0x01);
SPIFlashCS_H();
}
voidspi_flash_erase_sector(uint32_taddress)
{
spi_flash_write_enable();
spi_flash_wait_for_write_end();
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_SE);
gd_eval_spi_rw((address&0x00FF0000)>>0x10);
gd_eval_spi_rw((address&0x0000FF00)>>0x08);
gd_eval_spi_rw((address&0x000000FF)>>0x00);
SPIFlashCS_H();
spi_flash_wait_for_write_end();
}
voidspi_flash_erase_block32(uint32_taddress)
{
spi_flash_write_enable();
spi_flash_wait_for_write_end();
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_BE32);
gd_eval_spi_rw((address&0x00FF0000)>>0x10);
gd_eval_spi_rw((address&0x0000FF00)>>0x08);
gd_eval_spi_rw((address&0x000000FF)>>0x00);
SPIFlashCS_H();
spi_flash_wait_for_write_end();
}
voidspi_flash_fast_read(uint32_taddress,uint8_t*buffer,uint16_tlength)
{
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_FastRead);
gd_eval_spi_rw((address&0x00FF0000)>>0x10);
gd_eval_spi_rw((address&0x0000FF00)>>0x08);
gd_eval_spi_rw((address&0x000000FF)>>0x00);
gd_eval_spi_rw(SPI_FLASH_DUMMY);
for(uint16_ti=0;i<length;i++)
{
buffer
=gd_eval_spi_rw(SPI_FLASH_DUMMY);
}
SPIFlashCS_H();
}
voidspi_flash_page_program(uint32_taddress,uint8_t*buffer,uint16_tlength)
{
spi_flash_write_enable();
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_PP);
gd_eval_spi_rw((address&0x00FF0000)>>0x10);
gd_eval_spi_rw((address&0x0000FF00)>>0x08);
gd_eval_spi_rw((address&0x000000FF)>>0x00);
for(uint16_ti=0;i<length;i++)
{
gd_eval_spi_rw(buffer
);
}
SPIFlashCS_H();
spi_flash_wait_for_write_end();
}
voidspi_flash_init(void)
{
gd_eval_spi_init();
SPIFlashCS_H();
xUserPrintf("\r\nSPIFlashInitOK!\r\n");
}
voidspi_flash_read(uint32_taddress,uint8_t*buffer,uint16_tlength)
{
spi_flash_fast_read(address,buffer,length);
}
voidspi_flash_write(uint32_taddress,uint8_t*buffer,uint16_tlength)
{
uint16_toffset=0;
uint16_tnum_head=0,num_tail=0,num_page=0;
num_head=PAGE_SIZE-(address%PAGE_SIZE);
//xUserPrintf("\r\nnum_head=%d,length=%d\r\n",num_head,length);
if(num_head>=length)
{
//xUserPrintf("\r\nLengthPP\r\n");
spi_flash_page_program(address,&buffer[offset],length);
}
else
{
//xUserPrintf("\r\nHeadPP\r\n");
spi_flash_page_program(address,&buffer[offset],num_head);
offset+=num_head;
length-=num_head;
address+=num_head;
num_page=length/PAGE_SIZE;
num_tail=length%PAGE_SIZE;
//xUserPrintf("\r\nnum_page=%d\r\n",num_page);
//xUserPrintf("\r\nnum_tail=%d\r\n",num_tail);
for(uint16_ti=0;i<num_page;i++)
{
//xUserPrintf("\r\nPagePP\r\n");
spi_flash_page_program(address,&buffer[offset],PAGE_SIZE);
offset+=PAGE_SIZE;
address+=PAGE_SIZE;
}
if(num_tail)
{
//xUserPrintf("\r\nTailPP\r\n");
spi_flash_page_program(address,&buffer[offset],num_tail);
}
}
}
voidspi_flash_shell_rdid(void)
{
uint32_tid=0;
SPIFlashCS_L();
gd_eval_spi_rw(SPI_FLASH_CMD_RDID);
id=gd_eval_spi_rw(SPI_FLASH_DUMMY);
id<<=8;
id|=gd_eval_spi_rw(SPI_FLASH_DUMMY);
id<<=8;
id|=gd_eval_spi_rw(SPI_FLASH_DUMMY);
xUserPrintf("\r\nSPIFlashRDID:0x%x\r\n",id);
SPIFlashCS_H();
}
voidspi_flash_shell_erase(uint32_taddress)
{
spi_flash_erase_sector(address);
xUserPrintf("\r\nSPIFlashSectorErase:0x%x\r\n",address);
}
voidspi_flash_shell_erase_all(void)
{
for(uint16_ti=0;i<SECTOR_COUNT;i++)
{
spi_flash_shell_erase(i*SECTOR_SIZE);
}
}
voidspi_flash_shell_read(uint32_taddress,uint16_tlength)
{
uint8_tbuffer[500];
memset(buffer,0,sizeof(buffer));
spi_flash_read(address,buffer,length);
xUserPrintf("\r\nSPIFlashRead:\r\n");
for(uint16_ti=0;i<length;i++)
{
xUserPrintf("0x%x",buffer
);
}
xUserPrintf("\r\n");
}
voidspi_flash_shell_write(uint32_taddress,uint16_tlength)
{
uint8_tbuffer[500];
for(uint16_ti=0;i<sizeof(buffer);i++)
{
buffer
=i%256;
}
spi_flash_write(address,buffer,length);
}