Accessing a Compact Flash Card from BASCOM
This application note is written by Josef Franz Vögel.
The software described in the Application Note was developed some time ago. In the past years, Josef has created a real FAT16 and FAT32 file system out of it, which is now fully integrated in BASCOM-AVR. You can find more information in the Help-File and the web-site of the author at http://members.aon.at/voegel Notice that this new Filesystem supports not only CF, but also harddisk, virtual disk(memory) and MMC to mention a few.
Josef is well know from his FP trig library and this application note will be
used in the future to create a real file system for BASCOM.
The text below is part of the AN and also written by Josef.
After the development of my glass house
(Wintergarten) controlling system, I wanted collect the climatic data, such as
outside and interior temperature, sunshine intensity and rain in order to be
able to evaluate it later, building some statistisc, diagrams and so on.
First I send the data online to a terminal
program on a PC and stored it there in a text-file. But this solution have the
disadvantage, that I need always a PC (or Laptop) on the embedded system. Next I
thougth about to store the data in a comprimized form in the EEPROM on the
ATMega103, but even the 4 kByte EEPROM can hold only the data of few days.
So I searched the Internet for other
solution for long time logging on an embedded system.
I found a very interesting article for
embedded systems on
http://www.circuitcellar.com/echips-pdfs/0201/c0201mspdf.pdf
about to store data in a compact flash card.
With a CompactFlash Card you have a huge
amount of memory to a low price.
The Compactflash Memory Card can be used in
three mode:
· Memory Mode
· I/O Mode
· IDE Mode
I decided to use it in Memory Mode to keep things simple and use lowest count of pins of
the controller to attach the flashcard.
The 17 pins are 8 for data, 3 for register
addressing and 6 for controlling.
You can see in the schematic, that the connection is very
simple, only one pullup resistor is needed.
I used a ATMEGA103 Test-Board from RIBU
Electronic Austria. But it should be no problem to use any other developing
system. This boards provides VCC and Gnd on every port, but extra lines for VCC
and Gnd will do it as well.
I transfered the PIC-Routines from the
above mentioned article to AVR and build it modular, so they can be used in a
easy way from BASCOM.
The routines are:
· ReadSector:
Read one or more Sectors (512 Bytes) from the CF-Card to SRAM
· WriteSector:
Write one or more Sectors (512 Bytes) from SRAM to the CF-Card
· GetDriveIdentity:
Read CF-Card Identity Information to SRAM
· DriveInit:
Set Input and Out-Ports in Controller and resets the CF-Card
· DriveReset:
Resets the CF-Card
· DriveCheck:
Checks, if CF-Card is plugged in
I wrote the routines in ASM to save
code-space and execution time.
This functions are located in
FlashCardDrive.Bas. There are the ASM-routines and the BASCOM-Interface
routines, which allows to call the ASM-routine from BASCOM as normal Sub of
Function.
Now the Usage of the Functions/Subs:
Sub
ReadSector ( SRAMPointer,
SectorNumber, SectorCount)
SRAMPointer
(Type Word): Pointer to memorylocation to which the transfer from the CF-Card is
written
SectorNumber
(Type Long): Sectornumber on the CF-Card
SectorCount
(Type Byte): Count of sectors (each 512 bytes) to read from the CF-Card
(hightest value is 127, which can be handled by the routine)
Reads
1 to 127 Sectors from the CF-Card and stores it in the SRAM starting at a
desired address.
Example:
$Include "FlashCardDrive.bas"
Dim TransferBuffer(512) as Byte ' Hold Sector to and from CF-Card
Dim wSRAMPointer as Word ' Address-Pointer for read and write
Dim lSectorNumber as Long ' Sector Number
DriveInit ' Set pins to CF-Card and reset card, only needed at start
' give Address of first Byte of the 512 Byte Buffer to
Word-Variable
wSRAMPointer = VarPtr(TransferBuffer(1))
' Set Sectornumber, sector 32 normally holds the Boot
record sector of first
' partition
lSectorNumber = 32
' Now read in sector 32 (1 Sector) from CF-Card
ReadSector wSRAMPointer , lSectorNumber , 1
' Now Sector number 32 is in Byte-Array TransferBuffer
Sub
WriteSector ( SRAMPointer,
SectorNumber, SectorCount)
SRAMPointer
(Type Word): Pointer to memorylocation from which the transfer to the CF-Card is
written
SectorNumber
(Type Long): Sectornumber on the CF-Card
SectorCount
(Type Byte): Count of sectors (at 512 bytes) to read from the CF-Card (Hightest
value is 127, which can be handled by the routine)
Writes
1 to 127 Sectors to the CF-Card from the SRAM starting at a desired address.
Example:
$Include "FlashCardDrive.bas"
Dim TransferBuffer(512) as Byte ' Hold Sector to and from CF-Card
Dim wSRAMPointer as Word ' Address-Pointer for read and write
Dim lSectorNumber as Long ' Sector Number
DriveInit ' Set pins to CF-Card and reset card, only neede ar start
' give Address of first Byte of the 512 Byte Buffer to
Word-Variable
wSRAMPointer = VarPtr(TransferBuffer(1))
' Set Sectornumber to 2
lSectorNumber = 2
' Now write Content of Byte-Array TransferBuffer to
CF-Card at Sector 2
ReadSector wSRAMPointer , lSectorNumber , 1
Sub
GetDriveIdentity (SRAMPointer)
SRAMPointer
(Type Word): Pointer to memorylocation to which the transfer from the CF-Card is
written
Store
the special Card Information (512 Bytes) into SRAM starting at a desired
address. Check Compact-FlashCard Specification for meaning of this information.
Example:
$Include "FlashCardDrive.bas"
Dim TransferBuffer(512) as Byte ' Hold Sector to and from CF-Card
Dim wSRAMPointer as Word ' Address-Pointer for read and write
Dim lSectorNumber as Long ' Sector Number
DriveInit ' Set pins to CF-Card and reset card, only needed at start
' give Address of first Byte of the 512 Byte Buffer to
Word-Variable
wSRAMPointer = VarPtr(TransferBuffer(1))
' Now read in Card Identity Information
GetCardIdentity wSRAMPointer
' Now 512 Byte of Card Identity Inforation is in
Byte-Array TransferBuffer
Inits
the Input and Output – Ports of the Controller and resets the CF-Card
Resets
the CF-Card (Hardware-Reset)
Function
DriveCheck() as Byte
Checks
whether the CF-Card is plugged in (Pin CD1 is Low). It return 1, it CD1 is Low,
otherwise it return 0
$Include "FlashCardDrive.bas"
if DriveCheck() = 1 then
DriveInit
else
print "Card not inserted, check
Card!"
end if
A compact flash provide a huge array of
512-Byte Sectors. With the above mentioned routines reading and writing of every
sectors is possible. A small card with 16 MB have for example approxemitely
31.250 Sectors.
I you want to use the previous described
functions in a application, you have to $Include "FlashCardDrive.bas"
Testing
enviroment
To test the Sub/Functions and get first experiences with the
Compact-Flash Card i wrote an additional tiny interpreter, so the user can read
and write sectors of the Card with short comands in a terminal program on a PC
connected to the controller via a RS232. Preparing a test-sector in SRAM is also
possible.
The Commands are:
CFI
[Compact
Flash Identity]: Reads the Card Identity Information and dumps it
to the terminal. It shows also the available Number of Sectors on the Card and
the Memory in Bytes
CFR
[Compact
Flash Reset]: Resets the Compactflash-Card
MBR
[Master
Boot Record]: Reads the first sector (sector 0) of the Card
(Master Boot Record) and dumps it to the terminal. It also reads the partition
table located in this sector and shows installed partitions with first sector,
last sector and number of sectors in a partition and the code for the installed
file system.
SD <SectorNumber>
[Sector
Dump]: Read
<Sectornumber> from Compactflash Card and dumps it to Terminal
SD
<SectorNumberStart> <SectorNumberEnd>
[Sector
Dump]: Dumps Sectors from
<SectornumberStart> to <SectorNumbersEnd> to Terminal
MD
[<SRAMStart>] [<SRAMEnd>]
[Memory
Dump]: Dumps the SRAM Buffer
to the Terminal. In the first 512 Bytes of the defined SRAM buffer(with 1024
Bytes to work with 2 sectos too) for the interpreter all readings from the CF
are stored. With parameter <SRAMStart> every desired SRAM area can be
dumped. With <SRAMEnd> it dumps to this address, otherwise it dumps 512
Bytes (1 Sector). The address shown at the beginning of the line is always
relatively to the starting address.
SW
<SectorNumberStart> <SectorCount> [<SRAMPointer>]
[Sector
Write]:Write
<SectorCount> Sectors from SRAM to the Compactflash Card starting at
<SectorNumberStart>. Without parameter <SRAMPointer> the defined
SRAM-TransferBuffer is used, with the parameter <SRAMPointer> you can
write from any SRAM memory-location.
MB
<Byte1> [<Byte2>] [<Byte2>] ...... [<Byte8>]
[Memory
Byte]: Write single Bytes to
the Transfer Buffer. For <Byte> the ASCII – Code must be typed. For
exampe 65 or $41 for Letter ‚A‘. Writing to Transfer Buffer starts at
address of MemroyPointer. Up to 8 Bytes are possible with one MB command.
MF
<Byte> [<BufferStart>] [<BufferEnd>]
[Memory
Byte]: Fill the Transfer
Buffer with <Byte> from <BufferStart> to <BufferEnd>. For
<Byte> the ASCII – Code must be typed. For exampe 65 or $41 for Letter
‚A‘. Without <BufferStart> and <BufferEnd> the buffer from the
MemoryPointer in the Transfer Buffer to End of the Buffer is filled. You can
start also filling at <BufferStart> and end at <BufferEnd>.
MT
<Text>
[Memory
Text]: Fill the SRAM-Transfer
Buffer with <Text> starting at the position of the memorypointer.
MP
<MemoryPointer>
[Memory
Pointer]: Adjust the
SRAM-Transfer Buffer Pointer for next writing with MB, MT or MF
The
actual Memory-Pointer is shown with the Prompt.
All values can written in decimal or hex.
If hex is used the value must be preceeded by a $-sign like $3B.
With the commands MF, MB and MT you can
prepare a test sector with desired content to write it to Compactflashcard and
read it back.
A short example with some comands with a
flash Cards which is 'Formatted' as a Harddisk.
User-input is bold, added comments are in green.
0000>cfi ' Get Card Identity Information
Read Card Info
0000 8A 84 D4 03 00 00 08 00 00 00 40 02 20 00 03 00 Š„Ô.......@. ...
0010 00 D4 00 00 20 20 20 20 30 30 32 33 39 30 31 47 .Ô.. 0023901G
0020 30 32 4F 32 38 34 39 33 02 00 02 00 04 00 64 56 02O28493......dV
0030 20 67 2E 38 34 31 61 53 44 6E 73 69 20 6B 44 53 g.841aSDnsi kDS
0040 46 43 2D 42 32 31 20 38 20 20 20 20 20 20 20 20 FC-B21 8
0050 20 20 20 20 20 20 20 20 20 20 20 20 20 20 01 00 ..
0060 00 00 00 02 00 00 00 01 00 00 01 00 D4 03 08 00 ............Ô...
0070 20 00 00 D4 03 00 00 01 00 D4 03 00 00 00 00 00 ..Ô.....Ô......
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 20 ..............
0110 20 20 20 20 20 20 30 30 32 33 39 30 31 47 30 32 0023901G02
0120 4F 32 38 34 39 33 00 00 00 00 00 00 00 00 00 00 O28493..........
0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
250880 Sectors
= 128450560 Bytes
CF-Buffersize
= 2 Sectors = 1024 Bytes
0000>mbr ' Get Master Boot Record (Sector 0)
Read Master
Boot Record ... done
0000 FA 33 C0 8E D0 BC 00 7C 8B F4 50 07 50 1F FB FC ú3ŔŽĐĽ.|‹ôP.P.űü
0010 BF 00 06 B9 00 01 F2 A5 EA 1D 06 00 00 BE BE 07 ż..ą..ňĄę....ľľ.
0020 B3 04 80 3C 80 74 0E 80 3C 00 75 1C 83 C6 10 FE ł.€<€t.€<.u.�Ć.ţ
0030 CB 75 EF CD 18 8B 14 8B 4C 02 8B EE 83 C6 10 FE ËuďÍ.‹.‹L.‹î�Ć.ţ
0040 CB 74 1A 80 3C 00 74 F4 BE 8B 06 AC 3C 00 74 0B Ët.€<.tôľ‹.¬<.t.
0050 56 BB 07 00 B4 0E CD 10 5E EB F0 EB FE BF 05 00 V»..´.Í.^ëđëţż..
0060 BB 00 7C B8 01 02 57 CD 13 5F 73 0C 33 C0 CD 13 ».|¸..WÍ._s.3ŔÍ.
0070 4F 75 ED BE A3 06 EB D3 BE C2 06 BF FE 7D 81 3D OuíľŁ.ëÓľÂ.żţ}�=
0080 55 AA 75 C7 8B F5 EA 00 7C 00 00 49 6E 76 61 6C UŞuÇ‹őę.|..Inval
0090 69 64 20 70 61 72 74 69 74 69 6F 6E 20 74 61 62 id partition tab
00A0 6C 65 00 45 72 72 6F 72 20 6C 6F 61 64 69 6E 67 le.Error loading
00B0 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 65 operating syste
00C0 6D 00 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 74 m.Missing operat
00D0 69 6E 67 20 73 79 73 74 65 6D 00 00 00 00 00 00 ing system......
00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01 ..............€.
01C0 01 00 06 07 E0 D2 20 00 00 00 E0 D2 03 00 00 00 ....ŕŇ ...ŕŇ....
01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............UŞ
Partition-Table
Partition 1
Sector: 32 to 250624 = 250592 Sectors; File-System Type: 06
0000>mp
$100 ' Place Memory Write pointer to HEX 100
0100>mt
Hello World '
Write Text to adjusted Memory Pointer
010B>mb
32 33 34 $41 $42 $43 '
Store some bytes
0111>mf
$55 $118 $12F '
fill Hex 118 to 12F with Hex 55 (='U')
0130>sw
3 1 ' Write Transfer Buffer to Sector 3
Write 1
Sector(s) to 3 at CF-Card from Transfer-Buffer ... done
0130>sd
3 ' Show sector 3
Read Sector: 3
... done
0000 FA 33 C0 8E D0 BC 00 7C 8B F4 50 07 50 1F FB FC ú3ŔŽĐĽ.|‹ôP.P.űü
0010 BF 00 06 B9 00 01 F2 A5 EA 1D 06 00 00 BE BE 07 ż..ą..ňĄę....ľľ.
0020 B3 04 80 3C 80 74 0E 80 3C 00 75 1C 83 C6 10 FE ł.€<€t.€<.u.�Ć.ţ
0030 CB 75 EF CD 18 8B 14 8B 4C 02 8B EE 83 C6 10 FE ËuďÍ.‹.‹L.‹î�Ć.ţ
0040 CB 74 1A 80 3C 00 74 F4 BE 8B 06 AC 3C 00 74 0B Ët.€<.tôľ‹.¬<.t.
0050 56 BB 07 00 B4 0E CD 10 5E EB F0 EB FE BF 05 00 V»..´.Í.^ëđëţż..
0060 BB 00 7C B8 01 02 57 CD 13 5F 73 0C 33 C0 CD 13 ».|¸..WÍ._s.3ŔÍ.
0070 4F 75 ED BE A3 06 EB D3 BE C2 06 BF FE 7D 81 3D OuíľŁ.ëÓľÂ.żţ}�=
0080 55 AA 75 C7 8B F5 EA 00 7C 00 00 49 6E 76 61 6C UŞuÇ‹őę.|..Inval
0090 69 64 20 70 61 72 74 69 74 69 6F 6E 20 74 61 62 id partition tab
00A0 6C 65 00 45 72 72 6F 72 20 6C 6F 61 64 69 6E 67 le.Error loading
00B0 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 65 operating syste
00C0 6D 00 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 74 m.Missing operat
00D0 69 6E 67 20 73 79 73 74 65 6D 00 00 00 00 00 00 ing system......
00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0100 48 65 6C 6C 6F 20 57 6F 72 6C 64 20 21 22 41 42 Hello World !"AB
0110 43 00 00 00 00 00 00 00 55 55 55 55 55 55 55 55 C.......UUUUUUUU
0120 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01 ..............€.
01C0 01 00 06 07 E0 D2 20 00 00 00 E0 D2 03 00 00 00 ....ŕŇ ...ŕŇ....
01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............UŞ
' The previous manipulated range is yellow
marked
0000>sw
4 8 0 ' Write all ATMEGA103 SRAM (from Address 0
' with 8
sectors (=4096 Bytes) to Card
'
starting at sector 4
Write 8
Sector(s) to 4 at CF-Card from SRAM Address 0000 ... done
0000>
How to start:
· Load FlashDisk.bas, FlashCardDrive.bas and
Interpreter.bas in same directory.
· If not using Hardware-UART 0, 9600 Baud, 4 MHz
Cristall, ATMEGA103 adjust them in FlashCard.bas.
· IF not using same schematic between AVR (Port A
for Data, Port B for Controlling and Port C for register-addressing) and
FlashCard as shown in this application note, adjust hardware-settings in
FlashCardDrive.bas.
· Compile FlashCard.bas
· Program AVR
· Connect AVR to PC via a RS232
· Start a terminal program
· (Re-)Start AVR
· Inside Terminal program you can make tests with
the Card as shown above.
I made tests with 15 MB Card (Canon
FC-15M), and a 128 MB Card (SanDisk). Both have a buffersize of 2 Sector (=1024
Bytes). I made the experience, that if I write on the 15MB Card only one sector
(=512 Bytes) at once a second sector (normally the sector after the written one)
lost the data. Writing 2 Sectors (=1024 Bytes) at once will work right. On the
128 MB Card I don't have detected such behaviour. I would be glad to hear some
experiences from other user of Cards with a buffersize of 2 sectors.
Comments and experiences are welcomed to josef.voegel@aon.at
Download file for this note
To get more information I suppose following
Links:
http://www.circuitcellar.com/echips-pdfs/0201/c0201mspdf.pdf
http://www.sandisk.com/download/Product%20Manuals/cf_r7.pdf |