日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

【GD32H757Z海棠派開發(fā)板使用手冊】第十一講 SPI-SPI NOR FLASH讀寫實驗

聚沃科技 ? 2024-06-04 11:42 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

wKgZomYgeJOAUiXJAB6mQrDJGEg027.png

11.1實驗內容

通過本實驗主要學習以下內容:

  • SPI簡介
  • GD32H7 SPI簡介
  • SPI NOR FLASH——GD25Q128ESIGR簡介
  • 使用GD32H7 SPI接口實現(xiàn)對GD25Q128ESIGR的讀寫操作

11.2實驗原理

11.2.1SPI簡介

SPI(Serial Peripheral interface),顧名思義是串行外設接口,和UART不同的是,SPI是同步通訊接口,所以帶有時鐘線,而UART是異步通訊接口,不需要時鐘線。

SPI通常使用4根線,分別為SCK、MOSI、MISO、NSS(CS):

  • SCK:串列時脈,由主機發(fā)出
  • MOSI:主機輸出從機輸入信號(數(shù)據(jù)由主機發(fā)出)
  • MISO:主機輸入從機輸出信號(數(shù)據(jù)由從機發(fā)出)
  • NSS:片選信號,由主機發(fā)出,一般是低電位有效

SPI默認為全雙工工作,在這種工作模式下,主機通過MOSI線發(fā)送數(shù)據(jù)的同時,也在MISO線上接受數(shù)據(jù),簡單來說就是主機和從機之間進行數(shù)據(jù)交換。

SPI是一個可以實現(xiàn)一主多從的通訊接口,從機的片選由主機NSS腳來控制:

wKgZomZGtu6APTaFAAG8RWzLK4U261.png

每個通訊時刻,只有一個從機NSS被主機選中,選中方式為主機拉低響應的NSS(CS)腳。

SPI的數(shù)據(jù)線只有一條(雖然有MOSI和MISO,但實際上每個CLK主機都只能發(fā)送和接受一個bit),所以稱之為單線SPI。從SPI衍生出來的還有4線制SPI(QSPI)和8線制SPI(OSPI)以及其他多線制SPI,這個我們后面具體再聊。

11.2.2GD32H7 SPI簡介

GD32H7 的SPI主要特性如下:

?具有全雙工、 半雙工和單工模式的主從操作;

? 32位寬度,獨立的發(fā)送和接收FIFO;

? 4位到32位數(shù)據(jù)幀格式;

?低位在前或高位在前的數(shù)據(jù)位順序;

?軟件和硬件NSS管理,MOSI與MISO引腳復用功能的交換;

?硬件CRC計算、發(fā)送和校驗;

?發(fā)送和接收支持DMA模式;

?支持SPI TI模式;

?多主機多從機功能;

?配置和設置保護;

?可調的數(shù)據(jù)幀之間的最小延時和NSS與數(shù)據(jù)流之間的最小延時;

?主機模式錯誤可觸發(fā)中斷,上溢、 下溢和CRC錯誤檢測;

?可調的主設備接收器采樣時間;

?可配置的FIFO閾值(數(shù)據(jù)打包) ;

?在從機模式,下溢條件可配置;

?支持SPI四線功能的主機模式(只有SPI3 / 4)。

以下為GD32H7 SPI的框圖:

wKgaomZeitGAb4p8AADlvien-Qc228.png

如果小伙伴用過GD的其他系列MCU的SPI的話,就會發(fā)現(xiàn)H7和其他系列再SPI上的一個很大的不同,比如聚沃發(fā)布的紫藤派開發(fā)板用到的GD32F470的SPI是通過一個發(fā)送緩沖區(qū)和一個接受緩沖區(qū)這兩個緩沖區(qū)來進行數(shù)據(jù)收發(fā)的,而H7產(chǎn)品則采用FIFO的模式進行數(shù)據(jù)收發(fā)管理,且發(fā)送FIFO(TXFIFO)對應TX位移寄存器,接受FIFO(RXFIFO)對應RX位移寄存器。當CPU或DMA將數(shù)據(jù)寫到TXFIFO中(需要先判斷TXFIFO是否有足夠的空間能夠寫入數(shù)據(jù)),TXFIFO中的數(shù)據(jù)將會被轉移到TX位移寄存器中,實現(xiàn)發(fā)送;反之,當RX位移寄存器收到數(shù)據(jù),會將數(shù)據(jù)轉移到RXFIFO中(需要保證RXFIFO有足夠的空間存入數(shù)據(jù)),RXFIFO會通知CPU或者DMA取走數(shù)據(jù)。

GD32H7的SPI TxFIFO和RxFIFO的大小都為16*32位,F(xiàn)IFO的存在使得當CPU或者DMA來不及處理SPI數(shù)據(jù)時,能夠防止發(fā)生數(shù)據(jù)過載或丟失。需要提醒的是,SPI正在發(fā)送的數(shù)據(jù)不一定是最新寫到TxFIFO中的數(shù)據(jù),因為最新數(shù)據(jù)在TxFIFO的末尾;CPU或者DMA接收到的數(shù)據(jù)不一定就是SPI最新的數(shù)據(jù),因為SPI最新的數(shù)據(jù)在RxFIFO的末尾。

全雙工模式下,當GD32H7 SPI主機TX位移寄存器被寫入數(shù)據(jù)時,TX位移寄存器通過MOSI信號線將字節(jié)傳送給從機,從機也將自己的位移寄存器內容通過MISO信號線返回給主機的RX位移寄存器。外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的字節(jié);反之,若主機要讀取從機的一個字節(jié),就必須發(fā)送一個空字節(jié)來引發(fā)從機的傳輸。

SPI數(shù)據(jù)bit在CLK的有效邊沿被鎖存,而有效邊沿是可以選擇的,分別為:

  • 第一個上升沿
  • 第一個下降沿
  • 第二個下降沿
  • 第二個上升沿

通過SPI_CFG1寄存器中的CKPL位和CKPH位來設置有效鎖存沿。其中CKPL位決定了空閑狀態(tài)時SCK的電平,CKPH位決定了第一個或第二個時鐘跳變沿為有效采樣邊沿。SPI_CFG1中的LF位可以配置數(shù)據(jù)順序, 當LF=1時,SPI先發(fā)送LSB位,當LF=0時,則先發(fā)送MSB位。SPI_CFG0中的DZ[4:0]位域配置數(shù)據(jù)長度, 可以設置數(shù)據(jù)長度為4位至32位。下圖為SPI的時序圖:

wKgZomZGtwyAMa87AAEFndP9lRg166.png

4線SPI(QSPI)的時序圖如下(CKPL=1, CKPH=1, LF=0) ,我們可以看到QSPI是通過MOSI、MISO、IO2、IO3來進行數(shù)據(jù)收或發(fā),所以QSPI是工作在半雙工模式:

wKgaomZGtxiAQZDAAACi0HWwbFI179.png

這里再介紹下SPI的NSS(片選)功能。NSS電平由主機來控制,主機將需要操作的從機NSS拉低,從而使該從機在總線上生效。

主機控制NSS的方式有兩種——硬件方式和軟件方式。主機硬件NSS模式下,NSS腳只能選擇特定IO口(具體見datasheet中IO口功能表),當開始進行數(shù)據(jù)讀寫時,NSS自動拉低,這種方式的優(yōu)點是主機NSS由硬件自動控制,缺點是只能控制一個從機;主機NSS軟件模式下,NSS可以使用任意IO口,需要控制哪個從機,軟件將對于IO拉低即可,這種方式的優(yōu)點是可以實現(xiàn)一個主機多個從機的通訊,缺點是軟件需要介入控制NSS腳。

從機獲取NSS狀態(tài)的方式也有兩種——硬件方式和軟件方式。從機硬件NSS模式下,SPI從NSS引腳獲取NSS電平, 在軟件NSS模式(NSSIM = 1) 下,SPI根據(jù)SNSSI位得到NSS電平。

SPI除了單線全雙工模式外,還有很多其他方式,比如可以實現(xiàn)只用MOSI進行數(shù)據(jù)收和發(fā)的半雙工通訊,這樣就可以省下MISO用作他處了,具體可以參考GD32FH7系列官方用戶手冊。

這里著重介紹下H7 SPI的數(shù)據(jù)長度和SPI_CFG0中的BYTEN(bit23)和WORDEN(bit24)。BYTEN和WORDEN用來指示對FIFO的訪問寬度:

wKgaomZeiw6ATZdnAAA_mySfJPU353.png

建議SPI的數(shù)據(jù)長度設置(SPI_CFG0中的DZ[4:0]位域)和FIFO訪問寬度匹配,比如設置SPI數(shù)據(jù)長度為8,則需要配置FIFO訪問寬度為字節(jié)訪問,若配置FIFO訪問寬度為半字訪問,當發(fā)送一個8位數(shù)據(jù)時,總線上會產(chǎn)生16個clock,從而導致數(shù)據(jù)錯位。

下面介紹下SPI的發(fā)送和接受流程:

發(fā)送流程

在完成初始化過程之后, SPI模塊使能并保持在空閑狀態(tài)。在主機模式下, 當軟件寫一個數(shù)據(jù)到TxFIFO時,發(fā)送過程開始。在從機模式下,當SCK引腳上的SCK信號開始翻轉, 且NSS引腳電平有效, 發(fā)送過程開始。 所以, 在從機模式下,應用程序必須確保在數(shù)據(jù)發(fā)送開始前, 數(shù)據(jù)已經(jīng)寫入TxFIFO中。

當SPI開始發(fā)送一個數(shù)據(jù)幀時, 首先將這個數(shù)據(jù)幀從TxFIFO加載到移位寄存器中,然后開始發(fā)送加載的數(shù)據(jù)。

對SPI_TDATA的寫訪問由TP——TxFIFO數(shù)據(jù)包空間有效標志事件管理。

wKgZomZeix6AI-Y1AABvvFGtuoY065.png

當TP標志設置為1時,應用程序對SPI數(shù)據(jù)寄存器寫入適當數(shù)量的數(shù)據(jù),以傳輸數(shù)據(jù)包的內容。在上傳新的完整包后,應用程序檢查TP值,檢查TxFIFO是否可以接收額外的數(shù)據(jù)包,如果TP = 1,則逐包上傳,直到TP讀取0。
在主機模式下, 若想要實現(xiàn)連續(xù)發(fā)送功能, 那么在當前數(shù)據(jù)幀發(fā)送完成前, 軟件應該將下一個數(shù)據(jù)寫入SPI_TDATA寄存器中。 只要TxFIFO中存在數(shù)據(jù), 數(shù)據(jù)發(fā)送便一直繼續(xù), 直至TxFIFO變?yōu)榭铡?

接收流程
在最后一個采樣時鐘邊沿之后, 接收到的數(shù)據(jù)將從移位寄存器存入到RxFIFO, 且RP——RxFIFO數(shù)據(jù)包空間有效標志 位置1。

wKgaomZeiyuAHBE9AAB2Wee2k-c095.png

軟件通過讀SPI_RDATA寄存器獲得接收的數(shù)據(jù), 此操作會自動清除RP標志位(當RxFIFO數(shù)據(jù)量少于FIFOLVL標準)。 在全雙工主機模式(MFD)中, 僅當TxFIFO非空時,硬件才接收下一個數(shù)據(jù)幀。
對SPI_RDATA的讀訪問由RP事件管理。 當RP標志設置為1時,應用程序讀取SPI數(shù)據(jù)寄存器相當數(shù)量的數(shù)據(jù),以下載單個數(shù)據(jù)包內容。下載完整數(shù)據(jù)包后,應用程序會檢查RP值,查看RxFIFO中是否有其他數(shù)據(jù)包,如果有,則逐包下載,直到RP讀到0。
接收數(shù)據(jù)時, 主機提供時鐘信號, 當主機停止或掛起SPI時才會停止接收流程。主機通過將MSTART位置1來啟動流程, 可通過向SPI_CTL0寄存器的MSPDR為寫1來請求掛起,或者向MASP位寫1來設置上溢掛起。

11.2.3SPI FLASH——GD25Q128ESIGR簡介

GD25Q128ESIGR是一款容量為128Mbit(即16Mbyte)的SPI接口的NOR FLASH,其支持SPI和QSPI模式,芯片示意圖如下:

wKgaomZGtzGAeKaSAABOyFlqAis956.png

GD25Q128ESIGR管腳定義如下:

wKgZomZGtz2AHBTpAADoXtfKGP0321.png

GD25Q128ESIGR內部flash結構如下:

wKgaomZei1CANfeEAACqzNN5-BY495.png

下面介紹GD25Q128ESIGR的一些功能碼。

Write Enable (WREN) (06H) :接受到該命令后,GD25Q128ESIGR做好接受數(shù)據(jù)并進行存儲的準備,時序如下:

wKgaomZGt1uADgO6AABE5nXZFUw843.png

Read Status Register (RDSR) (05H or 35H or 15H) :讀GD25Q128ESIGR的狀態(tài),時序如下:

wKgaomZGt2iAZ27JAADcULbDKgM319.png

Read Data Bytes (READ) (03H) :接受到該命令后,GD25Q128ESIGR將數(shù)據(jù)準備好供主機讀走,時序如下:

wKgZomZGt3OAfcktAAC-cw2PFnk420.png

Dual Output Fast Read (3BH) :使GD25Q128ESIGR切換到QSPI模式,時序如下:

wKgZomZGt4WAXYejAAD4-W0AVwI742.png

Quad Output Fast Read (6BH) :QSPI讀命令,時序如下:

wKgaomZGt5CARXRwAAFdcIES_y0316.png

Quad Page Program (32H) :QSPI寫命令,時序如下:

wKgZomZGt52AfzjcAAD4QGFpgL4956.png

Sector Erase (SE) (20H) :Sector擦除命令,時序如下:

wKgaomZGt8SAJ6rzAABsjZB4j98071.png

GD25Q128ESIGR就介紹到這里,讀者可以在兆易創(chuàng)新官網(wǎng)下載該NOR FLASH的datasheet以獲取更多信息。

11.3硬件設計

海棠派開發(fā)板SPI——NOR FLASH的硬件設計如下:

wKgaomZGt9CAQQMZAAC_TVQigbY825.png

從圖中可以看出,本實驗使用的是普通單線SPI,GD25Q128ESIGR的片選由GD32H757的PF6控制,并采用主機NSS軟件模式,GD25Q128ESIGR的SO、SI和SCLK分別和GD32H757的PF8(SPI4_MISO)、PB9(SPI4_MOSI)以及PF7(SPI4_CLK)相連。

11.4代碼解析

11.4.1SPI初始化函數(shù)

在driver_spi.c文件中定義了SPI初始化函數(shù)driver_spi_init:

C void driver_spi_init(typdef_spi_struct *spix) { spi_parameter_struct spi_init_struct; rcu_periph_clock_enable(spix->rcu_spi_x); /* spi configure */ spi_i2s_deinit(spix->spi_x); spix->spi_sck_gpio->speed=GPIO_OSPEED_60MHZ; spix->spi_mosi_gpio->speed=GPIO_OSPEED_60MHZ; spix->spi_miso_gpio->speed=GPIO_OSPEED_60MHZ; driver_gpio_general_init(spix->spi_cs_gpio); driver_gpio_general_init(spix->spi_sck_gpio); driver_gpio_general_init(spix->spi_mosi_gpio); driver_gpio_general_init(spix->spi_miso_gpio); if(spix->spi_mode==MODE_DMA) { if(spix->spi_rx_dma!=NULL) { if(spix->frame_size==SPI_DATASIZE_8BIT){ driver_dma_com_init(spix->spi_rx_dma,(uint32_t)&SPI_RDATA(spix->spi_x),NULL,DMA_Width_8BIT,DMA_PERIPH_TO_MEMORY); } else if(spix->frame_size==SPI_DATASIZE_16BIT){ driver_dma_com_init(spix->spi_rx_dma,(uint32_t)&SPI_RDATA(spix->spi_x),NULL,DMA_Width_16BIT,DMA_PERIPH_TO_MEMORY); } else if(spix->frame_size==SPI_DATASIZE_32BIT){ driver_dma_com_init(spix->spi_rx_dma,(uint32_t)&SPI_RDATA(spix->spi_x),NULL,DMA_Width_32BIT,DMA_PERIPH_TO_MEMORY); } } if(spix->spi_tx_dma!=NULL) { if(spix->frame_size==SPI_DATASIZE_8BIT){ driver_dma_com_init(spix->spi_tx_dma,(uint32_t)&SPI_TDATA(spix->spi_x),NULL,DMA_Width_8BIT,DMA_MEMORY_TO_PERIPH); } else if(spix->frame_size==SPI_DATASIZE_16BIT){ driver_dma_com_init(spix->spi_tx_dma,(uint32_t)&SPI_TDATA(spix->spi_x),NULL,DMA_Width_16BIT,DMA_MEMORY_TO_PERIPH); } else if(spix->frame_size==SPI_DATASIZE_32BIT){ driver_dma_com_init(spix->spi_tx_dma,(uint32_t)&SPI_TDATA(spix->spi_x),NULL,DMA_Width_32BIT,DMA_MEMORY_TO_PERIPH); } } } if(spix->spi_cs_gpio!=NULL) { driver_gpio_pin_set(spix->spi_cs_gpio); } spi_struct_para_init(&spi_init_struct); /* SPI3 parameter config */ spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; spi_init_struct.device_mode = spix->device_mode; spi_init_struct.data_size = spix->frame_size; spi_init_struct.clock_polarity_phase = spix->clock_polarity_phase; if(spix->device_mode==SPI_MASTER){ spi_init_struct.nss = SPI_NSS_SOFT; }else{ spi_init_struct.nss = SPI_NSS_HARD; } spi_init_struct.prescale = spix->prescale; spi_init_struct.endian = spix->endian; spi_init(spix->spi_x, &spi_init_struct); /* enable SPI byte access */ spi_byte_access_enable(spix->spi_x); /* configure SPI current data number */ spi_current_data_num_config(spix->spi_x, 0); spi_nss_output_enable(spix->spi_x); /* enable SPI3 */ spi_enable(spix->spi_x); /* start SPI master transfer */ spi_master_transfer_start(spix->spi_x, SPI_TRANS_START); }

11.4.2SPI輪訓接受一個數(shù)函數(shù)

在driver_spi.c文件中定義了使用輪訓方式發(fā)送接受一個字節(jié)數(shù)據(jù)函數(shù)driver_spi_master_transmit_receive_byte:

C uint8_t driver_spi_master_transmit_receive_byte(typdef_spi_struct *spix,uint8_t byte) { spi_i2s_flag_clear(spix->spi_x, SPI_STATC_TXURERRC|SPI_STATC_RXORERRC|SPI_STATC_CRCERRC|SPI_STATC_FERRC|SPI_STATC_CONFERRC); driver_spi_flag_wait_timeout(spix,SPI_FLAG_TP,SET); spi_i2s_data_transmit(spix->spi_x,byte); driver_spi_flag_wait_timeout(spix,SPI_FLAG_RP,SET); return spi_i2s_data_receive(spix->spi_x); }

上面函數(shù)中有帶超時功能的等待SPI狀態(tài)的函數(shù)driver_spi_flag_wait_timeout,該函數(shù)定義在driver_spi.c:

C Drv_Err driver_spi_flag_wait_timeout(typdef_spi_struct *spix, uint32_t flag ,FlagStatus wait_state) { __IO uint64_t timeout = driver_tick; while(wait_state!=spi_i2s_flag_get(spix->spi_x, flag)){ if((timeout+SPI_TIMEOUT_MS) <= driver_tick) { return DRV_ERROR; } } return DRV_SUCCESS; }

11.4.3SPI NOR FLASH 接口bsp層函數(shù)

操作NOR FLASH的函數(shù)都定義在bsp層文件bsp_spi_nor.c中,這個文件中定義的函數(shù)都是針對NOR FLASH特性來實現(xiàn)的,我們選取幾個函數(shù)進行介紹。

1、NOR FLASH按sector擦除函數(shù)bsp_spi_nor_sector_erase,該函數(shù)流程是:使能NOR FLASH的寫功能->拉低片選->向NOR FLASH發(fā)送sector擦除指令SE(0x20)->從低地址到高地址發(fā)送需要擦除的地址->拉高片選->等待NOR FALSH內部操作完成(循環(huán)去讀NOR FLASH狀態(tài),直到讀出編程狀態(tài)為0)

C void bsp_spi_nor_sector_erase(uint32_t sector_addr) { /* send write enable instruction */ bsp_spi_nor_write_enable(); /* sector erase */ /* select the flash: chip select low */ bsp_spi_nor_cs_low(); /* send sector erase instruction */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,SE); /* send sector_addr high nibble address byte */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,(sector_addr & 0xFF0000) >> 16); /* send sector_addr medium nibble address byte */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,(sector_addr & 0xFF00) >> 8); /* send sector_addr low nibble address byte */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,sector_addr & 0xFF); /* deselect the flash: chip select high */ bsp_spi_nor_cs_high(); /* wait the end of flash writing */ bsp_spi_nor_wait_for_write_end(); }

2、按page寫數(shù)據(jù)函數(shù)bsp_spi_nor_page_write,該函數(shù)實現(xiàn)在page范圍內寫數(shù)據(jù),該函數(shù)流程是:使能NOR FLASH的寫功能->拉低片選->向NOR FLASH發(fā)送寫指令WRITE(0x02)->從低地址到高地址發(fā)送要寫的地址(每次進行寫數(shù)據(jù)時,只需要給初始地址即可,寫完一個數(shù)據(jù)后NOR FLASH內部會自動把地址+1)->寫數(shù)據(jù)->拉高片選->等待NOR FALSH內部操作完成(循環(huán)去讀NOR FLASH狀態(tài),直到讀出編程狀態(tài)為0)

C void bsp_spi_nor_page_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write) { /* enable the write access to the flash */ bsp_spi_nor_write_enable(); /* select the flash: chip select low */ bsp_spi_nor_cs_low(); /* send "write to memory" instruction */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,WRITE); /* send write_addr high nibble address byte to write to */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,(write_addr & 0xFF0000) >> 16); /* send write_addr medium nibble address byte to write to */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,(write_addr & 0xFF00) >> 8); /* send write_addr low nibble address byte to write to */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,write_addr & 0xFF); /* while there is data to be written on the flash */ while(num_byte_to_write--){ /* send the current byte */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,*pbuffer); /* point on the next byte to be written */ pbuffer++; } /* deselect the flash: chip select high */ bsp_spi_nor_cs_high(); /* wait the end of flash writing */ bsp_spi_nor_wait_for_write_end(); }

3、按buffer寫數(shù)據(jù)函數(shù)bsp_spi_nor_buffer_write,該函數(shù)實現(xiàn)任意長度數(shù)據(jù)寫入,使用page寫函數(shù)搭配算法,可以跨page進行寫數(shù)據(jù):

C void bsp_spi_nor_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write) { uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0; addr = write_addr % SPI_FLASH_PAGE_SIZE; count = SPI_FLASH_PAGE_SIZE - addr; num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE; num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE; /* write_addr is SPI_FLASH_PAGE_SIZE aligned */ if(0 == addr){ /* num_byte_to_write < SPI_FLASH_PAGE_SIZE */ if(0 == num_of_page) bsp_spi_nor_page_write(pbuffer,write_addr,num_byte_to_write); /* num_byte_to_write > SPI_FLASH_PAGE_SIZE */ else{ while(num_of_page--){ bsp_spi_nor_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE); write_addr += SPI_FLASH_PAGE_SIZE; pbuffer += SPI_FLASH_PAGE_SIZE; } bsp_spi_nor_page_write(pbuffer,write_addr,num_of_single); } }else{ /* write_addr is not SPI_FLASH_PAGE_SIZE aligned */ if(0 == num_of_page){ /* (num_byte_to_write + write_addr) > SPI_FLASH_PAGE_SIZE */ if(num_of_single > count){ temp = num_of_single - count; bsp_spi_nor_page_write(pbuffer,write_addr,count); write_addr += count; pbuffer += count; bsp_spi_nor_page_write(pbuffer,write_addr,temp); }else bsp_spi_nor_page_write(pbuffer,write_addr,num_byte_to_write); }else{ /* num_byte_to_write > SPI_FLASH_PAGE_SIZE */ num_byte_to_write -= count; num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE; num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE; bsp_spi_nor_page_write(pbuffer,write_addr, count); write_addr += count; pbuffer += count; while(num_of_page--){ bsp_spi_nor_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE); write_addr += SPI_FLASH_PAGE_SIZE; pbuffer += SPI_FLASH_PAGE_SIZE; } if(0 != num_of_single) bsp_spi_nor_page_write(pbuffer,write_addr,num_of_single); } } }

4、按buffer讀數(shù)據(jù)函數(shù)bsp_spi_nor_buffer_read,該函數(shù)實現(xiàn)任意地址讀數(shù)據(jù),該函數(shù)流程是:拉低片選->向NOR FLASH發(fā)送讀指令READ(0x03)->從低地址到高地址發(fā)送要讀的地址(每次進行讀數(shù)據(jù)時,只需要給初始地址即可,讀完一個數(shù)據(jù)后NOR FLASH內部會自動把地址+1)->讀數(shù)據(jù)->拉高片選:

C void bsp_spi_nor_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read) { /* select the flash: chip slect low */ bsp_spi_nor_cs_low(); /* send "read from memory " instruction */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,READ); /* send read_addr high nibble address byte to read from */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,(read_addr & 0xFF0000) >> 16); /* send read_addr medium nibble address byte to read from */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,(read_addr& 0xFF00) >> 8); /* send read_addr low nibble address byte to read from */ driver_spi_master_transmit_receive_byte(&BOARD_SPI,read_addr & 0xFF); /* while there is data to be read */ while(num_byte_to_read--){ /* read a byte from the flash */ *pbuffer = driver_spi_master_transmit_receive_byte(&BOARD_SPI,NOR_DUMMY_BYTE); /* point to the next location where the byte read will be saved */ pbuffer++; } /* deselect the flash: chip select high */ bsp_spi_nor_cs_high(); }

11.4.4main函數(shù)實現(xiàn)

以下為main函數(shù)代碼:

C int main(void) { //延時、共用驅動部分初始化 driver_init(); //初始化LED組和默認狀態(tài) bsp_led_group_init(); bsp_led_on(&LED1); bsp_led_off(&LED2); //初始化UART打印 bsp_uart_init(&BOARD_UART); //初始化SPI bsp_spi_init(&BOARD_SPI); //初始化SPI NOR bsp_spi_nor_init(); printf_log("\n\rSPI Flash:GD25Q configured...\n\r"); //讀取flash id flash_id = bsp_spi_nor_read_id(); printf_log("\n\rThe Flash_ID:0x%X\n\r",flash_id); //比對flash id是否一致 if(SFLASH_4B_ID == flash_id || SFLASH_16B_ID == flash_id) { printf_log("\n\rWrite to tx_buffer:\n\r"); //準備數(shù)據(jù) for(uint16_t i = 0; i < BUFFER_SIZE; i++){ tx_buffer[i] = i; printf_log("0x%02X ",tx_buffer[i]); if(15 == i%16){ printf_log("\n\r"); } } printf_log("\n\r"); printf_log("\n\rRead from rx_buffer:\n\r"); //擦除要寫入的sector bsp_spi_nor_sector_erase(FLASH_WRITE_ADDRESS); //寫入數(shù)據(jù) bsp_spi_nor_buffer_write(tx_buffer,FLASH_WRITE_ADDRESS,TX_BUFFER_SIZE); //延時等待寫完成 delay_ms(10); //回讀寫入數(shù)據(jù) bsp_spi_nor_buffer_read(rx_buffer,FLASH_READ_ADDRESS,RX_BUFFER_SIZE); /* printf_log rx_buffer value */ for(uint16_t i = 0; i < BUFFER_SIZE; i++){ printf_log("0x%02X ", rx_buffer[i]); if(15 == i%16){ printf_log("\n\r"); } } printf_log("\n\r"); //比較回讀和寫入數(shù)據(jù) if(ERROR == memory_compare(tx_buffer,rx_buffer,BUFFER_SIZE)){ printf_log("Err:Data Read and Write aren't Matching.\n\r"); //寫入錯誤 /* turn off all leds */ bsp_led_on(&LED2); /* turn off all leds */ bsp_led_on(&LED1); while(1); }else{ printf_log("\n\rSPI-GD25Q16 Test Passed!\n\r"); } }else{ //ID讀取錯誤 /* spi flash read id fail */ printf_log("\n\rSPI Flash: Read ID Fail!\n\r"); /* turn off all leds */ bsp_led_on(&LED2); /* turn off all leds */ bsp_led_on(&LED1); while(1); } while(1){ /* turn off all leds */ bsp_led_toggle(&LED2); /* turn off all leds */ bsp_led_toggle(&LED1); delay_ms(200); } }

main函數(shù)中實現(xiàn)了向特定NOR FLASH地址寫數(shù)據(jù),并回讀出來,并將寫入的數(shù)據(jù)和回讀出來的數(shù)據(jù)進行對比,看是否寫入成功。

11.5實驗結果

將本實驗例程燒錄到GD32H757紫海棠派開發(fā)板中,將會顯示對外部SPI flash寫入以及讀取的數(shù)據(jù)以及最終的校驗結果,如果寫入讀取校驗正確,將會顯示SPI-GD25QXX Test Passed,LED1和LED2將會交替閃爍。

教程GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關注聚沃科技官網(wǎng)

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6078

    文章

    45590

    瀏覽量

    673940
  • mcu
    mcu
    +關注

    關注

    147

    文章

    19160

    瀏覽量

    404732
  • 開發(fā)板
    +關注

    關注

    26

    文章

    6433

    瀏覽量

    121184
  • NOR flash
    +關注

    關注

    2

    文章

    109

    瀏覽量

    23957
  • GD32
    +關注

    關注

    7

    文章

    434

    瀏覽量

    27654
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    如何使用 SPI NOR 閃存啟動電路?

    嘗試從 SPI NOR 閃存啟動自定義 T2080 我能夠使用 CW IDE 中的閃存編程器將自定義 RCW bin 文件加載到串行 NOR 閃存中,但在使用
    發(fā)表于 04-21 09:07

    使用JL杰理AC696N開發(fā)板實現(xiàn)PC模式下讀取外掛SPI Flash虛擬為U盤的具體案例操作說明_V1.0

    開發(fā)板上的三個SPI引腳( SPIDI 、 SPICLK 、 SPICS )通過跳線帽或杜邦線連接到外掛Flash芯片的對應引腳。 Flash型號 :支持市面上主流的
    發(fā)表于 04-18 00:04

    通用SPI接口的NOR Flash存儲器特性

    在嵌入式系統(tǒng)設計中,NOR Flash存儲器憑借其快速讀取和可靠的數(shù)據(jù)存儲能力,成為代碼存儲與直接執(zhí)行(XIP)的核心器件。英尚代理推出的一款適合工業(yè)級應用的SPI接口NOR
    的頭像 發(fā)表于 04-07 15:15 ?176次閱讀

    JL杰理AC696N系列芯片SPI接口實戰(zhàn):驅動Flash、LCD與RGB燈

    文章闡述了,杰理AC696N系列芯片功能:驅動Flash、LCD、RGB等。AC696N開發(fā)板支持SPI主機模式,可輕松驅動這種類型外設。
    的頭像 發(fā)表于 04-01 17:49 ?1243次閱讀
    JL杰理AC696N系列芯片<b class='flag-5'>SPI</b>接口實戰(zhàn):驅動<b class='flag-5'>Flash</b>、LCD與RGB燈

    NOR Flash 到 NAND Flash 和SD NAND,從底層結構到應用差異

    nor flash,nor nand,sd nand,spi nor,nand flash
    的頭像 發(fā)表于 03-05 18:24 ?459次閱讀
    從<b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b> 到 NAND <b class='flag-5'>Flash</b> 和SD NAND,從底層結構到應用差異

    深入解析Rockchip SFC驅動:SPI Flash傳輸流程與問題排查指南

    Controller)驅動 (spi-rockchip-sfc.c),用于高效管理SPI Flash讀寫傳輸。本文基于Linux內核驅動代碼與Rockchip官方
    的頭像 發(fā)表于 02-04 07:13 ?844次閱讀
    深入解析Rockchip SFC驅動:<b class='flag-5'>SPI</b> <b class='flag-5'>Flash</b>傳輸流程與問題排查指南

    SPI NOR FlashSPI NAND Flash存儲芯片的區(qū)別

    SPI NOR FlashSPI NAND Flash并非相互替代,而是互補關系。SPI
    的頭像 發(fā)表于 01-29 16:58 ?927次閱讀
    <b class='flag-5'>SPI</b> <b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b>和<b class='flag-5'>SPI</b> NAND <b class='flag-5'>Flash</b>存儲芯片的區(qū)別

    ESP32-C5迷你開發(fā)板上手指南!輕松驅動SPI屏幕!

    本文將帶你一步步完成WT9932C5-TINY開發(fā)板的燒錄與SPI屏幕驅動,從硬件連接到軟件燒錄,直至最終的效果演示。無需復雜的前期準備,跟著教程操作即可快速上手。硬件連接1準備材料1
    的頭像 發(fā)表于 01-19 18:04 ?1212次閱讀
    ESP32-C5迷你<b class='flag-5'>開發(fā)板</b>上手指南!輕松驅動<b class='flag-5'>SPI</b>屏幕!

    國產(chǎn)SPI NOR Flash接口閃存介紹

    在當今各類電子設備對存儲性能要求日益提升的背景下,SPI NOR Flash憑借其高速讀取、低功耗及靈活接口等優(yōu)勢,成為嵌入式系統(tǒng)代碼存儲的關鍵元件。GT25Q系列SPI
    的頭像 發(fā)表于 12-26 11:51 ?686次閱讀

    高性能SPI NOR FLASH芯片ZB25VQ系列推薦

    在嵌入式系統(tǒng)、物聯(lián)網(wǎng)設備及各類存儲應用中,SPI NOR FLASH芯片因其接口簡單、功耗低、讀寫速度快等特點,成為代碼存儲與數(shù)據(jù)緩存的常見選擇。S
    的頭像 發(fā)表于 12-01 14:52 ?901次閱讀

    SPI NOR FLASH是什么,與SPI NAND Flash的區(qū)別

    SPI NOR FLASH是什么? ? SPI NOR FLASH是一種非易失性存儲器,它通過串
    的頭像 發(fā)表于 08-21 09:26 ?1901次閱讀

    【BPI-CanMV-K230D-Zero開發(fā)板體驗】+閃存讀寫程序的分析

    0xC8,其設備ID則是0x18。 圖3 讀取ID 至于數(shù)據(jù)的讀寫,則需要依據(jù)該程序框架自行補充完成。 仍以讀取芯片ID為例,通常的C語言程序為: u32 SPI_FLASH_ReadID(void
    發(fā)表于 06-30 16:28

    【Banana Pi BPI-RV2開發(fā)板試用體驗】開箱上電

    BPI-RV2 RISC-V開源路由器之開箱上電 背景 現(xiàn)在剛好正在研究短距及網(wǎng)絡相關的東東。 最近剛好有幸得到了一塊香蕉 BPI-RV2 RISC-V 開源路由器開發(fā)板。感謝電子發(fā)燒友
    發(fā)表于 06-26 19:51

    【Banana Pi BPI-RV2開發(fā)板試用體驗】開發(fā)板介紹視頻

    一. 開發(fā)板介紹香蕉 BPI-RV2 RISC-V 路由器開發(fā)板采用矽昌通信 SF21H8898 芯片方案矽昌 SF21H8898 四核6
    發(fā)表于 06-24 23:51

    第十七章 SPI——讀寫串行FLASH

    本章介紹SPI協(xié)議,其為高速全雙工通信總線,含物理層、協(xié)議層內容,還講解W55MH32的SPI特性、初始化及DMA相關配置。
    的頭像 發(fā)表于 06-19 17:06 ?1450次閱讀
    <b class='flag-5'>第十</b>七章 <b class='flag-5'>SPI</b>——<b class='flag-5'>讀寫</b>串行<b class='flag-5'>FLASH</b>
    隆子县| 邢台县| 大渡口区| 淮滨县| 磐安县| 云霄县| 庆安县| 化德县| 容城县| 荥经县| 涿鹿县| 凭祥市| 景德镇市| 梁平县| 金昌市| 密云县| 垫江县| 新巴尔虎左旗| 嘉善县| 灵寿县| 屏东市| 博野县| 光泽县| 丰都县| 林甸县| 横峰县| 榆中县| 兰州市| 方城县| 商河县| 登封市| 阿克苏市| 辰溪县| 安图县| 临清市| 黄陵县| 易门县| 新泰市| 泗水县| 乌兰浩特市| 沾化县|