從本文開始,測試學習一些 RT-Thread 常用的組件與軟件包,先從剛學完的 SPI 設備開始。
目錄
前言
一、SFUD 組件簡介
1.1 基本簡介
1.2 SFUD 對 Flash 的管理
二、SFUD 組件操作函數(shù)
2.1 初始化相關函數(shù)
2.2 設備訪問函數(shù)
2.2.1 讀數(shù)據(jù)
2.2.2 擦除數(shù)據(jù)
2.2.3 寫數(shù)據(jù)
2.2.4 Flash 狀態(tài)相關
三、使用測試
3.1 使用步驟
3.1.1 使能 SPI 設備
3.1.2 使能 SFUD 組件包
3.1.3 掛載 SFUD 設備
3.1.4 應用程序查找設備
3.1.5 使用 API 進行讀寫操作
3.2 讀寫測試
結語
前言
RT-Thread 專欄更新至今,從開發(fā)環(huán)境到內(nèi)核到設備模型,其實我們已經(jīng)把使用 RT-Thread 的基礎知識都講過一遍,認真學習的朋友實際上都已經(jīng)可以使用 RT-Thread 完成一些實際小項目了。
上一篇文章最后說過,RT-Thread 有一個很大的特點在于他的生態(tài)比一般的 RTOS 完善,我們在實際應用中,有許許多多現(xiàn)成的官方或者很多開發(fā)者提供的組件或者軟件包,我們可以直接導入工程進行使用。
針對我們 RT-Thread 實際應用,很多時候不僅是要知道基本的理論,還需要真正的知道怎么實際“用”起來。
基于本專欄的開發(fā)環(huán)境 RT-Thread Studio,本文開始我們來測試幾個典型的 組件與軟件包,來看看他們實際是如何使用的。
我們剛講完 SPI 設備,本文就從與 SPI 設備相關的組件 SFUD 組件說起。
☆
說明,對于 RT-Thread記錄 中組件與軟件包部分的文章,我并不計劃講太多的原理,因為我們的最終目的還是在于應用,
在之間講解 RT-Thread 的基礎中,為了讓大家更明白 RT-Thread 內(nèi)核以及 I/O 設備模型,也沒少分析源碼以及講解實現(xiàn)原理,核心的部分都是自己研究源碼。
對于 組件與軟件包 部分,我側(cè)重點會在與的記錄測試使用的過程,使得我們能夠快速上手。
☆
??
本 RT-Thread 專欄記錄的開發(fā)環(huán)境:
RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發(fā)環(huán)境 及 配合CubeMX開發(fā)快速上手)
RT-Thread記錄(二、RT-Thread內(nèi)核啟動流程 — 啟動文件和源碼分析)
??
RT-Thread 內(nèi)核篇系列博文鏈接:
RT-Thread記錄(三、RT-Thread 線程操作函數(shù)及線程管理與FreeRTOS的比較)
RT-Thread記錄(四、RT-Thread 時鐘節(jié)拍和軟件定時器)
RT-Thread記錄(五、RT-Thread 臨界區(qū)保護)
RT-Thread記錄(六、IPC機制之信號量、互斥量和事件集)
RT-Thread記錄(七、IPC機制之郵箱、消息隊列)
RT-Thread記錄(八、理解 RT-Thread 內(nèi)存管理)
RT-Thread記錄(九、RT-Thread 中斷處理與階段小結)
??
在STM32L051C8 上使用 RT-Thread 應用篇系列博文連接:
RT-Thread 應用篇 — 在STM32L051上使用 RT-Thread (一、無線溫濕度傳感器 之 新建項目)
RT-Thread 應用篇 — 在STM32L051上使用 RT-Thread (二、無線溫濕度傳感器 之 CubeMX配置)
RT-Thread 應用篇 — 在STM32L051上使用 RT-Thread (三、無線溫濕度傳感器 之 I2C通訊)
RT-Thread 應用篇 — 在STM32L051上使用 RT-Thread (四、無線溫濕度傳感器 之 串口通訊)
??
RT-Thread 設備篇系列博文鏈接:
RT-Thread記錄(十、全面認識 RT-Thread I/O 設備模型)
RT-Thread記錄(十一、I/O 設備模型之UART設備 — 源碼解析)
RT-Thread記錄(十二、I/O 設備模型之UART設備 — 使用測試)
RT-Thread記錄(十三、I/O 設備模型之PIN設備)
RT-Thread記錄(十四、I/O 設備模型之ADC設備)
RT-Thread記錄(十五、I/O 設備模型之SPI設備)
??
RT-Thread 組件與軟件包系列博文鏈接:
本文是第一篇
一、SFUD 組件簡介
SFUD (全稱 Serial Flash Universal Driver)是一款開源的串行 SPI Flash 通用驅(qū)動庫。
1.1 基本簡介
基礎介紹借用官方的說明:由于現(xiàn)有市面的串行 Flash 種類居多,各個 Flash 的規(guī)格及命令存在差異, SFUD 就是為了解決這些 Flash 的差異現(xiàn)狀而設計,讓我們的產(chǎn)品能夠支持不同品牌及規(guī)格的 Flash,提高了涉及到 Flash 功能的軟件的可重用性及可擴展性,同時也可以規(guī)避 Flash 缺貨或停產(chǎn)給產(chǎn)品所帶來的風險。
在 RT-Thread 中,SFUD 組件的 SPI 驅(qū)動是以 RTThread 的I/O設備模型框架為基礎設計的。
使用 SFUD 組件,我們不用自己寫 SPI Flash 的驅(qū)動。
支持 SPI/QSPI 接口、面向?qū)ο螅ㄍ瑫r支持多個 Flash 對象)、可靈活裁剪、擴展性強、支持 4 字節(jié)地址。
☆ SFUD是個開源的組件,對于該組件真正權威的參考說明就是該組件作者寫好的 README.md
文件(永遠要記住第一作者的文檔、官方的文檔永遠是最具有參考價值的)?!?/p>
使用 RT-Thread Studio 打開 README 文件如下圖,基本的介紹,函數(shù)使用,說明該有的都有,大家可自行查看:


本文不深入分析源碼實現(xiàn)原理,對于理論只做簡單說明。
1.2 SFUD 對 Flash 的管理
我們以前講過,面向?qū)ο笏枷氲某绦蛟O計,一般都會使用一個結構體 表示一個對象,我們講過的線程、IPC機制,I/O 設備都有他們的設備控制塊結構體。
對于 SPI Flash 設備,SFUD 也定義了一個結構體 sfud_flash
進行管理,其位置和內(nèi)容如下圖:

在這個對象控制塊中,有一個成員為 chip
,其類型為芯片信息的結構體sfud_flash_chip
,如下圖:

在 SFUD 組件中,已經(jīng)定義好了一些支持的 chip 信息,如下圖:

基本上包括了市面上通用的 SPI Flash 芯片,如果使用的flash不支持 SFUD 組件,可根據(jù) README 文件自行添加。
簡單的概述就到這里,下面我們來看看 SFUD 組件提供的操作函數(shù)。
二、SFUD 組件操作函數(shù)
根據(jù) SFUD 組件的 README 文件,SFUD 組件提供的 API 框架圖如下:

這里要說明一下,上面的 API 是 SFUD 對外標準的通用 API,就是不管用什么系統(tǒng),或者使用裸機,移植好了 SFUD組件這些 API 都可以使用。
對于我們使用的 RT-Thread 來說,訪問設備的函數(shù)就是 SFUD 設備的標準 API。
但是對于初始化相關的部分來說,RT-Thread 官方給我們寫好了標準的驅(qū)動函數(shù)。
2.1 初始化相關函數(shù)
在工程文件中,與 RT-Thread 初始化驅(qū)動文件如下:

其提供的函數(shù)有( 對于 RT-Thread 中初始化相關的函數(shù)使用,在本文后面使用測試小節(jié)會有詳細示例說明):
/**
* Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
使用 SFUD 探測 spi_dev_name 從設備,
并將 spi_dev_name 連接的 flash 初始化為塊設備,名稱 spi_flash_dev_name
*/
rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name);
/**
* Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
* rt_sfud_flash_probe 調(diào)用了此函數(shù)
使得與底層 SFUD 本身的初始化文件關聯(lián)起來
*/
rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg);
/**
* Delete SPI flash device
刪除SPI SFUD 設備
*/
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev);
/**
* Find sfud flash device by SPI device name
通過 SPI 設備名稱 找到一個 SFUD Flash 設備
*/
sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name);
/**
* Find sfud flash device by flash device name
通過 Flash 設備名稱 找到一個 SFUD Flash 設備
*/
sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name);
函數(shù)我們不做深入分析,大家需要學會使用,以前有很多文章都有源碼分析說明,源碼自己查看,比如其中比較關鍵的一個函數(shù) rt_sfud_flash_probe_ex
:

2.2 設備訪問函數(shù)
設備訪問函數(shù),SFUD 組件中 README 文件都有說明的,函數(shù)使用的注意事項可查看組件說明文件。
這里統(tǒng)一列一下方便以后復制使用:
2.2.1 讀數(shù)據(jù)
/*
參數(shù) 描述
flash Flash 設備對象
addr 起始地址
size 從起始地址開始讀取數(shù)據(jù)的總大小
data 讀取到的數(shù)據(jù)
*/
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
2.2.2 擦除數(shù)據(jù)
部分擦除:
/*
參數(shù) 描述
flash Flash 設備對象
addr 起始地址
size 從起始地址開始擦除數(shù)據(jù)的總大小
*/
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)
全片擦除:
/*
參數(shù) 描述
flash Flash 設備對象
*/
sfud_err sfud_chip_erase(const sfud_flash *flash)
2.2.3 寫數(shù)據(jù)
直接寫:
/*
參數(shù) 描述
flash Flash 設備對象
addr 起始地址
size 從起始地址開始寫入數(shù)據(jù)的總大小
data 待寫入的數(shù)據(jù)
*/
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
先擦除再寫:
/*
參數(shù) 描述
flash Flash 設備對象
addr 起始地址
size 從起始地址開始寫入數(shù)據(jù)的總大小
data 待寫入的數(shù)據(jù)
*/
sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
2.2.4 Flash 狀態(tài)相關
讀取 Flash 狀態(tài):
/*
參數(shù) 描述
flash Flash 設備對象
status 當前狀態(tài)寄存器值
*/
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
修改 Flash 狀態(tài):
/*
參數(shù) 描述
flash Flash 設備對象
is_volatile 是否為易閃失的,true: 易閃失的,及斷電后會丟失
status 當前狀態(tài)寄存器值
*/
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
三、使用測試
本小節(jié)說明一下在 RT-Thread Studio 上使用 SFUD組件的步驟,然后我們使用示例進行基本的測試:
3.1 使用步驟
3.1.1 使能 SPI 設備
根據(jù)文章 RT-Thread記錄(十五、I/O 設備模型之SPI設備)接描述 中 《3.1 SPI 設備使用步驟》說明使能 SPI 總線。
注冊 SPI 總線設備,使用list_device
可查看結果:

3.1.2 使能 SFUD 組件包
和使能 SPI 設備一樣,在 RT-Thread Studio 打開 RT-Thread Settings 打開 SFUD 組件使能,如下圖:

使能完成,我們在應用層就可直接調(diào)用上一小節(jié)將的 SFUD 操作函數(shù)了。
在工程中, SFUD 組件相關的程序位置如下:

3.1.3 掛載 SFUD 設備
在使用 SFUD 設備前,需要掛載,類似把 SPI 設備掛載至 SPI 總線上一樣,使用如下操作:

忘了另外一塊開發(fā)板不是 W25Q128 而是 W25Q64,所以最終找到的是 W25Q64DW。
這里有個小問題說明一下, DBG 定義的問題,自己把mian里面的注釋稍微修改一下:

3.1.4 應用程序查找設備
使用 rt_sfud_flash_find
或者 rt_sfud_flash_find_by_dev_name
獲取設備句柄:

3.1.5 使用 API 進行讀寫操作
完成上述步驟,就可以根據(jù)自己的應用,使用上面介紹的 SFUD 組件操作函數(shù)訪問設備部分進行 Flash 的操作了。
比如:

3.2 讀寫測試
在上面的使用步驟說明中,其實我已經(jīng)把自己做的簡單測試都說了一遍,這里我們上一下測試部分代碼,然后看一下測試效果:
#include
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include
#include "board.h"
#include "drv_spi.h"
#include "spi_flash_sfud.h"
#ifndef DBG_TAG
#define DBG_TAG "main"
#endif
#ifndef DBG_LVL
#define DBG_LVL DBG_LOG
#endif
#include
//省略...
sfud_flash *test_sfud = NULL;
const uint8_t test_data[] = "this is a test data!";
//省略...
static void key1_thread_entry(void *par){
while(1){
if(key1_read == 0){
rt_thread_mdelay(10); //去抖動
if(key1_read == 0){
rt_kprintf("write flash ..\r\n");
// sfud_write(test_sfud, 13, sizeof(test_data), test_data);
sfud_erase_write(test_sfud, 13, sizeof(test_data), test_data);
}
while(key1_read == 0){rt_thread_mdelay(10);//去抖動
}
}
rt_thread_mdelay(1);
}
}
static void key2_thread_entry(void *par){
uint8_t read_data[30] = {0};
// void *str = RT_NULL;
while(1){
if(key2_read == 0){
rt_thread_mdelay(10); //去抖動
if(key2_read == 0){
rt_kprintf("read flash ..\r\n");
// sfud_read(test_sfud, 0, sizeof(test_data), (uint8_t *)str);
sfud_read(test_sfud, 13, sizeof(test_data), read_data);
rt_kprintf("%s",read_data);
}
while(key2_read == 0){rt_thread_mdelay(10);//去抖動
}
}
rt_thread_mdelay(1);
}
}
//省略...
int main(void)
{
//省略...
rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4); // CS 腳:PA4
/* 使用 SFUD 探測 spi10 從設備,并將 spi10 連接的 flash 初始化為塊設備,名稱 W25Q128 */
if (RT_NULL == rt_sfud_flash_probe("W25Q64", "spi10"))
{
return -RT_ERROR;
};
// test_sfud = rt_sfud_flash_find("spi10"); //
test_sfud = rt_sfud_flash_find_by_dev_name("W25Q64");
if(RT_NULL == test_sfud){
LOG_E("find sfud_flash failed!...\n");
}
//省略...
return RT_EOK;
}
測試結果:

測試細節(jié)說明:
在測試的時候我使用了一個按鍵線程寫 flash,最開始的時候使用的是 512 字節(jié)大小的線程棧:

使用函數(shù)sfud_erase_write
會比 sfud_write
函數(shù)占用更多的內(nèi)存。
結語
本文我們從上一篇文章剛學完的 SPI 設備相關的 SFUD 組件開始,接觸到了 RT-Thread 的組件與軟件包,可以看出,對于常用的設備使用 RT-Thread 開發(fā)有多么的方便了。
??
但是前提當然是得對 RT-Thread 的面向?qū)ο蟮乃枷耄琁/O 設備模型等基礎有一定的認識,如果只是為了使用,看一篇文章即可,如果是為了理解掌握,還得多多了解 RT-Thread 基礎相關知識,比如博主的 RT-Thread 專欄 = =! O(∩_∩)O哈哈~
再次申明一下,對于組件與軟件包,因為都是大佬開發(fā)者們寫好的驅(qū)動,所以我偏向的重點是在于學會使用,說明文檔在每個組件或者軟件包都有作者詳細的說明,那才是最好的參考資料。
??
希望大家多多支持!本文就到這里,謝謝!
-
FlaSh
+關注
關注
10文章
1668瀏覽量
151075 -
RTOS
+關注
關注
24文章
844瀏覽量
120821 -
組件
+關注
關注
1文章
530瀏覽量
18322 -
RT-Thread
+關注
關注
32文章
1372瀏覽量
41556 -
SFUD
+關注
關注
0文章
5瀏覽量
1131
發(fā)布評論請先 登錄
RT-Thread記錄(十七、 AT組件-使用at軟件包)

RT-Thread Studio配置QSPI和SFUD的相關資料推薦
基于RT-Thread的EasyFlash移植參考示例
RT-Thread軟件包定義和使用

記錄——基于 RT-Thread 實現(xiàn) USB 虛擬串口

RT-Thread 應用筆記 - RTC Alarm 組件的使用

RT-Thread學習筆記 RT-Thread的架構概述

評論