天天看點

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

我的 github:

https://github.com/lovewinds13/stm32f013_study。

STM32F103 相關代碼均送出到此倉庫。

1. 硬體連接配接

W25Q64 将 8M 的容量分為 128 個塊(Block),每個塊大小為 64K 位元組,每個塊又分為 16個扇區(Sector),每個扇區 4K 個位元組。

W25Q64 的最少擦除機關為一個扇區,也就是每次必須擦除 4K 個位元組。操作需要給 W25Q64 開辟一個至少 4K 的緩存區,對 SRAM 要求比較高,要求晶片必須有 4K 以上 SRAM 才能很好的操作。

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

W25Q64 的擦寫周期多達 10W 次,具有 20 年的資料儲存期限,支援電壓為 2.7~3.6V,W25Q64 支援标準的 SPI,還支援雙輸出/四輸出的 SPI,最大 SPI 時鐘可以到 80Mhz(雙輸出時相當于 160Mhz,四輸出時相當于 320M)。

1.1  硬體連接配接

與 STM32 的引腳連接配接如下:這裡是使用SPI1配置。

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)
STM32引腳 對應SPI功能
PA2 片選CS
PA5 時鐘SCK
PA6 MISO
PA7 MOSI

STM32 的 SPI 功能很強大, SPI 時鐘最多可以到 18Mhz,支援 DMA,可以配置為 SPI 協定或者 I2S 協定(僅大容量型号支援)。

1.2 SPI 通訊的通訊時序

SPI 協定定義了通訊的起始和停止信号、資料有效性、時鐘同步等環節。

我們以讀取 FLASH 的狀态寄存器的時序圖分析一下,時序圖也是書寫軟體模拟時序的依據。

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

如上圖,我們知道書寫 FLASH (來自華邦 W25X 手冊)支援的是模式 0 (CPOL = 0 && CPHA == 0) 和 模式 3(CPOL = 1 && CPHA == 1)

CS、SCK、MOSI 信号都由主機控制産生,而 MISO 的信号由從機産生,主機通過該信号線讀取從機的資料。MOSI 與 MISO 的信号隻在 CS 為低電平的時候才有效,在 SCK 的每個時鐘周期 MOSI 和 MISO 傳輸一位資料。

1.2.1.  通訊的起始和停止信号

在上圖,CS 信号線由高變低,為 SPI 通訊的起始信号。CS 是每個從機各自獨占的信号線,當從機在自己的 CS 線檢測到起始信号後,就知道自己被主機選中了,開始準備與主機通訊。當 CS 信号由低變高,為 SPI 通訊的停止信号,表示本次通訊結束,從機的選中狀态被取消。

1.2.2. 資料有效性

SPI 使用 MOSI 及 MISO 信号線來傳輸資料,使用 SCK 信号線進行資料同步。

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

MOSI 及 MISO 資料線在 SCK 的每個時鐘周期傳輸一位資料。資料傳輸時,MSB 先行或 LSB 先行并沒有作硬性規定,但要保證兩個 SPI 通訊裝置之間使用同樣的協定,一般都會采用圖中的 MSB 先行模式。

觀察上圖,可知模式 0 和 3 都是在上升沿讀取資料。

示例:FLASH 讀取 JEDEC_ID (0x9F),SPI 模式 0,,頻率 f = 1MHz。

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

讀取 JEDEC_ID  時,FLASH 回複的一個字:0xC8。

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

1.2.3 STM32 SPI外設

STM32 的 SPI 外設可用作通訊的主機及從機,支援最高的 SCK 時鐘頻率為 f pclk  / 2 (STM32F103 型号的晶片預設 f pclk1 為 72MHz,f pclk2 為 36MHz),完全支援 SPI 協定的 4 種模式,資料幀長度可設定為 8 位或 16 位,可設定資料 MSB 先行或 LSB 先行。它還支援雙線全雙工、雙線單向以及單線模式。

SPI架構:

stm32 spi slave_SPI專題(二)——STM32驅動FLASH(W25Q64)

通訊引腳 :

SPI 的所有硬體架構都從上圖中左 MOSI、MISO、SCK及 NSS 線展開的。

STM32 晶片有多個 SPI 外設,它們的 SPI 通訊信号引出到不同的 GPIO 引腳上,使用時必須配置到這些指定的引腳。

2. 軟體配置

這裡使用 STM32 的 SPI1 的主模式,SPI 相關的庫函數和定義分布在檔案 stm32f10x_spi.c 以及頭檔案 stm32f10x_spi.h 中。

2.1 配置相關引腳的複用功能

第一步就要使能 SPI1 的時鐘, SPI1 的時鐘通過 APB2ENR 的第 12 位來設定。其次要設定 SPI1 的相關引腳為複用輸出,這樣才會連接配接到 SPI1 上否則這些 IO 口還是預設的狀态,也就是标準輸入輸出口。這裡我們使用的是 PA5、 PA6、 PA7  這 3 個(SCK、 MISO、 MOSI、CS 使用軟體管理方式),是以設定這三個為複用 IO。

宏定義:

IO 配置:

2.2 初始化 SPI1,設定 SPI1 工作模式

接下來初始化 SPI1,設定 SPI1 為主機模式,設定資料格式為 8 位,然設定 SCK 時鐘極性及采樣方式。并設定 SPI1 的時鐘頻率(最大 18Mhz),以及資料的格式(MSB 在前還是 LSB 在前)。這在庫函數中是通過 SPI_Init 函數來實作。

函數原型:

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
           

第一個參數是 SPI 标号,第二個參數結構體類型 SPI_InitTypeDef 為相關屬性設定。

SPI_InitTypeDef 的定義如下:

參數 解釋
SPI_Direction 設定 SPI 的通信方式,可以選擇為半雙工,全雙工,以及串行發和串行收方式
SPI_Mode 設定 SPI 的主從模式,主機模式 (SPI_Mode_Master),從機模式 (PI_Mode_Slave)。
SPI_DataSiz 資料為 8 位還是 16 位幀格式選擇項。SPI_DataSize_8b(8 位),SPI_DataSize_16b (16位)
SPI_CPOL 設定時鐘極性
SPI_CPHA 設定時鐘相位,也就是選擇在串行同步時鐘的第幾個跳變沿(上升或下降)資料被采樣,可以為第一個或者第二個條邊沿采集
SPI_NSS 設定 NSS 信号由硬體(NSS 管腳)還是軟體控制
SPI_BaudRatePrescaler 設定 SPI 波特率預分頻值也就是決定 SPI 的時鐘的參數 ,從不分頻道 256 分頻 8 個可選值 ,選擇 256 分頻值SPI_BaudRatePrescaler_256, 傳輸速度為 36M/256=140.625KHz。
SPI_FirstBit 設定資料傳輸順序是 MSB 位在前還是 LSB 位在前。SPI_FirstBit_MSB (高位在前)
SPI_CRCPolynomial 設定 CRC 校驗多項式,提高通信可靠性,大于 1 即可

初始化的範例格式為:

2.3 SPI 傳輸資料

通信接口需要有發送資料和接受資料的函數,固件庫提供的發送資料函數原型為:

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
           

往 SPIx 資料寄存器寫入資料 Data,進而實作發送。

固件庫提供的接受資料函數原型為:

這從 SPIx 資料寄存器讀出接收到的資料。

收發單個位元組資料:

收發多個位元組資料:

2.4 檢視 SPI 傳輸狀态

在 SPI 傳輸過程中,要判斷資料是否傳輸完成,發送區是否為空等等狀态,

通過函數 SPI_I2S_GetFlagStatus 實作的,判斷發送是否完成的方法是:

3. SPI FLASH 操作

3.1 宏定義部分

3.2 中間層函數封裝

注明: 此部分函數的封裝是為了統一硬體 SPI 和軟體模拟 SPI 接口。

//--------------------------------------------------------------------------------------------------------//    函 數 名: hal_spi_send_bytes//    功能說明: SPI 發送資料,包含軟體和硬體通信方式//    形    參:     mode:通信方式選擇(0:軟體SPI;1:硬體SPI)//                pbdata:發送資料的首位址//                send_length:發送資料長度//    返 回 值: 執行狀态(true or false)//    日    期: 2020-03-12//    備    注: 中間層封裝底層接口//    作    者: by 霁風AI//--------------------------------------------------------------------------------------------------------uint8_t hal_spi_send_bytes(uint8_t mode, uint8_t *pbdata, uint16_t send_length)
{if (mode == 0)
    {for (uint16_t i = 0; i         {
            Spi_WriteByte(pbdata[i]);
        }return true;
    }else if (mode == 1)
    {
        spi_master_send_some_bytes(1, pbdata, send_length);//        for (uint16_t i = 0; i //        {//            spi_master_send_recv_byte(1, pbdata[i]);//        }return true;
    }else 
    {return false;
    }
}//--------------------------------------------------------------------------------------------------------//    函 數 名: hal_spi_recv_bytes//    功能說明: SPI 接收資料,包含軟體和硬體通信方式//    形    參:     mode:通信方式選擇(0:軟體SPI;1:硬體SPI)//                pbdata:發送資料的首位址//                send_length:發送資料長度//    返 回 值: 執行狀态(true or false)//    日    期: 2020-03-12//    備    注: 中間層封裝底層接口//    作    者: by 霁風AI//--------------------------------------------------------------------------------------------------------uint8_t hal_spi_recv_bytes(uint8_t mode, uint8_t *pbdata, uint16_t recv_length)
{if (mode == 0)
    {for (uint16_t i = 0; i         {
             *pbdata++ = Spi_ReadByte();    //軟體模拟SPI
        }   return true;
    }else if (mode == 1)
    {
        spi_master_recv_some_bytes(1, pbdata, recv_length);    //硬體SPI//        for (uint16_t i = 0; i //        {//            *pbdata++ = spi_master_send_recv_byte(1, 0xFF);//        }return true;
    }else 
    {return false;
    }
}
           

關于軟體模拟 SPI 部分代碼,參看:

軟體模拟SPI代碼:

(https://github.com/lovewinds13/stm32f013_study/blob/master/Driver/src/drvsfspi.c) 。

此處不再貼出。

3.3 FLASH 部分