SD Mode: Hỗ trợ SD Card trong chế độ SD Bus (1 bit). Gồm một số port chính sau:
CMD: tín hiệu 2 chiều lệnh/phản hồi, tín hiệu hai chiều này được sử dụng để khởi tạo thẻ và chuyển các lệnh dữ liệu. Các lệnh được gửi từ các bus SD chủ đến thẻ và đáp ứng được trả về từ các thẻ đến máy chủ. Mỗi thẻ lệnh được đi trước bởi một bit bắt đầu (0) và đã thành công bằng một bit cuối (1). Tổng chiều dài là 48 bit. Mỗi thẻ được bảo vệ bởi các bit CRC để các lỗi truyền dẫn có thể được phát hiện và các hoạt động có thể được lặp đi lặp lại. Các thẻ phản hồi có một trong bốn chương trình mã hóa, tùy thuộc vào nội dung của nó. Chiều dài thẻ hoặc 48 bit hoặc 136 bit.
Hình 5.1-3: Định dạng phản hồi
DAT[3 : 0]: Dữ liệu hai chiều. Các tín hiệu DAT hoạt động ở chế độ push pull. Chỉ có một thẻ hoặc máy chủ điều khiển tín hiệu này tại một thời điểm. Dữ liệu luôn được truyền theo từng khối (block), kết thúc mỗi khối là CRC. Bit CRC được tính toán và kiểm tra cho mỗi đường DAT riêng lẻ. Các thẻ gửi các máy chủ phản ứng tình trạng CRC và chỉ bận rộn trên chỉ DAT0, DAT1-DAT3 trong thời kỳ đó thì không quan tâm.
Hình 5.1-4: Định dạng dữ liệu
Thẻ SD có thể sử dụng hoặc một đường dữ liệu (DAT0) hoặc bốn đường dữ liệu (DAT0-DAT3) để truyền dữ liệu. Tốc độ truyền dữ liệu tối đa cho một dòng dữ liệu duy nhất là 50 Mb/s và 200 Mb (25 MB) mỗi giây.
CLK: Máy chủ đến xung đồng hồ SD Card. Với mỗi chu kỳ của tín hiệu này, việc chuyển giao một bit trên các lệnh và các dòng dữ liệu được thực hiện. Các tần số có thể thay đổi giữa 0 và tần số xung đồng hồ tối đa.
Quá trình đọc dữ liệu: Bắt đầu khi host gửi yêu cầu đến thẻ, thẻ sẽ gửi phản hồi lại, sau đó dữ liệu sẽ được thẻ gửi đi (tùy vào lệnh mà dữ liệu sẽ gồm 1 khối hay nhiều khối), cuối cùng host phát lệnh ngừng đọc.
Hình 5.1-5: Định dạng chuyển dữ liệu
5.2. ĐỊNH DẠNG LƢU TRỮ TRONG SD CARD
FAT là bảng cấp phát tập tin, gồm nhiều phần tử. Chiều dài mỗi phần tử được tính bằng số bit, biểu thị số đếm của bảng FAT.
Nguyên lý của hệ thống FAT là dựa vào một bảng để duy trì và theo dõi các trạng thái các phân đoạn trên không gian địa chỉ khác nhau dùng để lưu trữ tập tin. Bảng này liệt kê tuần tự số thứ tự của các Cluster dành cho file nằm trên đĩa. Số lượng sector có trong một Cluster là do hệ điều hành áp đặt cho từng loại đĩa thích hợp. Khi FAT đã chỉ định Cluster nào dành cho file thì toàn bộ các sector trong Cluster đó bị file chiếm giữ.
Khi dung lượng đĩa cứng ngày càng tăng thì FAT bộc lộ nhiều hạn chế, do đó FAT càng ngày càng cải tiến cho ra nhiều phiên bản như FAT12, FAT16 và FAT32. Trong đề tài này, ta chỉ quan tâm đến FAT16 do dung lượng thẻ nhớ là 2GB.
Cấu trúc phân vùng:
FAT tổ chức thành 2 phân vùng: vùng hệ thống và vùng dữ liệu.
Hình 5.2-1: Loại phân vùng Lệnh Phản hồi Khối dữ liệu CRC Từ thẻ đến máy chủ Từ máy chủ đến thẻ Dữ liệu từ thẻ đến máy chủ CMD
DAT Khối dữ liệu CRC Khối dữ liệu CRC
Lệnh Phản hồi Dừng đọc
Hoạt động dừng dữ liệu Hoạt động đọc khối
Vùng hệ thống :
Boot sector : gồm một số sector đầu tiên của phân vùng. Sector đầu tiên chứa các thông số quan trọng của chương trình. Các sector còn lại nếu có chứa các thông tin hỗ trợ cho việc xác định tổng số cluster trống và tìm kiếm Cluster trống được hiệu quả.
Bảng FAT: Thường có 2 bảng FAT trong một phân vùng FAT. Bảng FAT đầu tiên nằm ở sau sector ưu tiên, bảng FAT thứ 2 nếu có (thường phục vụ cho việc backup) sẻ nằm kế tiếp sau bảng FAT 1. Kích thước mỗi phần tử là 16 bit (2 byte). Mỗi một Cluster được biễu diễn bằng một ô trong bảng FAT.
Thƣ mục gốc (Root Directory): Gồm 1 dãy các phần tử (gọi là entry), mỗi phần tử có kích thước 32 byte chứa các thông tin của một tập tin hoặc một thư mục. Thông tin của một tập tin hoặc một thư mục có thể chiếm một hay nhiều entry.
Vùng dữ liệu: Mỗi phần tử nằm trên vùng dữ liệu gọi là Cluster có kích thước 2n sector vùng này chịu trách nhiệm ghi nội dung của file hoặc thư mục. Đơn vị lưu trữ 4KB.
5.3 XÂY DỰNG SD CARD
Hình 5.3-1 biểu diễn sơ đồ khối của ứng dụng SD Card.
Trước tiên, vào phần mềm Quartus II tạo một project. Sau đó, chọn họ và thiết bị.
Hình 5.3-2: Chọn nơi lưu, đặt tên project và tên thư mục
Hình 5.3-3: Chọn họ và thiết bị
Trong project này, chúng ta sẽ thực hiện tạo một hệ thống SOPC bằng cách sử dụng SOPC Builder. Hệ thống này sẽ được tạo ra bằng file Verilog HDL, đặt tên cho hệ thống là DE3_SOPC.
Hình 5.3-4: Tạo hệ thống phần cứng
Ta tạo một hệ thống SOPC gồm: CPU, RAM, JTAG UART, System ID, Timer, pio_led, pio_button, pio_sd_clk, pio_sd_cmd, pio_sd_dat và pll:
Đầu tiên, ta chọn Processor/Nios II Processor: CPU là bộ xử lý trung tâm, điều khiển hoạt động của hệ thống.
Tiếp theo, ta chọn Memories and Memory Controllers/On-Chip/On-Chip Memory (RAM or ROM): RAM dung để lưu trữ dữ liệu và lệnh chương trình.
Sau khi tạo bộ nhớ RAM xong, quay trở lại CPU để gán RAM cho nó.
Hình 5.3-7: Gán bộ nhớ RAM cho CPU
Tiếp theo, chọn Interface Protocols/Serial/JTAG UART: JTAG UART có chức năng kết nối với máy chủ để nạp chương trình hệ thống xuống board DE3 thông qua cổng USB Blaster.
Hình 5.3-8: Cấu hình JTAG UART
Chọn Peripherals/Debug and Performance/System ID Perpheral: System ID là module cung cấp một số tác dụng nhận dạng hệ thống phần cứng trên board DE3.
Tùy thuộc vào thời gian delay cần thiết kế mà ta có thể thay đổi giá trị trong Period, đơn vị trong Units. Ta vào Peripherals/Microcontroller Peripherals/Interval Timer:
Hình 5.3-10: Cấu hình Timer
Giao thức PIO sẽ thiết kế 5 mạch kết nối gồm: 1 ngõ ra 24 bit (LED RGB), 1 ngõ vào (button), 1 ngõ ra (SD_CLK), 1 ngõ vào ra (SD_CMD) và 1 ngõ vào ra (SD_DAT).
Hình 5.3-11: Cấu hình PIO
Hình 5.3-13: Cấp xung clock ngõ ra 50Mhz
Để biên dịch hệ thống, ta cần gán địa chỉ nền cho các core đã thiết kế. Chọn System/Auto-Assign Base Addresses
Kết quả sau khi gán địa chỉ nền:
Hình 5.3-15: Tạo hệ thống thành công
Sau khi xây dựng hệ thống hoàn chỉnh, bắt đầu gán chân cho hệ thống và nạp xuống board. Quay lại phần mềm Quartus II vào File chọn Add/Remove Files in Project sẽ xuất hiện hộp thoại, chỉ đến file .v.
Hình 5.3-16: Thêm file .v
Để gán chân chân cho hệ thống, ta vào File/New chọn Block Diagram/ Schematic File. Vào Symbol Tool để lấy sơ đồ khối hệ thống (DE3_SOPC).
Sau đó, ta thực hiện gán chân cho hệ thống, vào Pin Tool để lấy ngõ vào, ngõ ra, ngõ vào ra. Vào Assignments/Import Assignments… dẫn tập tin DE3_SDCARD.qsf để xác định chân cụ thể. Lưu ý: gán chân chỗ ngõ vào/ra/hai chiều.
Hình 5.3-17: Gán chân cho hệ thống
Hình 5.3-18: Biên dịch thành công
Sau khi biên dịch xong, nhấp vào Programmer, chọn Start để nạp file DE3_SDCARD.sof xuống board DE3. Kết quả nạp xuống board thành công.
Hình 5.3-19: Nạp xuống board thành công
Khi nạp xuống board thành công, tiến hành viết chương trình ứng dụng cho hệ thống phần cứng đã được thiết kế bằng chương trình Nios II Software Build Tools for Eclipse.
Ta chọn đường dẫn nơi lưu trữ phần mềm ứng dụng:
Hình 5.3-21: Chọn nơi lưu trữ phần mềm
Sau khi đã chọn đường dẫn, cửa sổ soạn thảo chương trình ứng dụng được tạo ra. Vào File/New chọn Nios II Application and BSP from Template.
Hình 5.3-23: Tạo ứng dụng mới dựa trên code có sẵn
Chương trình ứng dụng sử dụng code mẫu có sẵn và đánh đoạn code thay thế code có sẵn theo ý muốn.
#include <stdio.h>
#include "terasic_lib\terasic_includes.h" #include "terasic_fat\FatFileSystem.h" #include "terasic_sdcard\SDCardDriver.h"
bool Fat_Test(FAT_HANDLE hFat, char *pDumpFile){ bool bSuccess;
int nCount = 0;
FAT_BROWSE_HANDLE hBrowse; FILE_CONTEXT FileContext;
bSuccess = Fat_FileBrowseBegin(hFat, &hBrowse); if (bSuccess){
while(Fat_FileBrowseNext(&hBrowse, &FileContext)){ if (FileContext.bLongFilename){
alt_u8 *pData8;
pData16 = (alt_u16 *)FileContext.szName; pData8 = FileContext.szName; printf("[%d]", nCount); while(*pData16){ if (*pData8) printf("%c", *pData8); pData8++; if (*pData8) printf("%c", *pData8); pData8++; // pData16++;} printf("\n"); }else{
printf("[%d]%s\n", nCount, FileContext.szName);} nCount++;}}
if (bSuccess && pDumpFile && strlen(pDumpFile)){ FAT_FILE_HANDLE hFile;
hFile = Fat_FileOpen(hFat, pDumpFile); if (hFile){
char szRead[256];
int nReadSize, nFileSize, nTotalReadSize=0; nFileSize = Fat_FileSize(hFile);
if (nReadSize > sizeof(szRead)) nReadSize = sizeof(szRead); printf("%s dump:\n", pDumpFile);
while(bSuccess && nTotalReadSize < nFileSize){ nReadSize = sizeof(szRead);
if (nReadSize > (nFileSize - nTotalReadSize)) nReadSize = (nFileSize - nTotalReadSize); if (Fat_FileRead(hFile, szRead, nReadSize)){ int i;
for(i=0;i<nReadSize;i++){ printf("%c", szRead[i]);} nTotalReadSize += nReadSize;}
else{ bSuccess = FALSE;
printf("\nFaied to read the file \"%s\"\n", pDumpFile);}} // while if (bSuccess) printf("\n");
Fat_FileClose(hFile);} else{ bSuccess = FALSE;
printf("Cannot find the file \"%s\"\n", pDumpFile); }} return bSuccess;}
int main()
const alt_u32 LED_GREEN_PATTERN = 0xFF00FF; const alt_u32 LED_RED_PATTERN = 0x00FFFF; FAT_HANDLE hFat;
printf("========== DE3 SDCARD Demo [13/04/2015]\n"); while(1){
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, LED_BLUE_PATTERN); hFat = Fat_Mount(FAT_SD_CARD, 0);
if (hFat){
printf("sdcard mount success!\n");
printf("Root Directory Item Count:%d\n", Fat_FileCount(hFat)); Fat_Test(hFat, "test.txt");
Fat_Unmount(hFat);
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, LED_GREEN_PATTERN); }else{
printf("Failed to mount the SDCARD!\nPlease insert the SDCARD into DE3 board and press BUTTON3.\n");
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, LED_RED_PATTERN); } // wait users to press BUTTON3
while ((IORD_ALTERA_AVALON_PIO_DATA(PIO_BUTTON_BASE) & 0x08) == 0x08); IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, LED_BLUE_PATTERN); usleep(400*1000); // debounce
} // while return 0;}
Sau đó, ta thực hiện biên dịch chương trình ứng dụng, nhấp chuột phải vào DE3_SDCARD chọn Build Project.
Hình 5.3-25: Biên dịch chương trình thành công
Để chạy chương trình ứng dụng, nhấp chuột phải lên DE3_SDCARD chọn Run As/Run Configuration để tạo New_configuration, sau đó Run để chạy chương trình xuống board.
Hình 5.3-26: Chạy chương trình ứng dụng
Kết quả khi chạy chương trình là “HAI QUYEN & HONG HANH [10/5/2015]”.
Hình 5.3-27: Kết quả chạy thành công
Khi chương trình thực thi, nó phát hiện thẻ SD được chèn vào. Nếu một thẻ SD được tìm thấy, nó sẽ kiểm tra thẻ SD có định dạng hệ thống tập tin FAT hay chưa. Nếu một
hệ thống tập tin FAT được tìm thấy, nó sẽ tìm kiếm tất cả các file trong thư mục gốc của hệ thống tập tin FAT và lúc này đèn xanh lá sẽ được sáng.
Hình 5.3-28: Phát hiện thẻ SD thành công
Mặt khác, LED màu đỏ sáng nếu chương trình không thành công phân tích các hệ thống tập tin FAT hoặc không có thẻ SD được tìm thấy trong các ổ cắm thẻ SD của Board DE3. Nếu người dùng nhấn button3 của Board DE3, chương trình sẽ thực hiện quá trình trên một lần nữa.
CHƢƠNG 6: KẾT LUẬN VÀ ĐỊNH HƢỚNG PHÁT TRIỂN ĐỀ TÀI 6.1 KẾT LUẬN
Trong thời gian 4 tháng tìm hiểu đề tài, nhóm đã hoàn thành việc nghiên cứu board DE3 và xây dựng ứng dụng đọc dữ liệu từ SD Card. Qua đề tài này, nhóm có thêm kiến thức về FPGA, Altera DE3, cách xây dựng hệ thống SOPC từ Quartus II và cách sử dụng Nios II để lập trình cho hệ thống phần cứng được thiết kế. Bên cạnh việc có thêm kiến thức mới, chúng tôi cũng học được cách làm việc nhóm hiệu quả. Tuy hoàn thành được việc đọc dữ liệu từ SD Card nhưng do thời gian hạn chế nên nhóm chưa thực được những ứng dụng khác trên Altera DE3 như: nhận dữ liệu qua cổng USB.
6.2 ĐỊNH HƢỚNG PHÁT TRIỂN ĐỀ TÀI
Nghiên cứu board DE3 và xây dựng ứng dụng mà nhóm thực hiện chỉ hoàn thành ở mức cơ bản đọc dữ liệu từ SD Card. Trong thời gian tới, ứng dụng cần được cải tiến và có nhiều tính năng hơn.
Định hướng phát triển cho đề tài:
Xây dựng thêm ứng dụng nhận dữ liệu qua cổng USB có trên board và kết nối được với các thiết bị như máy nghe nhạc, điện thoại... .
TÀI LIỆU THAM KHẢO
[1] DE3 User Manual.
URL: https://www.altera.com/support/training/university/de3.html
[2] Aseem Vasudev and Jayanti Addepalli. Interfacing SD Cards with Blackfin® Processors. 2010.
[3] Getting Started with the Graphical User Interface.
URL:https://www.altera.com/en_US/pdfs/literature/hb/nios2/n2sw_nii52017.pdf
PHỤ LỤC A
SỰ GIAO TIẾP GIỮA BOARD VÀ THÀNH PHẦN TRÊN BOARD
Button và LED đơn:
http://www.mediafire.com/watch/txd4h7er4gtfdyj/WP_20150510_172(1).mp4
Button và LED 7 đoạn:
PHỤ LỤC B
HƢỚNG DẪN XÂY DỰNG SD CARD
Khi tạo xong project ứng dụng, ta nhấp chuột phải vào DE3_SDCARD chọn New/Source Folder để tạo thư mục chứa các thư viện xây dựng thẻ SD.
Hình B.1: Tạo project ứng dụng
Chúng ta sẽ tạo 3 thư mục đó là terasic_fat, terasic_lib và terasic_sdcard. Ta nhấp chuột phải vào DE3_SDCARD chọn New/Source Folder để tạo một thư mục.
Hình B.2: Tạo thư mục chứa các thư viện
Khi thư mục terasic_fat được tạo ra, ta nhấp chuột phải vào nó và chọn New, sau đó chọn Source File và Header File để tạo thư viện .c và .h, ta đặt tên là
Hình B.3: Tạo thư viện .c
Hình B.4: Tạo thư viện .h Thư viện FatFileSystem.c:
#include <string.h> // memcpy
#include "..\terasic_lib\terasic_includes.h" #include "FatFileSystem.h"
#include "FatInternal.h" #ifdef DEBUG_FAT
#define FAT_DEBUG(x) DEBUG(x) #else
#define FAT_DEBUG(x) #endif
void fatComposeShortFilename(FAT_DIRECTORY *pDir, char *szFilename); bool fatSameLongFilename(alt_u16 *p1, alt_u16 *p2);
FAT_HANDLE Fat_Mount(FAT_DEVICE FatDevice, DEVICE_HANDLE hDevice){ //Fat_Unmount(); FAT_HANDLE hFat = 0; if (FatDevice == FAT_SD_CARD){ #ifdef SUPPORT_SD_CARD hFat = fatMountSdcard(); #endif //SUPPORT_SD_CARD
}else if (FatDevice == FAT_USB_DISK){ #ifdef SUPPORT_USB_DISK
hFat = fatMountUsbDisk(hDevice); #endif }
return hFat; }
void Fat_Unmount(FAT_HANDLE Fat){
VOLUME_INFO *pVol = (VOLUME_INFO *)Fat; if (!pVol) return;
#ifdef FAT_READONLY if (pVol->szFatTable){ free(pVol->szFatTable);
pVol->szFatTable = 0; } #endif //#ifdef FAT_READONLY
pVol->bMount = FALSE; free(pVol); }
bool Fat_FileBrowseBegin(FAT_HANDLE hFat, FAT_BROWSE_HANDLE
*pFatBrowseHandle){
VOLUME_INFO *pVol = (VOLUME_INFO *)hFat; if (!pVol) return FALSE;
if (!pVol->bMount) return FALSE; pFatBrowseHandle->DirectoryIndex = 0; pFatBrowseHandle->hFat = hFat;
return TRUE;}
bool Fat_FileBrowseNext(FAT_BROWSE_HANDLE *pFatBrowseHandle, FILE_CONTEXT *pFileContext){
bool bFind = FALSE, bVlaid, bError=FALSE, bLongFilename = FALSE; int OrderValue = 0;
FAT_DIRECTORY *pDir;
unsigned int nSecter, nOffset; char szBlock[512];
VOLUME_INFO *pVol = (VOLUME_INFO *)pFatBrowseHandle->hFat; if (!pVol) return FALSE;
if (!pVol->bMount) return FALSE;
do{nOffset=(sizeof(FAT_DIRECTORY)*pFatBrowseHandle->DirectoryIndex)/pVol- > BPB_BytsPerSec;
nSecter = pVol->RootDirectoryEntrySecter + nOffset; if (!pVol->ReadBlock512(pVol->DiskHandle, nSecter, szBlock)){ bError = TRUE;}
else{
nOffset=(sizeof(FAT_DIRECTORY)*pFatBrowseHandle>DirectoryIndex)%pVol- >BPB_BytsPerSec;
pDir = (FAT_DIRECTORY *)(szBlock + nOffset); pFatBrowseHandle->DirectoryIndex++;
bVlaid = fatIsValid(pDir);
if (bVlaid){ if ((pDir->Attribute & ATTR_LONG_NAME) == ATTR_LONG_NAME) { FAT_LONG_DIRECTORY *pLDIR = (FAT_LONG_DIRECTORY *)pDir;
// check attribute
if ((pLDIR->LDIR_Attr & ATTR_LONG_NAME) != ATTR_LONG_NAME){ bError = TRUE; }else{ // check order if (OrderValue == 0){ if (bLongFilename) bError = TRUE; else
OrderValue = pLDIR->LDIR_Ord & 0x3F;
memset(pFileContext->szName, 0, sizeof(pFileContext->szName)); }else{
if ((pLDIR->LDIR_Ord & 0x3F) != OrderValue) bError = TRUE;}} // if (!bError){ int BaseOffset; bLongFilename = TRUE; OrderValue--; BaseOffset = OrderValue * 26; // cast filename memcpy(pFileContext->szName+BaseOffset, pLDIR->LDIR_Name1, 10); memcpy(pFileContext->szName+BaseOffset+10, pLDIR->LDIR_Name2, 12); memcpy(pFileContext->szName+BaseOffset+22, pLDIR->LDIR_Name3, 4);}
}else{
if (bLongFilename){ pFileContext->Attribute = ATTR_LONG_NAME; if ((pDir->Attribute & (ATTR_ARCHIVE | ATTR_DIRECTORY)) == 0) bError = TRUE;
else
bFind = TRUE;}
else{ fatComposeShortFilename(pDir, pFileContext->szName); bFind = TRUE;}
if (bFind){ // my ext
pFileContext->bLongFilename = bLongFilename;
pFileContext->bFile = (pDir->Attribute & ATTR_ARCHIVE)?TRUE:FALSE; pFileContext->bDirectory = (pDir->Attribute & ATTR_DIRECTORY)?TRUE:FALSE; pFileContext->bVolume = (pDir->Attribute & ATTR_VOLUME_ID)?TRUE:FALSE; // pFileContext->Attribute = pDir->Attribute; pFileContext->CreateTime = pDir->CreateTime; pFileContext->LastAccessDate = pDir->LastAccessDate; pFileContext->FirstLogicalClusterHi = pDir->FirstLogicalClusterHi; pFileContext->LastWriteTime = pDir->LastWriteTime; pFileContext->LastWriteDate = pDir->LastWriteDate; pFileContext->FirstLogicalCluster = pDir->FirstLogicalCluster; pFileContext->FileSize = pDir->FileSize;}}}} }while (!bFind && !fatIsLast(pDir) && !bError);
return bFind;} /*
bool Fat_FileBrowseNext(FAT_BROWSE_HANDLE *pFatBrowseHandle, FAT_DIRECTORY *pDirectory){
bool bFind = FALSE, bError=FALSE; FAT_DIRECTORY *pDir;
unsigned int nSecter, nOffset; char szBlock[512];
VOLUME_INFO *pVol = (VOLUME_INFO *)pFatBrowseHandle->hFat; if (!pVol) return FALSE;
if (!pVol->bMount) return FALSE; do{
nOffset = (sizeof(FAT_DIRECTORY)*pFatBrowseHandle->DirectoryIndex)/pVol- >BPB_BytsPerSec;
// if (!SD_read_block(nSecter, szBlock)){
if (!pVol->ReadBlock512(pVol->DiskHandle, nSecter, szBlock)){ bError = TRUE;
}else{
nOffset = (sizeof(FAT_DIRECTORY)*pFatBrowseHandle->DirectoryIndex)%pVol- >BPB_BytsPerSec;
pDir = (FAT_DIRECTORY *)(szBlock + nOffset);
printf("[%d]=%02Xh\n", pFatBrowseHandle->DirectoryIndex, pDir->Name[0]); pFatBrowseHandle->DirectoryIndex++;
bFind = fatIsValid(pDir); if (bFind){
*pDirectory = *pDir;
printf("find....\n");}} }while (!bFind && !fatIsLast(pDir) && !bError); return bFind;}
*/
unsigned int Fat_FileCount(FAT_HANDLE Fat){ unsigned int nCount = 0;
FAT_BROWSE_HANDLE hBrowse; FILE_CONTEXT FileContext; if (Fat_FileBrowseBegin(Fat, &hBrowse)){ while(Fat_FileBrowseNext(&hBrowse, &FileContext)) nCount++;} return nCount;}
bool fatSameLongFilename(alt_u16 *p1, alt_u16 *p2){ bool bSame = TRUE;
while(bSame && ((*p1 != 0) || (*p2 != 0))){ if (*p1 != *p2){ bSame = FALSE;} p1++; p2++;} return bSame;}
void fatComposeShortFilename(FAT_DIRECTORY *pDir, char *szFilename){ int i,nPos=0;
i=0;
while(i < 8 && pDir->Name[i] != 0 && pDir->Name[i] != ' ') szFilename[nPos++] = pDir->Name[i++];
if (pDir->Attribute & (ATTR_ARCHIVE | ATTR_DIRECTORY)){
szFilename[nPos++] = '.'; i=0;
while(i < 3 && pDir->Extension[i] != 0 && pDir->Extension[i] != ' ') szFilename[nPos++] = pDir->Extension[i++];}
szFilename[nPos++] = 0;} // File Access
FAT_FILE_HANDLE Fat_FileOpen(FAT_HANDLE Fat, const char *pFilename){ bool bFind = FALSE;
FAT_BROWSE_HANDLE hBrowse; FILE_CONTEXT FileContext;
FAT_FILE_INFO *pFile = 0;
if (Fat_FileBrowseBegin(Fat, &hBrowse)){
while (!bFind && Fat_FileBrowseNext(&hBrowse, &FileContext)){