翌创ET6001开发板提供了对NorFlash存储器件的读写功能,所支持的芯片为W25X40。
由资料可知,W25X40是一款4M的flash,其工作电压为2.7-3.6V,存储容量4M-bit。具有双向SPI输出功能,是普通SPI接口的2倍速度。
该芯片与开发板的连接关系为:
CLK---GPIO2_0
MISO---GPIO2_1
MOSI---GPIO2_2
CS----GPIO2_3
由于在开发板上并没有配置该芯片,故在完成程序编译和运行的情况下,其运行结果如图1所示。
图1 无芯片测试
由此可知,测试程序的基本功能为:
手头有一款W25Q16的存储模块,由资料可知W25Q16是一款16M-bit的存储芯片,工作电压为2.7V到3.6V,正常工作时电流小于5mA。
W25Q16的每一页有256个字节,共有8192页,每16页是一个扇区。每页的256个字节用一次页编程指令接口完成。每次擦除128页(32KB块)或全片擦除。
这里用该存储模块来进行读写测试,相应的引脚连接关系为:
CLK---GPIO2_0
DO ---GPIO2_1
DI---GPIO2_2
CS----GPIO2_3
读取芯片ID的函数为:
static void SPI_ReadDeviceID(void)
{
uint8_t sendData[20] = {0};
uint8_t receiveData[20] = {0};
SPI_InitType init;
SPI_DeInit(SPI0);
SPI_StructInit(&init);
init.dataFrameSize = 0x7;
init.transferMode = SPI_EEPROM_READ;
init.clkDiv = 2;
init.rxSampleDly = 2;
init.readDataNum = 2;
SPI_Init(SPI0, &init);
SPI_Enable(SPI0);
sendData[0] = FLASHCMD_READ_DEVICE_ID;
sendData[1] = 0x0;
sendData[2] = 0x0;
sendData[3] = 0x0;
SPI_Transmit(SPI0, (uint8_t *)(&sendData), 4, MAX_TIMEOUT);
SPI_Receive(SPI0, receiveData, 2, MAX_TIMEOUT);
printf("read w25x40 device identification [0x%x,0x%x]\n", receiveData[0], receiveData[1]);
}
进行芯片整体擦除的函数为:
static void SPI_DeviceChipErase(void)
{
SPI_DeviceWriteEnable();
uint8_t sendData;
sendData = FLASHCMD_CHIP_ERASE;
SPI_Transmit(SPI0, (uint8_t *)(&sendData), 1, MAX_TIMEOUT);
while (!SPI_IsDeviceReady());
}
读取数据的函数为:
static void SPI_DeviceRead(void)
{
uint32_t i;
uint32_t addr = 0;
uint8_t data[4] = {0};
uint8_t sendData[4] = {0};
while(SPI_STATE_READY != SPI_GetState(SPI0));
while (!SPI_IsDeviceReady());
while(SPI_STATE_READY != SPI_GetState(SPI0));
SPI_ConfigTransMode(SPI0, SPI_EEPROM_READ);
SPI_ConfigFrameNum(SPI0, 4);
sendData[0] = FLASHCMD_READ_DATA;
sendData[1] = (addr & 0xFF0000) >> 16;
sendData[2] = (addr & 0xFF00) >> 8;
sendData[3] = addr & 0xFF;
SPI_Transmit(SPI0, (uint8_t *)(&sendData), 4, MAX_TIMEOUT);
SPI_Receive(SPI0, data, 4, MAX_TIMEOUT);
for (i = 0;i < 4;i++) {
printf("read data = 0x%x\n",data[i]);
}
}
写入数据的函数为:
static void SPI_DeviceWrite(void)
{
bool state;
uint32_t addr = 0x0;
uint8_t data[8] = {0};
state = SPI_DeviceWriteEnable();
if (state == false)
return ;
data[0] = FLASHCMD_PAGE_PROGRAM;
while(SPI_STATE_READY != SPI_GetState(SPI0));
data[1] = (uint8_t)((addr & 0xFF0000) >> 16);
data[2] = (uint8_t)((addr & 0xFF00) >> 8);
data[3] = (uint8_t)(addr & 0xFF);
data[4] = 0x12;
data[5] = 0x34;
data[6] = 0x56;
data[7] = 0x78;
SPI_Transmit(SPI0, data, 8, MAX_TIMEOUT);
while(SPI_STATE_READY != SPI_GetState(SPI0));
while (!SPI_IsDeviceReady());
printf("write data 0x12,0x34,0x56,0x78\n");
}
需注意的是,无论是读取函数还是是写入函数,其操作地址都是在函数内通过变量addr来指定的,这样就不如以参数的方式来指定地址更为方便。
在连接后,其工作状态如图2及运行结果见图3所示,说明尽管所提供的例程是为W25X40所准备的,但对于W25Q16来说依然有效。
图2 运行状态
图3 运行结果
有了W25Q16存储模块的支持,就可为开发板提供更大的数据存储空间以放置常用的相对固定数据,如字库和图片库等,作用还是很强的。