XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX 作 者:ZHS(文化人)
XX 聯繫方式:文章末尾Chat快問(或進羣:471144274)
XX 版權聲明:原創文章,歡迎評論和轉載~轉載時能告訴我一聲就最好了
XX 要說的話:作者水平有限,難免有不足之處,懇請指正!
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1. QCC300X 外部Flash的讀寫
QCC300x是使用外部Flash片子,使用外部flash的好處就是成本下來了,大家都知道,CSR的片子一直是很貴的,這樣的片子就只能對成本要求不高的項目優先,在使用外部Flash時,我們一般默認使用32M(因爲官方配置就是這個參數,會讓使用方便的多),然而我們在使用過程往往使用不了這麼大的空間,現在我們就利用起來,一起來學習對外部Flash的應用。
1.1. 爲外部flash分區
要對外部Flash使用,必先是對外部Flash進行分區,上一節做Upgrade時有對分區文件說明,即XXX.ptn文件。
需要注意的是外部的Flash可以作爲兩種用途使用,一種是隻讀的文件系統,另一種是未處理的連續數據分區(Raw Serial),只讀的文件系統是對於代碼,語音文件,用戶文件等保存於Flash中,但是這個需要以文件的形式打包寫入,在代碼中不可以被修改,僅僅可以讀取。
未處理的連續數據分區,就是純粹的Flash數據,在程序中可以寫入和讀取。
使用文件系統時我們需要掛載分區,使用Raw Serial分區時 不需要掛載分區。
我們想實現一個在Flash中的數據寫入和讀取,所以Flash在原來的分區下添加一個Raw Serial分區:
0, 8K, PS, (none) # For PS Store
1, 32K, RO, i1107e_patch_bundle.xuv # Logical #0 : For DSP & firmware patches #0,1
2, 32K, RO, (erase) # Logical #0 : For DSP & firmware patches #0,2
3, 612K, RO, (erase) # Logical #1 Audio prompts #1,1
4, 612K, RO, (erase) # Logical #1 Audio prompts #1,2
5, 300K, RO, i1107e.xuv # Logical #2 Main application image and other files. #2,1
6, 300K, RO, (erase) # Logical #2 Main application image and other files. #2,2
7, 8K, RO, system_i1107e.xuv # Logical #3 PSFS #3,1
8, 8K, RO, (erase) # Logical #3 PSFS #3,2
9, 8K, RS, (erase)
10, 8K, RS, (erase)
11, *, RS, (erase)
即添加分區9和10,大小爲8K,分區類型是RS(Raw Serial),(erase)每次下載重新擦除。
需要說明一下,這個分區文件涉及下載軟件Xide.exe的下載流程,新添加的分區儘量填寫每次下載擦除,否則會影響下載,
我之前有調試過使用(none)會導致下載有很久的卡頓,導致下載時間超長。
1.2. Flash寫入數據
Flash在分好區後就可以讀寫了,Flash的讀寫也是一個流的概論,寫入需要獲取一個Sink,讀取需要獲取一個Source ,需要注意的是Flash在沒有數據時是讀取不到數據的,直接讀取未寫入數據的Flash會是空。
1.2.1. 獲取Flash的Sink
獲取Sink的方法,ADK提供了兩個函數,可以獲取Flash的Sink,分別是
Sink StreamPartitionOverwriteSink(partition_filesystem_devices device,
uint16 partition)
Sink StreamPartitionResumeSink(partition_filesystem_devices device,
uint16 partition,uint16 first_word);
可以在Partition 和Stream的代碼文件中找到。
第一個函數重新寫入Flash,獲取的Sink寫入後會覆蓋之前寫入的數據。
第二個函數是再次寫入Flash。第三個參數是需要寫入的起始地址,如果Sink中已經存在數據,可以使用
uint32 PartitionSinkPosition(Sink sink)函數來獲取已經存在的Flash數據大小
partition_filesystem_devices :是選擇分區文件的類型,我們需要選擇Flash
Partition:這個參數就是我們分區時分的分區號,就是XXX.ptn文件中添加的9或10分區號。
1.2.2. 設置Flash的寫入配置
Flash在寫入是需要設置其寫入配置,配置需要如下函數設置:
bool PartitionSetMessageDigest(Sink sink, partition_message_digest_type md_ty, uint16 *data, uint16 len)
這個函數可以設置Flash的配置,
sink: The sink that is writing to the partition
md_type: The type of message digest:
PARTITION_MESSAGE_DIGEST_APP_SIGNATURE: Signed with the application DFU key (see note)
PARTITION_MESSAGE_DIGEST_CRC: Filesystem CRC
PARTITION_MESSAGE_DIGEST_SKIP: Do not perform verification
data: pointer to the message digest
len: length of message digest. 2 for CRC verification, 66 for signature verification
1.2.3. 獲取Flash的狀態
這一步不是必要的,我們在操作Flash,如果需要查看看狀態可使用:
bool PartitionGetInfo(partition_filesystem_devices device, uint16 partition,partition_info_key key, uint32 *value)
參數說明:
device: The device to query. Set to PARTITION_SERIAL_FLASH to query the serial flash device.
partition: The number of the partition to query.
key: The type of information requested:
PARTITION_INFO_IS_MOUNTED: Whether a partition is mounted or not (1 = mounted, 0 = unmounted).
PARTITION_INFO_SIZE: The size of the partition in words.
PARTITION_INFO_TYPE: The type of the partition (0 = unused, 1 = filesystem, 2 = PS Store).
value: The pointer to return the query result to
1.2.4. 寫入Flash數據
寫入數據是最後的一步,但是沒有前面的鋪墊,是不能寫入成功的,我們得到的分區Sink,就是我們寫入數據入口。
拿到Sink後,我們不能盲目寫入,可以使用SinkSlack(Sink sink),查看一下Sink可以寫入的最大數據量,我測試過程中獲取到的是48,說明Flash每次最大隻能寫入48個字符,如果我們需要大量寫入,可以分批寫入數據。
數據寫入:
第一步:使用SinkMap(Sink sink) 獲取一個指針;SinkClaim(Sink sink ,uint16 extra) 聲明一下寫入的大小,爲了檢查能否寫入,如果返回0xFFFF,說明不能寫入。
第二步:使用memcpy() 把需要寫入的數據搬運到SinkMap()指針指向的地址上,
第三步:使用SinkFlush(Sink sink uint6 amount)實現Flash的真正寫入。
第四步:使用SinkClose(Sink sink)關閉Sink
需要注意的是:
1,Sink寫入數據後,如果需要讀取,必先使用第四步關閉Sink才能讀取,但是使用SinkClose()關閉Sink後,不能再次對Flash寫入,需要使用重啓寫入函數對Flash重啓寫入。
2,如果需要多次分批寫入Flash,不要SinkClose()關閉Sink,完全寫入完成後,再關閉Sink,關閉後,再次寫入Flash失效,需要重新覆蓋寫入,
3,Sink再次寫入時,需要重新獲取Sink,獲取的Sink偏移需要PartitionSinkGetPosition函數獲取即可。
如果上面的步驟沒有出錯,恭喜你,你的Flash數據寫入成功。
1.2.5. Flash寫入程序附錄
示例代碼只是初步演示:
Flash的寫入:
static void test_flash_resave_date(uint8 *data,uint16 len )
{
Sink sink;
bool ok=FALSE;
/* 獲取分區9 的Sink , flashsize:記錄Flash 寫入的大小*/
sink = StreamPartitionResumeSink(PARTITION_SERIAL_FLASH, 9,flashsize);
if (!sink)
{
printf("UPG: Failed to open raw partition %u for resume\n", 9);
return;
}
/* 寫入Flash 配置*/
/* Disable the crc check */
ok = PartitionSetMessageDigest(sink, PARTITION_MESSAGE_DIGEST_SKIP,NULL, 0);
printf(" Set Digest ok=%d , get pasition size %ld ,slack=size %d\n",ok,
PartitionSinkGetPosition(sink),
SinkSlack(sink));
if((SinkClaim(sink, sizeof(data)) != 0xFFFF))
{
memcpy(SinkMap(sink), data, len);
ok = SinkFlush(sink, len);
printf("SinkFlush ok=%d \n",ok);
}
flashsize = PartitionSinkGetPosition(sink);
}
如果需要寫入後結束,直接在函數後面添加SinkClose,如下:
static void test_flash_resave_date(uint8 *data,uint16 len )
{
Sink sink;
bool ok=FALSE;
/* 獲取分區9 的Sink , flashsize:記錄Flash 寫入的大小*/
sink = StreamPartitionResumeSink(PARTITION_SERIAL_FLASH, 9,flashsize);
if (!sink)
{
printf("UPG: Failed to open raw partition %u for resume\n", 9);
return;
}
/* 寫入Flash 配置*/
/* Disable the crc check */
ok = PartitionSetMessageDigest(sink, PARTITION_MESSAGE_DIGEST_SKIP,NULL, 0);
printf(" Set Digest ok=%d , get pasition size %ld ,slack=size %d\n",ok,
PartitionSinkGetPosition(sink),
SinkSlack(sink));
if((SinkClaim(sink, sizeof(data)) != 0xFFFF))
{
memcpy(SinkMap(sink), data, len);
ok = SinkFlush(sink, len);
printf("SinkFlush ok=%d \n",ok);
}
flashsize = PartitionSinkGetPosition(sink);
SinkClose(sink);
}
注意1、獲取分區後,前面會有兩個字節的數據,不清楚是什麼,只能從第三個字節開始寫;
注意2、SinkSlack(Sink sink)查看最大寫入數據量;
注意3、SinkClaim(Sink sink ,uint16 extra) 聲明寫入的大小,返回值表示能否寫入,如果返回0xFFFF,說明不能寫入;
注意4、封裝flash操作接口,可參考Upgrade_fw_if.c裏的接口;
FlashDataIFPartitionOpen
FlashDataIFPartitionClose
FlashDataIFPartitionWrite
FlashDataIFPartitionRead
FlashDataIFPartitionGetOffset
FlashDataIFGetPhysPartitionNum
FlashDataIFGetPhysPartitionSize
typedef Sink FlashDataIFPartitionHdl;
Sink FlashDataIFPartitionOpen(uint16 physPartition, uint16 Offset)
{
Sink sink;
sink = StreamPartitionResumeSink(PARTITION_SERIAL_FLASH, physPartition, Offset);
if(!sink)
{
printf("Failed to open raw partition %d for resum\r\n", physPartition);
return 0;
}
PartitionSetMessageDigest(sink, PARTITION_MESSAGE_DIGEST_SKIP, NULL, 0);
return (FlashDataIFPartitionHdl)(int)sink;
}
uint16 FlashDataIFPartitionClose(FlashDataIFPartitionHdl handle)
{
Sink sink = (Sink)(int)handle;
if(!sink)
return 1;
if(!SinkClose(sink))
{
printf("Unable to close SINK\r\n");
return 1;
}
return 0;
}
uint16 FlashDataIFPartitionWrite(FlashDataIFPartitionHdl handle, uint8 *data, uint16 len)
{
Sink sink = (Sink)(int)handle;
if(!sink)
return 0;
if(SinkClaim(sink, len) == 0xFFFF)
{
printf("Failed to claim\r\n");
return 0;
}
memcpy(SinkMap(sink), data, len);
if(!SinkFlush(sink, len))
{
printf("Failed to flush data\r\n");
return 0;
}
return len;
}
1.3. Flash 讀取數據
讀取數據和寫數據是一個反流程,需要獲取一個Source ,通過Source獲取Flash的數據。
需要注意的是Flash的讀取是一次性讀取,獲取的Source包含了整個分區的數據,但是Source的大小僅僅最大是2K的數據,
我們在使用過程,如果需要讀取較多的數據,可以分批讀取。
1.3.1. 獲取Flash 的 Source
獲取Source直接使用PartitionGetRawSerialSource函數獲取即可:
Source PartitionGetRawSerialSource(partition_filesystem_devices device, uint16 partition);
參數說明:
device: The device to query. Set to PARTITION_SERIAL_FLASH to query the serial flash device.
partition: The number of the partition to query.
1.3.2. 讀取Flash數據
讀取數據時需要注意的是Flash必先是寫入數據了,否則獲取的Source就是一個空的數據,不可以使用。
一切準備好的話,讀取Flash就比較簡單了,
第一步:通過SourceMap() 獲取Flash的數據指針,
第二步:通過SourceSize() 獲取數據的大小,
需要注意的是:
如果獲取的數據大於2K,可能實際數據會大於2k,可以使用SourceDrop()去掉已經讀取完的數據,在重複第一、二步驟分別讀取數據,直到數據讀取完成。
第三步:通過SuorceClose() 關閉Source
1.3.3. 讀取Flash程序附錄
示例代碼只是初步演示:
static void test_flash_read_date(void)
{
const uint8 *date;
uint16 date_size,i;
Source source_flash;
source_flash = PartitionGetRawSerialSource(PARTITION_SERIAL_FLASH,9);
date = SourceMap(source_flash);
date_size = SourceSize(source_flash);
printf("source %X addr Map %p\n",(uint16 )source_flash, date);
printf("flash Size = %d,",date_size);
/*每次讀取500,直到讀取完成*/
while(date_size>500)
{
printf("flash Size = %d,",date_size);
for(i=0;i<500;i++)
printf("%x ",date[i]);
printf("\n");
SourceDrop(source_flash,500);
date = SourceMap(source_flash);
date_size = SourceSize(source_flash);
}
if(date_size>0)
{
for(i=0;i<date_size;i++)
printf("%x ",date[i]);
}
printf("\n");
SourceClose(source_flash);
}