Yeah, that works. Also use the "partitionError" command to get the error number - which are enumed in the constant section. If no error occured partition error returns zero.
@william chan, this is a copy of kyedos, which shows one way to start the driver and mount it. The RTC has been disabled.
{{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SD3.01 FATEngine Demo
//
// Author: Kwabena W. Agyeman
// Updated: 1/2/2011
// Designed For: P8X32A
// Version: 1.0
//
// Copyright (c) 2011 Kwabena W. Agyeman
// See end of file for terms of use.
//
// Update History:
//
// v1.0 - Original release - 7/27/2010.
// v1.1 - Updated code for new file system driver - 1/2/2011.
// Nyamekye
modifications by J. Moxham Dr_Acula to create KyeDOS v3. Pins setup for the Dracblade (similar to the Propeller Demo Board)
- name this file KyeDOS3
- changed sd pins to 12,13,14,15. WP and CD = -1
- RTC DAT and CLK -1
- Audio and Microphone pins all set to -1
comment out 'adc: "PCM2.1_ADCEngine.spin" and compile to find all PUBs referenced by this
comment out adcengine start and PRI programTapeWavFile and dac: "PCM2.1_DACEngine.spin" and PRI programPlayWavFile
comment out programPlayWavFile(stringPointer) and programTapeWavFile(stringPointer) and PRI scope
comment out if(_VGA_Enabled) group
startup is ifnot( fat.FATEngineStart(_SD_DO, _SD_CLK, _SD_DI, _SD_CS, _SD_WP, _SD_CD, _RTC_DAT, _RTC_CLK, -1) and {
} com.COMEngineStart(_receiverPin, _transmitterPin, _baudRateSpeed))
comment out 'bmp: "VGA64_BMPEngine.spin" _VGA_BG_Color = bmp#black _VGA_FG_Color = bmp#green
add OBJ VT100: "VGA_1024_VT100" ' VGA VT100 Terminal Driver
copied VGA_1024_VT100.spin and VGA_80x40.spin to the working folder
added VT100 startup code - now have a blinking white cursor on a blue screen. 80x40 text.
commented out ' long scopeSwtich, scopeStack[17], scopeHeap[((_VGA_H_Res * _VGA_V_Res) * 2) / 32]
(need to watch memory F8 here while adding more objects to the OBJ section)
added key : "Pocketerm_Keyboard" ' pocketerm keyboard
added lcd : "DracLCD" ' 20x4 LCD driver for dracblade
added delay: "Timing" ' for millisecond delays
added the keyboard startup key.startx(26, 27, %100, 40) 'Start Keyboard Driver pin,pin,num,repeatrate
added lcd.start - this is dracblade specific with a 20x4 local keyboard. You can leave this out if not used
commented out the existing .com driver. There is a bug with xmodem with corrupted bytes above 100 in the buffer, this does not show up with typing as the buffer never gets this full
added 2 port serial driver (variation on Tim Moore's code). Copied object to current directory sio : "pcFullDuplexSerial2FC"
F8 now fails with all instances of .com
Added some printstring routines that send data to VGA and to the serial port and the LCD display and do CRLF properly
added sio.addport. removed startup for the .com
global search and replace "com.transmitstring" to "printstring"
global search and replace "com.transmitbyte" to "printchar"
edited a line with #comquotation marks. Keep doing F8 to find errors
edited PRI shellline so it can accept Backspace and can read from keyboard and serial port
found that the string engine syntax has changed. putcharacter is now buildstring
found that the string engine syntax has chnaged. getcharacters is now builtstring
rewrote PRI shelldecision
replaced instances of quotationmarks from the serial driver to a local variable quote (ascii 34)
added local contstants Horizontal_tab, Linefeed, CarriageReturn. Did global find/replace
F8 finally compiles with no errors!
added sio.start, print signon message
added PRI DisplayBinaryFiles. Changed to the new syntax for reading entries
** edited the string engine - added PUB endsWithString(stringToSearch, stringToFind) '' 12 Stack Longs
baud rate 38400 for testing
comment out ' _newLineCharacter = 13 , replace with crlf
go through the DAT shellProgramHelpStrings and replace _newlinecharacter with byte 13 and byte 10
commented out the wav file commands in the help section (can always uncomment them later) amd the PRI
replace instances of PrintChar(_newLineCharacter) with crlf or with printstringcr. Multiple instances
removed "are you sure" from the boot command
edited the 'help' commands so they each fit on one line
moved the check for mounted card after every command to above the loop so only checks once.
working on a very strange bug in programDIR - if send more than a certain number of tabs to the VT100 the whole spin program shuts down. Possibly overrunning a buffer and overwriting code. Need a better solution to line up files in columns
also shows up with the LS command.
added a constant _LCD_Enabled so can easily turn this off for boards that do not have it
added a constant for VGA_enabled and also Serial_Enabled - can turn each of these on or off
added a printdecimal for debugging
added running .exe files, eg to run MOVIE.EXE type movie see programCommand
added simple wildcards to the "DIR" command, so can type dir *.exe and see just these files
changed the command line (.exe files) so it stores the command line in a text file COMMAND.TXT ready for other programs to read.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
_leftChannelVolume = 32
_rightChannelVolume = 32
_baudRateSpeed = 115200 ' Teraterm does not work at this speed. Use hyperterminal or other programs
' _newLineCharacter = 13
_clearScreenCharacter = 16
_homeCursorCharacter = 1
_receiverPin = 31
_transmitterPin = 30
_RTC_DAT = -1 ' -1 ifnot installed.
_RTC_CLK = -1 ' -1 ifnot installed.
_VGA_Enabled = true ' VGA display on
_VGA_PinGroup = 2
_LCD_Enabled = true ' false or true for 20x4 LCD display
_Serial_Enabled = true ' send output to serial port
_leftChannelAudioPin = -1 ' -1 ifnot installed.
_rightChannelAudioPin = -1 ' -1 ifnot installed.
_leftMicFeedBackPin = -1 ' -1 ifnot installed.
_leftMicInputPin = -1 ' -1 ifnot installed.
_rightMicFeedBackPin = -1 ' -1 ifnot installed.
_rightMicInputPin = -1 ' -1 ifnot installed.
_SD_DO = 12
_SD_CLK = 13
_SD_DI = 14
_SD_CS = 15
_SD_WP = -1 ' -1 ifnot installed.
_SD_CD = -1 ' -1 ifnot installed.
Quote = 34
Horizontal_Tab = 9
Line_Feed = 10
Carriage_Return =13
OBJ
fat: "SD3.01_FATEngine.spin"
taf: "SD3.01_FATEngine.spin"
rtc: "DS1307_RTCEngine.spin"
'com: "RS232_COMEngine.spin"
str: "ASCII0_STREngine.spin"
'adc: "PCM2.1_ADCEngine.spin"
'dac: "PCM2.1_DACEngine.spin"
'bmp: "VGA64_BMPEngine.spin"
VT100: "VGA_1024_VT100" ' VGA VT100 Terminal Driver
key : "Pocketerm_Keyboard" ' pocketerm keyboard
lcd : "DracLCD" ' 20x4 LCD driver for dracblade
delay: "Timing" ' for millisecond delays
sio : "pcFullDuplexSerial2FC"
VAR
'
' long scopeSwtich, scopeStack[17], scopeHeap[((_VGA_H_Res * _VGA_V_Res) * 2) / 32]
byte CommandLine[80] ' complete command line as typed in
byte LineOfText1[80] ' general purpose string buffer
byte LineOfText2[80] ' general purpose string buffer
byte LineOfText3[80] ' general purpose string buffer
PUB shell
VT100.start(16) ' start the vga driver VGA starts on pin 16
VT100.startcursor ' start the cursor
VT100.color(%00001000_11111100) ' Blue_White blue =3/4 power 10, white =full
VT100.cursorset(5) ' cursor type 5
VT100.clearscreen ' clear the screen
'vt100.str(string("Testing for SD card",13,10)) ' helpful message if card is out, better than just a blank screen
key.startx(26, 27, %100, 40) 'Start Keyboard Driver pin,pin,num,repeatrate
sio.AddPort(0, _receiverPin, _transmitterPin, -1, -1, 0, 0, _baudRateSpeed)
'sio.AddPort(1, _port2receiverPin, _port2transmitterPin, -1, -1, 0, 0, 120000) ' shamcom works 108000 to 120000 (teraterm can't do 112800 even though it can select it)
'sio.tx(1,65) ' test port 2
if(_LCD_Enabled)
lcd.start ' start the LCD display
ifnot( fat.FATEngineStart(_SD_DO, _SD_CLK, _SD_DI, _SD_CS, _SD_WP, _SD_CD, _RTC_DAT, _RTC_CLK, -1))
' com.COMEngineStart(_receiverPin, _transmitterPin, _baudRateSpeed))
' adc.ADCEngineStart(_leftMicInputPin, _leftMicFeedBackPin, _rightMicInputPin, _rightMicFeedBackPin, 16_000)
' dac.DACEngineStart(_leftChannelAudioPin, _rightChannelAudioPin, 0) )
reboot
' dac.leftChannelVolume(_leftChannelVolume)
' dac.rightChannelVolume(_rightChannelVolume)
' if(_VGA_Enabled)
' ifnot( bmp.BMPEngineStart(_VGA_PinGroup, 1, _VGA_H_Res, _VGA_V_Res, @scopeHeap) and {
' } (cognew(scope, @scopeStack) <> -1))
' reboot
sio.start ' start the com port note can't print anything to screen till sio.start unless only do to vga screen
PrintStringCR(string("Testing for SD card")) ' helpful message if card is out, better than just a blank screen
fat.mountPartition(0) ' mount the sd card
VT100.clearscreen ' if the sd card is not inserted, will leave the message on the screen as a reminder. If it is inserted, start with a blank screen
PrintStringCR(string("*** KyeDOS SD card operating system v3.01 by Kwabena W. Agyeman & J. Moxham ***"))
PrintString(string("Type Help for command listing"))
crlf
'DisplayBinaryFiles ' display all files ending in .BIN
sio.rxflush(0) ' in case try to send an xmodem transfer
ifnot(fat.partitionMounted)
printstring(string("Card Not Mounted "))
repeat
result := shellLine(string(">"))
'printstring(string("Running command: ")) ' commands run so quickly no need to print this
'printstring(result)
str.copy(result,@commandline)' save for later on if this is a command line with parameters eg "xmodem r filename.txt"
crlf
result := \shellCommands(result)
printstring(result)
crlf
if(fat.partitionError)
crlf
PRI shellCommands(stringPointer)
stringPointer := str.tokenizeString(stringPointer)
programClear(stringPointer)
programEcho(stringPointer)
programReboot(stringPointer)
programHelp(stringPointer)
programMount(stringPointer)
programUnmount(stringPointer)
programFreeSpace(stringPointer)
programUsedSpace(stringPointer)
programList(stringPointer)
programDIR(stringPointer)
programConcatenate(stringPointer)
programChangeDirectory(stringPointer)
programChangeAttributes(stringPointer)
programMove(stringPointer)
programRemove(stringPointer)
programEra(stringPointer) ' same as programremove
programMakeFile(stringPointer)
programMakeDirectory(stringPointer)
programCopy(stringPointer)
programDifference(stringPointer)
programBoot(stringPointer)
programFormat(stringPointer)
programDate(stringPointer)
programTime(stringPointer)
' programRamSet(stringPointer)
' programRamGet(stringPointer)
' programSQW(stringPointer)
' programOUT(stringPointer)
' programPlayWavFile(stringPointer)
' programTapeWavFile(stringPointer)
programDump(stringPointer)
programTest(stringPointer)
programCommand(StringPointer) ' is it a command ie a .exe file?
abort string("Command Not Found! Try Help")
crlf
{
PRI shellLine(prompt)
printstring(prompt)
repeat
result := com.receivedByte
str.buildString(result)
while((result <> carriage_return) and (result <> carriage_return) and (result <> com#null))
return str.trimString(str.builtString(true))
}
PRI shellLine(prompt)
PrintString(prompt)
repeat
result:=0
repeat
if key.gotkey <>0 ' scan both the local keyboard and the com port
result:=key.getkey
if sio.rxavail(0)
result :=sio.rx(0)
until result <>0 ' until something comes in either port
if result==200
result :=8 ' backspace keycode is 200 but convert to 8
PrintChar(result) ' send to vga and to com port
str.buildString(result) ' build an input string
while((result <> 13) and (result <> 10) and (result <> 0))
return str.trimString(str.builtstring(true))
{
PRI shellDecision(prompt, characterToFind, otherCharacterToFind)
printstring(prompt)
repeat
prompt := com.receivedByte
result or= ((prompt == characterToFind) or (prompt == otherCharacterToFind))
if(prompt == com#backspace)
return false
while((prompt <> carriage_return) and (prompt <> carriage_return) and (prompt <> com#null))
}
PRI shellDecision(prompt, characterToFind, otherCharacterToFind)
PrintString(prompt~)
repeat
result := key.getkey
prompt or= ((result == characterToFind) or (result == otherCharacterToFind))
while((result <> 13) and (result <> 10) and (result <> 0))
return prompt
PRI programClear(stringPointer)
ifnot(str.stringCompareCI(string("clear"), stringPointer))
rtc.pauseForMilliseconds(500)
printstring(string(_clearScreenCharacter, _homeCursorCharacter))
abort false
PRI programEcho(stringPointer)
ifnot(str.stringCompareCI(string("echo"), stringPointer))
printstring(str.trimString(stringPointer += 5))
crlf
abort false
PRI programReboot(stringPointer)
ifnot(str.stringCompareCI(string("reboot"), stringPointer))
printstring(string("Rebooting "))
repeat 3
rtc.pauseForMilliseconds(500)
printstring(string(". "))
rtc.pauseForMilliseconds(500)
reboot
PRI programHelp(stringPointer)
ifnot(str.stringCompareCI(string("help"), stringPointer))
printstring(@shellProgramHelpStrings)
abort false
DAT shellProgramHelpStrings
byte 13,10
byte "Command Listing"
byte 13,10
byte "<clear> - Clear the screen."
byte 13,10
byte "<echo> <string> - Echo the string argument."
byte 13,10
byte "<reboot> - Reboot the propeller chip."
byte 13,10
byte "<help> - Show the command listing."
byte 13,10
byte "<mount> <partition> - Mount the file system."
byte 13,10
byte "<unmount> - Unmount the file system."
byte 13,10
byte "<df> <fast> - Free sector count. F=Fast. 1 Sector = 512 Bytes"
byte 13,10
byte "<du> <fast> - Used sector count. F=Fast. 1 Sector = 512 Bytes"
byte 13,10
byte "<ls> <all> - List contents of the working directory. A=All."
byte 13,10
byte "<dir> - List contents. Includes wildcards eg dir *.exe"
byte 13,10
byte "<cat> <file> <hex> - Print the ASCII interpreted contents of a file."
byte 13,10
byte "<cd> <directory> - Change directory."
byte 13,10
byte "<chmod> <entry> <attributes> - Change Attrib: R=R/O, H=Hidden, S=Sys, A=Arch"
byte 13,10
byte "<mv> <oldPath> <newPath> - Move a file or directory."
byte 13,10
byte "<rm> <path> or <era> - Remove a file or directory."
byte 13,10
byte "<mkfile> <name> - Make a new file."
byte 13,10
byte "<mkdir> <name> - Make a new directory."
byte 13,10
byte "<cp> <oldPath> <newPath> - Copy a file."
byte 13
byte 10
byte "<diff> <path> <path> - Print differences between two files."
byte 13,10
byte "<boot> <file> - Reboot the propeller chip from a file."
byte 13,10
byte "<filename> - Reboot and run filename.exe"
byte 13,10
byte "<format> <partition> - Format and mount the file system."
byte 13,10
byte "<date> - Display the current date and time."
byte 13,10
byte "<time> - Change the current date and time."
byte 13,10
' byte "<set> <byteNumber> <byteValue> - Set the value of a SRAM byte on the RTClock."
' byte 13,10
' byte "<get> <byteNumber> - Get the value of a SRAM byte on the RTClock."
' byte 13,10
' byte "<sqw> <frequencyNumber> - Set the frequecny of the SWQ / OUT pin. (0=1Hz, 1=4096Hz, 2=8192Hz, 3=32768Hz)."
' byte 13,10
' byte "<out> <digitalState> - Set the state of the SWQ / OUT pin. (0=low, 1=high)."
' byte 13,10
' byte "<play> <file> - Play a WAV file."
' byte 13,10
' byte "<tape> <file> - Tape a WAV file."
' byte 13,10
byte "<dump> - Dump the ROM font."
byte 13,10
byte "<test> - Speed test the file system."
byte 13,10, 0
PRI programMount(stringPointer)
ifnot(str.stringCompareCI(string("mount"), stringPointer))
if(fat.mountPartition(stringPointer := str.decimalToInteger(str.tokenizeString(0))))
printstringcr(string("Please unmount the disk next time"))
taf.mountPartition(stringPointer)
printstring(fat.partitionWriteProtected & string("Write Protected "))
printstring(string("Disk 0x"))
printstring(str.integerToHexadecimal(fat.partitionDiskSignature, 8))
printstring(string(" with Volume ID 0x"))
printstring(str.integerToHexadecimal(fat.partitionVolumeIdentification, 8))
printstring(string(" a.k.a "))
printstring(str.trimString(fat.partitionVolumeLabel))
printstringcr(string(" ready"))
abort 0
PRI programUnmount(stringPointer)
ifnot(str.stringCompareCI(string("unmount"), stringPointer))
taf.unmountPartition
fat.unmountPartition
printstringcr(string("Disk ready for removal"))
abort 0
PRI programFreeSpace(stringPointer)
ifnot(str.stringCompareCI(string("df"), stringPointer))
printstring(string("The ", quote))
printstring(str.trimString(fat.partitionFileSystemType))
printstring(string(quote, " ", quote))
printstring(str.trimString(fat.partitionVolumeLabel))
printstring(string(quote, " parition has "))
printstring(1 + str.integerToDecimal(fat.partitionCountOfClusters, 10))
printstring(string(" clusters and "))
printstring(1 + str.integerToDecimal(fat.partitionDataSectors, 10))
printstring(string(" total sectors, where each cluster is "))
printstring(1 + str.integerToDecimal(fat.partitionSectorsPerCluster, 3))
printstring(string(" sectors large and each sector is "))
printstring(1 + str.integerToDecimal(fat.partitionBytesPerSector, 3))
printstringcr(string(" bytes"))
printstring(string("And there are... please wait... "))
printstring(1 + str.integerToDecimal(fat.partitionFreeSectorCount(byte[str.tokenizeString(0)]), 10))
printstringcr(string(" Free Sectors"))
abort 0
PRI programUsedSpace(stringPointer)
ifnot(str.stringCompareCI(string("du"), stringPointer))
printstring(string("The ", quote))
printstring(str.trimString(fat.partitionFileSystemType))
printstring(string(quote, " ", quote))
printstring(str.trimString(fat.partitionVolumeLabel))
printstring(string(quote, " parition has "))
printstring(1 + str.integerToDecimal(fat.partitionCountOfClusters, 10))
printstring(string(" clusters and "))
printstring(1 + str.integerToDecimal(fat.partitionDataSectors, 10))
printstring(string(" total sectors where each cluster is "))
printstring(1 + str.integerToDecimal(fat.partitionSectorsPerCluster, 3))
printstring(string(" sectors large and each sector is "))
printstring(1 + str.integerToDecimal(fat.partitionBytesPerSector, 3))
printstringcr(string(" bytes"))
printstring(string("And there are... please wait... "))
printstring(1 + str.integerToDecimal(fat.partitionUsedSectorCount(byte[str.tokenizeString(0)]), 10))
printstringcr(string(" Used Sectors"))
abort 0
PRI programList(stringPointer) : counter | buffer, flag
ifnot(str.stringCompareCI(string("ls"), stringPointer))
stringPointer := str.tokenizeString(0)
flag := (str.findCharacter(stringPointer, "A") or str.findCharacter(stringPointer, "a"))
fat.listEntries("W")
repeat while(buffer := fat.listEntries("N"))
printstring(buffer)
ifnot(flag)
if(++counter // 8)
PrintChar(horizontal_tab)
else
crlf
else
if(fat.listIsReadOnly)
printstring(string(" [ R"))
else
printstring(string(" [ _"))
if(fat.listIsHidden)
PrintChar("H")
else
PrintChar("_")
if(fat.listIsSystem)
PrintChar("S")
else
PrintChar("_")
if(fat.listIsDirectory)
PrintChar("D")
else
PrintChar("_")
if(fat.listIsArchive)
PrintChar("A")
else
PrintChar("_")
printstring(string(" ] [ "))
printstring(1 + str.integerToDecimal(fat.listSize, 10))
printstring(string(" ] [ Accessed "))
printstring(1 + str.integerToDecimal(fat.listAccessMonth, 2))
PrintChar("/")
printstring(1 + str.integerToDecimal(fat.listAccessDay, 2))
PrintChar("/")
printstring(1 + str.integerToDecimal(fat.listAccessYear, 4))
printstring(string(" ] [ Created "))
printstring(1 + str.integerToDecimal(fat.listCreationHours, 2))
PrintChar(":")
printstring(1 + str.integerToDecimal(fat.listCreationMinutes, 2))
PrintChar(":")
printstring(1 + str.integerToDecimal(fat.listCreationSeconds, 2))
PrintChar(" ")
printstring(1 + str.integerToDecimal(fat.listCreationMonth, 2))
PrintChar("/")
printstring(1 + str.integerToDecimal(fat.listCreationDay, 2))
PrintChar("/")
printstring(1 + str.integerToDecimal(fat.listCreationYear, 4))
printstring(string(" ] [ Modified "))
printstring(1 + str.integerToDecimal(fat.listModificationHours, 2))
PrintChar(":")
printstring(1 + str.integerToDecimal(fat.listModificationMinutes, 2))
PrintChar(":")
printstring(1 + str.integerToDecimal(fat.listModificationSeconds, 2))
PrintChar(" ")
printstring(1 + str.integerToDecimal(fat.listModificationMonth, 2))
PrintChar("/")
printstring(1 + str.integerToDecimal(fat.listModificationDay, 2))
PrintChar("/")
printstring(1 + str.integerToDecimal(fat.listModificationYear, 4))
printstringcr(string(" ]"))
if((counter // 8) and counter)
crlf
abort 0
PRI programConcatenate(stringPointer) : counter | buffer, flag
ifnot(str.stringCompareCI(string("cat"), stringPointer))
fat.openFile(str.tokenizeString(0), "R")
stringPointer := str.tokenizeString(0)
flag := (str.findCharacter(stringPointer, "H") or str.findCharacter(stringPointer, "h"))
repeat until(fat.fileSize == fat.fileTell)
if(flag)
PrintChar("$")
printstring(str.integerToHexadecimal(fat.readByte, 2))
if(++counter // 16)
PrintChar(horizontal_tab)
else
crlf
else
PrintChar(fat.readByte)
if((counter // 8) and counter)
crlf
fat.closeFile
abort 0
PRI programChangeDirectory(stringPointer)
ifnot(str.stringCompareCI(string("cd"), stringPointer))
stringPointer := str.tokenizeString(0)
fat.changeDirectory(stringPointer)
taf.changeDirectory(stringPointer)
abort 0
PRI programChangeAttributes(stringPointer)
ifnot(str.stringCompareCI(string("chmod"), stringPointer))
fat.changeAttributes(str.tokenizeString(0), str.tokenizeString(0))
abort 0
PRI programMove(stringPointer)
ifnot(str.stringCompareCI(string("mv"), stringPointer))
fat.moveEntry(str.tokenizeString(0), str.tokenizeString(0))
abort 0
PRI programRemove(stringPointer)
ifnot(str.stringCompareCI(string("rm"), stringPointer))
fat.deleteEntry(str.tokenizeString(0))
abort 0
PRI programERA(stringPointer) ' same as ProgramRemove
ifnot(str.stringCompareCI(string("era"), stringPointer))
fat.deleteEntry(str.tokenizeString(0))
abort 0
PRI programMakeFile(stringPointer)
ifnot(str.stringCompareCI(string("mkfile"), stringPointer))
fat.newFile(str.tokenizeString(0))
abort 0
PRI programMakeDirectory(stringPointer)
ifnot(str.stringCompareCI(string("mkdir"), stringPointer))
fat.newDirectory(str.tokenizeString(0))
abort 0
PRI programCopy(stringPointer) | sector[128]
ifnot(str.stringCompareCI(string("cp"), stringPointer))
fat.openfile(str.tokenizeString(0), "R")
stringPointer := str.tokenizeString(0)
taf.newFile(stringPointer)
taf.openfile(stringPointer, "W")
repeat
result := fat.readData(@sector, 512)
taf.writeData(@sector, result)
while(result == 512)
fat.closeFile
taf.closeFile
abort 0
PRI programDifference(stringPointer) | byte0, byte1
ifnot(str.stringCompareCI(string("diff"), stringPointer))
fat.openfile(str.tokenizeString(0), "R")
taf.openfile(str.tokenizeString(0), "R")
repeat until(fat.fileSize == fat.fileTell)
byte0 := fat.readByte
byte1 := taf.readByte
if(byte0 <> byte1)
printstring(string("Difference: $"))
printstring(1 + str.integerToHexadecimal(byte0, 2))
printstring(string(" <> $"))
printstring(1 + str.integerToHexadecimal(byte1, 2))
printstring(string(" at $"))
printstringcr(1 + str.integerToHexadecimal(result, 8))
result += 1
fat.closeFile
taf.closeFile
abort 0
PRI programBoot(stringPointer)
ifnot(str.stringCompareCI(string("boot"), stringPointer))
stringPointer := str.tokenizeString(0)
'printstring(string("Are you sure you want to reboot from "))
'printstring(stringPointer)
'if(shellDecision(string(" - [y]es or [n]o? : "), "Y", "y"))
fat.bootPartition(stringPointer)
abort 0
PRI programFormat(stringPointer)
ifnot(str.stringCompareCI(string("format"), stringPointer))
stringPointer := str.tokenizeString(0)
printstring(string("Are you sure you want to format ", quote))
printstring(fat.partitionVolumeLabel)
if(shellDecision(string(quote," All data will be erased! - [y]es or [n]o? : "), "Y", "y"))
if(shellDecision(string("Are you absolutely sure? [y]es or [n]o : "), "Y", "y"))
printstringcr(string("Formatting Partition..."))
fat.formatPartition(str.decimalToInteger(str.tokenizeString(0)))
abort 0
PRI programDate(stringPointer)
ifnot(str.stringCompareCI(string("date"), stringPointer))
ifnot(rtc.readTime)
abort string("Operation Failed")
crlf
printstring(lookup(rtc.clockDay: string("Sunday"), {
} string("Monday"), {
} string("Tuesday"), {
} string("Wednesday"), {
} string("Thursday"), {
} string("Friday"), {
} string("Saturday")))
printstring(string(", "))
printstring(lookup(rtc.clockMonth: string("January"), {
} string("Feburary"), {
} string("March"), {
} string("April"), {
} string("May"), {
} string("June"), {
} string("July"), {
} string("August"), {
} string("September"), {
} string("October"), {
} string("November"), {
} string("December")))
PrintChar(" ")
printstring(1 + str.integerToDecimal(rtc.clockDate, 2))
printstring(string(", "))
printstring(1 + str.integerToDecimal(rtc.clockYear, 4))
PrintChar(" ")
printstring(1 + str.integerToDecimal(rtc.clockMeridiemHour, 2))
PrintChar(":")
printstring(1 + str.integerToDecimal(rtc.clockMinute, 2))
PrintChar(":")
printstring(1 + str.integerToDecimal(rtc.clockSecond, 2))
PrintChar(" ")
if(rtc.clockMeridiemTime)
printstringcr(string("PM"))
else
printstringcr(string("AM"))
abort false
PRI programTime(stringPointer) | time[6]
ifnot(str.stringCompareCI(string("time"), stringPointer))
printstringcr(string("Please enter the exact time,"))
time := str.decimalToInteger(shellLine(string("Year (2000 - 2127): ")))
time[1] := str.decimalToInteger(shellLine(string("Month (1 - 12): ")))
time[2] := str.decimalToInteger(shellLine(string("Date (1 - 31): ")))
time[3] := str.decimalToInteger(shellLine(string("Day (1 - 7): ")))
time[4] := str.decimalToInteger(shellLine(string("Hours (0 - 23): ")))
time[5] := str.decimalToInteger(shellLine(string("Minutes (0 - 59): ")))
ifnot(rtc.writeTime(str.decimalToInteger(shellLine(string("Seconds (0 - 59): "))), {
} time[5], {
} time[4], {
} time[3], {
} time[2], {
} time[1], {
} time))
abort string("Operation Failed")
crlf
crlf
programDate(string("date"))
printstringcr(string("Operation Successful"))
abort false
{
PRI programRamSet(stringPointer)
ifnot(str.stringCompareCI(string("set"), stringPointer))
result := rtc.writeSRAM(str.decimalToInteger(str.tokenizeString(0)), str.decimalToInteger(str.tokenizeString(0)))
stringPointer := string("Failure!", _newLineCharacter)
if(result)
stringPointer := string("Success!", _newLineCharacter)
printstring(stringPointer)
abort false
PRI programRamGet(stringPointer)
ifnot(str.stringCompareCI(string("get"), stringPointer))
printstring(1 + str.integerToDecimal(rtc.readSRAM(str.decimalToInteger(str.tokenizeString(0))), 3))
PrintChar(_newLineCharacter)
abort false
}
{
PRI programSQW(stringPointer)
ifnot(str.stringCompareCI(string("sqw"), stringPointer))
result := rtc.clockSquareWaveOut(str.decimalToInteger(str.tokenizeString(0)) & 1, 1)
stringPointer := string("Failure!", _newLineCharacter)
if(result)
stringPointer := string("Success!", _newLineCharacter)
printstring(stringPointer)
abort false
PRI programOUT(stringPointer)
ifnot(str.stringCompareCI(string("out"), stringPointer))
result := rtc.clockSquareWaveOut(0, ((str.decimalToInteger(str.tokenizeString(0)) & 1) << 1))
stringPointer := string("Failure!", _newLineCharacter)
if(result)
stringPointer := string("Success!", _newLineCharacter)
printstring(stringPointer)
abort false
}
{
PRI programPlayWavFile(stringPointer) | numberOfChannels, sampleRate ' Google "WAV format" for info about this function...
ifnot(str.stringCompareCI(string("play"), stringPointer))
printstring(string("Please wait...", _newLineCharacter))
stringPointer := fat.openFile(str.tokenizeString(0), "R")
if(fat.readLong <> $46_46_49_52)
abort string("Not RIFF file", _newLineCharacter)
if((fat.readlong + 8) <> fat.fileSize)
abort string("Chunk size incorrect", _newLineCharacter)
if(fat.readLong <> $45_56_41_57)
abort string("Not WAVE file", _newLineCharacter)
if(fat.readLong <> $20_74_6D_66)
abort string(quote, "fmt ", quote, " missing", _newLineCharacter)
if(fat.readLong <> 16)
abort string("Subchunk 1 size incorrect", _newLineCharacter)
if(fat.readShort <> 1)
abort string("Not LPCM file", _newLinecharacter)
dac.numberOfChannelsSetup(numberOfChannels := fat.readShort)
dac.sampleRateSetup(sampleRate := fat.readLong)
fat.fileSeek(34)
dac.bitsPerSampleSetup(result := fat.readShort)
dac.sampleSignSetup(result == 16)
fat.fileSeek(28)
if(fat.readLong <> (sampleRate * numberOfChannels * result / 8))
abort string("Byte rate incorrect", _newLineCharacter)
if(fat.readShort <> (numberOfChannels * result / 8))
abort string("Block align incorrect", _newLineCharacter)
fat.fileSeek(36)
if(fat.readLong <> $61_74_61_64)
abort string(quote, "data", quote, " missing", _newLineCharacter)
result := fat.readlong
if((result + constant(36 + 8)) <> fat.fileSize)
abort string("Subchunk 2 size incorrect", _newLineCharacter)
printstring(string("Now playing "))
printstring(stringPointer)
printstring(string(_newLineCharacter, "Press enter to quit ", _newLineCharacter))
dac.startPlayer
scopeSwtich := true
repeat ((result + 511) / 512)
fat.readData(dac.transferData, 512)
if(com.receivedNumber)
result := com.receivedByte
if((result == carriage_return) or (result == carriage_return) or (result == com#null))
printstring(string("Quiting", _newLineCharacter))
quit
scopeSwtich := false
dac.stopPlayer
dac.clearData
fat.closeFile
abort 0
}
{
PRI programTapeWavFile(stringPointer) ' Google "WAV format" for info about this function...
ifnot(str.stringCompareCI(string("tape"), stringPointer))
printstring(string("Please wait...", _newLineCharacter))
stringPointer := str.tokenizeString(0)
fat.newFile(stringPointer)
stringPointer := fat.openFile(stringPointer, "W")
printstring(string("Now taping "))
printstring(stringPointer)
printstring(string(_newLineCharacter, "Press enter to save ", _newLineCharacter))
fat.writeString(string("RIFF____WAVEfmt "))
fat.writeLong(16)
fat.writeShort(1)
fat.writeShort(1)
fat.writeLong(16_000)
fat.writeLong(16_000)
fat.writeShort(1)
fat.writeShort(8)
fat.writeString(string("data____"))
adc.sampleRateSetup(16_000)
adc.numberOfChannelsSetup(1)
adc.bitsPerSampleSetup(8)
adc.sampleSignSetup(0)
adc.clearData
repeat while(result < (posx - constant(36 + 8)))
fat.writeData(adc.transferData, 512)
result += 512
if(com.receivedNumber)
stringPointer := com.receivedByte
if((stringPointer == carriage_return) or (stringPointer == carriage_return) or (stringPointer == com#null))
printstring(string("Saving", _newLineCharacter))
quit
fat.fileSeek(40)
fat.writeLong(result)
fat.fileSeek(4)
fat.writeLong(result + 36)
fat.closeFile
abort 0
}
PRI programDump(stringPointer) | outsideCounter, insideCounter
ifnot(str.stringCompareCI(string("dump"), stringPointer))
fat.openFile(fat.newFile(string("P8X32A.TXT")), "W")
fat.writeString(string("P8X32A Character Set", carriage_return, line_feed, carriage_return, line_feed))
repeat outsideCounter from 0 to 255
printstring(string("Dumping character #"))
printstringcr(1 + str.integerToDecimal(outsideCounter, 3))
fat.writeString(string("Character #"))
fat.writeString(1 + str.integerToDecimal(outsideCounter, 3))
fat.writeString(string(carriage_return, carriage_return, carriage_return, carriage_return))
repeat result from 0 to 31
repeat insideCounter from (outsideCounter & 1) to 31 step 2
if(long[32_768][result + ((outsideCounter >> 1) << 5)] & (|<insideCounter))
fat.writeByte(".")
else
fat.writeByte(" ")
fat.writeString(string(carriage_return, carriage_return))
fat.writeString(string(carriage_return, carriage_return))
fat.closeFile
abort 0
PRI programTest(stringPointer) | counter, buffer
ifnot(str.stringCompareCI(string("test"), stringPointer))
fat.newFile(stringPointer := string("P8X32A.ROM"))
buffer := startTest(stringPointer, "W", string("Byte write test... "))
repeat counter from 32_768 to 65_535 step 1
fat.writeByte(byte[counter])
stopTest("W", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "R", string("Byte read test... "))
repeat counter from 32_768 to 65_535 step 1
if(fat.readByte <> byte[counter])
fat.closeFile
abort string("Byte read back failed")
crlf
stopTest("R", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "W", string("Word write test... "))
repeat counter from 32_768 to 65_535 step 2
fat.writeShort(word[counter])
stopTest("W", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "R", string("Word read test... "))
repeat counter from 32_768 to 65_535 step 2
if(fat.readShort <> word[counter])
fat.closeFile
abort string("Word read back failed")
crlf
stopTest("R", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "W", string("Long write test... "))
repeat counter from 32_768 to 65_535 step 4
fat.writeLong(long[counter])
stopTest("W", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "R", string("Long read test... "))
repeat counter from 32_768 to 65_535 step 4
if(fat.readLong <> long[counter])
fat.closeFile
abort string("Long read back failed")
crlf
stopTest("R", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "W", string("Sector write test... "))
repeat counter from 32_768 to 65_535 step 512
fat.writeData(counter, 512)
stopTest("W", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "R", string("Sector read test... "))
repeat counter from 32_768 to 65_535 step 512
fat.readData(counter, 512)
stopTest("R", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "W", string("Memory write test... "))
repeat counter from 32_768 to 65_535 step 32_768
fat.writeData(counter, 32_768)
stopTest("W", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "R", string("Memory read test... "))
repeat counter from 32_768 to 65_535 step 32_768
fat.readData(counter, 32_768)
stopTest("R", 32_768, (cnt - buffer))
fat.newFile(fat.deleteEntry(stringPointer))
buffer := startTest(stringPointer, "A", string("Block append test... "))
fat.writeData(32_768, 32_768)
stopTest("W", 32_768, (cnt - buffer))
buffer := startTest(stringPointer, "R", string("Reverse seek test... "))
repeat counter from 32_767 to 0 step 512
fat.fileSeek(counter)
stopTest("R", 32_768, (cnt - buffer))
fat.deleteEntry(stringPointer)
abort 0
PRI startTest(path, mode, message)
fat.openFile(path, mode)
printstring(message)
return cnt
PRI stopTest(mode, count, cycles)
if(mode == "W")
printstring(string("Writ "))
else
printstring(string("Read "))
printstring(1 + str.integerToDecimal((count >> 10), 3))
printstring(string(" KBs at "))
printstring(1 + str.integerToDecimal((multiplyDivide(count, cycles) >> 10), 3))
printstringcr(string(" KBs per second"))
fat.closeFile
PRI multiplyDivide(dividen, divisor) | productHigh, productLow
productHigh := clkfreq ** dividen
productLow := clkfreq * dividen
if(productHigh => divisor)
return posx
repeat 32
dividen := (productHigh < 0)
productHigh := ((productHigh << 1) + (productLow >> 31))
productLow <<= 1
result <<= 1
if((productHigh => divisor) or dividen)
productHigh -= divisor
result += 1
{
PRI scope | displayPointer, currentDisplay
bmp.displayColor(0, _VGA_BG_Color)
bmp.displayColor(1, _VGA_FG_Color)
displayPointer := constant((_VGA_H_Res * _VGA_V_Res) / 32)
repeat
bmp.displayWait(1)
bmp.displayPointer(@scopeHeap[displayPointer & currentDisplay])
not currentDisplay
bmp.displayClear(0, @scopeHeap[displayPointer & currentDisplay])
repeat result from 0 to constant(_VGA_H_Res - 1)
if(scopeSwtich)
bmp.plotPixel( 1, {
} result, {
} (constant(_VGA_V_Res / 2) + (dac.leftChannelOutput ~> constant(16 - (>|_VGA_V_Res)))), {
} @scopeHeap[displayPointer & currentDisplay])
else
bmp.plotPixel( 1, {
} result, {
} (constant(_VGA_V_Res / 2) + (adc.leftChannelInput ~> constant(16 - (>|_VGA_V_Res)))), {
} @scopeHeap[displayPointer & currentDisplay])
}
PUB PrintStringCR(pstring)' sends pstring to the vga and serial port
PrintString(pstring) ' print the string
crlf
PUB PrintString(pstring)' sends pstring to the vga and serial port with no CRLF
if (_VGA_Enabled)
vt100.str(pstring) ' send to vga screen
if (_Serial_Enabled)
sio.str(0,pstring) ' send to com port
if (_lcd_Enabled)
lcd.str(pstring) ' send to 20x4 lCD display
PUB PrintChar(c) ' sends c to vga and serial port
if (_VGA_Enabled)
vt100.out(c) ' send to vga
if (_Serial_Enabled)
sio.tx(0,c) ' send to com port
if (_lcd_Enabled)
LCD.out(c) ' send to LCD display
PUB CRLF
PrintChar(13) ' send to vga
PrintChar(10) ' send to vga
PUB PrintDecimal(number) ' print the decimal value, useful for debuggin
PrintString(str.integerToDecimal(number, 10))
PRI DisplayBinaryFiles | buffer
PrintString(string("Use the BOOT command to run the following binary Spin programs/emulations:"))
crlf
fat.listEntries("W")
repeat while(buffer := fat.listEntries("N"))
buffer := str.trimstring(buffer)
if str.endswithstring(buffer,string(".BIN")) == -1
PrintString(buffer)
crlf
crlf
PRI ProgramDir(StringPointer) | buffer,counter,match
ifnot(str.stringCompareCI(string("dir"), stringPointer))
stringPointer := str.tokenizeString(0) ' get the *.exe bit
str.copy(stringpointer,@lineoftext1) ' move to lineoftext1
str.mid(@lineoftext1,@lineoftext2,str.instr(@lineoftext1,"."),4) ' get string from . to end = extension
counter:=0
crlf
fat.listEntries("W")
repeat while(buffer := fat.listEntries("N"))
str.copy(buffer,@LineOfText1) ' copy filename to LineOfText
str.trimstring(@lineoftext1)
str.mid(@lineoftext1,@lineoftext3,str.instr(@lineoftext1,"."),4) ' get string from . to end = extension
match := false ' setup for below
if str.len(@lineoftext2) == 0
match := true ' no extension so always print it
else
ifnot str.stringcompareci(@lineoftext2,@lineoftext3) ' reverse logic ?!
match := true ' found a match
if match == true
PrintString(@lineoftext1) ' print file name
counter++ ' add one to counter
repeat 13-str.len(@lineoftext1) ' add spaces so columns line up
printchar(" ") ' print space
if counter == 6 ' new line
counter :=0
crlf
crlf
abort 0 ' so knows a command was run
PRI ProgramCommand(StringPointer) | buffer,i ' look for .exe files (ie .binary files renamed to .exe) and if found, run the program
fat.listEntries("W")
str.copy(stringpointer,@lineoftext2) ' copy the command to lineoftext2
str.stringConcatenate(@lineoftext2, string(".exe")) ' add extension for executable files to lineoftext2
repeat while(buffer := fat.listEntries("N"))
str.copy(buffer,@LineOfText1) ' copy filename to LineOfText1
str.trimstring(@lineoftext1) ' remove any leading/trailing spaces
ifnot str.stringcompareci(@lineoftext1,@lineoftext2)' does it match? (ignore case)
str.copy(buffer,@lineoftext3) ' can't use "buffer" as it gets overwritten
'printstringcr(string("Saving command line in COMMAND.TXT and running program"))
'printstring(string("Command line: "))
'printstring(@commandline)
' above commented out as 1) about to blank the screen, 2) debugged and 3) if running xmodem don't want any further data on the serial lines
' possibly could put this output back if use the vga screen only.
result := \fat.newFile(string("COMMAND.TXT")) ' All aborts traps must have "variable := \function" setup.
if(fat.partitionError == fat#Entry_Already_Exist) ' file already exists
result := \fat.deleteEntry(string("COMMAND.TXT")) ' delete the old file
result := \fat.newfile(string("COMMAND.TXT")) ' recreate the file
result := \fat.openFile(string("COMMAND.TXT"), "W") ' create file and open file
result := \fat.writestring(@commandline) ' store the command line as it was typed
result := \fat.closefile ' close the file
result := \fat.bootpartition(@lineoftext3) ' reboot
' ***************************************************************************************
'printstring(@lineoftext1) ' testing string functions
'str.left(@lineoftext1,@lineoftext2,3) ' find leftmost characters in a string
'printstring(@lineoftext2)
'str.trimstring(@lineoftext1)
'printstring(@lineoftext1)
'str.trimstring(@lineoftext1)
'str.mid(@lineoftext1,@lineoftext2,4,2) ' find middle characters in a string
'printstring(@lineoftext2)
'printstring(str.integertodecimal(str.len(@lineoftext2),5))
'str.copy(string("hello"),@lineoftext1) ' copy fixed value into a string
'printstring(@lineoftext1)
'str.str(@lineoftext1,55) ' decimal to string with no leading zeros
'printstring(@lineoftext1)
'str.stringfill(@lineoftext1,10,65)
'printstring(@lineoftext1)
'str.str(@lineoftext1,1234)' convert to string
'str.str(@lineoftext1,str.decimaltointeger(@lineoftext1)) ' convert back
'printstring(@lineoftext1)
' str.left(@lineoftext1,@lineoftext2,str.len(@lineoftext1)-4) ' remove extension
' printstring(@lineoftext2) ' print it out
{{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TERMS OF USE: MIT License
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}}
I am still a bit confused with the Start and Mount operations.
On FSRW 2.6 I usually mount first at Propeller start up and delay file operations until much later.
Can I start the FATEngine, Mount the SD card but delay the file operations until much later? (maybe hours later)
But the way the example code is shown in the Application Note, once "code" returns it means an error has occurred and the Supervisor Cog cannot proceed as usual.
Do you have an example code where the Supervisor Cog starts the FATEngine, Mounts the SD card and then proceeds with its normal execution without any file operations.
Yeah, you can. The start operation just launches the SD SPI bus mater cog to start listening for commands. Nothing more.The mount operation actaully tells the SPI bus master card to start communicating with the SD card.
Um... for your other question... so, that's the idea. Abort and Return both return error codes to the upper level spin method. So... it's just a mater of chaning that if you want to. But the easist way of writing the error handler is to call a function that actualy has all your code in it and assume that nothing critically worng happens in that code. If it does abort back to the upper level.
Look at the demo SD_card_profilier tester code again. Its best to write your code like that. Because it will be robust. I could have broken up the large function where I preform all SD card operations into smaller functions with different error handlers but there wsa no need to. May you do have a need to.
to set the date and time before creating a new file so that the file date and time stamp is correct even though there is no RTC chip.
I can't find the equivalent in FATEngine. How do I do this in FATEngine?
That feature was removed because if the time stamp on a file is not correct there is no point to having it. The driver without the RTC just ouputs all 0's for the time and date.
If you want to add time stamping features... look at the "readTime" funtion in the versions with the RTC and then put the code that you think you need for that function in the "readTime" function in the version without the RTCs. Its really simple. You'll understand what to do no problem.
In FSRW 2.6 it does not keep updating the time for you. There was a "get_seconds" command added to the block driver that tracks elapsed seconds (I was using the code for automatically releasing the card after a period of disuse). Thus this functionality _could_ be added to FSRW, but my reasoning was that if someone provided a time-stamp once, they could do it again, saving FSRW from code bloat. I'm not saying my reasoning was valid...[8^) Once again, I really wish the standard propeller tool supported conditional compilation.
Jonathan
P.S. Dave, I'm working on back-porting your directory support into the FSRW C source, for an intermediate release of FSRW...I already have the safe block driver reading and writing at > 1MB/s (w/ 32kB clusters...slightly slower writing under FAT32 with 8kB clusters).
P.S. Dave, I'm working on back-porting your directory support into the FSRW C source, for an intermediate release of FSRW...I already have the safe block driver reading and writing at > 1MB/s (w/ 32kB clusters...slightly slower writing under FAT32 with 8kB clusters).
That's great! There are limitations on how I did the directory support, such as the directory must be in the first 2GB of the file system. It could be fixed for locations greater than 2GB with a few changes.
It seems that openFile with append mode does not create the file if it does not exist, unlike popen in FSRW.
How do I make openFile create a file automatically if the filename does not exist?
How to check for existence of a file?
Kye: I am confused. What is the latest version please?
SD_MMC_FATEngine.spin (version 2.0) from Obex and AN006 dated 25/9/2011
SD_3.01_FATEngine.spin (version log stops at 1.7) from Dracs KyeDos3.0 dated 6/1/2011
BTW here are my results for the version 2.0
### SD Card Profile ###
Disk Signature: 0x00000000
Partition 0 - 0xDC666872
R3_20120120 FAT16
512 - Bytes Per Sector
32 - Sectors Per Cluster
1982944 - Total Sectors
61967 - Total Clusters
64 - Used Sectors
1982880 - Free Sectors
32 KB Stride Speed Test:
writeByte - 4 KBs
writeShort - 8 KBs
writeLong - 14 KBs
writeData - 128 KBs
readByte - 4 KBs
readShort - 8 KBs
readLong - 16 KBs
readData - 330 KBs
Kye: Another question... Is there a method to find the current sector on the SD card?
I open a number of files for read only to determine the starting sector address in ZiCog. The I access the SD pasm driver directly to read and write sectors from CPM. I have tried a number of the PRI routines but nothing returns the files first sector address on the card. Any tips on how to get this?
The newest version is in the OBEX. Parallax has not updated their version they posted on the Parallax Semiconductor website.
...
That's a nice fast SD card you have there!
...
The readWriteCurrentSector function returns the sector number it was called on. That function basically encapsulates the logic for figure out what sector to read or write given the "current cluster" and "current byte" and it sets the "current sector". The "current sector" variable is equal to the "current byte" variable divided by 512. However, the "current byte" variable may be ahead of the "current sector" variable - this allows me to know when to switch clusters... if you look at the readWriteCurrentCluster code...
Anyway, just look at what "readWriteCurrentSector" returns to get the sector number from the start of the partition... then add in the "hiddenSectors" variable to get the absolute sector number. You could make a function that does exactly what "readWriteCurrentSector" does without the reading and writing part. If you plan on using the "readWriteBLock" function you don't need to add in the "hiddenSectors" variable.
reads really good what you have coded so far. How much would it take to add constants (or maybe conditional compiling directives) to switch the SD-card-routines
to the Prop-C3-board?
Some months ago I made some quick tries to get KyeDOS working on the C3 but had no success mainly because I did not rty it long enough to understand what I have to change.
@ stefan, it ought to be possible to just change the pin numbers for the SD card. Do you have a link for the C3 schematic by any chance? (There are many links to a low resolution copy but I once did manage to find a proper resolution one, but I have forgotton where!).
@richaj45, the SD card needs 4 pins - chip select (low to enable), data out, data in, clock.
Of course, if you are feeling cunning you can have multiple SPI devices sharing data out, data in and clock, and then you only need one pin per device to drive chip select.
kye: Thanks for that info. I can now try it out. I do know what numbers I expect, so it is easy to verify.
My card is a 1GB SanDisk. The test was done on a RamBlade3 - I am running at 6.5MHz (104MHz) Its a nice speed improvement!
richaj: I presume you are meaning is it a 1bit SPI interface or the faster 4bit parallel interface. Sorry, its the 1bit because the 4bit requires a licence to use and the payment of big$ to the card consortium.
no it is not done with just changing the pin-numbers because the C3 has a SPI-MUX-bus.
So the driver must be adapted to that.
I attach two pictures that I found on the FTP-server for the C3 ftp://ftp.propeller-chip.com/PropC3
To be really honest. In this case I'm really lazy. I don't want to dive into the details of FSRW, SPI-routines and the FAT-Engine.
What I would like to do is download a ready to run KyeDOS-Version adapated to the C3-board.
Download demofiles. Copying them on an empty micro-SD-card download a demofile into the EEPROM.
Switching on the C3-board and have a a DOS-prompt on the serial terminal. Not on VGA (eating too much memory) , No TV (don't have a small TV handy).
Serial is what you have as soon as you want to download code into the EEPROM or RAM.
I know that's asking for a finished version where others have done all the work. Nobody is forced to fiddle around with the code
If somebody enjoys doing it and testing it until it's running reliably please do it or if somebody has done it already please attach the code
to a posting or upload to the OBEX.
Edit 21.01.2012 this forum-software needs manual quality-checks after uploading. T´he original png-picture was blurred to unreadability through converting it to a "LEGO"-JPG
I uploaded the original png-file as zip to keep the good quality.
bumb: if you (the forum-members) think my wish is to much work for others and too less work on my own I would like to read a clear statement telling the truth what you think about it.
Kye: Here are the results for the same card on the same pc & prop, but with 5MHz (=80MHz).
### SD Card Profile ###
Disk Signature: 0x00000000
Partition 0 - 0x146A7AD4
R3_20120120 FAT16
512 - Bytes Per Sector
32 - Sectors Per Cluster
1982944 - Total Sectors
61967 - Total Clusters
217568 - Used Sectors
1765376 - Free Sectors
32 KB Stride Speed Test:
writeByte - 3 KBs
writeShort - 6 KBs
writeLong - 12 KBs
writeData - 206 KBs
readByte - 3 KBs
readShort - 6 KBs
readLong - 12 KBs
readData - 266 KBs
readData... 266 KBs @ 5MHz and 330 KBs @ 6.5MHz nice improvement here!
The writeData is interesting... 206 KBs @ 5MHz and 128 KBs @ 6.5MHz opposite to what was expected!
Yeah, no clue. Maybe it was just a hiccup that time. There's a lot of stuff going on in the SD card that can make write performance dreadful out of nowhere.
Read performance should stay constant, however.
---
I'm done collecting data measurements BTW. But, thanks for posting anyway. I think the driver is pretty solid right now. The performance isn't bad on it either.
To be really honest. In this case I'm really lazy. I don't want to dive into the details of FSRW, SPI-routines and the FAT-Engine.
Well I guess the truth of it is that I don't have a C3 so I haven't written any code for the C3. Sorry.
Looking at the schematic, I think that is a 161 counter chip, so you clear it and then send a certain number of pulses and that selects the SPI device. I don't know which device is the SD card, but I think the code ought to be fairly simple, and you could write it in Spin if you like.
thank you for pointing to the C3-emulationsite.
The problem for me is how do I quickly find all the places in the code that are affected by this.
If I understood right. the spi-driver is PASM. So I guess I have to change things there.
Or do you think I setup the spi-channel in SPIN in my own mtehod and then call un unchanged KyeDOS?
I guess it won't work this way.
Um, if you search the forums for a post by Mike Green about my driver application note documentation you'll find a version of the driver made for the C3 by Mike Green.
thanks for pointing me to this version. Is it called C3 FATEngine?
OK so I have a FATEngine. But how does this FatEngine work together with KyeDos?
Do I simply replace the file "SD3.01_FATEngine.spin"
with the C3-version of the file "SD-MMC_FATEngine.spin" ?
I'm a beginner about the FATEngine and KyeDos and have no overview about what is based on what (like experts have)
So it would be very nice if somebody could post a description of which files to replace where
or attaching a version that works properly on the C3-board.
Comments
Agree. I will too...
Do you have a paypal account?
I can transfer USD 5 to your account.
I am confused with the mountPartition command.
Is this the simple way to do it?
if fat.FATEngineStart(sd_do_pin,sd_clk_pin,sd_di_pin,sd_cs_pin,-1,-1,-1,-1,-1)
\fat.mountPartition(0)
if fat.partitionMounted
lcd.str(string("SDCard Mounted"))
else
lcd.str(string("No SDCard !"))
PRI code ' Put the file system calls in a separate method to trap aborts.
Shouldn't it be called
PRI perform_sd_operations ' Put the file system calls in a separate method to trap aborts.
for better clarity?
I am still a bit confused with the Start and Mount operations.
On FSRW 2.6 I usually mount first at Propeller start up and delay file operations until much later.
Can I start the FATEngine, Mount the SD card but delay the file operations until much later? (maybe hours later)
But the way the example code is shown in the Application Note, once "code" returns it means an error has occurred and the Supervisor Cog cannot proceed as usual.
Do you have an example code where the Supervisor Cog starts the FATEngine, Mounts the SD card and then proceeds with its normal execution without any file operations.
Sorry for being such a slow learner.
Um... for your other question... so, that's the idea. Abort and Return both return error codes to the upper level spin method. So... it's just a mater of chaning that if you want to. But the easist way of writing the error handler is to call a function that actualy has all your code in it and assume that nothing critically worng happens in that code. If it does abort back to the upper level.
Look at the demo SD_card_profilier tester code again. Its best to write your code like that. Because it will be robust. I could have broken up the large function where I preform all SD card operations into smaller functions with different error handlers but there wsa no need to. May you do have a need to.
Are you working for Parallax now?
Another question,
I am now using the latest SD-MMC-FATEngine. ( without RTC )
Previously in FSRW, i use
sd.setdate(years,months,days,hours,minutes,seconds)
to set the date and time before creating a new file so that the file date and time stamp is correct even though there is no RTC chip.
I can't find the equivalent in FATEngine. How do I do this in FATEngine?
If you want to add time stamping features... look at the "readTime" funtion in the versions with the RTC and then put the code that you think you need for that function in the "readTime" function in the version without the RTCs. Its really simple. You'll understand what to do no problem.
Jonathan
P.S. Dave, I'm working on back-porting your directory support into the FSRW C source, for an intermediate release of FSRW...I already have the safe block driver reading and writing at > 1MB/s (w/ 32kB clusters...slightly slower writing under FAT32 with 8kB clusters).
It seems that openFile with append mode does not create the file if it does not exist, unlike popen in FSRW.
How do I make openFile create a file automatically if the filename does not exist?
How to check for existence of a file?
Sorry for so many questions.
SD_MMC_FATEngine.spin (version 2.0) from Obex and AN006 dated 25/9/2011
SD_3.01_FATEngine.spin (version log stops at 1.7) from Dracs KyeDos3.0 dated 6/1/2011
BTW here are my results for the version 2.0
### SD Card Profile ###
Disk Signature: 0x00000000
Partition 0 - 0xDC666872
R3_20120120 FAT16
512 - Bytes Per Sector
32 - Sectors Per Cluster
1982944 - Total Sectors
61967 - Total Clusters
64 - Used Sectors
1982880 - Free Sectors
32 KB Stride Speed Test:
writeByte - 4 KBs
writeShort - 8 KBs
writeLong - 14 KBs
writeData - 128 KBs
readByte - 4 KBs
readShort - 8 KBs
readLong - 16 KBs
readData - 330 KBs
I open a number of files for read only to determine the starting sector address in ZiCog. The I access the SD pasm driver directly to read and write sectors from CPM. I have tried a number of the PRI routines but nothing returns the files first sector address on the card. Any tips on how to get this?
...
That's a nice fast SD card you have there!
...
The readWriteCurrentSector function returns the sector number it was called on. That function basically encapsulates the logic for figure out what sector to read or write given the "current cluster" and "current byte" and it sets the "current sector". The "current sector" variable is equal to the "current byte" variable divided by 512. However, the "current byte" variable may be ahead of the "current sector" variable - this allows me to know when to switch clusters... if you look at the readWriteCurrentCluster code...
Anyway, just look at what "readWriteCurrentSector" returns to get the sector number from the start of the partition... then add in the "hiddenSectors" variable to get the absolute sector number. You could make a function that does exactly what "readWriteCurrentSector" does without the reading and writing part. If you plan on using the "readWriteBLock" function you don't need to add in the "hiddenSectors" variable.
Thanks,
reads really good what you have coded so far. How much would it take to add constants (or maybe conditional compiling directives) to switch the SD-card-routines
to the Prop-C3-board?
Some months ago I made some quick tries to get KyeDOS working on the C3 but had no success mainly because I did not rty it long enough to understand what I have to change.
keep up the good work
best regards
Stefan
Thank you
rich
@richaj45, the SD card needs 4 pins - chip select (low to enable), data out, data in, clock.
Of course, if you are feeling cunning you can have multiple SPI devices sharing data out, data in and clock, and then you only need one pin per device to drive chip select.
My card is a 1GB SanDisk. The test was done on a RamBlade3 - I am running at 6.5MHz (104MHz) Its a nice speed improvement!
richaj: I presume you are meaning is it a 1bit SPI interface or the faster 4bit parallel interface. Sorry, its the 1bit because the 4bit requires a licence to use and the payment of big$ to the card consortium.
no it is not done with just changing the pin-numbers because the C3 has a SPI-MUX-bus.
So the driver must be adapted to that.
I attach two pictures that I found on the FTP-server for the C3 ftp://ftp.propeller-chip.com/PropC3
To be really honest. In this case I'm really lazy. I don't want to dive into the details of FSRW, SPI-routines and the FAT-Engine.
What I would like to do is download a ready to run KyeDOS-Version adapated to the C3-board.
Download demofiles. Copying them on an empty micro-SD-card download a demofile into the EEPROM.
Switching on the C3-board and have a a DOS-prompt on the serial terminal. Not on VGA (eating too much memory) , No TV (don't have a small TV handy).
Serial is what you have as soon as you want to download code into the EEPROM or RAM.
I know that's asking for a finished version where others have done all the work. Nobody is forced to fiddle around with the code
If somebody enjoys doing it and testing it until it's running reliably please do it or if somebody has done it already please attach the code
to a posting or upload to the OBEX.
Edit 21.01.2012 this forum-software needs manual quality-checks after uploading. T´he original png-picture was blurred to unreadability through converting it to a "LEGO"-JPG
I uploaded the original png-file as zip to keep the good quality.
bumb: if you (the forum-members) think my wish is to much work for others and too less work on my own I would like to read a clear statement telling the truth what you think about it.
best regards
Stefan
### SD Card Profile ###
Disk Signature: 0x00000000
Partition 0 - 0x146A7AD4
R3_20120120 FAT16
512 - Bytes Per Sector
32 - Sectors Per Cluster
1982944 - Total Sectors
61967 - Total Clusters
217568 - Used Sectors
1765376 - Free Sectors
32 KB Stride Speed Test:
writeByte - 3 KBs
writeShort - 6 KBs
writeLong - 12 KBs
writeData - 206 KBs
readByte - 3 KBs
readShort - 6 KBs
readLong - 12 KBs
readData - 266 KBs
readData... 266 KBs @ 5MHz and 330 KBs @ 6.5MHz nice improvement here!
The writeData is interesting... 206 KBs @ 5MHz and 128 KBs @ 6.5MHz opposite to what was expected!
Read performance should stay constant, however.
---
I'm done collecting data measurements BTW. But, thanks for posting anyway. I think the driver is pretty solid right now. The performance isn't bad on it either.
Well I guess the truth of it is that I don't have a C3 so I haven't written any code for the C3. Sorry.
Looking at the schematic, I think that is a 161 counter chip, so you clear it and then send a certain number of pulses and that selects the SPI device. I don't know which device is the SD card, but I think the code ought to be fairly simple, and you could write it in Spin if you like.
I found a good description here http://www.c3emulation.com/ and there is a description and code here http://www.c3emulation.com/index.php/memory/113-c3-spi-set-channel
thank you for pointing to the C3-emulationsite.
The problem for me is how do I quickly find all the places in the code that are affected by this.
If I understood right. the spi-driver is PASM. So I guess I have to change things there.
Or do you think I setup the spi-channel in SPIN in my own mtehod and then call un unchanged KyeDOS?
I guess it won't work this way.
best regards
Stefan
Thanks,
thanks for pointing me to this version. Is it called C3 FATEngine?
OK so I have a FATEngine. But how does this FatEngine work together with KyeDos?
Do I simply replace the file "SD3.01_FATEngine.spin"
with the C3-version of the file "SD-MMC_FATEngine.spin" ?
I'm a beginner about the FATEngine and KyeDos and have no overview about what is based on what (like experts have)
So it would be very nice if somebody could post a description of which files to replace where
or attaching a version that works properly on the C3-board.
best regards
Stefan