一、簡介
在嵌入式領域,FLASH是一種常用的儲存設備,Flash閃存作為嵌入式系統的主要儲存設備有其自身的特性。Fash的寫入操作隻能把對應位置的1修改成0,而不能把0修改為1,而擦除Fash就是把對應存儲塊的内容恢複為1。是以,一般情況下向Fash寫入内容時,需要先擦除對應的存儲區間,這種擦除是以塊(Bock)為機關進行的。閃存主要有NOR和NAND兩種技術。因為Flash存儲器的擦寫次數是有限的,NAND閃存還有特殊的硬體接口和讀寫時序,于是就出現了專門針對FLASH的檔案系統。比較常用的有jffs2,yaffs2,logfs,ubifs。本文基于小淩派-RK2206開發闆 + OpenHarmony輕量級作業系統 + LitteFS檔案系統,通過hal_file标準接口實作對Flash讀寫功能。
二、hal_file标準接口
頭檔案://utils/native/lite/hals/file/hal_file.h
1、HalFileOpen()
打開/建立檔案,類似于Linux的open函數。
int HalFileOpen(const char *path, int oflag, int mode);
參數說明:

傳回值為LOS_OK表示成功,其餘為失敗。
2、HalFileClose()
關閉檔案,類似于Linux的close函數。
int HalFileClose(int fd);
參數說明:
傳回值為LOS_OK表示成功,其餘為失敗。
3、HalFileRead()
從檔案中讀取一段内容,類似于Linux的read函數。
int HalFileRead(int fd, char* buf, unsigned int len);
參數說明:
傳回值為從檔案讀取内容的大小,0或者小于0則為失敗。
4、HalFileWrite()
往檔案寫入一段内容,類似于Linux的write函數。
int HalFileWrite(int fd, const char* buf, unsigned int len);
參數說明:
傳回值為成功寫入到檔案的内容大小,0或者小于0則為失敗。
5、HalFileDelete()
删除檔案,類似于Linux的unlink函數。
int HalFileDelete(const char* path);
參數說明:
傳回值為LOS_OK為成功,其餘則為失敗。
6、HalFileStat()
擷取檔案大小,類似于Linux的stat函數。
int HalFileStat(const char* path, unsigned int* fileSize);
參數說明:
傳回值為LOS_OK為成功,其餘則為失敗。
7、HalFileSeek()
檔案所在位置移動,類似于Linux的lseek函數。
int HalFileSeek(int fd, int offset, unsigned int whence);
參數說明:
傳回值為LOS_OK為成功,其餘則為失敗。
三、程式設計
本例程示範如何在小淩派-RK2206開發闆上使用鴻蒙LiteOS-M核心接口,進行檔案讀寫開發。例程流程如下所示:
(1)建立一個檔案;
(2)每5秒進行1次檔案讀寫操作;
(3)檔案辨別移動到檔案起始處,讀檔案内容,并列印;
(4)檔案辨別移動到檔案起始處,寫檔案内容;
(5)循環上述的第2~4步驟。
1、任務建立代碼分析
在file_example函數中通過LOS_TaskCreate函數建立一個線程:hal_file_thread。
void file_example()
{
unsigned int thread_id;
TSK_INIT_PARAM_S task = {0};
unsigned int ret = LOS_OK;
task.pfnTaskEntry = (TSK_ENTRY_FUNC)hal_file_thread;
task.uwStackSize = 1024 * 10;
task.pcName = "hal_file_thread";
task.usTaskPrio = 25;
ret = LOS_TaskCreate(&thread_id, &task);
if (ret != LOS_OK)
{
printf("Falied to create hal_file_thread ret:0x%x\n", ret);
return;
}
}
APP_FEATURE_INIT(file_example);
2. 檔案讀寫代碼分析
hal_file_thread函數負責打開檔案,每5秒移動到檔案頭讀取資料,再移動到檔案頭寫入一段内容,重複以上流程。
void hal_file_thread()
{
int fd;
char buffer[1024];
int read_length, write_length;
int current = 0;
/* 打開檔案,如果沒有該檔案就建立,如有該檔案則打開
* O_TRUNC_FS => 清空檔案内容
*/
//fd = HalFileOpen(FILE_NAME, O_RDWR_FS | O_CREAT_FS, 0);
fd = HalFileOpen(FILE_NAME, O_RDWR_FS | O_CREAT_FS | O_TRUNC_FS, 0);
if (fd == -1)
{
printf("%s HalFileOpen failed!\n", FILE_NAME);
return;
}
while (1)
{
/* 檔案位置移動到檔案開始位置 */
HalFileSeek(fd, 0, SEEK_SET);
memset(buffer, 0, sizeof(buffer));
/* 讀取檔案内容 */
read_length = HalFileRead(fd, buffer, sizeof(buffer));
printf("read: \n");
printf(" length = %d\n", read_length);
printf(" content = %s\n", buffer);
/* 檔案位置移動到檔案開始位置 */
HalFileSeek(fd, 0, SEEK_SET);
memset(buffer, 0, sizeof(buffer));
snprintf(buffer, sizeof(buffer), "Hello World(%d) => ", current);
/* 寫入檔案 */
write_length = HalFileWrite(fd, buffer, strlen(buffer));
current++;
LOS_Msleep(5000);
}
HalFileClose(fd);
}
四、編譯過程
1、搭建和下載下傳源代碼
我已将OpenHarmony源代碼上傳到Gitee社群中,大家可以根據以下網址下載下傳。
https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts
注意:編譯環境可根據以下網址來操作:https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts/blob/master/vendor/lockzhiner/rk2206/README_zh.md
2、修改編譯腳本
修改 vendor/lockzhiner/rk2206/sample 路徑下 BUILD.gn 檔案,指定 a7_hal_file 參與編譯。
"./a7_hal_file:hal_file_example",
修改 device/lockzhiner/rk2206/sdk_liteos 路徑下 Makefile 檔案,添加 -lhal_file_example 參與編譯。
apps_LIBS = -lhal_file_example
3、編譯固件
hb set -root .
hb set
hb build -f
4、燒寫固件
請參考Gitee網址的說明手冊(“燒錄列印”章節):https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts/blob/master/device/rockchip/README_zh.md
五、實驗結果
程式編譯燒寫到開發闆後,按下開發闆的RESET按鍵,通過序列槽軟體檢視日志如下:
HalFileInit: Flash Init Successful!
read:
length = 0
content =
read:
length = 18
content = Hello World(0) =>
read:
length = 18
content = Hello World(1) =>
好了,今天的課程就到這裡,我們下次再見!