STM32F103之SPI軟件讀寫W25Q64

一、W25Q64簡介

1.1 簡介? ? ? ?

W25Q64(Nor flash)、? ?24位地址,64Mbit/8MByte、是一種低成本、小型化、使用簡單的非易失性存儲器,常用于數據存儲、字庫存儲、固件程序存儲等場景?
? ? ? ? 時鐘頻率:最大80MHz(STM32F103系統時鐘為72MHz)、160MHz(MOSI,MISO同時發送,同時接受)、320MHz(將引腳DO、DI、WP、HOLD同時接收或發送)

W25Q64封裝
引腳描述

VCC:? 2.7-3.6V
WP:? ? 寫保護,低電平有效,當為低電平時,不可寫
HOLD:數據保持、低電平有效;如果在正常讀寫flash時,突然產生中斷,想用SPI去操控其他器件,要是把CS置1,則flash時序就會終止;若將HOLD置0,則時序可以保持原有狀態

1.2 框圖-地址劃分

24位地址,可尋址范圍:0x000000-0xFFFFFF;由于W25Q64的容量為8MB,所以其地址范圍為0x000000-0x7FFFFF

flash 框圖
flash 空間劃分

將8MB的空間劃分為塊(block),每一個塊的容量為64KB,共劃分128塊
將每一個64KB塊劃分為扇區,一個塊可劃分為16個扇區,一共有2048個扇區
將每一4KB的扇區劃分為頁,一個扇區可劃分16個頁;也可以看作一個flash可劃分為32768個頁
一頁是256字節 ,一塊是256頁

如果想要往第3個塊第210頁的第118個字節寫入,物理地址是多少呢?
第三個塊對應高八位字節:0x020000
第210個頁對應中間八位(頁地址鎖存器):0x00D100
第118個字節對應第八位((字節地址鎖存器):0x000075
所以物理地址為:0x02D175(24位地址)


例如寫入地址為0x123456,對應的是多少呢
0x12->18,也就是塊17(或第18個塊)
0x34->52,也就是塊17頁51(或第52個頁)
0x56->86,也就是塊17頁51的85字節(或第86個字節)

也就是說18*16+52-1=4659,對應4659頁的85字節開始寫入

當往flash中寫入數據時,寫入的數據先緩存到256字節頁緩沖區,再從緩沖區轉到flash里,這需要一定的時間,在這期間,芯片的flash的busy標志位將被置1;
注意:由于緩沖區只有256個字節,所以寫入的一個時序連續寫入的數據量不能超過256個字節

1.3 讀寫flash注意事項

寫入時
<1>寫入操作前必須進行寫使能
<2>每個數據位只能由1改寫為0,不能由0改寫為1
? ? ? 例如 原來數據為0x78(01111000),想要在本地址直接寫入0x11(00010001),就會變為? ? ? ? ? ? ? 00010000
<3>寫入前必須想先要擦除,擦除后,所有數據位變為1(0xFF表示空白)
<5>擦除必須按最小單元進行(最小單元為扇區(4KB=4096字節))
? ? ? ?想要單獨改寫某一個字節,可以先將扇區的全部數據讀出后,該寫完讀出來的數據后再? ? ? ? ? 寫入或者一個字節占一個扇區
<6>連續寫入多字節時,最多寫入一頁的數據;超過尾頁的數據會回到頁尾覆蓋數據(不能跨頁)
<7>寫入操作結束后,芯片進入忙狀態,不響應新的讀寫操作(擦除時也會進入忙狀態)(可讀狀態寄存器的busy位)

讀取
<1>直接調用讀取時序、無需使能、無需額外操作,沒有頁的限制讀取操作結束后不會進入忙狀態,但不能在忙狀態時讀取

?注意:當給定一個地址時,數據會按地址自增寫入,且不可跨頁寫入,如果大于頁的容量會從本頁頭開始覆蓋;寫使能只對之后跟隨的一條指令有效

?二、軟件模擬SPI讀取flash

SPI是一種協議,軟件可以進行模擬,如果板子上沒有SPI端口或者SPI的端口被占用時,軟件可以進行模擬,通過軟件控制四個引腳的高低電平,從而達到硬件的效果,本節進行軟件模擬SPI(模式0),與硬件不同的是,對于軟件的四個引腳,輸入引腳(CS,CLK,MOSI)配置為上拉或浮空輸入,輸出引腳(MISO)配置為推挽輸出
對于SPI不了解的可以看一下https://mpbeta.csdn.net/mp_blog/creation/editor/148934665

引腳配置

/****************************
*@brief    SPI引腳初始化
*@param  void
*@return   void
*@note     PB13->CLK PB14->MISO->DOPB12->CS  PB15->MOSI->DI/
對于軟件來說輸出引腳配置為推挽輸出
輸入引腳配置為上拉輸入或浮空輸入
*@time  2025-6-27
******************************/
void Soft_SPI_Init(void)
{/*1.打開IO引腳時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);/*2.引腳模式配置*/GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP                   ;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15|GPIO_Pin_12 ;//輸出配置為推挽輸出GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz                  ;GPIO_Init(GPIOB,&GPIO_InitStruct)                            ;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU                      ;//輸入配置為浮空輸入GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14                         ;GPIO_Init(GPIOB,&GPIO_InitStruct)                            ;/*3.CS片選默認高電平、CLK默認低電平*/SOFT_SPI_CS(1)                                               ;//宏定義SOFT_SPI_CLK(0)                                              ;//宏定義
}
SPI模式0 時序

對于模式0,時鐘默認低電平且在時鐘的第一個邊沿進行采樣 ,有時序圖可知,MCU在時鐘下降沿通過MOSI輸出高位,在時鐘上升沿時,采樣 從機通過MOSI(對應主機MISO的)輸出的電平,在寫數據收發時序時只需要盯著主機,從機我們無法干涉

數據交換

/****************************
*@brief  交換數據
*@param     void
*@return    void
*@note     高位先發,SPI模式0
*@time  2025-6-27
******************************/
int8_t Soft_SPI_Dataswap(int8_t Send_Data)
{int8_t Receive_Data=0x00;for(int8_t i=0;i<8;i++){SOFT_SPI_MOSI(Send_Data>>(7-i)&0x01)  ;//高位數據通過MOSI送出SOFT_SPI_CLK(1)                       ;//時鐘上升沿//if(Soft_SPI_MISO()==1){Receive_Data |=(0x80>>i);}Receive_Data|=SOFT_SPI_MISO()<<(7-i)  ;//主機從從機的MOSI口接收的高位數據SOFT_SPI_CLK(0)                       ;//時鐘下降沿}return Receive_Data;
}

當時鐘為低電平時,主機通過 SOFT_SPI_MOSI(Send_Data>>(7-i)&0x01)? 將1位數據通過MOSI口送出;當時鐘位上升沿時,主機進行采樣,通過?Receive_Data|=SOFT_SPI_MISO()<<(7-i)? 將從機的MOSI上的數據采入
注意:由于C語言時逐語句進行的,所以不可能發送的同時進行接收,可以利用RTOS或者FPGA

flash函數封裝

/****************************
*@brief  讀取ID
*@param  uint8_t *MID 廠商IDuint16_t *DID 設備ID
*@return void
*@note   void
*@time  2025-6-28
******************************/
void Soft_SPI_ReadID_W25Q64(uint8_t *MID,uint16_t *DID)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_R_ID)  ;*MID = Soft_SPI_Dataswap(0XFF)    ;*DID = Soft_SPI_Dataswap(0XFF)    ;*DID <<= 8;*DID |=  Soft_SPI_Dataswap(0XFF);SOFT_SPI_STOP;
}
/****************************
*@brief    寫使能
*@param  void
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_W_ENABLE_W25Q64(void)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_W_ENABLE)  ;//指令SOFT_SPI_STOP;
}	
/****************************
*@brief   等待寄存器忙狀態
*@param    void
*@return   void
*@note    busy位維1,表示忙
*@time  2025-6-28
******************************/
void Soft_SPI_R_Status_W25Q64_busy(void)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_GetStatus);//讀取指令while(Soft_SPI_Dataswap(0xFF)&0x01)  ;//busy=1時等待SOFT_SPI_STOP;
}	
/****************************
*@brief    頁編程
*@param  uint8_t ArrayData[]數據uint32_t Address寫入的數據地址uint16_t len     字節個數
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_W_Data_W25Q64(uint8_t *ArrayData,uint32_t Address,uint16_t cnt)
{Soft_SPI_W_ENABLE_W25Q64();//寫使能SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_W_DATA);//寫指令/*函數Soft_SPI_Dataswap()一次只能交換8位*/Soft_SPI_Dataswap(Address>>16);   //高地址,決定哪塊Soft_SPI_Dataswap(Address>>8);    //中間地址,決定哪個扇區Soft_SPI_Dataswap(Address>>0);    //低地址,決定哪個頁/*寫數據*/for(uint16_t i=0;i<cnt;i++){Soft_SPI_Dataswap(ArrayData[i]);}SOFT_SPI_STOP;Soft_SPI_R_Status_W25Q64_busy();//busy等待
}
/****************************
*@brief   扇區擦除
*@param  uint32_t Address擦除地址
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_Sector_Clean_W25Q64(uint32_t Address)
{Soft_SPI_W_ENABLE_W25Q64();//寫使能SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_SECTOR_CLEAN );//指令/*函數Soft_SPI_Dataswap()一次只能交換8位*/Soft_SPI_Dataswap(Address>>16);   //高地址,決定哪塊Soft_SPI_Dataswap(Address>>8);    //中間地址,決定哪個扇區Soft_SPI_Dataswap(Address>>0);    //低地址,決定哪個頁SOFT_SPI_STOP;Soft_SPI_R_Status_W25Q64_busy();//busy等待
}
/****************************
*@brief    讀數據
*@param  uint8_t* ArrayData 輸出數據uint32_t Address   讀出的數據起始地址uint16_t len       字節個數
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_R_Data_W25Q64(uint8_t *ArrayData,uint32_t Address,uint32_t cnt)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_R_DATA);//寫指令/*函數Soft_SPI_Dataswap()一次只能交換8位*/Soft_SPI_Dataswap(Address>>16);   //高地址,決定哪塊Soft_SPI_Dataswap(Address>>8);    //中間地址,決定哪個扇區Soft_SPI_Dataswap(Address>>0);    //低地址,決定哪個頁/*讀數據*/for(uint32_t i=0;i<cnt;i++){ArrayData[i]= Soft_SPI_Dataswap(0xFF);}SOFT_SPI_STOP;
}

上述代碼對讀取ID,寫使能,讀數據,寫數據,擦除進行了封裝,相同的流程是
①片選語句拉低(SOFT_SPI_START)
②flash操作指令(Soft_SPI_Dataswap(指令))
③讀/寫數據
④片選語句拉低(SOFT_SPI_STOP)
注意:
可以跨頁讀但不能跨頁寫;
寫之前須寫使能;
一次最多寫入256字節數據;
再次寫入相同地址需要先擦除,再寫入;
擦除、寫入操作(包括寫入寄存器)會使busy置1,busy置1不再響應讀,寫,擦除操作(讀不能使busy置1,但busy置1時不可讀)

三、整個代碼

運行代碼:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/86822.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/86822.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/86822.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue3+element-plus 組件功能實現 上傳功能

一、整體功能概述 這段代碼實現了一個基于 Vue 3 和 Element Plus 組件庫的文件導入及預覽功能模塊。主要包含了一個主導入對話框&#xff08;用于上傳文件、展示文件相關信息、進行導入操作等&#xff09;以及一個用于預覽文件內容的預覽對話框。支持導入特定格式&#xff08;…

OpenCV中創建Mat對象

第1章 創建Mat對象 1.1. 創建空的 Mat 對象 cv::Mat mat; 1.2. 創建灰度圖像 // 創建一個 3 行 4 列、8位無符號單通道矩陣&#xff08;相當于灰度圖&#xff09; cv::Mat mat(3, 4, CV_8UC1); 1.3. 創建彩色圖像 // 創建三通道矩陣&#xff08;相當于彩色圖像&#xff0…

10、做中學 | 五年級下期 Golang循環控制

一、一個小需求 我想要打印10遍hello world,你想怎么編寫呢&#xff1f; // 需求&#xff1a;打印10遍"hello world"fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world…

機器學習算法-K近鄰算法-KNN

1. K近鄰算法是什么&#xff1f; 定義&#xff1a; K近鄰是一種基于實例的懶惰學習&#xff08;Lazy Learning&#xff09;算法&#xff0c;用于分類和回歸任務。 核心思想&#xff1a;“物以類聚”——通過計算樣本間的距離&#xff0c;找到目標點的最近K個鄰居&#xff0c;…

基于vue框架的法律知識咨詢普及系統gwuv7(程序+源碼+數據庫+調試部署+開發環境)帶論文文檔1萬字以上,文末可獲取,系統界面在最后面。

系統程序文件列表 項目功能&#xff1a;用戶,知識類型,律師,律師推薦,法律知識,新聞類型,法律新聞,咨詢律師 開題報告內容 基于Vue框架的法律知識咨詢普及系統開題報告 一、研究背景與意義 隨著法治社會建設的深入推進&#xff0c;公眾對法律知識的需求呈現爆發式增長。然而…

Netty 揭秘CompositeByteBuf:零拷貝優化核心技術

CompositeByteBuf 類 核心設計目標?? ??虛擬緩沖區??&#xff1a;將多個 ByteBuf 合并為單一邏輯視圖&#xff0c;減少數據復制。??零拷貝優化??&#xff1a;通過組合而非復制提升性能。??引用計數管理??&#xff1a;統一管理底層 ByteBuf 的生命周期。 核心成…

用css實現文字字體顏色漸變

用css實現文字字體顏色漸變 background-clip 是CSS3中新增的屬性&#xff0c;可以用于指定背景圖片或顏色的繪制范圍。利用 background-clip 屬性實現文字顏色從左到右、從綠到白的漸變效果&#xff1a; 代碼如下&#xff1a; .gradient-color {background-image: linear-gr…

SpringBatch處理數據性能優化

SpringBatch的Step默認使用同步方式批量處理數據&#xff0c;也可以通過配置將讀數改為同步&#xff0c;處理和寫入改為異步方式。 1、同步處理Step SpringBatch的Step一般由ItemReader、ItemProcessor和ItemWriter組成&#xff0c;其中ItemProcessor是可選的。他的設計思路的…

【機器學習深度學習】前饋神經網絡(單隱藏層)

目錄 一、什么是前饋神經網絡&#xff1f; 二、數學表達式是什么&#xff1f; 三、為什么需要“非線性函數”&#xff1f; 四、NumPy 實現前饋神經網絡代碼示例 五、 運行結果 六、代碼解析 6.1 初始化部分 6.2 前向傳播 6.3 計算損失&#xff08;Loss&#xff09; 6…

設計模式系列(08):創建型模式 - 原型模式

系列導讀&#xff1a;完成創建型模式的學習&#xff0c;我們來看最后一個創建型模式——原型模式。它通過復制已有對象來創建新對象&#xff0c;是一種獨特的創建方式。 解決什么問題&#xff1a;通過復制現有對象來創建新對象&#xff0c;而不是重新實例化。適用于對象創建成本…

區塊鏈到底是什么?

區塊鏈本質上是一種去中心化的分布式賬本技術&#xff0c;具有以下核心特點&#xff1a; - 去中心化&#xff1a;沒有中央管理機構&#xff0c;數據由網絡中的多個節點共同維護&#xff0c;比如比特幣網絡中各個節點都保存著完整賬本。 - 分布式存儲&#xff1a;數據不是存在一…

系統架構設計師論文分享-論ATAM的使用

我的軟考歷程 摘要 2023年2月&#xff0c;我司通過了研發紗線MES系統的立項&#xff0c;該系統為國內紗線工廠提供SAAS服務&#xff0c;旨在提高紗線工廠的數字化和智能化水平。我在本項目中擔任系統架構設計師&#xff0c;負責整個項目的架構設計工作。本文結合我在該項目中…

vue-28(服務器端渲染(SSR)簡介及其優勢)

服務器端渲染&#xff08;SSR&#xff09;簡介及其優勢 服務器端渲染&#xff08;SSR&#xff09;是現代網絡應用的關鍵技術&#xff0c;特別是使用 Vue.js 等框架構建的應用。它通過在服務器上渲染初始應用狀態來彌補傳統單頁應用&#xff08;SPA&#xff09;的局限性&#x…

工業電子 | 什么是SerDes,為何工業和汽車應用需要它?

重點內容速覽&#xff1a; 1. 什么是SerDes&#xff1f; 2. ADI&#xff1a;私有協議的GMSL將向公有協議轉變 3. TI&#xff1a;工業和汽車有兩套SerDes解決方案 4. Microchip&#xff1a;推出通用協議SerDes芯片 5. 羅姆&#xff1a;主要針對汽車領域 6. 國產SerDes芯…

大事件項目記錄4-用戶接口開發-更新用戶基本信息

4&#xff09;更新用戶基本信息。 UserController.java&#xff1a; UserMapper.java&#xff1a; Update("update user set nickname #{nickname},email #{email},update_time #{updateTime} where id #{id}")void update(User user); UserServiceInterface…

Transformer結構--輸入編碼(BPE,PE)

在Transformer結構中&#xff0c;輸入編碼是模型處理文本數據的關鍵步驟&#xff0c;其中**BPE&#xff08;Byte Pair Encoding&#xff0c;字節對編碼&#xff09;和PE&#xff08;Positional Encoding&#xff0c;位置編碼&#xff09;**是兩種重要的編碼方式&#xff0c;它們…

Confluence-測試用例設計指導方法

測試經驗知識庫 典型的測試場景驗證點各個項目有價值的經驗和測試點 測試經驗知識庫 - 草稿測試用例執行量化指導建議 何時需要進行全量測試和如何定義和執行測試用例量的一些建議和標準 端對端&#xff08;E2E&#xff09;測試用例設計指導方案 在測試行業中&#xff0c;端到端…

淺析JVM

一、JVM運行流程 如圖&#xff1a; JVM由四個部分構成&#xff1a; 1.類加載器 加載類文件到內存2.運行時數據區 寫的程序需要加載到這里才能運行3.執行引擎 負責解釋命令&#xff0c;提交操作系統執行4.本地接口 融合不同編程語言為java所用&#xff0c;如Java程序驅動打印…

多個 Job 并發運行時共享配置文件導致上下文污染,固化 Jenkins Job 上下文

基于 context.py 固化 Jenkins Job 上下文的完整方案&#xff0c;適用于你當前的工作流&#xff08;Python Jenkins Pipeline&#xff09;&#xff0c;解決&#xff1a; 多個 Job 并發運行時共享配置文件導致上下文污染&#xff1b;讀取環境變量或 JSON 文件時被其他 Job 修改…

簡木易支付系統 功能齊全,對接接口超多

簡木易支付系統&#xff0c;作為一款引領行業潮流的卓越支付解決方案&#xff0c;依托先進的 PHP MySQL 技術架構精心打造。在開發過程中&#xff0c;它巧妙運用了功能強大的 ThinkPHP8 框架&#xff0c;完美融合前端主流技術 Vue、Element 以及 Layuiadmin&#xff0c;共同鑄…