spi flash驱动代码分析(二)
发布时间:2020-12-15 20:08:35 所属栏目:百科 来源:网络整理
导读:一、spi flash裸机驱动代码 /**W25Q64一共8M容量?*分为128个快,每块大小为64K字节?*每块又可以分为16个扇区,每个扇区4K字节?//每次擦除最少一个扇区,也就是4K字节?//25Q64?一共有2048个扇区*一页256字节*/#define W25Q64_PAGE_SIZE 256 //一页的大小,256
一、spi flash裸机驱动代码 /* *W25Q64一共8M容量? *分为128个快,每块大小为64K字节? *每块又可以分为16个扇区,每个扇区4K字节?//每次擦除最少一个扇区,也就是4K字节?//25Q64?一共有2048个扇区 *一页256字节 */ #define W25Q64_PAGE_SIZE 256 //一页的大小,256字节 #define W25Q64_SECTOR_SIZE (4*1024) //扇区大小,字节 #define W25Q64_BLOCK_SIZE (16*W25Q64_SECTOR_SIZE) #define W25Q64_SIZE (128*W25Q64_BLOCK_SIZE) void W25q64_Init(void) { 1.可以用GPIO模拟SPI 2.也可以用spi控制器<span style="white-space:pre"> </span> } /******************************************************************************* * Function Name : W25q_ReadWriteByte * Description : W25q芯片SPI读写接口函数 * Input : None * Output : None * Return : None * Date : 2014-05-14 * Author : ADT LL *******************************************************************************/ static uint8_t W25q_ReadWriteByte(uint8_t data) { return SSP_SendData(data); } /******************************************************************************* * Function Name : W25q64_WaitForIdle * Description : 读状态寄存器 * Input : None * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_WaitForIdle(void) { uint8_t status=0; CS1_RESET; W25q_ReadWriteByte(0x05); do { status = W25q_ReadWriteByte(0xA5); }while (status&0x01 == 0x01); CS1_SET; } /******************************************************************************* * Function Name : W25q64_WriteEnable * Description : 写使能 * Input : None * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_WriteEnable(void) { CS1_RESET; W25q_ReadWriteByte(0x06); CS1_SET; } /******************************************************************************* * Function Name : W25q64_4KErase * Description : 4K片擦除 * Input : addr:起始地址 * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_4KErase(uint32_t addr) { W25q64_WriteEnable(); CS1_RESET; W25q_ReadWriteByte(0x20); W25q_ReadWriteByte((addr & 0xFF0000)>>16); W25q_ReadWriteByte((addr & 0x00FF00)>>8); W25q_ReadWriteByte(addr & 0xFF); CS1_SET; W25q64_WaitForIdle(); } /******************************************************************************* * Function Name : W25q64_32KErase * Description : 32K片擦除 * Input : addr:起始地址 * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_32KErase(uint32_t addr) { W25q64_WriteEnable(); CS1_RESET; W25q_ReadWriteByte(0x52); W25q_ReadWriteByte((addr & 0xFF0000)>>16); W25q_ReadWriteByte((addr & 0x00FF00)>>8); W25q_ReadWriteByte(addr & 0xFF); CS1_SET; W25q64_WaitForIdle(); } /******************************************************************************* * Function Name : W25q64_64KErase * Description : 64K片擦除 * Input : addr:起始地址 * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_64KErase(uint32_t addr) { W25q64_WriteEnable(); CS1_RESET; W25q_ReadWriteByte(0xD8); W25q_ReadWriteByte((addr & 0xFF0000)>>16); W25q_ReadWriteByte((addr & 0x00FF00)>>8); W25q_ReadWriteByte(addr & 0xFF); CS1_SET; W25q64_WaitForIdle(); } /******************************************************************************* * Function Name : W25q64_ChipErase * Description : Chip片擦除 * Input : addr:起始地址 * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_ChipErase(uint32_t addr) { W25q64_WriteEnable(); CS1_RESET; W25q_ReadWriteByte(0xC7); W25q_ReadWriteByte((addr & 0xFF0000)>>16); W25q_ReadWriteByte((addr & 0x00FF00)>>8); W25q_ReadWriteByte(addr & 0xFF); CS1_SET; W25q64_WaitForIdle(); } /******************************************************************************* * Function Name : W25q64_Erase * Description : 擦除操作,最小以4K为单位进行,从擦除。 * Input : sectornum:块数,擦除的空间大小为sectornum*4K --例如:如果sectornum=1,则擦除4K字节, sectornum=3,则擦除12K=4K*3个字节 addr:起始地址 * Output : None * Return : 状态码 * Date : 2014-10-25 * Author : ADT LL *******************************************************************************/ int W25q64_Erase(uint32_t base_addr,int sector_count) { if (base_addr % W25Q64_SECTOR_SIZE ) { return -1; } if (base_addr>=W25Q64_SIZE) return -1; while(sector_count = sector_count / 16) { W25q64_64KErase(base_addr); base_addr += 16*W25Q64_SECTOR_SIZE; } while(sector_count = sector_count / 8) { W25q64_32KErase(base_addr); base_addr += 8*W25Q64_SECTOR_SIZE; } while(sector_count--) { W25q64_4KErase(base_addr); base_addr += W25Q64_SECTOR_SIZE; } return 0; } /******************************************************************************* * Function Name : W25q64_PageProgram * Description : 页写 * Input : buf:要写内的数据 len:数据长度 add:起始地址 * Output : None * Return : 状态码 * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ static int W25q64_PageProgram(uint8_t *buf,uint16_t len,uint32_t addr) { if (addr>=W25Q64_SIZE) return -1; if (len<=0 || len>256) return -1;//没有数据不操作 W25q64_WriteEnable(); CS1_RESET; W25q_ReadWriteByte(0x02); W25q_ReadWriteByte((addr & 0xFF0000)>>16); W25q_ReadWriteByte((addr & 0x00FF00)>>8); W25q_ReadWriteByte(addr & 0xFF); while (len--) { W25q_ReadWriteByte(*buf); buf++; } CS1_SET; W25q64_WaitForIdle(); return 0; } /******************************************************************************* * Function Name : W25q64_Write * Description : 数据存储,为防止意外的擦除 * Input : buf:要写内的数据 len:数据长度 add:起始地址 * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_Write(uint8_t *buf,uint32_t addr) { uint8_t pagenum; uint8_t addrbyte;//最低八位地址 addrbyte = addr%W25Q64_PAGE_SIZE; if (len > (W25Q64_PAGE_SIZE - addrbyte))//跨页了 { W25q64_PageProgram(buf,W25Q64_PAGE_SIZE - addrbyte,addr);//写满本页 addr += W25Q64_PAGE_SIZE-addrbyte; buf += W25Q64_PAGE_SIZE-addrbyte; len -= W25Q64_PAGE_SIZE-addrbyte; pagenum = len/W25Q64_PAGE_SIZE; while (pagenum--) { W25q64_PageProgram(buf,W25Q64_PAGE_SIZE,addr); addr += W25Q64_PAGE_SIZE; buf += W25Q64_PAGE_SIZE; len -= W25Q64_PAGE_SIZE; } W25q64_PageProgram(buf,len,addr); } else { W25q64_PageProgram(buf,addr); } } /******************************************************************************* * Function Name : W25q64_WriteStatus * Description : 写状态寄存器 * Input : status:状态值 * Output : None * Return : None * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ void W25q64_WriteStatus(uint16_t status) { W25q64_WriteEnable(); CS1_RESET; W25q_ReadWriteByte(0x01); W25q_ReadWriteByte(status & 0xFF); W25q_ReadWriteByte((status>>8) & 0xFF); CS1_SET; W25q64_WaitForIdle(); } /******************************************************************************* * Function Name : W25q64_ReadStatus * Description : 读状态寄存器 * Input : None * Output : None * Return : 状态寄存器值 * Date : 2014-10-24 * Author : ADT LL *******************************************************************************/ uint16_t W25q64_ReadStatus(void) { uint16_t status=0; CS1_RESET; W25q_ReadWriteByte(0x05); status = W25q_ReadWriteByte(0xFF); CS1_SET; CS1_RESET; W25q_ReadWriteByte(0x35); status |= W25q_ReadWriteByte(0xFF)<<8; CS1_SET; return status; } /******************************************************************************* * Function Name : W25q64_ReadDeviceID * Description : 读字库芯片ID * Input : None * Output : None * Return : None * Date : 2014-10-20 * Author : ADT LL *******************************************************************************/ uint16_t W25q64_ReadDeviceID(void) { uint16_t DeviceID=0; CS1_RESET; W25q_ReadWriteByte(0x90); W25q_ReadWriteByte(0x00); W25q_ReadWriteByte(0x00); W25q_ReadWriteByte(0x00); DeviceID = W25q_ReadWriteByte(0xFF)<<8; DeviceID |= W25q_ReadWriteByte(0xFF); CS1_SET; return DeviceID; } /******************************************************************************* * Function Name : W25q64_Read * Description : 读数据 * Input : buf:数据缓冲区 len:长度 addr:起始地址 * Output : None * Return : 返回状态,暂无意义 * Date : 2014-10-20 * Author : ADT LL *******************************************************************************/ uint8_t W25q64_Read(uint8_t *buf,uint32_t len,uint32_t addr) { uint32_t i; uint8_t status; //if (addr>=W25Q64_TOPADDR) return W25Q64_ADDRERROR; CS1_RESET; status = W25q_ReadWriteByte(CODE_READDATA); status = W25q_ReadWriteByte((addr & 0xFF0000)>>16); status = W25q_ReadWriteByte((addr & 0x00FF00)>>8); status = W25q_ReadWriteByte(addr & 0xFF); for (i=0; i<len; i++) { buf[i] = W25q_ReadWriteByte(0xFF); } status = 0; CS1_SET; return status; }
/*GPIO模拟SPI协议读写函数*/ uint8_t SPI_RW(uint8_t data) { char buf[24]; uint8_t bit_ctr; for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit { if((data & 0x80)) { MOSI_H; } else { MOSI_L; } data = (data << 1); SCK_H; delayUs(1); data |= MISO ? 1 : 0; SCK_L; delayUs(1); } return(data); }2.如果是spi控制器读写spi spi flash的CS片选如果接spi接口的SSEL要注意,由于 spi控制器的SSEL端不受代码控制的,这里我单独用了一个gpio来做CS片选。 uint8_t SSP_SendData(uint8_t data) { #ifndef GPIO_SPI LPC_SSP1->DR = data; while( (LPC_SSP1->SR & 0x01) == 0 ); /* 等待TFE置位,即发送FIFO空 */ while((LPC_SSP1->SR & 0x04) == 0); /*等待接收fifo不为空*/ return (LPC_SSP1->DR); #else return SPI_RW(data); #endif } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |