日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

第24章 QSPI—读写串行FLASH

發布時間:2023/12/13 综合教程 43 生活家
生活随笔 收集整理的這篇文章主要介紹了 第24章 QSPI—读写串行FLASH 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本章參考資料:《STM32F76xxx參考手冊》、《STM32F76xxx規格書》、庫幫助文檔《STM32F779xx_User_Manual.chm》及《SPI總線協議介紹》。

若對SPI通訊協議不了解,可先閱讀《SPI總線協議介紹》文檔的內容學習。

關于FLASH存儲器,請參考“常用存儲器介紹”章節,實驗中FLASH芯片的具體參數,請參考其規格書《W25Q128》來了解。

24.1 QSPI協議簡介

QSPI是Queued SPI的簡寫,是Motorola公司推出的SPI接口的擴展,比SPI應用更加廣泛。在SPI協議的基礎上,Motorola公司對其功能進行了增強,增加了隊列傳輸機制,推出了隊列串行外圍接口協議(即QSPI協議)。QSPI 是一種專用的通信接口,連接單、雙或四(條數據線) SPI Flash 存儲介質。

該接口可以在以下三種模式下工作:

①間接模式:使用 QSPI 寄存器執行全部操作

②狀態輪詢模式:周期性讀取外部 Flash 狀態寄存器,而且標志位置 1 時會產生中斷(如擦除或燒寫完成,會產生中斷)

③內存映射模式:外部 Flash 映射到微控制器地址空間,從而系統將其視作內部存儲器

采用雙閃存模式時,將同時訪問兩個 Quad-SPI Flash,吞吐量和容量均可提高二倍。

1.1.1 QSPI功能框圖

QSPI功能框圖,雙閃存模式禁止見圖 24-1。

圖 24-1QUADSPI 功能框圖(雙閃存模式禁止)

我們的開發板采用的是雙閃存禁止的模式連接單片QSPI Flash。QSPI 使用 6 個信號連接Flash,分別是四個數據線BK1_IO0~BK1_IO3,一個時鐘輸出CLK,一個片選輸出(低電平有效)BK1_nCS,它們的作用介紹如下:

(1)BK1_nCS:片選輸出(低電平有效),適用于 FLASH 1。如果 QSPI 始終在雙閃存模式下工作,則其也可用于 FLASH 2從設備選擇信號線。QSPI通訊以BK1_nCS線置低電平為開始信號,以BK1_nCS線被拉高作為結束信號。

(2)CLK:時鐘輸出,適用于兩個存儲器,用于通訊數據同步。它由通訊主機產生,決定了通訊的速率,不同的設備支持的最高時鐘頻率不一樣,如STM32的QSPI時鐘頻率最大為fpclk/2,兩個設備之間通訊時,通訊速率受限于低速設備。

(3)BK1_IO0:在雙線 / 四線模式中為雙向 IO,單線模式中為串行輸出,適用于FLASH 1。

(4)BK1_IO1:在雙線 / 四線模式中為雙向 IO,單線模式中為串行輸入,適用于FLASH 1。

(5)BK1_IO2:在四線模式中為雙向 IO,適用于 FLASH 1。

(6)BK1_IO3:在四線模式中為雙向 IO,適用于 FLASH 1。

24.1.2 QSPI命令序列

QUADSPI 通過命令與 Flash 通信 每條命令包括指令、地址、交替字節、空指令和數據這五個階段 任一階段均可跳過,但至少要包含指令、地址、交替字節或數據階段之一。nCS 在每條指令開始前下降,在每條指令完成后再次上升。先看看QSPI四線模式下的讀命令時序,見圖 24-2。

圖 24-2四線模式下的讀命令時序

1.指令階段

這一階段,將在 QUADSPI_CCR[7:0] 寄存器的 INSTRUCTION 字段中配置的一條 8 位指令發送到 Flash,指定待執行操作的類型。

盡管大多數 Flash 從 IO0/SO 信號(單線 SPI 模式)只能以一次 1 位的方式接收指令,但指令階段可選擇一次發送 2 位(在雙線 SPI 模式中通過 IO0/IO1)或一次發送 4 位(在四線SPI 模式中通過 IO0/IO1/IO2/IO3)。這可通過 QUADSPI_CCR[9:8] 寄存器中的 IMODE[1:0]字段進行配置。

若 IMODE = 00,則跳過指令階段,命令序列從地址階段(如果存在)開始。

1.地址階段

在地址階段,將1-4字節發送到Flash,指示操作地址。待發送的地址字節數在QUADSPI_CCR[13:12]寄存器的ADSIZE[1:0]字段中進行配置。在間接模式和自動輪詢模式下,待發送的地址字節在QUADSPI_AR寄存器的ADDRESS[31:0]中指定在內存映射模式下,則通過 AHB(來自于 Cortex ® 或 DMA)直接給出地址。地址階段可一次發送1 位(在單線SPI模式中通過SO)、2位(在雙線SPI模式中通過IO0/IO1)或4位(在四線 SPI 模式中通過 IO0/IO1/IO2/IO3)。這可通過QUADSPI_CCR[11:10]寄存器中的ADMODE[1:0]字段進行配置。

若 ADMODE = 00,則跳過地址階段,命令序列直接進入下一階段(如果存在)。

2.交替字節階段

在交替字節階段,將 1-4 字節發送到 Flash,一般用于控制操作模式。待發送的交替字節數在 QUADSPI_CCR[17:16] 寄存器的 ABSIZE[1:0] 字段中進行配置。待發送的字節在QUADSPI_ABR 寄存器中指定。

交替字節階段可一次發送 1 位(在單線 SPI 模式中通過 SO)、2 位(在雙線 SPI 模式中通過 IO0/IO1)或 4 位(在四線 SPI 模式中通過 IO0/IO1/IO2/IO3)。這可通過QUADSPI_CCR[15:14] 寄存器中的 ABMODE[1:0] 字段進行配置。

若 ABMODE = 00,則跳過交替字節階段,命令序列直接進入下一階段(如果存在)。交替字節階段存在僅需發送單個半字節而不是一個全字節的情況,比如采用雙線模式并且僅使用兩個周期發送交替字節時。在這種情況下,固件可采用四線模式 (ABMODE = 11) 并發送一個字節,方法是 ALTERNATE 的位 7 和 3 置“1”(IO3 保持高電平)且位 6 和 2 置“0”(IO2 線保持低電平)。此時,半字節的高 2 位存放在 ALTERNATE 的位 4:3,低 2位存放在位 1 和 0 中。例如,如果半字節 2 (0010) 通過 IO0/IO1 發送,則 ALTERNATE 應設置為 0x8A (1000_1010)。

3.空指令周期階段

在空指令周期階段,給定的 1-31 個周期內不發送或接收任何數據,目的是當采用更高的時鐘頻率時,給 Flash 留出準備數據階段的時間。這一階段中給定的周期數在QUADSPI_CCR[22:18] 寄存器的 DCYC[4:0] 字段中指定。在 SDR 和 DDR 模式下,持續時間被指定為一定個數的全時鐘周期。若 DCYC 為零,則跳過空指令周期階段,命令序列直接進入數據階段(如果存在)。空指令周期階段的操作模式由 DMODE 確定。為確保數據信號從輸出模式轉變為輸入模式有足夠的“周轉”時間,使用雙線和四線模式從Flash 接收數據時,至少需要指定一個空指令周期。

4.數據階段

在數據階段,可從 Flash 接收或向其發送任意數量的字節。

在間接模式和自動輪詢模式下,待發送/接收的字節數在 QUADSPI_DLR 寄存器中指定。在間接寫入模式下,發送到 Flash 的數據必須寫入 QUADSPI_DR 寄存器。在間接讀取模式下,通過讀取 QUADSPI_DR 寄存器獲得從 Flash 接收的數據。在內存映射模式下,讀取的數據通過 AHB 直接發送回 Cortex 或 DMA。數據階段可一次發送/接收 1 位(在單線 SPI 模式中通過 SO)、2 位(在雙線 SPI 模式中通過 IO0/IO1)或 4 位(在四線 SPI 模式中通過 IO0/IO1/IO2/IO3)。這可通過QUADSPI_CCR[15:14] 寄存器中的 ABMODE[1:0] 字段進行配置。若 DMODE = 00,則跳過數據階段,命令序列在拉高 nCS 時立即完成。這一配置僅可用于僅間接寫入模式。

24.2 QUADSPI 信號接口協議模式

24.2.1 單線 SPI 模式

傳統 SPI 模式允許串行發送/接收單獨的 1 位。在此模式下,數據通過 SO 信號(其 I/O 與IO0 共享)發送到 Flash。從 Flash 接收到的數據通過 SI(其 I/O 與 IO1 共享)送達。通過將(QUADSPI_CCR 中的)IMODE/ADMODE/ABMODE/DMODE 字段設置為 01,可對不同的命令階段分別進行配置,以使用此單個位模式。在每個已配置為單線模式的階段中:

IO0 (SO) 處于輸出模式
IO1 (SI) 處于輸入模式(高阻抗)
IO2 處于輸出模式并強制置“0”(以禁止“寫保護”功能)
IO3 處于輸出模式并強制置“1”(以禁止“保持”功能)

若 DMODE = 01,這對于空指令階段也同樣如此。

24.2.2 雙線 SPI 模式

在雙線模式下,通過 IO0/IO1 信號同時發送/接收兩位。通過將 QUADSPI_CCR 寄存器的 IMODE/ADMODE/ABMODE/DMODE 字段設置為 10,可對不同的命令階段分別進行配置,以使用雙線 SPI 模式。在每個已配置為單線模式的階段中:

IO0/IO1 在數據階段進行讀取操作時處于高阻態(輸入),在其他情況下為輸出
IO2 處于輸出模式并強制置“0”
IO3 處于輸出模式并強制置“1”

在空指令階段,若 DMODE = 01,則 IO0/IO1 始終保持高阻態。

24.2.3 四線 SPI 模式

在四線模式下,通過 IO0/IO1/IO2/IO3 信號同時發送/接收四位。通過將 QUADSPI_CCR 寄存器的 IMODE/ADMODE/ABMODE/DMODE 字段設置為 11,可對不同的命令階段分別進行配置,以使用四線 SPI 模式。在每個已配置為四線模式的階段中,IO0/IO1/IO2/IO3 在數據階段進行讀取操作時均處于高阻態(輸入),在其他情況下為輸出。在空指令階段中,若 DMODE = 11,則 IO0/IO1/IO2/IO3 均為高阻態。IO2 和 IO3 僅用于 Quad SPI 模式 如果未配置任何階段使用四線 SPI 模式,即使 UADSPI激活,對應 IO2 和 IO3 的引腳也可用于其他功能。

24.2.4 SDR 模式

默認情況下,DDRM 位 (QUADSPI_CCR[31]) 為 0,QUADSPI 在單倍數據速率 (SDR) 模式下工作。在 SDR 模式下,當 QUADSPI 驅動 IO0/SO、IO1、IO2、IO3 信號時,這些信號僅在 CLK的下降沿發生轉變。在 SDR 模式下接收數據時,QUADSPI 假定 Flash 也通過 CLK 的下降沿發送數據。默認情況下 (SSHIFT = 0 時),將使用 CLK 后續的邊沿(上升沿)對信號進行采樣。

24.2.5 DDR 模式

若 DDRM 位 (QUADSPI_CCR[31]) 置 1,則 QUADSPI 在雙倍數據速率 (DDR) 模式下工作。在 DDR 模式下,當 QUADSPI 在地址/交替字節/數據階段驅動 IO0/SO、IO1、IO2、IO3 信號時,將在 CLK 的每個上升沿和下降沿發送 1 位。指令階段不受 DDRM 的影響。始終通過 CLK 的下降沿發送指令。在 DDR 模式下接收數據時,QUADSPI 假定 Flash 通過 CLK 的上升沿和下降沿均發送數據。若 DDRM = 1,固件必須清零 SSHIFT 位 (QUADSPI_CR[4])。因此,在半個 CLK 周期后(下一個反向邊沿)對信號采樣。四線模式下DDR命令時序見圖 24-3。

圖 24-3四線模式下DDR命令時序

24.2.6 雙閃存模式

若 DFM 位 (QUADSPI_CR[6]) 為 1,QUADSPI 處于雙閃存模式。QUADSPI 使用兩個外部四線 SPI Flash(FLASH 1 和 FLASH 2),在每個周期中發送/接收 8 位(在 DDR 模式下為16 位),能夠有效地將吞吐量和容量擴大一倍。每個 Flash 使用同一個 CLK 并可選擇使用同一個 nCS 信號,但其 IO0、IO1、IO2 和 IO3 信號是各自獨立的。雙閃存模式可與單比特模式、雙比特模式以及四比特模式結合使用,也可與 SDR 或 DDR 模

式相結合。Flash 的大小在 FSIZE[4:0] (QUADSPI_DCR[20:16]) 中指定,指定的值應能夠反映 Flash 的總容量,即單個組件容量的 2 倍。如果地址 X 為偶數,QUADSPI 賦給地址 X 的字節是存放于 FLASH 1 的地址 X/2 中的字節,QUADSPI 賦給地址 X+1 的字節是存放于 FLASH 2 的地址 X/2 中的字節。也就是說,偶地址中的字節存儲于 FLASH 1,奇地址中的字節存儲于 FLASH 2。

在雙閃存模式下讀取 Flash 狀態寄存器時,需要讀取的字節數是單閃存模式下的 2 倍。這意味著在狀態寄存器獲取指令到達后,如果每個 Flash 給出 8 個有效位,則 QUADSPI 必須配置為 2 個字節(16 位)的數據長度,它將從每個 Flash 接收 1 個字節。如果每個 Flash 給出一個 16 位的狀態,則 QUADSPI 必須配置為讀取 4 字節,以在雙閃存模式下可獲取兩個Flash 的所有狀態位。結果(在數據寄存器中)的最低有效字節是 FLASH 1 狀態寄存器的最低有效字節,而下一個字節是 FLASH 2 狀態寄存器的最低有效字節。數據寄存器的第三個字節是 FLASH 1 的第二個字節,第四個字節是 FLASH 2 的第二個字節(Flash 具有 16 位狀態寄存器時)。

偶數個字節必須始終在雙閃存模式下訪問。因此,若 DRM = 1,則數據長度字段(QUADSPI_DLR[0]) 的位 0 始終保持為 1。

在雙閃存模式下,FLASH 1 接口信號的行為基本上與正常模式下相同。在指令、地址、交替字節以及空指令周期階段,FLASH 2 接口信號具有與 FLASH 1 接口信號完全相同的波形。也就是說,每個 Flash 總是接收相同的指令與地址。然后,在數據階段,BK1_IOx 和BK2_IOx 總線并行傳輸數據,但發送到 FLASH 1(或從其接收)的數據與 FLASH 2 中的不同。

24.3 QUADSPI 間接模式

在間接模式下,通過寫入 QUADSPI 寄存器來觸發命令;并通過讀寫數據寄存器來傳輸數據,就如同對待其他通信外設那樣。

若 FMODE = 00 (QUADSPI_CCR[27:26]),則 QUADSPI 處于間接寫入模式,字節在數據階段中發送到 Flash。通過寫入數據寄存器 (QUADSPI_DR) 的方式提供數據。

若 FMODE = 01,則 QUADSPI 處于間接讀取模式,在數據階段中從 Flash 接收字節。通過讀取 QUADSPI_DR 來獲取數據。

讀取/寫入的字節數在數據長度寄存器 QUADSPI_DLR) 中指定。

如果 QUADSPI_DLR =0xFFFF_FFFF(全為“1”),則數據長度視為未定義,QUADSPI 將繼續傳輸數據,直到到達(由 FSIZE 定義的)Flash 的結尾。如果不傳輸任何字節,DMODE (QUADSPI_CCR[25:24])應設置為 00。如果 QUADSPI_DLR = 0xFFFF_FFFF 并且 FSIZE = 0x1F(最大值指示一個 4GB 的Flash),在此特殊情況下,傳輸將無限繼續下去,僅在出現終止請求或 QUADSPI 被禁止后停止。在讀取最后一個存儲器地址后(地址為 0xFFFF_FFFF),將從地址 = 0x0000_0000開始繼續讀取。

當發送或接收的字節數達到編程設定值時,如果 TCIE = 1,則 TCF 置 1 并產生中斷。在數據數量不確定的情況下,將根據 QUADSPI_CR 中定義的 Flash 大小,在達到外部 SPI 的限制時,TCF 置 1。

24.3.1 觸發命令啟動

從本質上講,在固件給出命令所需的最后一點信息時,命令即會啟動。根據 QUADSPI 的配置,在間接模式下有三種觸發命令啟動的方式。在出現以下情形時,命令立即啟動:

1、對 INSTRUCTION[7:0] (QUADSPI_CCR) 執行寫入操作,如果沒有地址是必需的(當ADMODE = 00)并且不需要固件提供數據(當 FMODE = 01 或 DMODE = 00);

2、對 ADDRESS[31:0] (QUADSPI_AR) 執行寫入操作,如果地址是必需的(當 ADMODE =00)并且不需要固件提供數據 (當 FMODE = 01 或 DMODE = 00);

3、對 DATA[31:0] (QUADSPI_DR) 執行寫入操作,如果地址是必需的(當 ADMODE != 00)并且需要固件提供數據(當 FMODE = 00 并且 DMODE != 00)。

寫入交替字節寄存器 (QUADSPI_ABR) 始終不會觸發命令啟動。如果需要交替字節,必須預先進行編程。如果命令啟動,BUSY 位(QUADSPI_SR 的位 5)將自動置 1。

24.3.2 FIFO 和數據管理

在間接模式中,數據將通過 QUADSPI 內部的一個 32 字節 FIFO。FLEVEL[5:0](QUADSPI_SR[13:8]) 指示 FIFO 目前保存了多少字節。

在間接寫入模式下 (FMODE = 00),固件寫入 QUADSPI_DR 時,將在 FIFO 中加入數據。字寫入將在 FIFO 中增加 4 個字節,半字寫入增加 2 個字節,而字節寫入僅增加 1 個字節。如果固件在 FIFO 中加入的數據過多(超過 DL[31:0] 指示的值),將在寫入操作結束(TCF置 1)時從 FIFO 中清除超出的字節。

對 QUADSPI_DR 的字節/半字訪問必須僅針對該 32 位寄存器的最低有效字節/半字。FTHRES[3:0] 用于定義 FIFO 的閾值 如果達到閾值,FTF(FIFO 閾值標志)置 1 在間接讀取模式下,從 FIFO 中讀取的有效字節數超過閾值時,FTF 置 1。從 Flash 中讀取最后一個字節后,如果 FIFO 中依然有數據,則無論 FTHRES 的設置為何,FTF 也都會置 1。在間接寫入模式下,當 FIFO 中的空字節數超過閾值時,FTF 置 1。

如果 FTIE = 1,則 FTF 置 1 時產生中斷。如果 DMAEN = 1,則 FTF 置 1 時啟動數據傳送。如果閾值條件不再為“真”(CPU 或 DMA 傳輸了足夠的數據后),則 FTF 由 HW 清零。在間接模式下,當 FIFO 已滿,QUADSPI 將暫時停止從 Flash 讀取字節以避免上溢。請注意,只有在 FIFO 中的 4 個字節為空 (FLEVEL ≤ 11) 時才會重新開始讀取 Flash。因此,若FTHRES ≥ 13,應用程序必須讀取足夠的字節以確保 QUADSPI 再次從 Flash 檢索數據。否則,只要 11 < FLEVEL < FTHRES,FTF 標志將保持為“0”。

24.4 QUADSPI Flash 配置

外部 SPI Flash的參數可以通過配置寄存器 (QUADSPI_DCR)實現。這里配置Flash的容量是設置FSIZE[4:0] 字段,使用下面的公式定義外部存儲器的大小:

FSIZE+1 是對 Flash 尋址所需的地址位數。在間接模式下,Flash 容量最高可達 4GB(使用32 位進行尋址),但在內存映射模式下的可尋址空間限制為 256MB。如果 DFM = 1,FSIZE 表示兩個 Flash 容量的總和。QUADSPI 連續執行兩條命令時,它在兩條命令之間將片選信號 (nCS) 置為高電平默認僅一個 CLK 周期時長。如果 Flash 需要命令之間的時間更長,可使用片選高電平時間 (CSHT) 字段指定 nCS 必須保持高電平的最少 CLK 周期數(最大為 8)。時鐘模式 (CKMODE) 位指示命令之間的 CLK 信號邏輯電平(nCS = 1 時)。

24.5 QSPI初始化結構體詳解

跟其它外設一樣,STM32 HAL庫提供了QSPI初始化結構體及初始化函數來配置SPI外設。初始化結構體及函數定義在庫文件“stm32f7xx_hal_spi.h”及“stm32f7xx_hal _spi.c”中,編程時我們可以結合這兩個文件內的注釋使用或參考庫幫助文檔。了解初始化結構體后我們就能對SPI外設運用自如了,見代碼清單 241。

代碼清單 241QSPI_InitTypeDef初始化結構體

1 typedefstruct{

2 uint32_tClockPrescaler; //預分頻因子

3 uint32_tFifoThreshold; //FIFO中的閾值

4 uint32_tSampleShifting; //采樣移位

5 uint32_tFlashSize; //Flash大小

6 uint32_tChipSelectHighTime; //片選高電平時間

7 uint32_tClockMode; //時鐘模式

8 uint32_tFlashID; //Flash ID

9 uint32_tDualFlash; //雙閃存模式

10 } QSPI_InitTypeDef;

這些結構體成員說明如下,其中括號內的文字是對應參數在STM32 HAL庫中定義的宏:

(1)ClockPrescaler

本成員設置預分頻因子,對應寄存器QUADSPI_CR[31:24]即PRESCALER[7:0],取值范圍是0—255,可以實現1—256級別的分頻。僅可在 BUSY = 0 時修改該字段。

(2)FifoThreshold

本成員設置FIFO 閾值級別,對應寄存器QUADSPI_CR[12:8]即FTHRES[4:0],定義在間接模式下 FIFO 中將導致 FIFO 閾值標志(FTF,QUADSPI_SR[2])置 1 的字節數閾值。

(3)SampleShifting

本成員設置采樣,對應寄存器QUADSPI_CR[4],默認情況下,QUADSPI 在 Flash 驅動數據后過半個 CLK 周期開始采集數據。使用該位,可考慮外部信號延遲,推遲數據采集。可以取值0:不發生移位;1:移位半個周期。在 DDR 模式下 (DDRM = 1),固件必須確保 SSHIFT = 0。

(4)FlashSize

本成員設置FLASH大小,對應寄存器QUADSPI_CCR[20:16]的FSIZE[4:0]位。定義外部存儲器的大小,簡介模式Flash容量最高可達4GB(32位尋址),但是在內存映射模式下限制為256MB,如果是雙閃存則可以達到512MB。

(5)ChipSelectHighTime

本成員設置片選高電平時間,對應寄存器QUADSPI_CR[10:8]的CSHT[2:0]位,定義片選 (nCS) 在發送至 Flash 的命令之間必須保持高電平的最少 CLK 周期數。可以取值1~8個周期。

(6)ClockMode

本成員設置時鐘模式,對應寄存器QUADSPI_CR[0]位,指示CLK在命令之間的電平,可以選模式0,1: nCS 為高電平(片選釋放)時,CLK 必須保持低電平;或者模式3 ,1:nCS 為高電平(片選釋放)時,CLK 必須保持高電平。

(7)FlashID

本成員用于選擇Flash1或者Flash2,單閃存模式下選擇需要訪問的flash。

(8)DualFlash

本成員用于激活雙閃存模式,0:禁止雙閃存模式;1:使能雙閃存模式。雙閃存模式可以使系統吞吐量和容量擴大一倍。

代碼清單 242QSPI_CommandTypeDe通信配置命令結構體

1 typedefstruct{

2 uint32_tInstruction; //指令

3 uint32_tAddress; //地址

4 uint32_tAlternateBytes; //交替字節

5 uint32_tAddressSize; //地址長度

6 uint32_tAlternateBytesSize; //交替字節長度

7 uint32_tDummyCycles; //空指令周期

8 uint32_tInstructionMode; //指令模式

9 uint32_tAddressMode; //地址模式

10 uint32_tAlternateByteMode; //交替字節模式

11 uint32_tDataMode; //數據模式

12 uint32_tNbData; //數據長度

13 uint32_tDdrMode; //雙倍數據速率模式

14 uint32_tDdrHoldHalfCycle; //DDR保持周期

15 uint32_tSIOOMode; //僅發送指令一次模式

16 } QSPI_CommandTypeDef;

這些結構體成員說明如下,其中括號內的文字是對應參數在STM32 HAL庫中定義的宏:

(1)Instruction

本成員設置通信指令,指定要發送到外部 SPI 設備的指令。僅可在 BUSY = 0 時修改該字段。

(2)Address

本成員指定要發送到外部 Flash 的地址,BUSY = 0 或 FMODE = 11(內存映射模式)時,將忽略寫入該字段。在雙閃存模式下,由于地址始終為偶地址,ADDRESS[0] 自動保持為“0”。

(3)AlternateBytes

本成員指定要在地址后立即發送到外部 SPI 設備的可選數據,僅可在 BUSY = 0 時修改該字段。

(4)AddressSize

本成員定義地址長度,可以是8位,16位,24位或者32位。

(5)AlternateBytesSize

本成員定義交替字節長度,可以是8位,16位,24位或者32位。

(6)DummyCycles

本成員定義空指令階段的持續時間,在 SDR 和 DDR 模式下,它指定 CLK 周期數 (0-31)。

(7)InstructionMode

本成員定義指令階段的操作模式,00:無指令;01:單線傳輸指令;10:雙線傳輸指令;11:四線傳輸指令。

(8)AddressMode

本成員定義地址階段的操作模式,00:無地址;01:單線傳輸地址;10:雙線傳輸地址;11:四線傳輸地址。

(9)AlternateByteMode

本成員定義交替字節階段的操作模式00:無交替字節;01:單線傳輸交替字節;10:雙線傳輸交替字節;11:四線傳輸交替字節。

(10)DataMode

本成員定義數據階段的操作模式,00:無數據;01:單線傳輸數據;10:雙線傳輸數據;11:四線傳輸數據。該字段還定義空指令階段的操作模式。

(11)NbData

本成員設置數據長度,在間接模式和狀態輪詢模式下待檢索的數據數量(值 + 1)。對狀態輪詢模式應使用不大于 3 的值(表示 4 字節)。

(12)DdrMode

本成員為地址、交替字節和數據階段設置 DDR 模式,0:禁止 DDR 模式;1:使能 DDR 模式。

(13)DdrHoldHalfCycle

本成員設置DDR 模式下數據輸出延遲 1/4 個 QUADSPI 輸出時鐘周期,0:使用模擬延遲來延遲數據輸出;1:數據輸出延遲 1/4 個 QUADSPI 輸出時鐘周期。僅在 DDR 模式下激活。

(14)SIOOMode

本成員設置僅發送指令一次模式,。IMODE = 00 時,該位不起作用。0:在每個事務中發送指令;1:僅為第一條命令發送指令。

24.6 QSPI—讀寫串行FLASH實驗

FLSAH存儲器又稱閃存,它與EEPROM都是掉電后數據不丟失的存儲器,但FLASH存儲器容量普遍大于EEPROM,現在基本取代了它的地位。我們生活中常用的U盤、SD卡、SSD固態硬盤以及我們STM32芯片內部用于存儲程序的設備,都是FLASH類型的存儲器。在存儲控制上,最主要的區別是FLASH芯片只能一大片一大片地擦寫,而在“I2C章節”中我們了解到EEPROM可以單個字節擦寫。

本小節以一種使用QSPI通訊的串行FLASH存儲芯片的讀寫實驗為大家講解STM32的QSPI使用方法。實驗中STM32的QSPI外設采用主模式,通過查詢事件的方式來確保正常通訊。

24.6.1 硬件設計

圖 24-4SPI串行FLASH硬件連接圖

本實驗板中的FLASH芯片(型號:W25Q128)是一種使用QSPI/SPI通訊協議的NOR FLASH存儲器,它的CS/CLK/D0/D1/D2/D3引腳分別連接到了STM32對應的QSPI引腳QUADSPI_BK1_NCS/QUADSPI_CLK/QUADSPI_BK1_IO0/QUADSPI_BK1_IO1/QUADSPI_BK1_IO2/QUADSPI_BK1_IO3上,這些引腳都是STM32的復用引腳。

關于FLASH芯片的更多信息,可參考其數據手冊《W25Q128》來了解。若您使用的實驗板FLASH的型號或控制引腳不一樣,只需根據我們的工程修改即可,程序的控制原理相同。

24.6.2 軟件設計

為了使工程更加有條理,我們把讀寫FLASH相關的代碼獨立分開存儲,方便以后移植。在“工程模板”之上新建“bsp_qspi_flash.c”及“bsp_qspi_ flash.h”文件,這些文件也可根據您的喜好命名,它們不屬于STM32 HAL庫的內容,是由我們自己根據應用需要編寫的。

1.編程要點

(1)初始化通訊使用的目標引腳及端口時鐘;

(2)使能SPI外設的時鐘;

(3)配置SPI外設的模式、地址、速率等參數并使能SPI外設;

(4)編寫基本SPI按字節收發的函數;

(5)編寫對FLASH擦除及讀寫操作的的函數;

(6)編寫測試程序,對讀寫數據進行校驗。

2.代碼分析
控制FLASH的指令

FLASH芯片自定義了很多指令,我們通過控制STM32利用QSPI總線向FLASH芯片發送指令,FLASH芯片收到后就會執行相應的操作。

而這些指令,對主機端(STM32)來說,只是它遵守最基本的QSPI通訊協議發送出的數據,但在設備端(FLASH芯片)把這些數據解釋成不同的意義,所以才成為指令。查看FLASH芯片的數據手冊《W25Q128》,可了解各種它定義的各種指令的功能及指令格式,見表 24-1。

表 24-1FLASH常用芯片指令表(摘自規格書《W25Q128》)

指令

第一字節(指令編碼)

第二字節

第三字節

第四字節

第五字節

第六字節

第七-N字節

Write Enable

06h

 

 

 

 

 

 

Write Disable

04h

 

 

 

 

 

 

Read StatusRegister

05h

(S7–S0)

 

 

 

 

Write StatusRegister

01h

(S7–S0)

 

 

 

 

 

Read Data

03h

A23–A16

A15–A8

A7–A0

(D7–D0)

(Next byte)

continuous

Fast Read

0Bh

A23–A16

A15–A8

A7–A0

dummy

(D7–D0)

(Next Byte)continuous

Fast Read DualOutput

3Bh

A23–A16

A15–A8

A7–A0

dummy

I/O = (D6,D4,D2,D0) O = (D7,D5,D3,D1)

(one byteper 4 clocks, continuous)

Page Program

02h

A23–A16

A15–A8

A7–A0

D7–D0

Next byte

Up to 256 bytes

Block Erase(64KB)

D8h

A23–A16

A15–A8

A7–A0

 

 

 

Sector Erase(4KB)

20h

A23–A16

A15–A8

A7–A0

 

 

 

Chip Erase

C7h

 

 

 

 

 

 

Power-down

B9h

 

 

 

 

 

 

Release Power- down / Device ID

ABh

dummy

dummy

dummy

(ID7-ID0)

 

 

Manufacturer/ Device ID

90h

dummy

dummy

00h

(M7-M0)

(ID7-ID0)

 

JEDEC ID

9Fh

(M7-M0)

生產廠商

(ID15-ID8)

存儲器類型

(ID7-ID0)容量

 

 

 

該表中的第一列為指令名,第二列為指令編碼,第三至第N列的具體內容根據指令的不同而有不同的含義。其中帶括號的字節參數,方向為FLASH向主機傳輸,即命令響應,不帶括號的則為主機向FLASH傳輸。表中“A0~A23”指FLASH芯片內部存儲器組織的地址;“M0~M7”為廠商號(MANUFACTURER ID);“ID0-ID15”為FLASH芯片的ID;“dummy”指該處可為任意數據;“D0~D7”為FLASH內部存儲矩陣的內容。

在FLSAH芯片內部,存儲有固定的廠商編號(M7-M0)和不同類型FLASH芯片獨有的編號(ID15-ID0),見表 24-2。

表 24-2FLASH數據手冊的設備ID說明

FLASH型號

廠商號(M7-M0)

FLASH型號(ID15-ID0)

W25Q64

EF h

4017 h

W25Q128

EF h

4018 h

通過指令表中的讀ID指令“JEDEC ID”可以獲取這兩個編號,該指令編碼為“9F h”,其中“9F h”是指16進制數“9F” (相當于C語言中的0x9F)。緊跟指令編碼的三個字節分別為FLASH芯片輸出的“(M7-M0)”、“(ID15-ID8)”及“(ID7-ID0)”。

此處我們以該指令為例,配合其指令時序圖進行講解,見圖 24-5。

圖 24-5FLASH讀ID指令“JEDEC ID”的時序(摘自規格書《W25Q128》)

主機首先通過DIO(對應STM32的QUADSPI_BK1_IO0)線向FLASH芯片發送第一個字節數據為“9F h”,當FLASH芯片收到該數據后,它會解讀成主機向它發送了“JEDEC指令”,然后它就作出該命令的響應:通過DO(對應STM32的QUADSPI_BK1_IO1)線把它的廠商ID(M7-M0)及芯片類型(ID15-0)發送給主機,主機接收到指令響應后可進行校驗。常見的應用是主機端通過讀取設備ID來測試硬件是否連接正常,或用于識別設備。

對于FLASH芯片的其它指令,都是類似的,只是有的指令包含多個字節,或者響應包含更多的數據。

實際上,編寫設備驅動都是有一定的規律可循的。首先我們要確定設備使用的是什么通訊協議。如上一章的EEPROM使用的是I2C,本章的FLASH使用的是QSPI。那么我們就先根據它的通訊協議,選擇好STM32的硬件模塊,并進行相應的I2C或SPI模塊初始化。接著,我們要了解目標設備的相關指令,因為不同的設備,都會有相應的不同的指令。如EEPROM中會把第一個數據解釋為內部存儲矩陣的地址(實質就是指令)。而FLASH則定義了更多的指令,有寫指令,讀指令,讀ID指令等等。最后,我們根據這些指令的格式要求,使用通訊協議向設備發送指令,達到控制設備的目標。

定義FLASH指令編碼表

為了方便使用,我們把FLASH芯片的常用指令編碼使用宏來封裝起來,后面需要發送指令編碼的時候我們直接使用這些宏即可,見代碼清單 24-3。

代碼清單 24-3FLASH指令編碼表

1 /**

2 * @brief W25Q128FV 指令

3 */

4 /* 復位操作 */

5 #define RESET_ENABLE_CMD 0x66

6 #define RESET_MEMORY_CMD 0x99

7

8 #define ENTER_QPI_MODE_CMD 0x38

9 #define EXIT_QPI_MODE_CMD 0xFF

10

11 /* 識別操作 */

12 #define READ_ID_CMD 0x90

13 #define DUAL_READ_ID_CMD 0x92

14 #define QUAD_READ_ID_CMD 0x94

15 #define READ_JEDEC_ID_CMD 0x9F

16

17 /* 讀操作 */

18 #define READ_CMD 0x03

19 #define FAST_READ_CMD 0x0B

20 #define DUAL_OUT_FAST_READ_CMD 0x3B

21 #define DUAL_INOUT_FAST_READ_CMD 0xBB

22 #define QUAD_OUT_FAST_READ_CMD 0x6B

23 #define QUAD_INOUT_FAST_READ_CMD 0xEB

24

25 /* 寫操作 */

26 #define WRITE_ENABLE_CMD 0x06

27 #define WRITE_DISABLE_CMD 0x04

28

29 /* 寄存器操作 */

30 #define READ_STATUS_REG1_CMD 0x05

31 #define READ_STATUS_REG2_CMD 0x35

32 #define READ_STATUS_REG3_CMD 0x15

33

34 #define WRITE_STATUS_REG1_CMD 0x01

35 #define WRITE_STATUS_REG2_CMD 0x31

36 #define WRITE_STATUS_REG3_CMD 0x11

37

38

39 /* 編程操作 */

40 #define PAGE_PROG_CMD 0x02

41 #define QUAD_INPUT_PAGE_PROG_CMD 0x32

42 #define EXT_QUAD_IN_FAST_PROG_CMD 0x12

43

44 /* 擦除操作 */

45 #define SECTOR_ERASE_CMD 0x20

46 #define CHIP_ERASE_CMD 0xC7

47

48 #define PROG_ERASE_RESUME_CMD 0x7A

49#define PROG_ERASE_SUSPEND_CMD 0x75

SPI硬件相關宏定義

我們把SPI硬件相關的配置都以宏的形式定義到 “bsp_qspi_ flash.h”文件中,見代碼清單 244。

代碼清單 244SPI硬件配置相關的宏

1 #define QSPI_FLASH QUADSPI

2 #define QSPI_FLASH_CLK_ENABLE() __QSPI_CLK_ENABLE()

3

4 #define QSPI_FLASH_CLK_PIN GPIO_PIN_2

5 #define QSPI_FLASH_CLK_GPIO_PORT GPIOB

6 #define QSPI_FLASH_CLK_GPIO_ENABLE() __GPIOB_CLK_ENABLE()

7 #define QSPI_FLASH_CLK_GPIO_AF GPIO_AF9_QUADSPI

8

9 #define QSPI_FLASH_BK1_IO0_PIN GPIO_PIN_8

10 #define QSPI_FLASH_BK1_IO0_PORT GPIOF

11 #define QSPI_FLASH_BK1_IO0_CLK_ENABLE() __GPIOF_CLK_ENABLE()

12 #define QSPI_FLASH_BK1_IO0_AF GPIO_AF10_QUADSPI

13

14 #define QSPI_FLASH_BK1_IO1_PIN GPIO_PIN_9

15 #define QSPI_FLASH_BK1_IO1_PORT GPIOF

16 #define QSPI_FLASH_BK1_IO1_CLK_ENABLE() __GPIOF_CLK_ENABLE()

17 #define QSPI_FLASH_BK1_IO1_AF GPIO_AF10_QUADSPI

18

19 #define QSPI_FLASH_BK1_IO2_PIN GPIO_PIN_7

20 #define QSPI_FLASH_BK1_IO2_PORT GPIOF

21 #define QSPI_FLASH_BK1_IO2_CLK_ENABLE() __GPIOF_CLK_ENABLE()

22 #define QSPI_FLASH_BK1_IO2_AF GPIO_AF9_QUADSPI

23

24 #define QSPI_FLASH_BK1_IO3_PIN GPIO_PIN_6

25 #define QSPI_FLASH_BK1_IO3_PORT GPIOF

26 #define QSPI_FLASH_BK1_IO3_CLK_ENABLE() __GPIOF_CLK_ENABLE()

27 #define QSPI_FLASH_BK1_IO3_AF GPIO_AF9_QUADSPI

28

29 #define QSPI_FLASH_CS_PIN GPIO_PIN_6

30 #define QSPI_FLASH_CS_GPIO_PORT GPIOB

31 #define QSPI_FLASH_CS_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE()

32 #define QSPI_FLASH_CS_GPIO_AF GPIO_AF10_QUADSPI

以上代碼根據硬件連接,把與FLASH通訊使用的QSPI 、引腳號、引腳源以及復用功能映射都以宏封裝起來。

初始化QSPI的 GPIO

利用上面的宏,編寫QSPI的初始化函數,見代碼清單 24-5。

代碼清單 24-5QSPI的初始化函數

1 /**

2 * @brief QSPI_FLASH引腳初始化

3 * @param 無

4 * @retval 無

5 */

6 voidQSPI_FLASH_Init(void)

7 {

8

9 GPIO_InitTypeDef GPIO_InitStruct;

10

11 /* 使能 QSPI 及 GPIO 時鐘 */

12 QSPI_FLASH_CLK_ENABLE();

13 QSPI_FLASH_CLK_GPIO_ENABLE();

14 QSPI_FLASH_BK1_IO0_CLK_ENABLE();

15 QSPI_FLASH_BK1_IO1_CLK_ENABLE();

16 QSPI_FLASH_BK1_IO2_CLK_ENABLE();

17 QSPI_FLASH_BK1_IO3_CLK_ENABLE();

18 QSPI_FLASH_CS_GPIO_CLK_ENABLE();

19

20 //設置引腳

21 /*!< 配置 QSPI_FLASH 引腳: CLK */

22 GPIO_InitStruct.Pin = QSPI_FLASH_CLK_PIN;

23 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

24 GPIO_InitStruct.Pull = GPIO_NOPULL;

25 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

26 GPIO_InitStruct.Alternate = QSPI_FLASH_CLK_GPIO_AF;

27

28 HAL_GPIO_Init(QSPI_FLASH_CLK_GPIO_PORT, &GPIO_InitStruct);

29

30 /*!< 配置 QSPI_FLASH 引腳: IO0 */

31 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO0_PIN;

32 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO0_AF;

33 HAL_GPIO_Init(QSPI_FLASH_BK1_IO0_PORT, &GPIO_InitStruct);

34

35 /*!< 配置 QSPI_FLASH 引腳: IO1 */

36 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO1_PIN;

37 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO1_AF;

38 HAL_GPIO_Init(QSPI_FLASH_BK1_IO1_PORT, &GPIO_InitStruct);

39

40 /*!< 配置 QSPI_FLASH 引腳: IO2 */

41 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO2_PIN;

42 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO2_AF;

43 HAL_GPIO_Init(QSPI_FLASH_BK1_IO2_PORT, &GPIO_InitStruct);

44

45 /*!< 配置 QSPI_FLASH 引腳: IO3 */

46 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO3_PIN;

47 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO3_AF;

48 HAL_GPIO_Init(QSPI_FLASH_BK1_IO3_PORT, &GPIO_InitStruct);

49

50 /*!< 配置 SPI_FLASH_SPI 引腳: NCS */

51 GPIO_InitStruct.Pin = QSPI_FLASH_CS_PIN;

52 GPIO_InitStruct.Alternate = QSPI_FLASH_CS_GPIO_AF;

53 HAL_GPIO_Init(QSPI_FLASH_CS_GPIO_PORT, &GPIO_InitStruct);

54

55 /* QSPI_FLASH 模式配置 */

56 QSPIHandle.Instance = QUADSPI;

57 QSPIHandle.Init.ClockPrescaler = 2;

58 QSPIHandle.Init.FifoThreshold = 4;

59 QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;

60 QSPIHandle.Init.FlashSize = 23;

61 QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_8_CYCLE;

62 QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;

63 HAL_QSPI_Init(&QSPIHandle);

64 /*初始化QSPI接口*/

65 BSP_QSPI_Init();

66}

與所有使用到GPIO的外設一樣,都要先把使用到的GPIO引腳模式初始化,配置好復用功能。GPIO初始化流程如下:

(1)使用GPIO_InitTypeDef定義GPIO初始化結構體變量,以便下面用于存儲GPIO配置;

(2)調用宏定義使能QSPI引腳使用的GPIO端口時鐘和QSPI外設時鐘。

(3)向GPIO初始化結構體賦值,把CLK/IO0/IO1/IO2/IO3/NCS引腳初始化成復用推挽模式。

(4)使用以上初始化結構體的配置,調用HAL_GPIO_Init函數向寄存器寫入參數,完成GPIO的初始化。

(5)以上只是配置了QSPI使用的引腳,對QSPI外設模式的配置。在配置STM32的QSPI模式前,我們要先了解從機端的QSPI模式。本例子中可通過查閱FLASH數據手冊《W25Q128》獲取。根據FLASH芯片的說明,它支持SPI模式0及模式3,支持四線模式,支持最高通訊時鐘為104MHz,數據幀長度為8位。我們要把STM32的QSPI外設中的這些參數配置一致。見代碼清單 24-5。

(6)配置QSPI接口模式;時鐘三分頻最高通訊時鐘為72MHz(Flash最高支持104MHz);FIFO 閾值為 4 個字節;采樣移位半個周期;SPI FLASH 大小;W25Q128 大小為16M 字節,即這里地址位數為23+1=24,所以取值23;片選高電平時間為 1個時鐘(9.2*6=55.2ns),即手冊里面的 ;時鐘模式選擇為0;根據硬件連接選擇第一片Flash;最后調用HAL_QSPI_Init函數初始化QSPI模式。

初始化QSPI存儲器

初始化好QSPI外設后,還要初始化初始化QSPI存儲器,需要先復位存儲器,使能寫操作,配置狀態寄存器才可進行數據讀寫操作,見代碼清單 24-6。

代碼清單 24-6初始化QSPI存儲器

1 /**

2 * @brief初始化QSPI存儲器

3 * @retval QSPI存儲器狀態

4 */

5 uint8_tBSP_QSPI_Init(void)

6 {

7 QSPI_CommandTypeDef s_command;

8 uint8_tvalue = W25Q128FV_FSR_QE;

9

10 /* QSPI存儲器復位 */

11 if(QSPI_ResetMemory() != QSPI_OK) {

12 returnQSPI_NOT_SUPPORTED;

13 }

14

15 /* 使能寫操作 */

16 if(QSPI_WriteEnable() != QSPI_OK) {

17 returnQSPI_ERROR;

18 }

19 /* 設置四路使能的狀態寄存器,使能四通道IO2和IO3引腳 */

20 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

21 s_command.Instruction = WRITE_STATUS_REG2_CMD;

22 s_command.AddressMode = QSPI_ADDRESS_NONE;

23 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

24 s_command.DataMode = QSPI_DATA_1_LINE;

25 s_command.DummyCycles = 0;

26 s_command.NbData = 1;

27 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

28 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

29 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

30 /* 配置命令 */

31if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){

32 returnQSPI_ERROR;

33 }

34 /* 傳輸數據 */

35if(HAL_QSPI_Transmit(&QSPIHandle, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){

36 returnQSPI_ERROR;

37 }

38 /* 自動輪詢模式等待存儲器就緒 */

39 if(QSPI_AutoPollingMemReady(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) {

40 returnQSPI_ERROR;

41 }

42 returnQSPI_OK;

43 }

使用QSPI讀取大量數據

我們要從存取器中讀取大量數據,首先要用一個指針指向讀回來數據,并確定數據的首地址,數據大小,通過庫函數HAL_QSPI_Command發送配置命令,然后調用庫函數HAL_QSPI_Receive接收數據,最后等待操作完成,我們看看它的代碼實現,見代碼清單 247。

代碼清單 247使用QSPI讀取大量數據

1 /**

2 * @brief 從QSPI存儲器中讀取大量數據.

3 * @param pData: 指向要讀取的數據的指針

4 * @param ReadAddr: 讀取起始地址

5 * @param Size: 要讀取的數據大小

6 * @retval QSPI存儲器狀態

7 */

8 uint8_tBSP_QSPI_Read(uint8_t* pData, uint32_tReadAddr, uint32_tSize)

9 {

10 QSPI_CommandTypeDef s_command;

11 /* 初始化讀命令 */

12 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

13 s_command.Instruction = READ_CMD;

14 s_command.AddressMode = QSPI_ADDRESS_1_LINE;

15 s_command.AddressSize = QSPI_ADDRESS_24_BITS;

16 s_command.Address = ReadAddr;

17 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

18 s_command.DataMode = QSPI_DATA_1_LINE;

19 s_command.DummyCycles = 0;

20 s_command.NbData = Size;

21 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

22 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

23 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

24

25 /* 配置命令 */

26if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){

27 returnQSPI_ERROR;

28 }

29

30 /* 接收數據 */

31 if(HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK) {

32 returnQSPI_ERROR;

33 }

34 returnQSPI_OK;

35 }

使用QSPI寫入大量數據

我們要從存取器中寫入大量數據,首先要用一個指針指寫入數據,并確定數據的首地址,數據大小,根據寫入地址及大小判斷存儲器的頁面,然后通過庫函數HAL_QSPI_Command發送配置命令,然后調用庫函數HAL_QSPI_Transmit逐頁寫入數據,最后等待操作完成,我們看看它的代碼實現,見代碼清單 248。

代碼清單 248使用QSPI讀取大量數據

1 /**

2 * @brief 將大量數據寫入QSPI存儲器

3 * @param pData: 指向要寫入數據的指針

4 * @param WriteAddr: 寫起始地址

5 * @param Size: 要寫入的數據大小

6 * @retval QSPI存儲器狀態

7 */

8 uint8_tBSP_QSPI_Write(uint8_t* pData, uint32_tWriteAddr, uint32_tSize)

9 {

10 QSPI_CommandTypeDef s_command;

11 uint32_tend_addr, current_size, current_addr;

12 /* 計算寫入地址和頁面末尾之間的大小 */

13 current_addr = 0;

14

15 while(current_addr <= WriteAddr) {

16 current_addr += W25Q128FV_PAGE_SIZE;

17 }

18 current_size = current_addr - WriteAddr;

19

20 /* 檢查數據的大小是否小于頁面中的剩余位置 */

21 if(current_size > Size) {

22 current_size = Size;

23 }

24

25 /* 初始化地址變量 */

26 current_addr = WriteAddr;

27 end_addr = WriteAddr + Size;

28

29 /* 初始化程序命令 */

30 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

31 s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD;

32 s_command.AddressMode = QSPI_ADDRESS_1_LINE;

33 s_command.AddressSize = QSPI_ADDRESS_24_BITS;

34 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

35 s_command.DataMode = QSPI_DATA_4_LINES;

36 s_command.DummyCycles = 0;

37 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

38 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

39 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

40

41 /* 逐頁執行寫入 */

42 do{

43 s_command.Address = current_addr;

44 s_command.NbData = current_size;

45

46 /* 啟用寫操作 */

47 if(QSPI_WriteEnable() != QSPI_OK) {

48 returnQSPI_ERROR;

49 }

50

51 /* 配置命令 */

52if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

53 returnQSPI_ERROR;

54 }

55

56 /* 傳輸數據 */

57if(HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

58 returnQSPI_ERROR;

59 }

60

61 /* 配置自動輪詢模式等待程序結束 */

62 if(QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) {

63 returnQSPI_ERROR;

64 }

65

66 /* 更新下一頁編程的地址和大小變量 */

67 current_addr += current_size;

68 pData += current_size;

69current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr-current_addr) :

70 W25Q128FV_PAGE_SIZE;

71 } while(current_addr < end_addr);

72 returnQSPI_OK;

73 }

讀取FLASH芯片ID

根據“JEDEC”指令的時序,我們把讀取FLASH ID的過程編寫成一個函數,見代碼清單 249。

代碼清單 249讀取FLASH芯片ID

1 /**

2 * @brief 讀取FLASH ID

3 * @param 無

4 * @retval FLASH ID

5 */

6 uint32_tQSPI_FLASH_ReadID(void)

7 {

8 QSPI_CommandTypeDef s_command;

9 uint32_tTemp = 0;

10 uint8_tpData[3];

11 /* 讀取JEDEC ID */

12 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

13 s_command.Instruction = READ_JEDEC_ID_CMD;

14 s_command.AddressMode = QSPI_ADDRESS_1_LINE;

15 s_command.AddressSize = QSPI_ADDRESS_24_BITS;

16 s_command.DataMode = QSPI_DATA_1_LINE;

17 s_command.AddressMode = QSPI_ADDRESS_NONE;

18 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

19 s_command.DummyCycles = 0;

20 s_command.NbData = 3;

21 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

22 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

23 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

24

25if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

26 printf("something wrong ....
");

27 /* 用戶可以在這里添加一些代碼來處理這個錯誤 */

28 while(1) {

29

30 }

31 }

32 if(HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK) {

33 printf("something wrong ....
");

34 /* 用戶可以在這里添加一些代碼來處理這個錯誤 */

35 while(1) {

36

37 }

38 }

39

40 Temp = ( pData[2] | pData[1]<<8 )| ( pData[0]<<16 );

41

42 returnTemp;

43 }

這段代碼利用庫函數HAL_QSPI_Command發送讀取FLASHID指令,再調用庫函數HAL_QSPI_Receive讀取3個字節,獲取FLASH芯片對該指令的響應,最后把讀取到的這3個數據合并到一個變量Temp中。然后然后作為函數返回值,把該返回值與我們定義的宏“sFLASH_ID”對比,即可知道FLASH芯片是否正常。

FLASH寫使能以及讀取當前狀態

在向FLASH芯片存儲矩陣寫入數據前,首先要使能寫操作,通過“Write Enable”命令即可寫使能,見代碼清單 24-10。

代碼清單 24-10寫使能命令

1 /**

2 * @brief 發送寫入使能,等待它有效.

3 * @param QSPIHandle: QSPI句柄

4 * @retval 無

5 */

6 static uint8_tQSPI_WriteEnable()

7 {

8 QSPI_CommandTypeDef s_command;

9 QSPI_AutoPollingTypeDef s_config;

10 /* 啟用寫操作 */

11 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

12 s_command.Instruction = WRITE_ENABLE_CMD;

13 s_command.AddressMode = QSPI_ADDRESS_NONE;

14 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

15 s_command.DataMode = QSPI_DATA_NONE;

16 s_command.DummyCycles = 0;

17 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

18 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

19 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

20if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){

21 returnQSPI_ERROR;

22 }

23

24 /* 配置自動輪詢模式等待寫啟用 */

25 s_config.Match = W25Q128FV_FSR_WREN;

26 s_config.Mask = W25Q128FV_FSR_WREN;

27 s_config.MatchMode = QSPI_MATCH_MODE_AND;

28 s_config.StatusBytesSize = 1;

29 s_config.Interval = 0x10;

30 s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

31

32 s_command.Instruction = READ_STATUS_REG1_CMD;

33 s_command.DataMode = QSPI_DATA_1_LINE;

34 s_command.NbData = 1;

35

36if(HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){

37 returnQSPI_ERROR;

38 }

39 returnQSPI_OK;

40 }

與EEPROM一樣,由于FLASH芯片向內部存儲矩陣寫入數據需要消耗一定的時間,并不是在總線通訊結束的一瞬間完成的,所以在寫操作后需要確認FLASH芯片“空閑”時才能進行再次寫入。為了表示自己的工作狀態,FLASH芯片定義了一個狀態寄存器,見圖 24-6。

圖 24-6FLASH芯片的狀態寄存器

我們只關注這個狀態寄存器的第0位“BUSY”,當這個位為“1”時,表明FLASH芯片處于忙碌狀態,它可能正在對內部的存儲矩陣進行“擦除”或“數據寫入”的操作。

利用指令表中的“Read Status Register”指令可以獲取FLASH芯片狀態寄存器的內容,其時序見圖 24-7。

圖 24-7讀取狀態寄存器的時序

只要向FLASH芯片發送了讀狀態寄存器的指令,FLASH芯片就會持續向主機返回最新的狀態寄存器內容,直到收到SPI通訊的停止信號。HAL庫提供了具有等待FLASH芯片寫入結束功能的函數,見代碼清單 2411。

代碼清單 2411通過讀狀態寄存器等待FLASH芯片空閑

1 /**

2 * @brief 讀取存儲器的SR并等待EOP

3 * @param QSPIHandle: QSPI句柄

4 * @param Timeout 超時

5 * @retval 無

6 */

7 static uint8_tQSPI_AutoPollingMemReady(uint32_tTimeout)

8 {

9 QSPI_CommandTypeDef s_command;

10 QSPI_AutoPollingTypeDef s_config;

11 /* 配置自動輪詢模式等待存儲器準備就緒 */

12 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

13 s_command.Instruction = READ_STATUS_REG1_CMD;

14 s_command.AddressMode = QSPI_ADDRESS_NONE;

15 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

16 s_command.DataMode = QSPI_DATA_1_LINE;

17 s_command.DummyCycles = 0;

18 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

19 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

20 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

21

22 s_config.Match = 0x00;

23 s_config.Mask = W25Q128FV_FSR_BUSY;

24 s_config.MatchMode = QSPI_MATCH_MODE_AND;

25 s_config.StatusBytesSize = 1;

26 s_config.Interval = 0x10;

27 s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

28

29 if(HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config, Timeout) != HAL_OK) {

30 returnQSPI_ERROR;

31 }

32 returnQSPI_OK;

33 }

這段代碼直接調用HAL_QSPI_AutoPolling庫函數,設定命令參數及自動輪詢參數,最后設定超時返回,如果在超時等待時間內確定FLASH就緒則返回存儲器就緒狀態,否則返回存儲器錯誤。其實主要操作就是檢查它的“W25Q128FV_FSR_BUSY”(即BUSY位),一直等待到該標志表示寫入結束時才退出本函數,以便繼續后面與FLASH芯片的數據通訊。

FLASH扇區擦除

由于FLASH存儲器的特性決定了它只能把原來為“1”的數據位改寫成“0”,而原來為“0”的數據位不能直接改寫為“1”。所以這里涉及到數據“擦除”的概念,在寫入前,必須要對目標存儲矩陣進行擦除操作,把矩陣中的數據位擦除為“1”,在數據寫入的時候,如果要存儲數據“1”,那就不修改存儲矩陣 ,在要存儲數據“0”時,才更改該位。

通常,對存儲矩陣擦除的基本操作單位都是多個字節進行,如本例子中的FLASH芯片支持“扇區擦除”、“塊擦除”以及“整片擦除”,見表 24-3。

表 24-3本實驗FLASH芯片的擦除單位

擦除單位

大小

扇區擦除Sector Erase

4KB

塊擦除Block Erase

64KB

整片擦除Chip Erase

整個芯片完全擦除

FLASH芯片的最小擦除單位為扇區(Sector),而一個塊(Block)包含16個扇區,其內部存儲矩陣分布見圖 24-8。

圖 24-8FLASH芯片的存儲矩陣

使用扇區擦除指令“Sector Erase”可控制FLASH芯片開始擦寫,其指令時序見錯誤!未找到引用源。

圖 24-9扇區擦除時序

扇區擦除指令的第一個字節為指令編碼,緊接著發送的3個字節用于表示要擦除的存儲矩陣地址。要注意的是在扇區擦除指令前,還需要先發送“寫使能”指令,發送扇區擦除指令后,通過讀取寄存器狀態等待扇區擦除操作完畢,代碼實現見代碼清單 24-12。

代碼清單 24-12擦除扇區

1 /**

2 * @brief 擦除QSPI存儲器的指定塊

3 * @param BlockAddress: 需要擦除的塊地址

4 * @retval QSPI存儲器狀態

5 */

6 uint8_tBSP_QSPI_Erase_Block(uint32_tBlockAddress)

7 {

8 QSPI_CommandTypeDef s_command;

9 /* 初始化擦除命令 */

10 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

11 s_command.Instruction = SECTOR_ERASE_CMD;

12 s_command.AddressMode = QSPI_ADDRESS_1_LINE;

13 s_command.AddressSize = QSPI_ADDRESS_24_BITS;

14 s_command.Address = BlockAddress;

15 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

16 s_command.DataMode = QSPI_DATA_NONE;

17 s_command.DummyCycles = 0;

18 s_command.DdrMode = QSPI_DDR_MODE_DISABLE;

19 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

20 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

21

22 /* 啟用寫操作 */

23 if(QSPI_WriteEnable() != QSPI_OK) {

24 returnQSPI_ERROR;

25 }

26

27 /* 發送命令 */

28if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

29 returnQSPI_ERROR;

30 }

31

32 /* 配置自動輪詢模式等待擦除結束 */

33 if(QSPI_AutoPollingMemReady(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) {

34 returnQSPI_ERROR;

35 }

36 returnQSPI_OK;

37 }

3.main函數

最后我們來編寫main函數,進行FLASH芯片讀寫校驗,見錯誤!未找到引用源。

代碼清單 2413main函數

1 intmain(void)

2 {

3 /* 使能指令緩存 */

4 SCB_EnableICache();

5

6 /* 使能數據緩存 */

7 SCB_EnableDCache();

8

9 /* 設定系統時鐘為216MHz */

10 SystemClock_Config();

11

12 LED_GPIO_Config();

13 LED_BLUE;

14

15 /* 配置串口1為:115200 8-N-1 */

16 DEBUG_USART_Config();

17

18 printf("
這是一個16M串行flash(W25Q128)實驗(QSPI驅動)
");

19

20 /* 16M串行flash W25Q128初始化 */

21 QSPI_FLASH_Init();

22

23 /* 獲取 Flash Device ID */

24 DeviceID = QSPI_FLASH_ReadDeviceID();

25

26 Delay( 200 );

27

28 /* 獲取 SPI Flash ID */

29 FlashID = QSPI_FLASH_ReadID();

30

31 printf("
FlashID is 0x%X, Manufacturer Device ID is 0x%X
", FlashID, DeviceID);

32

33 /* 檢驗 SPI Flash ID */

34 if(FlashID == sFLASH_ID) {

35 printf("
檢測到QSPI FLASH W25Q128 !
");

36

37 /* 擦除將要寫入的 QSPI FLASH 扇區,FLASH寫入前要先擦除 */

38 BSP_QSPI_Erase_Block(FLASH_SectorToErase);

39

40 /* 將發送緩沖區的數據寫到flash中 */

41 BSP_QSPI_Write(Tx_Buffer, FLASH_WriteAddress, BufferSize);

42 printf("
寫入的數據為:
%s", Tx_Buffer);

43

44 /* 將剛剛寫入的數據讀出來放到接收緩沖區中 */

45 BSP_QSPI_Read(Rx_Buffer, FLASH_ReadAddress, BufferSize);

46 printf("
讀出的數據為:
%s", Rx_Buffer);

47

48 /* 檢查寫入的數據與讀出的數據是否相等 */

49 TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);

50

51 if( PASSED == TransferStatus1 ) {

52 LED_GREEN;

53 printf("
16M串行flash(W25Q128)測試成功!
");

54 } else{

55 LED_RED;

56 printf("
16M串行flash(W25Q128)測試失敗!
");

57 }

58 }// if (FlashID == sFLASH_ID)

59 else{

60 LED_RED;

61 printf("
獲取不到 W25Q128 ID!
");

62 }

63

64 while(1);

65 }

函數中初始化了系統時鐘、LED、串口SPI外設,然后讀取FLASH芯片的ID進行校驗,若ID校驗通過則向FLASH的特定地址寫入測試數據,然后再從該地址讀取數據,測試讀寫是否正常。

注意:

由于實驗板上的FLASH芯片默認已經存儲了特定用途的數據,如擦除了這些數據會影響到某些程序的運行。所以我們預留了FLASH芯片的“第0扇區(0-4096地址)”專用于本實驗,如非必要,請勿擦除其它地址的內容。如已擦除,可在配套資料里找到“刷外部FLASH內容”程序,根據其說明給FLASH重新寫入出廠內容。

24.6.3 下載驗證

用USB線連接開發板“USB TO UART”接口跟電腦,在電腦端打開串口調試助手,把編譯好的程序下載到開發板。在串口調試助手可看到FLASH測試的調試信息。

總結

以上是生活随笔為你收集整理的第24章 QSPI—读写串行FLASH的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

一本之道乱码区 | 国产呻吟在线 | 久久精品aaa | 深夜国产在线 | 国内亚洲精品 | 国产中文字幕一区二区三区 | 国产一区二区在线精品 | 日韩av看片 | 五月婷婷开心 | 97色婷婷成人综合在线观看 | 国产精品久久久久久久久久ktv | 欧美精品久久久久性色 | 亚洲黄色一级电影 | 欧美激情综合五月 | 不卡的av电影| 久草新在线 | 免费在线观看日韩视频 | 中文字幕一区二区三区视频 | 在线一级片 | 免费观看国产精品视频 | 91精品国产91热久久久做人人 | 91免费黄视频 | 国产精品一区二区在线观看 | 操少妇视频| 不卡的av在线播放 | 欧美狠狠色| 免费三级大片 | 最近中文字幕在线 | 麻豆视频免费入口 | av日韩国产 | 国产成人精品亚洲 | 免费成人短视频 | 成人a级免费视频 | 久久综合五月婷婷 | 亚洲国产精品成人精品 | 精品一二三区 | 精品成人久久 | 免费视频久久久 | 成人在线视频论坛 | av综合在线观看 | 91免费在线看片 | 欧美性生活大片 | 久久国产网 | 午夜精品一区二区三区在线观看 | 五月天国产精品 | 特级毛片网 | 欧美91精品国产自产 | 免费观看特级毛片 | 国产黄色大片 | 伊人资源视频在线 | 一级黄色av | 亚洲少妇xxxx | 日韩精品不卡在线 | 福利精品在线 | 欧美视频日韩 | 99久高清在线观看视频99精品热在线观看视频 | 国产精品久久嫩一区二区免费 | 国产精品乱码高清在线看 | 三上悠亚一区二区在线观看 | 午夜.dj高清免费观看视频 | 三级黄色网络 | 亚洲欧美激情插 | 中文字幕麻豆 | 日日干干夜夜 | 国产精品免费高清 | 国产在线免费观看 | av免费在线观看1 | 国产一区二区三区四区在线 | 久久久久久久久久久电影 | 天天干,天天草 | 毛片.com| 免费午夜网站 | 国产精品久久久久久久久久久杏吧 | 亚洲2019精品 | 久久一线 | 成人一区二区三区在线 | 黄色毛片视频免费观看中文 | 久久夜夜夜| 免费视频一级片 | 国产xx视频 | 中文国产成人精品久久一 | 99精品视频在线观看 | 在线 视频 一区二区 | 国产精品一区二区久久久久 | 国产精品久久久久久久午夜 | 波多野结衣最新 | 久久人人爽人人片 | 日韩av区 | 99精品国产在热久久 | 天天射天天色天天干 | 日韩免费看视频 | 日韩丝袜视频 | 欧美一级片播放 | 国产精品久久99综合免费观看尤物 | 九九免费观看全部免费视频 | 开心激情久久 | 久久开心激情 | 国产91精品一区二区麻豆亚洲 | 婷香五月| 热久久最新地址 | 欧美精彩视频 | 久久久久国产精品免费免费搜索 | 99久久精品国产系列 | 久久中文精品视频 | 久久久精品国产一区二区 | 日本黄网站 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 97超碰人人网 | 午夜12点 | 国产精品久久久久一区二区三区共 | 国产高清无av久久 | 久久久久中文字幕 | 国产视 | 超碰人人舔| 在线观看中文字幕视频 | 免费在线黄色av | 国产欧美精品一区二区三区四区 | 日本中出在线观看 | 福利片免费看 | 日本不卡一区二区三区在线观看 | 一区二区三区国产欧美 | a特级毛片 | 中文字幕在线观看你懂的 | 免费人成网 | 久久久在线 | 中文字幕久久精品一区 | 久久五月激情 | 欧美日韩一区二区三区在线观看视频 | 久久久久久久看片 | 精品国产乱码久久久久久天美 | 亚洲天堂网在线播放 | 91黄色在线观看 | 中文字幕一区二区三区久久蜜桃 | 五月婷香| 中文字幕一区二区三区精华液 | 探花视频在线观看+在线播放 | 国产自产在线视频 | 色婷婷啪啪免费在线电影观看 | 亚洲成人在线免费 | 99国产精品视频免费观看一公开 | 久久久久久国产精品 | 四虎影视成人永久免费观看亚洲欧美 | 欧美污在线观看 | 久草在线视频免赞 | 国产精品免费在线 | 五月婷婷综合网 | 国产又黄又爽又猛视频日本 | 中文字幕在线字幕中文 | 97视频免费观看2区 亚洲视屏 | 国产精品久久久免费看 | 欧美激情第八页 | 婷婷久久综合九色综合 | 欧美精品在线免费 | 韩国av电影网| 激情网婷婷 | 在线国产精品视频 | 99久久久久免费精品国产 | 操夜夜操 | 日韩精品字幕 | 一区二区三区四区五区六区 | 中文字幕一区三区 | 999视频网站| 成人国产精品一区二区 | 人人干天天射 | 久久9精品 | 久久精品欧美一区 | 免费看av在线 | 免费的黄色av | 国产精品成人一区二区三区吃奶 | 欧美精品一区二区蜜臀亚洲 | 成人av一区二区兰花在线播放 | 免费福利视频导航 | 亚洲精品玖玖玖av在线看 | 五月天综合网站 | 色综合激情久久 | 国产成人久久久77777 | 97品白浆高清久久久久久 | 国产一级二级在线 | 国产亚洲精品久久 | 日韩在线短视频 | 人人干在线观看 | 国产在线专区 | 欧美性生活一级片 | 99性视频| 91av在线免费观看 | 久久亚洲私人国产精品va | 日本中文字幕观看 | www.com.日本一级| 日韩精品久久一区二区三区 | 狠狠色噜噜狠狠狠狠2022 | 日本女人b| 五月婷婷丁香综合 | 91成版人在线观看入口 | www.亚洲精品 | 亚洲最大的av网站 | 亚洲成aⅴ人在线观看 | 精品1区二区 | 欧美性超爽 | 久久久久久网址 | 午夜色大片在线观看 | 久久免费精品一区二区三区 | 久久久久免费精品国产 | 国产精品美女久久久久久久网站 | 国产无遮挡猛进猛出免费软件 | 91福利免费 | 激情五月亚洲 | 99国产精品免费网站 | 欧美日韩精品在线观看视频 | 国产精品theporn | 日本三级久久久 | 69亚洲乱| 黄色av一区二区三区 | 久久香蕉电影网 | 日韩欧美xxx | 精品久久久久一区二区国产 | 国产精品综合久久久 | 久久久免费高清视频 | 精品福利视频在线观看 | 久99精品| 91黄色在线视频 | 日韩在线视频不卡 | 成人网页在线免费观看 | 久久久久久电影 | 最近中文字幕视频完整版 | 欧美日韩成人 | 国产精品久久久久久久久久久久 | 黄色三级免费网址 | 亚洲欧美精品一区二区 | 日韩影视在线 | 久久艹免费| 日韩中文在线观看 | 中文字幕免费观看全部电影 | www.夜夜骑.com| 日韩欧美有码在线 | 日韩性色 | 亚洲精品999 | 日韩成人免费在线观看 | 岛国一区在线 | 国产精品 美女 | 久久一区二区三区超碰国产精品 | 日韩专区一区二区 | av国产网站| 国产成人精品电影久久久 | 日日夜夜免费精品视频 | 久久国产精品99精国产 | 国产精品观看 | 久久蜜桃av | 狠狠的操狠狠的干 | 日韩欧美国产精品 | 91视频免费视频 | 欧美日韩一区三区 | 久久一区精品 | 日韩精品欧美专区 | 伊人av综合 | 天天操天| 国产精品麻豆免费版 | 国产一级特黄毛片在线毛片 | 久久第四色| 午夜婷婷在线观看 | 国产不卡av在线 | 在线有码中文 | 精品免费在线视频 | 日韩精品久久久久久久电影99爱 | 成年人电影免费看 | 亚洲午夜精品一区二区三区电影院 | 91传媒在线看 | 在线观看视频黄色 | 久99久在线| 又爽又黄又无遮挡网站动态图 | 亚洲狠狠丁香婷婷综合久久久 | 狠狠躁夜夜躁人人爽超碰91 | 久久视频一区二区 | 96精品在线 | 国产精品大片免费观看 | 久久爱综合 | 8x8x在线观看视频 | 亚洲最大的av网站 | 97成人超碰| 成人三级黄色 | 黄a网站 | 99精品国产99久久久久久福利 | 毛片视频网址 | 精品在线亚洲视频 | 99久高清在线观看视频99精品热在线观看视频 | 午夜性福利 | 日本精品视频在线观看 | 九九热国产视频 | 韩国在线视频一区 | 99热超碰在线 | 99精品视频在线播放免费 | 亚洲香蕉在线观看 | 狠狠色伊人亚洲综合网站色 | 黄色亚洲片 | 超碰在线资源 | 亚洲激情中文 | 91精品亚洲影视在线观看 | 最新国产精品拍自在线播放 | 午夜视频免费播放 | 欧美看片 | 久久99国产视频 | 一级免费黄色 | 国产午夜精品免费一区二区三区视频 | 最近高清中文在线字幕在线观看 | 91视频麻豆视频 | av黄免费看 | 精品在线一区二区三区 | 精品久久免费看 | 色婷丁香 | 黄色福利网 | 六月丁香婷婷在线 | 在线看片日韩 | 免费网站观看www在线观看 | 国产一区二区在线观看视频 | 国语自产偷拍精品视频偷 | 色综久久| 国产成人久久精品77777综合 | 啪嗒啪嗒免费观看完整版 | 欧美日韩在线观看不卡 | 日韩午夜小视频 | 国产生活一级片 | 色资源网免费观看视频 | 激情网第四色 | 91av观看| 中文字幕资源网在线观看 | 日韩精品在线看 | 亚洲黄色av | 一区在线电影 | 国产精品成人免费精品自在线观看 | 婷婷激情影院 | 久草免费在线 | 精品在线观看一区二区 | 日韩av网站在线播放 | 久久免费电影 | 日韩一级网站 | 久久影视中文字幕 | 午夜精品一二区 | 国产一级h | 91.dizhi永久地址最新 | 免费a v在线 | 久久久久久久久久久高潮一区二区 | 91精品国自产在线 | 亚洲国产wwwccc36天堂 | 久久99精品国产麻豆宅宅 | 日韩精品影视 | 日韩欧三级 | 欧美一级片| 激情视频区 | 欧美日韩国产成人 | 粉嫩av一区二区三区四区五区 | 麻豆精品传媒视频 | 久久综合五月天 | 亚洲第一av在线播放 | 久久午夜精品影院一区 | 日日躁夜夜躁aaaaxxxx | 欧美一区二区在线免费看 | 日韩精品久久久久久中文字幕8 | 国产精品区免费视频 | 色综合咪咪久久网 | av在线成人 | 国产精品爽爽久久久久久蜜臀 | 欧美性大战久久久久 | 久久久久免费精品国产小说色大师 | 免费亚洲视频在线观看 | 亚洲理论片在线观看 | 91av福利视频| 婷婷电影在线观看 | 精品国模一区二区 | 色综合网在线 | 日韩大陆欧美高清视频区 | 丁香激情视频 | 亚洲高清在线 | 欧美国产日韩一区二区 | 九九热中文字幕 | 奇米777777 | 91网站在线视频 | 国产一区免费观看 | 国产精品国产亚洲精品看不卡15 | 国产黄色片免费 | 欧美日韩中文国产一区发布 | 亚洲国产精品久久久久久 | 在线观看91网站 | 四虎影视成人精品国库在线观看 | 91精品视频免费看 | 精品国产一区二区三区蜜臀 | 天天草天天草 | a√天堂中文在线 | 国产99色| 欧美日高清视频 | 五月天六月婷 | 婷婷在线不卡 | 天天色宗合 | 中文字幕在线观看一区二区三区 | 成人毛片在线视频 | 日韩av电影免费在线观看 | 天堂麻豆 | 黄色大片免费播放 | 黄色大片网 | 欧美日韩在线视频观看 | 在线观看日韩精品 | 亚洲日日射 | 成人资源在线 | 久久久久免费精品国产 | 超碰公开在线观看 | 亚洲欧美国产精品va在线观看 | 国内精品久久久久久 | 国产高清av免费在线观看 | 18网站在线观看 | 国际精品久久久久 | 日本中文字幕影院 | 亚洲精品久久视频 | 九色在线| 黄色国产在线观看 | 欧美福利在线播放 | 天天夜夜操 | 国产美女精品人人做人人爽 | 成年人黄色大片在线 | 亚洲综合在线观看视频 | 色视频成人在线观看免 | 99久久精品视频免费 | 国产精品久久久久久久久久久杏吧 | 欧美日韩精品在线 | 国产成人久 | www.神马久久 | 亚洲va欧美 | 日韩超碰在线 | 国产精品国产毛片 | 久久99这里只有精品 | 伊人手机在线 | 97人人模人人爽人人少妇 | 国产日韩精品在线 | 日韩在线激情 | 免费日韩一区二区三区 | 国产裸体永久免费视频网站 | 2020天天干夜夜爽 | 黄色影院在线播放 | 国产无遮挡又黄又爽在线观看 | 亚洲国产精品成人女人久久 | 国产视频在线播放 | 国产精品高清一区二区三区 | bbw av | 久久久久久国产精品免费 | 91久久国产综合精品女同国语 | 国产视频2 | 天海翼一区二区三区免费 | 精品国产一区二区三区在线观看 | 久草手机视频 | 国产在线a不卡 | 久久情爱 | 免费av免费观看 | 天天操天天操天天爽 | 亚洲精区二区三区四区麻豆 | 爱射综合 | 一本一本久久a久久精品综合小说 | 欧美夫妻生活视频 | 狠狠色香婷婷久久亚洲精品 | 国产精品第二页 | 日韩一区二区三区高清免费看看 | 91精品综合在线观看 | 伊人伊成久久人综合网小说 | 国产麻豆剧果冻传媒视频播放量 | 五月婷网站| 日精品在线观看 | 日韩成人高清在线 | 在线a视频免费观看 | 成人在线免费av | 亚洲精品免费在线视频 | 天天干天天摸 | 国产h在线观看 | 国产综合精品久久 | 亚洲va在线va天堂va偷拍 | 国产精品视频专区 | 国产亚洲婷婷免费 | 久久久午夜视频 | 超碰在线91 | 久久精品三级 | 99中文视频在线 | 精品久久九九 | 天天操天天色天天射 | 欧美激情第八页 | 色夜视频 | 久久久久久久久久久久久国产精品 | av性网站| 天天天综合 | 久草久草视频 | 欧美最爽乱淫视频播放 | 国产欧美精品在线观看 | 91精品国产高清自在线观看 | 亚洲激情综合网 | 国产精品麻豆一区二区三区 | 久久9999久久免费精品国产 | 97国产大学生情侣酒店的特点 | 婷婷丁香花五月天 | 在线观看精品国产 | 黄色av成人在线 | 色小说av | 色九九视频 | 天天干天天干天天干天天干天天干天天干 | 在线观看精品一区 | 99999精品视频 | 精品在线观看一区二区三区 | 黄色a大片 | 亚洲免费在线观看视频 | 五月婷香蕉久色在线看 | 国产精品久久久久免费a∨ 欧美一级性生活片 | 天天撸夜夜操 | 97国产小视频| 精品在线视频一区二区三区 | 色先锋资源网 | 久久99热精品 | 中文在线免费视频 | 婷婷九月激情 | 国产高清一 | 在线激情av电影 | 国产精品免费看 | 中文高清av| 丁香婷婷综合五月 | 日本中文字幕在线播放 | www.色婷婷.com | 激情 婷婷 | 久久激五月天综合精品 | 久草在线视频国产 | 欧美日韩天堂 | 久久精品国产成人精品 | 在线观看 国产 | 天天色天天操天天爽 | 成人一区电影 | 在线高清一区 | 91av在线看 | 97福利视频 | 欧美韩日视频 | 国产精品免费观看国产网曝瓜 | 国产一级久久 | 国产亚洲视频在线免费观看 | 天天干人人 | 欧美亚洲一级片 | 人人干网 | 国产成人三级一区二区在线观看一 | 午夜av免费在线观看 | 日韩大片在线免费观看 | 国产在线高清视频 | 国产精品男女 | 国产一二三区在线观看 | 日韩亚洲国产中文字幕 | 久久精品99北条麻妃 | 在线观看日本韩国电影 | 日本高清免费中文字幕 | 毛片网站观看 | 99精品一区二区 | 91精品国产一区二区三区 | 国产护士在线 | 美女视频黄是免费的 | 在线免费观看黄网站 | 久草电影在线 | 西西人体4444www高清视频 | 在线免费观看视频一区 | .国产精品成人自产拍在线观看6 | 九九综合九九 | 久久99视频免费 | 日韩 精品 一区 国产 麻豆 | 97超级碰碰碰碰久久久久 | 婷婷视频在线观看 | 丁香资源影视免费观看 | 国产精品久久久久婷婷 | 天天五月天色 | 狠狠色噜噜狠狠狠合久 | 五月天久久综合网 | 日韩成人黄色 | 久99视频 | 欧美视频日韩视频 | 欧美淫aaa免费观看 日韩激情免费视频 | 亚洲欧洲成人精品av97 | 欧美日韩午夜在线 | 亚洲视频在线视频 | 日日草天天草 | 日本精品一 | av理论电影| 午夜手机电影 | 99视频在线观看免费 | 亚洲综合五月天 | 九九视频免费观看视频精品 | 五月激情天 | 草久中文字幕 | 日本在线视频网址 | 日韩欧美网址 | 精品在线免费观看 | 99久久久久久久久久 | 国产91勾搭技师精品 | 国产精品99免费看 | 蜜臀av性久久久久蜜臀av | 国产精品久久久久久久免费观看 | 亚洲高清av在线 | 黄网站大全 | 天天草天天干天天射 | 国产伦精品一区二区三区免费 | 国产在线播放不卡 | 国产黄在线免费观看 | 欧美日韩高清在线观看 | 99久久精品免费看国产免费软件 | 欧美日韩一区二区三区视频 | 精品国产伦一区二区三区观看方式 | 狠狠躁夜夜躁人人爽超碰91 | 欧美一级日韩免费不卡 | 91天堂在线观看 | 国内综合精品午夜久久资源 | 免费高清av在线看 | 久久精品视频一 | 深爱婷婷激情 | 三级黄在线 | 国产精品区在线观看 | 久久国产精品一区二区三区四区 | 99国产在线 | 日韩精品无码一区二区三区 | 国产在线观看你懂得 | 在线亚洲观看 | av免费看在线 | 亚洲区另类春色综合小说校园片 | 亚洲三级黄色 | 2024国产精品视频 | 人人搞人人搞 | 午夜视频在线观看一区二区 | 成人毛片在线观看 | 91精品一区二区三区蜜桃 | 中文字幕丰满人伦在线 | 中文字幕成人在线 | 久久国产精品久久久 | 国产在线观看h | 成年人国产视频 | 五月天综合网 | 又黄又网站 | 日本视频网 | 国产精品成人免费精品自在线观看 | 成人wwwxxx视频 | 亚洲一级久久 | 日韩免费中文字幕 | 成年人av在线播放 | 成人在线播放网站 | 99在线观看视频网站 | 国产精选视频 | 久久99精品久久久久久 | 国产精品6999成人免费视频 | 国产拍在线 | 伊人天天狠天天添日日拍 | 中文字幕视频网 | 国产精品黄色 | 久久久久久久毛片 | 天天草综合 | 日日夜夜免费精品视频 | 精品一区二区在线免费观看 | 深夜福利视频在线观看 | 精品国产免费看 | 亚洲毛片在线观看. | 久久久久区 | 欧美精品在线一区 | 玖玖精品在线 | 一区二区三区在线免费播放 | 激情欧美xxxx| 天天看天天干 | 91污在线观看 | 中文字幕 国产视频 | 国产亚州精品视频 | 人人爱人人舔 | 日本久久久亚洲精品 | 国产1级毛片 | 免费一级特黄毛大片 | 欧美精品亚洲精品日韩精品 | 特级毛片在线 | 91丨精品丨蝌蚪丨白丝jk | 91免费网站在线观看 | 波多野结衣网址 | 日本公妇在线观看高清 | 国产黄色免费看 | 久久一级片| 欧美在线观看视频一区二区三区 | 成人天堂网 | 1000部18岁以下禁看视频 | 午夜黄色| avsex| 天天干天天草天天爽 | 视频一区久久 | 久99视频 | av片在线观看 | 三上悠亚在线免费 | 中文字幕乱在线伦视频中文字幕乱码在线 | 久久色视频 | 中文字幕av全部资源www中文字幕在线观看 | 在线观看国产成人av片 | 亚洲国产小视频在线观看 | 亚洲国产中文字幕在线观看 | 国产中文字幕三区 | 自拍超碰在线 | 99热99re6国产在线播放 | 人人爽人人爽人人爽 | 欧美一区成人 | 午夜av免费观看 | 久久这里只有精品9 | 亚洲精品观看 | 精品人人人 | 久香蕉 | 爱色婷婷 | 在线亚洲高清视频 | 欧美久久九九 | 欧美最猛性xxxx | 久久久国产在线视频 | 69av国产| 国产精品免费久久久久影院仙踪林 | 亚洲电影av在线 | 欧美另类视频 | 天天射天天射天天射 | 天天综合天天做天天综合 | 久久丝袜视频 | 在线视频1卡二卡三卡 | av高清影院 | www五月 | 成年人免费观看国产 | 一区二区三区在线不卡 | 欧美国产日韩一区二区三区 | avlulu久久精品 | 五月婷婷开心 | av福利在线 | 精品亚洲一区二区 | 综合激情av | 国产97在线视频 | 日韩视频在线不卡 | 国产在线观看地址 | 国产精品毛片网 | 免费看黄在线 | a色视频 | 成人97视频一区二区 | 色a综合 | 国产成人区| 成人h电影在线观看 | 午夜久久电影网 | 亚洲aⅴ在线 | 中文字幕欧美日韩va免费视频 | 亚洲电影久久久 | 亚洲毛片一区二区三区 | 成人国产精品入口 | 美女免费视频一区 | 怡红院成人在线 | 日韩va亚洲va欧美va久久 | 九九视频网 | 美女久久一区 | 日韩精品一区二区三区电影 | 九九免费在线观看 | 最近中文字幕免费观看 | 久久精品站| 亚洲一区视频免费观看 | 狠狠色丁婷婷日日 | 日韩区欠美精品av视频 | 波多野结衣在线观看视频 | 欧美另类亚洲 | 999国内精品永久免费视频 | 亚洲一级片在线观看 | 久久免费的视频 | av电影免费在线看 | 在线播放国产一区二区三区 | 日韩精品字幕 | 日韩xxxxxxxxx | 日韩美女黄色片 | 中文字幕久久网 | 久久天堂网站 | 亚洲91中文字幕无线码三区 | 亚洲少妇xxxx | 99在线精品免费视频九九视 | 国内成人精品视频 | 国产资源av| 黄色软件网站在线观看 | 97国产一区| 中文字幕a∨在线乱码免费看 | 亚洲精品看片 | 国内精品久久天天躁人人爽 | 亚洲黄色av| 成 人 黄 色 视频 免费观看 | 粉嫩一区二区三区粉嫩91 | 99视频国产精品免费观看 | 五月天婷亚洲天综合网鲁鲁鲁 | 国产成人久久精品亚洲 | 中文字幕字幕中文 | a天堂一码二码专区 | 中文字幕在线视频一区 | 国产福利小视频在线 | 亚洲免费公开视频 | 色综合久久99 | 天天操夜操 | 日韩欧美在线观看一区二区三区 | 亚洲乱亚洲乱亚洲 | 丁香婷婷基地 | 欧美色888 | 国产看片免费 | 激情久久久久久久久久久久久久久久 | 天天操天天是 | 色综合亚洲精品激情狠狠 | 久久精品中文字幕免费mv | 天天色天天射综合网 | 成人免费网站在线观看 | 国产1级视频 | 91在线日韩 | 日本久久中文 | www.五月天婷婷 | 激情视频一区二区三区 | 不卡视频国产 | 五月天免费网站 | 99视频偷窥在线精品国自产拍 | 婷婷久久五月天 | a黄色影院 | 国产麻豆剧传媒免费观看 | 在线之家免费在线观看电影 | 日韩欧美69 | 亚洲免费资源 | 免费在线观看不卡av | 中文字幕av全部资源www中文字幕在线观看 | 日本久久久久久久久 | 久久久91精品国产 | 四虎影视精品 | 亚洲乱码精品 | 韩日av在线 | 午夜影院在线观看18 | 黄色成人在线观看 | 国产精品久久久网站 | 国产 一区二区三区 在线 | 国产手机在线观看 | 深爱开心激情 | 亚洲片在线观看 | 狠狠网亚洲精品 | 国产精品免费看久久久8精臀av | 最新av电影网站 | 久草网免费 | 欧美色插 | 欧美极品少妇xxxx | 欧美国产精品一区二区 | 精品国产自在精品国产精野外直播 | 麻豆94tv免费版 | 99久久精品免费看国产一区二区三区 | 天天操天天玩 | 在线视频中文字幕一区 | 日本久久久久久科技有限公司 | 午夜精品视频一区二区三区在线看 | 国产精品美女久久久久久2018 | 网站在线观看日韩 | 在线观看www.| 国产aaa毛片| 国产一级免费在线观看 | 91成人亚洲| 国内揄拍国产精品 | 久久久久成| 国产一区高清在线观看 | 久久久久久麻豆 | 九九综合在线 | 欧美色婷| 深夜免费福利在线 | 国产精品完整版 | 狠狠干网站| 国产手机在线观看视频 | 五月天网页 | www.伊人网.com| 久久婷婷丁香 | 久久精品—区二区三区 | 午夜婷婷网 | 男女啪啪免费网站 | 欧美性高跟鞋xxxxhd | 在线观看成年人 | 国产精品美女久久久网av | 久久一视频 | 久久综合综合久久综合 | 国产免费亚洲高清 | 美女网色| 黄色在线观看免费网站 | 91精品国产高清自在线观看 | 日韩免费网站 | 日韩av影视在线观看 | 久久精彩视频 | 国产无遮挡猛进猛出免费软件 | 国产一区二区三区午夜 | 天天色欧美 | 97色婷婷人人爽人人 | 日韩在线视频免费播放 | 婷婷色亚洲| 综合久久五月天 | 在线观看国产一区二区 | 久久9精品 | 中文字幕二区在线观看 | 99一区二区三区 | 亚洲永久精品视频 | 国产精品亚洲精品 | 国产99一区 | 成人h视频 | 视频三区在线 | 美女久久网站 | 成年人在线免费看视频 | 日黄网站 | 国产色网| 在线亚洲欧美视频 | 亚洲黄色网络 | 国产精品99久久免费观看 | 五月婷av| 久草在线高清视频 | 色婷婷播放 | 久久久亚洲麻豆日韩精品一区三区 | 欧美性大胆 | 国产手机视频在线播放 | av在观看 | 免费在线观看不卡av | 国产高清成人在线 | 国产白浆视频 | 人人舔人人舔 | 99精品欧美一区二区三区黑人哦 | 国产精品美女在线观看 | 天天天干天天天操 | 欧美性脚交 | 久久综合狠狠综合久久狠狠色综合 | 国产精品对白一区二区三区 | 国产精品久久一卡二卡 | 久久久国产一区二区三区四区小说 | www.天天干.com| 久久一区国产 | 91麻豆产精品久久久久久 | 国产资源av | 91亚色视频在线观看 | 在线综合 亚洲 欧美在线视频 | 国产亚洲精品女人久久久久久 | 亚洲精选视频免费看 | 日韩区欠美精品av视频 | 欧美午夜一区二区福利视频 | 欧美国产三区 | 精品免费 | www黄色av| 国产乱码精品一区二区蜜臀 | 欧美日韩91 | 丰满少妇在线观看网站 | 国产一线二线三线性视频 | 国产精品欧美在线 | 人人爽人人 | 天堂视频中文在线 | 成人小电影在线看 | 黄色tv视频 | 五月天久久激情 | 中文字幕在线日亚洲9 | 午夜视频在线观看一区二区三区 | 成年人视频免费在线 | av亚洲产国偷v产偷v自拍小说 | 996久久国产精品线观看 | 久久综合九色综合久久久精品综合 | 在线国产视频一区 | 国产一级二级三级在线观看 | 不卡视频一区二区三区 | 日本韩国精品一区二区在线观看 | 国产高清在线 | 欧美精品久久久久久久免费 | 精品久久影院 | 爱色av.com| 久久久久综合 | av网站大全免费 | 999国内精品永久免费视频 | 国产一级视屏 | 国产精品99在线播放 | 成人97视频 | av在线直接看 | 成人黄色在线 | 日韩欧美在线一区二区 | 日本成人黄色片 | 香蕉日日 | 在线免费试看 | 国产五月色婷婷六月丁香视频 | 91九色最新 | 国产视频中文字幕在线观看 | 美女av免费看 | 久久精品www人人爽人人 | 欧美大荫蒂xxx | 久久国产成人午夜av影院潦草 | 一区免费观看 | 成人毛片100免费观看 | 国产亚州av| 伊人久久影视 | 伊人久久电影网 | 五月婷婷激情网 | 亚洲经典中文字幕 | 五月激情姐姐 | 成人黄色在线视频 | 午夜精品久久久99热福利 | 91视频免费看片 | 欧美久久久久久久久久久 | 日韩av片无码一区二区不卡电影 | 97人人模人人爽人人喊网 | 亚洲不卡av一区二区三区 | 久久五月婷婷丁香 | 久久久麻豆精品一区二区 | 精品一区中文字幕 | 婷久久 | 久久精品国产99国产 | 久久成人国产精品入口 | 天天草夜夜 | 成人黄色电影视频 | 麻豆传媒视频在线免费观看 | 在线v片免费观看视频 | 精品在线你懂的 | 91视频黄色 | 亚洲精品黄色片 | 色综合久久66 |