来源:百问网_嵌入式Linux wiki_jz2440 新1期视频维基教程 (视频笔墨版)
作者:韦东山
本笔墨数:1277,阅读时长:1.5分钟

这节讲解如何利用SPI操作Flash,我们在上节课的代码上进行修正,添加一个文件 spi_flash.c 和其头文件 spi_flash.h 。
我们先做一个最大略的spi操作,读取Flash的ID, SPIFlashID() 。
Flash的ID有厂家ID和设备ID,分别用pMID和pDID来保存。
根据Flash的芯片手册 W25Q16DV.pdf 可以知道须要先发出一个指令0x90,再发送24位的地址0,再读取数据前8位是设备ID,然后是8位设备ID。进行操作前必须要片选SPI Flash,片选完还是开释SPI Flash:
void SPIFlashReadID(int pMID, int pDID){ SPIFlash_Set_CS(0); / 选中SPI FLASH / SPISendByte(0x90); SPIFlashSendAddr(0); pMID = SPIRecvByte(); pDID = SPIRecvByte(); SPIFlash_Set_CS(1);}
把个中的发送24地址封装成了一个函数 SPIFlashSendAddr() :
static void SPIFlashSendAddr(unsigned int addr){ SPISendByte(addr >> 16); SPISendByte(addr >> 8); SPISendByte(addr & 0xff);}
依次完成上面的子函数,先是SPI片选,上一节的事理图可以看到SPI Flash的片选是GPG2:
static void SPIFlash_Set_CS(char val){ if (val) GPGDAT |= (1<<2); else GPGDAT &= ~(1<<2);}
SPISendByte() 和前面OLED的是一样的,就不用写了,因此就只剩下 SPIRecvByte() ,放在 gpio_spi.c 里面实现:
unsigned char SPIRecvByte(void){ int i; unsigned char val = 0; for (i = 0; i < 8; i++) { val <<= 1; SPI_Set_CLK(0); if (SPI_Get_DI()) val |= 1; SPI_Set_CLK(1); } return val; }
在每个时钟周期读取DI引脚上的值,对付SOC便是MISO引脚:
static char SPI_Get_DI(void){ if (GPGDAT & (1<<5)) return 1; else return 0;}
至此,读取Flash的ID基本实现,末了在主函数里调用打印,分别在串口和OLED上显示:
SPIFlashReadID(&mid, &pid); printf("SPI Flash : MID = 0x%02x, PID = 0x%02x\n\r", mid, pid); sprintf(str, "SPI : %02x, %02x", mid, pid); OLEDPrint(4,0,str);
Makefile记得加上新天生的 spi_flash.o 。
「新品首发」STM32MP157开拓板火爆预售!
首批仅300套