中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站公司不給ftp怎么免費(fèi)制作網(wǎng)頁

網(wǎng)站公司不給ftp,怎么免費(fèi)制作網(wǎng)頁,重慶網(wǎng)站建設(shè)網(wǎng)領(lǐng)科技,物流網(wǎng)站建設(shè)方案SFUD簡介 SFUD是一個(gè)通用SPI Flash驅(qū)動庫,通過SFUD可以庫輕松完成對SPI Flash的讀/擦/寫的基本操作,而不用自己去看手冊,寫代碼造輪子。但是SFUD的功能不僅僅于此:①通過SFUD庫可以實(shí)現(xiàn)在一個(gè)項(xiàng)目中對多個(gè)Flash的同時(shí)驅(qū)動&#x…

SFUD簡介

SFUD是一個(gè)通用SPI Flash驅(qū)動庫,通過SFUD可以庫輕松完成對SPI Flash的讀/擦/寫的基本操作,而不用自己去看手冊,寫代碼造輪子。但是SFUD的功能不僅僅于此:①通過SFUD庫可以實(shí)現(xiàn)在一個(gè)項(xiàng)目中對多個(gè)Flash的同時(shí)驅(qū)動,只要把他們注冊到SFUD中即可 ②嵌入式產(chǎn)品因?yàn)楣┴泦栴}替換芯片型號是常有的事,如果我們的驅(qū)動代碼是針對某一個(gè)具體的Flash而寫的,那么每換一個(gè)型號可能就要修改一下代碼。SFUD庫通兼容市面上絕大多數(shù)的Flash型號,還可以在運(yùn)行時(shí)感知Flash芯片的基本屬性,因此替換Flash型號幾乎不用修改代碼。

本文先介紹SFUD的設(shè)計(jì)思路,最后再演示了SFUD庫在STM32上的移植。

Flash設(shè)備上下文結(jié)構(gòu)體

在SFUD中每一個(gè)Flash設(shè)備用一個(gè)設(shè)備上下文結(jié)構(gòu)體 sfud_flash?類型來表示,這個(gè)結(jié)構(gòu)體變量存儲的信息包括:Flash設(shè)備的固有屬性(如容量大小,廠商ID,擦除粒度,擦除操作指令碼);Flash設(shè)備使用的SPI接口;Flash設(shè)備在 flash_table 中的索引等信息。?

通過這個(gè) sfud_flash?上下文結(jié)構(gòu)體,SFUD就可以知道每個(gè)Flash設(shè)備的操作方法和狀態(tài)。這個(gè)結(jié)構(gòu)體有許多成員,有些通過用戶初始化,有些則通過SFUD庫自動初始化。

typedef struct {char *name;                /* 設(shè)備名稱 */size_t index;              /* 設(shè)備在flash_table中的索引 */sfud_flash_chip chip;      /* 設(shè)備信息 */sfud_spi spi;              /* 設(shè)備所使用的SPI接口  */bool init_ok;              /* 初始化狀態(tài)標(biāo)志 */bool addr_in_4_byte;       /* 是否使用4字節(jié)地址尋址模式 */struct {                   /* 向設(shè)備發(fā)送指令時(shí)等待響應(yīng)過程的延時(shí)和嘗試次數(shù) */void (*delay)(void);   /* 設(shè)備操作延時(shí)等待函數(shù) */size_t times;          /* 等待設(shè)備操作完成的重試次數(shù) */} retry;void *user_data;           /* 用戶自定義數(shù)據(jù) */#ifdef SFUD_USING_QSPI    /* 如果啟用QSPI接口 */sfud_qspi_read_cmd_format read_cmd_format;   /* 用于支持QSPI */
#endif#ifdef SFUD_USING_SFDP   /* 如果啟用SFDP機(jī)制 */sfud_sfdp sfdp;            /* 存儲設(shè)備的可發(fā)現(xiàn)參數(shù) */
#endif} sfud_flash, *sfud_flash_t;

?下面簡單的介紹各個(gè)成員的含義,后面會詳細(xì)介紹:

  • name:用戶自定義的Flash設(shè)備的名稱,僅僅用于方便調(diào)試觀察。由用戶初始化
  • index:當(dāng)前這個(gè)?sfud_flash上下文對象 在 flash_table 中的索引。由SFUD庫根據(jù)用戶配置來初始化
  • chip:記錄Flash設(shè)備的物理信息,例如芯片型號名稱,廠商ID,容量ID,擦除粒度,擦除指令等。這些信息可以由用戶初始化,也可以交給SFUD庫來初始化
  • spi:定義了操作Flash設(shè)備所使用的SPI接口,如SPI接口名,SPI的讀/寫操作函數(shù)實(shí)現(xiàn)等,由用戶初始化
  • init_ok:代表Flash設(shè)備是否初始化成功,由SFUD庫內(nèi)部設(shè)置
  • addr_in_4_byte:代表Flash芯片是否使用4字節(jié)存儲地址編碼模式,如果芯片容量大于16MB (256Mb),則需要開啟4字節(jié)地址尋址模式。由SUDP庫根據(jù)芯片容量來自動初始化
  • retry:定義了等待Flash操作執(zhí)行完成過程中的延時(shí)等待和失敗嘗試次數(shù)。SFUD庫在操作Flash時(shí),會讀取Flash的busy狀態(tài),如果Flash處于busy狀態(tài),則需要等待Flash退出busy狀態(tài)。等待過程中,每次先delay(),然后times--,直到Flash變?yōu)榉莃usy狀態(tài)正常退出,或者times減為0則判定Flash設(shè)備超時(shí)錯(cuò)誤。由用戶初始化
  • user_data:與Flash設(shè)備相關(guān)的用戶自定義數(shù)據(jù),由用戶初始化
  • read_cmd_format:QSPI操作時(shí)使用的快速讀取指令格式,當(dāng)啟用QSPI模式時(shí)由SUDP庫內(nèi)部初始化
  • sfdp:存儲Flash的可發(fā)現(xiàn)參數(shù),當(dāng)啟用SFDP機(jī)制時(shí)由SUDP庫內(nèi)部初始化

Flash設(shè)備表

SFUD支持同時(shí)驅(qū)動多個(gè)Flash物理設(shè)備,每一個(gè)Flash設(shè)備通過結(jié)構(gòu)體 sfud_flash?類型來表示。工程中所有用到的Flash設(shè)備通過一個(gè)全局?jǐn)?shù)組?flash_table 記錄。例如你的工程中只有一個(gè)Flash設(shè)備,那么 flash_table 數(shù)組中就只有一個(gè) sfud_flash?類型元素。

對于工程中用到的每個(gè)Flash設(shè)備,都需要通過配置文件 sfud_cfg.h 來進(jìn)行注冊,這個(gè)過程實(shí)際上就是定義并初始化 flash_table 中的每個(gè) sfud_flash?元素。這樣SFUD就知道了我們用到了多少Flash設(shè)備,以及他們的基本信息。

對于工程中用到的每個(gè)Flash設(shè)備,需要在 sfud_cfg.h 中:

  1. 要為他定義一個(gè)枚舉常量,這個(gè)枚舉常量的值用于表示Flash設(shè)備對應(yīng)的sfud_flash上下文對象在flash_table 中的索引,也作為這個(gè)Flash設(shè)備的sfud_flash上下文對象在SFUD庫中的ID,這樣就可以通過ID很方便的引用這個(gè)Flash設(shè)備的sfud_flash上下文對象
  2. 初始化flash_table中這個(gè)Flash設(shè)備對應(yīng)的sfud_flash上下文對象的成員

前面我們介紹了sfud_flash?類型的成員的含義,如果每個(gè)sfud_flash的全部的成員都需要用戶來定義的話,那樣實(shí)在太繁瑣。慶幸的是SFUD庫可以自動初始化sfud_flash的絕大部分成員,在最簡配置情況下,我們只需定義sfud_flash結(jié)構(gòu)體的name成員即可。

注意,指定數(shù)組下標(biāo)初始化和指定結(jié)構(gòu)體成員初始化方式都是C99才開始支持的語法,因此需要在keil中勾選C99 模式。

/*-----------------------sfud_cfg.h 配置文件-------------------------------------*/
enum 
{SFUD_W25Q64CV_DEVICE_INDEX = 0,    //定義Flash設(shè)備在flash_table中的索引SFUD_GD25Q64B_DEVICE_INDEX = 1,    //定義Flash設(shè)備在flash_table中的索引
};//定義并初始化flash_table中每個(gè)sfud_flash上下文對象
//static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;
#define SFUD_FLASH_DEVICE_TABLE                                          \
{                                                                        \[SFUD_W25Q64CV_DEVICE_INDEX] = {.name = "my_W25Q64CV", },            \[SFUD_GD25Q64B_DEVICE_INDEX] = {.name = "my_GD25Q64B", },            \
}

SFDP可發(fā)現(xiàn)參數(shù)

前面我們提到 sfud_flash?上下文結(jié)構(gòu)體中有些通過用戶初始化,有些則通過SFUD自動初始化。其中chip成員是非常重要的一個(gè)成員,它可以由用戶手動初始化(前提是用戶通過查詢Flash芯片的手冊,知曉這些信息并正確填寫這些信息),但更方便的情況是由SFUD庫來初始化。那么SFUD具體是通過什么手段獲取Flash設(shè)備的相關(guān)信息并正確初始化的呢?這里介紹SFDP機(jī)制可以實(shí)現(xiàn)這個(gè)功能。

SFDP(Serial Flash Discoverable Parameters)是JEDEC(固態(tài)技術(shù)協(xié)會)規(guī)范的一個(gè)標(biāo)準(zhǔn),所有遵循這個(gè)標(biāo)準(zhǔn)的Flash設(shè)備會在芯片內(nèi)部存儲自己的一個(gè)參數(shù)表,該表中會存放 Flash 容量、寫粒度、擦除指令碼、地址模式等規(guī)格參數(shù)。并允許外部主控通過SPI接口,以固定通信協(xié)議來讀取到這些參數(shù)表中的信息。這樣就可以在運(yùn)行時(shí)獲取到Flash的信息,而無需提前硬編碼。

在SFUD庫配置文件sfud_cfg.h中,通過開關(guān)宏 SFUD_USING_SFDP 來啟用對這個(gè)特性的支持。當(dāng)啟用這個(gè)宏后,SFUD庫的源文件 sfud_sfdp.c 將參與編譯,在Flash設(shè)備初始化時(shí),會調(diào)用sfud_read_sfdp()函數(shù)執(zhí)行sfdp可發(fā)現(xiàn)參數(shù)讀取操作,讀取到的參數(shù)存儲在Flash設(shè)備上下文結(jié)構(gòu)體的sfud_sfdp sfdp 成員中,然后再用sfdp參數(shù)初始化chip成員。這樣就完成了chip成員的初始化。

如果你實(shí)際使用的Flash設(shè)備不支持JEDEC SFDP標(biāo)準(zhǔn),則SFUD庫在運(yùn)行時(shí)會通過日志輸出提示。

/*---------------------sfud_cfg.h 配置文件-------------------------*/
//如果需要啟用SFDP,則定義這個(gè)宏
#define SFUD_USING_SFDP/*--------------------- sfud_sfdp.c SFDP機(jī)制實(shí)現(xiàn)-------------------------*/
//讀取sfdp參數(shù)
bool sfud_read_sfdp(sfud_flash *flash) {SFUD_ASSERT(flash);/* JEDEC basic flash parameter header */sfdp_para_header basic_header;if (read_sfdp_header(flash) && read_basic_header(flash, &basic_header)) {return read_basic_table(flash, &basic_header);} else {SFUD_INFO("Warning: Read SFDP parameter header information failed. The %s does not support JEDEC SFDP.", flash->name);return false;}
}

內(nèi)置的Flash芯片信息表

使用SFDP固然很方便,但是并不是所有的Flash芯片都支持,另外引入SFDP會使得代碼體積增加,同時(shí)在初始化時(shí)也需要額外的SPI通信來完成。如果你不想或者不能通過SFDP來初始化Flash設(shè)備,則可以使用另一種方式,即內(nèi)置的Flash芯片信息表。

這個(gè)機(jī)制的原理很簡單,就是將市面上常見的Flash的信息用表的形式列舉出來,如果你使用的Flash的廠商ID,類型ID,容量ID與Flash芯片信息表中列舉的某一個(gè)匹配,則當(dāng)前設(shè)備就采用表中記錄的信息來初始化。這個(gè)機(jī)制簡單粗暴,甚至你還可以繼續(xù)補(bǔ)全這個(gè)表,將你所使用的Flash芯片的信息列舉到其中,來使得SFUD庫支持你的某個(gè)特殊的Flash芯片。缺點(diǎn)也很明顯,就是需要定義一個(gè)大數(shù)組,占用了一定的存儲空間。

/*---------------------sfud.c------------------*/
//定義芯片信息表
static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;/*----------------sfud_flash_def.h--------------*/
//芯片信息表(部分內(nèi)容)的初始化
//芯片型號名,廠商ID,類型ID,容量ID,容量(bytes),寫模式,擦除粒度,最小擦除粒度使用的指令碼。
{"W25Q40BV", SFUD_MF_ID_WINBOND, 0x40, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25X40CL", SFUD_MF_ID_WINBOND, 0x30, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25X16AV", SFUD_MF_ID_WINBOND, 0x30, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},  \
{"W25Q16BV", SFUD_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},  \

為了使用Flash芯片信息表功能,需在sfud_cfg.h中定義SFUD_USING_FLASH_INFO_TABLE開關(guān)宏。如果同時(shí)啟用了SFDP和Flash芯片信息表功能,則在初始化時(shí),優(yōu)先使用SFDP。只有在SFDP不支持時(shí),才去使用Flash芯片信息表。

/*---------------------sfud_cfg.h 配置文件-------------------------*/
//如果需要啟用Flash芯片信息表,則定義這個(gè)宏
#define SFUD_USING_FLASH_INFO_TABLE

手動chip成員初始化

如果你既不想因?yàn)槭褂肧FDP使得代碼體積變大,也不想因?yàn)槭褂脙?nèi)置的Flash信息表而導(dǎo)致內(nèi)存占用,那么就可以將你所使用的Flash芯片的信息通過硬編碼的方式手動填寫注冊到flash_table中,即手動初始化chip成員。但這種方法的缺點(diǎn)就是如果更換Flash芯片型號,可能需要修改代碼。

為了驗(yàn)證并實(shí)現(xiàn)這一點(diǎn),我們需要在sfud_cfg.h中取消?SFUD_USING_SFDP 和?SFUD_USING_FLASH_INFO_TABLE宏定義,然后將實(shí)際用到的Flash芯片的信息(chip成員)手動填寫在 flash_table的SFUD_FLASH_DEVICE_TABLE定義中,如下代碼所示:

/*-----------------------sfud_cfg.h 配置文件-------------------------------------*///#define SFUD_USING_SFDP                //不使用SFDP
//#define SFUD_USING_FLASH_INFO_TABLE    //不使用falsh芯片信息表enum 
{SFUD_W25Q64CV_DEVICE_INDEX = 0,    //定義Flash設(shè)備在flash_table中的索引
};//定義并初始化flash_table中每個(gè)sfud_flash上下文對象
//static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;
#define SFUD_FLASH_DEVICE_TABLE                                          \
{                                                                        \[SFUD_W25Q64CV_DEVICE_INDEX] = {.name = "my_W25Q64CV",               \ .chip={"W25Q64CV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}},   \
}

chip成員

前面我們提到 sfud_flash 上下文對象的chip成員是非常重要的一個(gè)成員,之所以重要是因?yàn)镾FUD庫通過他提供的信息來實(shí)現(xiàn)芯片的擦除/讀/寫等基本操作。

下面代碼是chip成員的類型定義,它也是一個(gè)結(jié)構(gòu)體。chip成員的mf_id、type_id、capacity_id分別是廠商ID,類型ID和容量ID,這三個(gè)信息在SFUD中是通過read_jedec_id( ) 函數(shù)來獲取的。但是從本質(zhì)上來說這三個(gè)參數(shù)并不是重要的也不是必須的,SFUD只是依據(jù)這三個(gè)參數(shù)來初始化后面的四個(gè)更重要的參數(shù):capacity、write_mode、erase_gran、erase_gran_cmd,這四個(gè)參數(shù)直接影響了對Flash芯片的擦除/讀/寫操作的實(shí)現(xiàn)。

//chip成員的類型定義
typedef struct {char *name;                /**< 芯片型號名稱 */uint8_t mf_id;             /**< 廠商 ID */uint8_t type_id;           /**< 類型 ID */uint8_t capacity_id;       /**< 容量 ID */uint32_t capacity;         /**< 容量 (bytes) */uint16_t write_mode;       /**< 寫模式 @see sfud_write_mode */uint32_t erase_gran;       /**< 擦除粒度(bytes) */uint8_t erase_gran_cmd;    /**< 擦除最小粒度單元使用的指令碼*/
} sfud_flash_chip;

簡而言之,無論是通過SFDP,還是內(nèi)置的芯片信息表,還是手動填寫注冊芯片信息,只要能正確初始化chip成員的capacity、write_mode、erase_gran、erase_gran_cmd這四個(gè)參數(shù),SFUD庫就可以正常驅(qū)動Flash芯片。

SPI互斥鎖

假設(shè)有這樣的應(yīng)用場景:同一個(gè)SPI接口驅(qū)動了Flash設(shè)備A和B,且在不同的任務(wù)中分別讀寫Flash設(shè)備A和Flash設(shè)備B,則相當(dāng)于兩個(gè)任務(wù)競爭使用SPI接口,那么這個(gè)時(shí)候就要對SPI接口加鎖,以保證多任務(wù)下串化操作SPI接口,保證使用的正確性和一致性。對SPI加鎖可以使用RTOS的互斥鎖來實(shí)現(xiàn)。如果只有一個(gè)Flash設(shè)備,或者不同的Flash設(shè)備分別使用不同的SPI接口,或者沒有多任務(wù)搶占長場景,則可以不用加鎖。SFUD庫考慮到了多任務(wù)場景,可以通過實(shí)現(xiàn)spi成員的lock和unlock回調(diào)函數(shù)指針來實(shí)現(xiàn)spi接口加鎖和釋放鎖的邏輯。如果不需要,則初始化為NULL即可。

typedef struct __sfud_spi {// .../* SPI接口上鎖 */void (*lock)(const struct __sfud_spi *spi);/* SPI接口釋放鎖  */void (*unlock)(const struct __sfud_spi *spi);// ...
} sfud_spi, *sfud_spi_t;

SFUD初始化流程

當(dāng)配置文件就緒后,通過調(diào)用sfud_init()函數(shù)來初始化SFUD庫,這是SFUD的初始化入口。初始化過程就是遍歷flash_table,對其中注冊的每個(gè)Flash設(shè)備進(jìn)行初始化。下圖演示了設(shè)備dev0的初始化過程。

//SFUD總體初始化
sfud_err sfud_init(void) 
{sfud_err cur_flash_result = SFUD_SUCCESS, all_flash_result = SFUD_SUCCESS;size_t i;//遍歷Flash設(shè)備表,初始化所有注冊在表中的Flash設(shè)備for (i = 0; i < sizeof(flash_table) / sizeof(sfud_flash); i++) {flash_table[i].index = i;         //初始化每個(gè)sfud_flash對象在表中的索引cur_flash_result = sfud_device_init(&flash_table[i]);  //初始化單個(gè)Flash設(shè)備if (cur_flash_result != SFUD_SUCCESS) {all_flash_result = cur_flash_result;}}return all_flash_result;
}//單個(gè)Flash設(shè)備的初始化
sfud_err sfud_device_init(sfud_flash *flash) 
{sfud_err result = SFUD_SUCCESS;result = hardware_init(flash);     //單個(gè)Flash設(shè)備的硬件部分初始化if (result == SFUD_SUCCESS) {  result = software_init(flash); //單個(gè)Flash設(shè)備的軟件部分初始化}if (result == SFUD_SUCCESS) {flash->init_ok = true;SFUD_INFO("%s flash device initialized successfully.", flash->name);} else {flash->init_ok = false;SFUD_INFO("Error: %s flash device initialization failed.", flash->name);}return result;
}

SFUD移植過程

準(zhǔn)備SFUD源代碼文件

移植的第一步,就是將SFUD庫目錄下的 所有.c 和 .h 文件(一共7個(gè))都加入到工程中。移植過程中只需修改? sfud_cfg.h??和 sfud_port.c 這2個(gè)文件。

  1. sfud.h
  2. sfud.c
  3. sfud_def.h
  4. sfud_flash_def.h
  5. sfud_sfdp.c
  6. sfud_cfg.h? ? ? ? //移植配置文件
  7. sfud_port.c? ? ? ?//移植適配文件

主機(jī)SPI接口初始化

這部分代碼可以放在sfud_port.c中,也可以在MCU的BSP層中。

void RCC_config(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);   //使能SPI1時(shí)鐘
}//SPI1接口的初始化
void SPI1_config(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;//SCK:PA5 、MOSI:PA7 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);//MISO:PA6GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);//CS:PA2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE);
}

SFUD配置文件:sfud_cfg.h

  • 注冊Flash設(shè)備:通過枚舉常量定義Flash設(shè)備的ID,也就是這個(gè)對象在Flash設(shè)備表中的索引,然后在DEVICE_TABLE中注冊這個(gè)設(shè)備,這里只需初始化其name成員即可。
  • 啟用SFDP:根據(jù)需要啟用SFDP機(jī)制,如果需要?jiǎng)t定義SFUD_USING_SFDP宏
  • 啟用Flash芯片信息表:根據(jù)需要啟用Flash芯片信息表機(jī)制,如果需要?jiǎng)t定義?SFUD_USING_FLASH_INFO_TABLE宏
  • 啟用調(diào)試模式:定義宏SFUD_DEBUG_MODE來打開調(diào)試模式,可以通過printf輸出調(diào)試和日志信息
  • 啟用QSPI:定義宏SFUD_USING_QSPI啟用QSPI接口
  • 啟用Fast Read:定義宏SFUD_USING_FAST_READ啟用Fast Read模式
#ifndef _SFUD_CFG_H_
#define _SFUD_CFG_H_#define SFUD_DEBUG_MODE             //啟用調(diào)試模式
//#define SFUD_INFO(...)
#define SFUD_USING_SFDP             //啟用SFDP
//#define SFUD_USING_FLASH_INFO_TABLE //啟用Flash芯片信息表// #define SFUD_USING_FAST_READ     //啟用Fast Read模式
// #define SFUD_USING_QSPI          //啟用QSPI接口enum {SFUD_W25Q128_DEVICE_INDEX = 0,  //定義Flash設(shè)備的ID
};#define SFUD_FLASH_DEVICE_TABLE                                          \
{                                                                        \[SFUD_W25Q128_DEVICE_INDEX] = {.name = "W25Q128" },/*注冊Flash設(shè)備*/ \
}#endif /* _SFUD_CFG_H_ */

SFUD移植文件:sfud_port.c

1、實(shí)現(xiàn)sfud_spi_port_init()函數(shù)

此函數(shù)用于實(shí)現(xiàn)硬件平臺相關(guān)的初始化,主要用于設(shè)置sfud_flash *flash 對象的參數(shù)。在函數(shù)中,根據(jù)flash對象在flash_table中的索引(或者說ID)來區(qū)分不同的Flash對象,進(jìn)行針對性的初始化,因?yàn)轫?xiàng)目可能存在多個(gè)Flash設(shè)備,且他們的初始化參數(shù)不一樣。

2、實(shí)現(xiàn)spi_write_read()函數(shù)

此函數(shù)用于實(shí)現(xiàn)SPI接口的數(shù)據(jù)的收發(fā)。驅(qū)動Flash時(shí),一般過程為,首先是主機(jī)通過SPI接口發(fā)送指令,然后接收Flash設(shè)備的響應(yīng)數(shù)據(jù)。由于全雙工SPI的收發(fā)是同時(shí)進(jìn)行的,因此在接收Flash設(shè)備的數(shù)據(jù)時(shí),主機(jī)也要發(fā)送數(shù)據(jù)(dummy write),只不過這個(gè)數(shù)據(jù)沒有意義,僅僅是用于讓SCK產(chǎn)生同步時(shí)鐘來驅(qū)動從機(jī)將響應(yīng)的數(shù)據(jù)回傳到主機(jī)。

3、適配printf()

默認(rèn)使用printf函數(shù)來實(shí)現(xiàn)調(diào)試和日志信息輸出。這里需要對 sfud_log_info和sfud_log_debug函數(shù)進(jìn)行適配,簡單情況下可以對printf進(jìn)行重定向輸出到串口。當(dāng)代碼穩(wěn)定后,可以關(guān)閉調(diào)試和日志信息輸出功能,操作如下:

  • 在sfud_cfg.h中取消定義SFUD_DEBUG_MODE,關(guān)閉調(diào)試模式
  • 在sfud_cfg.h中定義#define SFUD_INFO(...) 為空實(shí)現(xiàn),關(guān)閉日志輸出
  • 在sfud_port.c中注釋掉 sfud_log_debug 和?sfud_log_info 函數(shù)的實(shí)現(xiàn)
  • 在sfud_port.c中注釋掉?static char log_buf[256];

#include <sfud.h>
#include <stdarg.h>
#include <stdio.h>
#include "stm32f10x.h"static char log_buf[256];   //打印日志和調(diào)試信息用的buf
void sfud_log_debug(const char *file, const long line, const char *format, ...);/*** @brief SPI用戶自定義參數(shù)結(jié)構(gòu)體*        用于記錄每個(gè)Flash設(shè)備使用的spi接口是哪個(gè),以及cs引腳是哪個(gè)*/
typedef struct {SPI_TypeDef * spix;       //驅(qū)動Flash芯片使用的SPI接口 GPIO_TypeDef* cs_gpio;    //驅(qū)動Flash芯片的CS引腳的GPIOuint16_t      cs_pin;     //驅(qū)動Flash芯片的CS引腳的GPIO編號
} spi_user_data_t;/*** @brief 定義SPI用戶自定義參數(shù)數(shù)組*        用于記錄每個(gè)Flash設(shè)備使用的spi接口是哪個(gè),以及cs引腳是哪個(gè)*/
static spi_user_data_t spi_user_data_table[] = { [SFUD_W25Q128_DEVICE_INDEX] =  {SPI1,GPIOA,GPIO_Pin_2},  };/*** @brief 定義延時(shí)等待函數(shù)的實(shí)現(xiàn),在RTOS環(huán)境下可以使用RTOS的延時(shí)機(jī)制,這里簡單使用軟件延時(shí)實(shí)現(xiàn)*/
static void sfud_delay(void)
{u32 i;for(i=0;i<800;i++);
}/*** @brief SPI接口的數(shù)據(jù)收發(fā)實(shí)現(xiàn)* @param spi : sfud_flash對象的spi成員* @param write_buf : 存儲主機(jī)發(fā)送給Flash的指令的緩沖區(qū)* @param write_size : write_buf中指令的長度* @param read_buf : 存儲Flash響應(yīng)給主機(jī)的數(shù)據(jù)的緩沖區(qū)* @param read_size : Flash響應(yīng)給主機(jī)的數(shù)據(jù)的長度* @retval 函數(shù)執(zhí)行的狀態(tài)*/
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,size_t read_size) {uint32_t i;sfud_err result = SFUD_SUCCESS;uint8_t send_data, read_data;spi_user_data_t* spi_dev    = (spi_user_data_t*)spi->user_data;GPIO_ResetBits(spi_dev->cs_gpio, spi_dev->cs_pin);     //CS=0,選中for (i = 0; i < write_size + read_size; i++) {/* 先寫緩沖區(qū)中的數(shù)據(jù)到 SPI 總線,數(shù)據(jù)寫完后,再寫 (0xFF) 到 SPI 總線 */if (i < write_size) {send_data = *write_buf++;} else {send_data = 0xFF;   //dummy write}/* 發(fā)送1字節(jié)數(shù)據(jù) */while (SPI_I2S_GetFlagStatus(spi_dev->spix, SPI_I2S_FLAG_TXE) == RESET) { /*TODO:這里建議加超時(shí)判斷,不要無限等待*/ }SPI_I2S_SendData(spi_dev->spix, send_data);/* 接收1字節(jié)數(shù)據(jù) */while (SPI_I2S_GetFlagStatus(spi_dev->spix, SPI_I2S_FLAG_RXNE) == RESET){ /*TODO:這里建議加超時(shí)判斷,不要無限等待*/ }read_data = SPI_I2S_ReceiveData(spi_dev->spix);/* 寫緩沖區(qū)中的數(shù)據(jù)發(fā)完后,再讀取 SPI 總線中的數(shù)據(jù)到讀緩沖區(qū) */if (i >= write_size) {*read_buf++ = read_data;}}				GPIO_SetBits(spi_dev->cs_gpio, spi_dev->cs_pin);     //CS=1,取消選中return result;
}#ifdef SFUD_USING_QSPI
/*** read flash data by QSPI*/
static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,uint8_t *read_buf, size_t read_size) {sfud_err result = SFUD_SUCCESS;return result;
}
#endif /* SFUD_USING_QSPI *//*** @brief 實(shí)現(xiàn)單個(gè)指定的Flash設(shè)備上下文對象 sfud_flash 的初始化* @param flash : 指定的Flash設(shè)備上下文對象* @retval 函數(shù)執(zhí)行的狀態(tài)*/
sfud_err sfud_spi_port_init(sfud_flash *flash) 
{sfud_err result = SFUD_SUCCESS;switch(flash->index){case SFUD_W25Q128_DEVICE_INDEX://RCC、GPIO、SPI接口初始化均在BSP層中執(zhí)行flash->name          = "Flashxx";   //Flash設(shè)備的名稱,非必須,僅僅用于調(diào)試flash->user_data     = NULL;        //用戶自定義數(shù)據(jù),這里不需要flash->spi.name      = "spixx";    //SPI接口的名稱,非必須,僅僅用于調(diào)試//flash->spi.qspi_read = NULL;     //這里不需要flash->spi.wr        = spi_write_read; //SPI接口的數(shù)據(jù)收發(fā)函數(shù)flash->spi.lock      = NULL;        //spi接口加鎖函數(shù),這里不需要flash->spi.unlock    = NULL;        //spi接口釋放鎖函數(shù),這里不需要flash->spi.user_data = &spi_user_data_table[flash->index];//SPI接口相關(guān)的用戶自定義數(shù)據(jù)flash->retry.delay   = sfud_delay; //執(zhí)行Flash操作時(shí)的延時(shí)等待函數(shù)flash->retry.times   = 1000;       //執(zhí)行flash操作時(shí)的等待嘗試次數(shù)break;default:result = SFUD_ERR_NOT_FOUND;}return result;
}void sfud_log_debug(const char *file, const long line, const char *format, ...) {va_list args;/* args point to the first variable parameter */va_start(args, format);printf("[SFUD](%s:%ld) ", file, line);/* must use vprintf to print */vsnprintf(log_buf, sizeof(log_buf), format, args);printf("%s\n", log_buf);va_end(args);
}void sfud_log_info(const char *format, ...) {va_list args;/* args point to the first variable parameter */va_start(args, format);printf("[SFUD]");/* must use vprintf to print */vsnprintf(log_buf, sizeof(log_buf), format, args);printf("%s\n", log_buf);va_end(args);
}

SFUD主要用戶接口說明

//描述:初始化所有注冊的flash對象。遍歷flash_table數(shù)組,初始化所有的flash對象。
sfud_err sfud_init(void)//描述:初始化一個(gè)指定的flash對象
sfud_err sfud_device_init(sfud_flash *flash);//根據(jù)ID(索引)獲取一個(gè)注冊的flash對象
sfud_flash *sfud_get_device(size_t index);//獲取flash對象數(shù)組,也就是flash_table
const sfud_flash *sfud_get_device_table(void);//描述:flash擦除操作
//參數(shù)flash:flash對象
//參數(shù)addr:擦除的起始地址
//參數(shù)size:擦除的空間大小,字節(jié)數(shù)
//注意:只要是被參數(shù)addr和size覆蓋的頁,不管地址是否對齊,都會被擦除
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)//描述:flash編程操作
//參數(shù)flash:flash對象
//參數(shù)addr:寫數(shù)據(jù)的起始地址
//參數(shù)size:寫入數(shù)據(jù)的長度,字節(jié)數(shù)
//參數(shù)data:存放代寫入的數(shù)據(jù)的緩沖區(qū)
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)//描述:flash讀取操作
//參數(shù)addr:讀數(shù)據(jù)的起始地址
//參數(shù)size:讀取的數(shù)據(jù)的長度,字節(jié)數(shù)
//參數(shù)data:存放讀出的數(shù)據(jù)的緩沖區(qū)
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)//描述:先擦除再寫入操作,等價(jià)于sfud_erase + sfud_write
sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data);//描述:全片擦除
sfud_err sfud_chip_erase(const sfud_flash *flash);

http://www.risenshineclean.com/news/64593.html

相關(guān)文章:

  • 做網(wǎng)站是什么優(yōu)化設(shè)計(jì)官方電子版
  • 網(wǎng)站與域名的關(guān)系廣告免費(fèi)發(fā)布信息平臺
  • 綿陽政府網(wǎng)站建設(shè)國內(nèi)建站平臺有哪些
  • 動漫谷網(wǎng)站建設(shè)策劃書網(wǎng)站推廣的平臺
  • 太平洋在線企業(yè)建站系統(tǒng)華聯(lián)股份股票
  • 做類似3d溜溜的網(wǎng)站網(wǎng)上怎么注冊公司免費(fèi)的
  • 投注網(wǎng)站建設(shè)需要優(yōu)書網(wǎng)
  • 在網(wǎng)站怎么做收款二維碼短信營銷
  • 泰州做直銷會員結(jié)算管理網(wǎng)站公司網(wǎng)站如何推廣
  • wordpress 主題庫安徽seo人員
  • ??诰W(wǎng)站建設(shè)公司哪家好抖音seo優(yōu)化
  • 圖書館網(wǎng)站建設(shè)情況說明網(wǎng)站排名優(yōu)化多少錢
  • 做網(wǎng)站避免上當(dāng)文案短句干凈治愈
  • 手機(jī)網(wǎng)站注冊頁面百度一下你就知道移動首頁
  • 阿里云輕云服務(wù)器可以放多個(gè)網(wǎng)站啊怎么做做網(wǎng)站需要準(zhǔn)備什么
  • dreamweaver最新版本引擎優(yōu)化是什么意思
  • 響應(yīng)式建站工具58同城發(fā)布免費(fèi)廣告
  • 公司名logo設(shè)計(jì)圖片seow是什么意思
  • 設(shè)計(jì)公司給公司做網(wǎng)站用了方正字體app開發(fā)教程
  • 網(wǎng)站做app的軟件叫什么seo快速優(yōu)化排名
  • 個(gè)人網(wǎng)站系統(tǒng)優(yōu)秀網(wǎng)站網(wǎng)頁設(shè)計(jì)圖片
  • 代辦公司營業(yè)執(zhí)照長沙seo推廣公司
  • 平度網(wǎng)站建設(shè)網(wǎng)絡(luò)優(yōu)化工程師簡歷
  • 網(wǎng)站建設(shè)入門教程視頻抖音代運(yùn)營公司
  • 站酷網(wǎng)站的圖是用什么做的百度指數(shù)app下載
  • 做機(jī)械的網(wǎng)站有哪些軟文營銷實(shí)施背景
  • 海外營銷網(wǎng)站設(shè)計(jì)英文seo實(shí)戰(zhàn)派
  • 網(wǎng)頁設(shè)計(jì)推薦網(wǎng)站百度推廣咨詢
  • 自己買域名可以做網(wǎng)站嗎百度如何做推廣
  • 和碩網(wǎng)站建設(shè)騰訊廣告投放平臺官網(wǎng)