1. 程式人生 > >STM8L151 使用硬體SPI驅動W25Q16 Flash

STM8L151 使用硬體SPI驅動W25Q16 Flash

SPI:有四根線的序列通訊協議,允許與其他裝置以半、全雙工、同步、序列方式通訊。 MISO:主模式輸入、從模式輸出線 MOSI:主模式輸出、從模式輸入線 CLK:時鐘線 NSS:從裝置選擇引腳,主裝置標準IO驅動,並用來區分從裝置 以STM8L 驅動SPI Flash W25Q16 為例說明記錄下,使用STM8L 的SPI該注意哪些地方,以及如何簡單驅動W25Q16。 華邦的W25Q16 SPI Flash晶片是採用SPI介面,至於該晶片的優缺點就不說了,STM8L上有一個硬體SPI,可以很方便的來驅動W25Q16,下面就來看看該如何配置STM8L的SPI 外設。
void SPI_FLASH_Init(void)
{ 
	//SPI_CLOCK:PB5, SPI_MOSI: PB6, SPI_MISO: PB7
	GPIO_Init(GPIOB, GPIO_Pin_5, GPIO_Mode_Out_PP_High_Fast);
	GPIO_Init(GPIOB, GPIO_Pin_6, GPIO_Mode_Out_PP_High_Fast);
	//主機模式,配置為輸入 該設定很關鍵
	GPIO_Init(GPIOB, GPIO_Pin_7, GPIO_Mode_In_PU_No_IT);
  	/* 初始化SPI */
	SPI_Init(SPI1, SPI_FirstBit_MSB, SPI_BaudRatePrescaler_4, SPI_Mode_Master,\
		 SPI_CPOL_High, SPI_CPHA_2Edge, \
		SPI_Direction_2Lines_FullDuplex, SPI_NSS_Soft, 0x07);
	
	SPI_Cmd(SPI1, ENABLE);	/* 使能SPI */
	
	/* 配置CS管腳 */
	GPIO_Init(SPI_CS , SPI_Pin_CS, GPIO_Mode_Out_PP_High_Fast);
	GPIO_WriteBit(SPI_CS, SPI_Pin_CS, SET);		/* 拉高不使能外部SPI裝置 */
}
在上面中要注意SPI 使用到的管腳PB5, PB6, PB7 的設定,在SPI主機模式中, PB5、PB6根據外圍電路可以設定為外部上拉輸出,也可設定為上面的內部上拉輸出,而PB7則要設定為內部上拉輸入或浮空輸入(外加上拉電阻),這些設定完還要開啟SPI外設的時鐘。 其中W25Q16的SPI匯流排模式是Mode0 或Mode3 ,這個在手冊中或本文中下面的時序圖中可以看出,那麼對於SPI的初始化就要考慮了,當 SPI_Init中引數為SPI_CPOL_High, SPI_CPHA_2Edge表示Mode0,為SPI_CPOL_Low, SPI_CPHA_1Edge表示Mode3,如果為其他組合那麼就會導致通訊資料錯位不正確。 下面是讀取Flash 廠商ID和裝置ID的函式,
uint8_t SPI_FLASH_SendByte(u8 byte)
{
  /* Loop while DR register in not emplty */
  while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
  /* Send byte through the SPI1 peripheral */
  SPI_SendData(SPI1, byte);
  /* Wait to receive a byte */
  while (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);
  /* Return the byte read from the SPI bus */
  return SPI_ReceiveData(SPI1);	 
 }
uint16_t SPI_FLASH_ReadID(void)
{
	u16 Device_ID = 0;
	/* Select the FLASH: Chip Select low */
	SPI_FLASH_CS_LOW(); //拉低片選管腳電平,選中外設
	/* Send "RDID " instruction */
	SPI_FLASH_SendByte(0x90); //讀取裝置ID指令
	SPI_FLASH_SendByte(0X00);
	SPI_FLASH_SendByte(0X00);
	SPI_FLASH_SendByte(0X00);
	/* Read a byte from the FLASH */
	Device_ID = (SPI_FLASH_SendByte(Dummy_Byte)<<8);
	Device_ID |= SPI_FLASH_SendByte(Dummy_Byte);
	SPI_FLASH_CS_HIGH();//拉高片選管腳電平,
	return Device_ID;
}
在W25Q16的手冊中, 函式讀回來的資料應該是上面的值,再看看手冊上的ID讀取指令0x90

獲取裝置ID的指令傳送順序如上圖,第一位元組先發0x90,然後發兩個dummy Byte(任何數值都可)和0x00,之後再讀取廠商ID和裝置ID,上面的函式基本實現的就是這個時序。 實測的測試結果如下,
結果與手冊給的ID一致。