單片機flash通用讀寫庫:TZFlash

單片機flash通用讀寫庫:TZFlash

本文博客鏈接:http://blog.csdn.net/jdh99,作者:jdh,轉載請註明.

說明

本文發佈單片機flash通用讀寫庫TZFlash,有兩個優點:

  • TZFlash將flash的讀寫抽象成文件讀寫,更易於使用。
  • flash寫入需要4字節對齊,TZFlash增加cache機制,可以將任意長度的寫入flash。

源碼

tzflash.h

// Copyright 2019-2019 The TZIOT Authors. All rights reserved.
// flash管理模塊頭文件

#ifndef TZFLASH_H
#define TZFLASH_H

#include "tzbasedef.h"

// TZFlashEraseFunc 函數類型:擦除flash
// addr:起始地址.size:擦除字節數
// 成功返回true,失敗返回false
typedef bool (*TZFlashEraseFunc)(int addr, int size);

// TZFlashWriteFunc 函數類型:寫入flash
// addr:起始地址.bytes:待寫入的字節流.size:寫入字節數
// 成功返回true,失敗返回false
typedef bool (*TZFlashWriteFunc)(int addr, uint8_t* bytes, int size);

// TZFlashReadFunc 函數類型:讀取flash
// addr:起始地址.bytes:讀取的字節流存放的緩存.size:讀取的字節數
// 成功返回true,失敗返回false
typedef bool (*TZFlashReadFunc)(int addr, uint8_t* bytes, int size);

// TZFlashOpenMode 打開模式
typedef enum {
    TZFLASH_READ_ONLY = 0,
    TZFLASH_WRITE_ONLY
} TZFlashOpenMode;

// TZFlashLoad 模塊載入
void TZFlashLoad(int pageSize, TZFlashEraseFunc eraseFunc, TZFlashWriteFunc writeFunc, TZFlashReadFunc readFunc);

// TZFlashOpen 打開flash文件.
// 注意:打開時會擦除flash.要保證打開的flash大小是頁的整數倍,否則會打開失敗
// 返回值爲0表示打開失敗
intptr_t TZFlashOpen(int addrStart, int size, TZFlashOpenMode mode);

// TZFlashWrite 向flash寫入數據
// 成功返回寫入的字節數,失敗返回-1
int TZFlashWrite(intptr_t fd, uint8_t* bytes, int size);

// TZFlashRead 從flash中讀取數據
// 成功返回讀取的字節數,失敗返回-1
int TZFlashRead(intptr_t fd, uint8_t* bytes, int size);

// TZFlashClose 關閉
void TZFlashClose(intptr_t fd);

#endif

tzflash.c

// Copyright 2019 The TZIOT Authors. All rights reserved.
// flash管理模塊主文件

#include "tzflash.h"

#define CACHE_SIZE 64

#pragma pack(1)

// tFlashInterface flash管理接口
typedef struct {
    int pageSize;
    TZFlashEraseFunc erase;
    TZFlashWriteFunc write;
    TZFlashReadFunc read;
} tFlashInterface;

// tFlashFile flash文件類型
typedef struct {
    int addrStart;
    int addrStop;
    int offset;
    TZFlashOpenMode mode;
    uint8_t cache[CACHE_SIZE];
    int cacheLen;
} tFlashFile;

#pragma pack()

static tFlashInterface gInterface;

// TZFlashLoad 模塊載入
void TZFlashLoad(int pageSize, TZFlashEraseFunc eraseFunc, TZFlashWriteFunc writeFunc, TZFlashReadFunc readFunc) {
    gInterface.pageSize = pageSize;
    gInterface.erase = eraseFunc;
    gInterface.write = writeFunc;
    gInterface.read = readFunc;
}

// TZFlashOpen 打開flash文件.
// 注意:只寫模式打開時會擦除flash.要保證打開的flash大小是頁的整數倍,否則會打開失敗
// 返回值爲0表示打開失敗
intptr_t TZFlashOpen(int addrStart, int size, TZFlashOpenMode mode) {
    if (mode == TZFLASH_WRITE_ONLY) {
        if (size % gInterface.pageSize != 0) {
            return 0;
        }
        if (gInterface.erase(addrStart, size) == false) {
            return 0;
        }
    }

    tFlashFile* file = malloc(sizeof(tFlashFile));
    if (file == NULL) {
        return 0;
    }
    file->addrStart = addrStart;
    file->addrStop = addrStart + size - 1;
    file->mode = mode;
    file->offset = file->addrStart;
    file->cacheLen = 0;
    return (intptr_t)file;
}

// TZFlashWrite 向flash寫入數據
// 成功返回寫入的字節數,失敗返回-1
int TZFlashWrite(intptr_t fd, uint8_t* bytes, int size) {
    tFlashFile* file = (tFlashFile*)fd;
    if (file->mode == TZFLASH_READ_ONLY) {
        return -1;
    }
    if (file->offset + file->cacheLen + size > file->addrStop) {
        return -1;
    }

    int delta = 0;
    int writeNum = 0;
    for (;;) {
        delta = CACHE_SIZE - file->cacheLen;
        // 比cache可寫入空間小則直接寫入
        if (size < delta) {
            memcpy(file->cache + file->cacheLen, bytes, (size_t)size);
            file->cacheLen += size;
            writeNum += size;
            break;
        }

        // 寫滿cache,再全部寫入flash
        memcpy(file->cache + file->cacheLen, bytes, (size_t)delta);
        file->cacheLen += delta;
        gInterface.write(file->offset, file->cache, file->cacheLen);
        file->offset += file->cacheLen;
        file->cacheLen = 0;
        size -= delta;
        writeNum += delta;
    }
    return writeNum;
}

// TZFlashRead 從flash中讀取數據
// 成功返回讀取的字節數,失敗返回-1
int TZFlashRead(intptr_t fd, uint8_t* bytes, int size) {
    tFlashFile* file = (tFlashFile*)fd;
    if (file->mode == TZFLASH_WRITE_ONLY) {
        return -1;
    }
    if (file->offset > file->addrStop) {
        return 0;
    }
    int delta = file->addrStop - file->offset + 1;
    int readSize = delta > size ? size : delta;
    gInterface.read(file->offset, bytes, readSize);
    file->offset += readSize;
    return readSize;
}

// TZFlashClose 關閉
void TZFlashClose(intptr_t fd) {
    tFlashFile* file = (tFlashFile*)fd;
    gInterface.write(file->offset, file->cache, file->cacheLen);
    free(file);
}

測試

#include "test_tzflash.h"
#include "tzflash.h"

#define PAGE_SIZE 1024
#define FLASH_SIZE 10240

static uint8_t gFlash[FLASH_SIZE] = {0};

static bool erase(int addr, int size);
static bool write(int addr, uint8_t* bytes, int size);
static bool read(int addr, uint8_t* bytes, int size);
static void testCase0(void);
static void testCase1(void);
static void testCase2(void);

void TestTZFlashRun(void) {
    printf("-------------------->test tz flash\n");
    TZFlashLoad(PAGE_SIZE, erase, write, read);
    testCase0();
    testCase1();
    testCase2();
    printf("-------------------->test end\n");
}

static bool erase(int addr, int size) {
    if (size % PAGE_SIZE != 0) {
        return false;
    }
    memset(gFlash + addr, 0, (size_t)size);
    return true;
}

static bool write(int addr, uint8_t* bytes, int size) {
    if (addr + size > FLASH_SIZE) {
        return false;
    }
    memcpy(gFlash + addr, bytes, (size_t)size);
    return true;
}

static bool read(int addr, uint8_t* bytes, int size) {
    if (size > FLASH_SIZE - addr) {
        return false;
    }
    memcpy(bytes, gFlash + addr, (size_t)size);
    return true;
}

static void testCase0(void) {
    printf("-------------------->testCase0\n");

    intptr_t fd = TZFlashOpen(0, PAGE_SIZE, TZFLASH_WRITE_ONLY);

    int writeNum = 0;
    writeNum = TZFlashWrite(fd, "i am jdh!", strlen("i am jdh"));
    printf("write:%s", "i am jdh!\n");
    writeNum += TZFlashWrite(fd, "123456789", strlen("123456789"));
    printf("write:%s", "123456789\n");
    writeNum += TZFlashWrite(fd, "abcde", strlen("abcde"));
    printf("write:%s", "abcde\n");

    TZFlashClose(fd);

    fd = TZFlashOpen(0, PAGE_SIZE, TZFLASH_READ_ONLY);
    char buf[100] = {0};
    int readNum = TZFlashRead(fd, buf, writeNum);

    TZFlashClose(fd);

    printf("write num:%d read num:%d read text:%s\n", writeNum, readNum, buf);
}

static void testCase1(void) {
    printf("-------------------->testCase1\n");

    intptr_t fd = TZFlashOpen(1024, PAGE_SIZE * 4, TZFLASH_WRITE_ONLY);

    uint8_t buf[255] = {0};
    for (int i = 0; i < 234; i++) {
        buf[i] = i;
    }

    int writeNum = 0;
    for (int i = 0; i < 10; i++) {
        writeNum += TZFlashWrite(fd, buf, 234);
    }
    printf("write num:%d\n", writeNum);

    TZFlashClose(fd);

    fd = TZFlashOpen(1024, PAGE_SIZE, TZFLASH_READ_ONLY);

    uint8_t buf1[255] = {0};
    int readNum = 0;
    for (int i = 0; i < 5; i++) {
        readNum = TZFlashRead(fd, buf1, 10);
        printf("read num:%d\n", readNum);
        for (int i = 0; i < 10; i++) {
            printf("%d ", buf1[i]);
        }
        printf("\n");
    }

    TZFlashClose(fd);
}

static void testCase2(void) {
    printf("-------------------->testCase2\n");

    intptr_t fd = TZFlashOpen(2048, PAGE_SIZE * 4, TZFLASH_WRITE_ONLY);

    uint8_t buf[1] = {0};
    int writeNum = 0;
    for (int i = 0; i < 1024; i++) {
        buf[0] = i;
        writeNum += TZFlashWrite(fd, buf, 1);
        if (i < 5 || i > 1020) {
            printf("write:%d:%d\n", i, buf[0]);
        }
    }
    printf("write num:%d\n", writeNum);

    TZFlashClose(fd);

    fd = TZFlashOpen(2048, PAGE_SIZE, TZFLASH_READ_ONLY);

    int readNum = 0;
    for (int i = 0; i < 1024; i++) {
        readNum += TZFlashRead(fd, buf, 1);
        if (i < 5 || i > 1020) {
            printf("read:%d:%d\n", i, buf[0]);
        }
    }
    printf("read num:%d\n", readNum);

    TZFlashClose(fd);
}

測試輸出:

-------------------->test tz flash
-------------------->testCase0
write:i am jdh!
write:123456789
write:abcde
write num:22 read num:22 read text:i am jdh123456789abcde
-------------------->testCase1
write num:2340
read num:10
0 1 2 3 4 5 6 7 8 9
read num:10
10 11 12 13 14 15 16 17 18 19
read num:10
20 21 22 23 24 25 26 27 28 29
read num:10
30 31 32 33 34 35 36 37 38 39
read num:10
40 41 42 43 44 45 46 47 48 49
-------------------->testCase2
write:0:0
write:1:1
write:2:2
write:3:3
write:4:4
write:1021:253
write:1022:254
write:1023:255
write num:1024
read:0:0
read:1:1
read:2:2
read:3:3
read:4:4
read:1021:253
read:1022:254
read:1023:255
read num:1024
-------------------->test end
發佈了202 篇原創文章 · 獲贊 1952 · 訪問量 163萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章