A Simple DOS for Micro Processors

Note:
    This page is also avaliable at the Code Project
    This is a link to newer code using stdint and no DMA (Not fully tested but should be OK.)

mfc_diskio

  • Download source - 76 Kb
  • Introduction

    There were two objectives with this project. To learn how to write effective code for a micro possessor with the Microsoft compiler and to write a simple, effective, DOS for a micro possessor.

    I have been working with the MSP430 micro computer and recently found out that the SPI mode is supported on (most?) micro SD cards. This is encouraging. I have wanted to use inexpensive removable memory that could easily be utilized by anyone from an MSP430 project. That means using the file system of the card, the FAT system, so specialized software is not needed on a Windows platform. This code should work on any micro computer, I have kept all but the low level stuff as plain as possible.

    I started by compiling FatFs directly to the micro. But it didn't work properly and occupied a large amount of ROM. Debugging it started to look like a can of worms.

    FatFs Website

    So I figured that the next place to start would be on a Windows box. I used an MFC application to get going so I could see what my code was doing at run time. It was just nice to have a higher class of debugging tools than appear with a micro computer development system. Next I took a look at DOSFS Embedded FAT by Lewin A.R.W. Edwards in VS. Much better, it has reasonable  documentation in the code. I got to the point where it hung in a loop not recognizing the FAT16 end of file table marker. It was looking for the FAT32 signature. But I could see how it was intended to work.

    DOSFS

    It was big and clunky and I wanted something small and simple. I didn't compile it with MSPGCC but it was advertised to make at about ~4k without the low level code. Not unreasonable for the likes of the MSP430F149. What I found was that what ever code I wrote in VS according to C rules could be ported to the micro with a copy and paste and it would work for the most part. So far I have found only one place where I had to cast with MSPGCC, where I didn't with the Microsoft compiler, so as not to loose the higher part of a DWORD . That was to force a mult16_32, and I plan to write that out. Another thing I saw that was unnecessary in both examples above was a 'Pack Data'. The MSP430 is little endian, just like the x86, so can read and write the FAT data directly. The code I have here, with low level and the main, compiled to ~3k. From the dump, it looks like ~1.5k for the DOS code.

    Background

    For now I'm targeting the MSP430F1612. It has DMA and the code written by F. Foust, Dept. of Electrical and Computer Engineering, Michigan State University, compiled and ran perfectly.

    Application Note - Secure Digital Card Interface for the MSP430

    This is low level access to the SD card that GetSectorData(...) and SetSectorData(...) wrap. A simpler version without DMA will be included in the future.

    My hardware development platform

    platform

    Using the Code(MFC)

    The extras in the MFC code is a call to enumerate drives on the box.

    void EnumDrives( HEDriveInfoSet& inSet );

    You will find the decelerations that support this in "HE_Drives.h" The code is in "HE_Drives.cpp"

    bool GetSectorData( pHEDriveInfo pDrvInfo, long sector, BYTE* buf );
    bool SetSectorData( pHEDriveInfo pDrvInfo, long sector, BYTE* buf );

    These are to read and write raw sectors on any mounted drive so be careful you don't smash your 'C' drive. I'm working on the SD card with a cheap USB adapter. The MFC gadget is a sector viewer, fun, but not that useful after all.

    Using the Code(DOS)

    There is test code in "mfc_diskioView.cpp" starting around line 200. Here I just started exercising the DOS code and making sure it reads and writes properly across clusters and appending a file. Once you are into the micro code the Low level access looks like:
    bool GetSectorData( DWORD sector );
    bool SetSectorData( DWORD sector );

    The buffer RAM is shared and there is only one drive on the micro. The code that ports to the micro is in "HE_dos.cpp" and "HE_dos.h". But there is no C++ in any of the code that ports. MSPGCC does an excellent job with C but I haven't tried to beat it up with C++. At that, I think abstraction is great for PC software, but you will tend to be very aware of what happens at the machine level with a micro. C++ is probably over kill for a few K of code. Besides, OO is in the mind...

    The function calls for the DOS interface are about as straight forward as it gets. There are only two structures. One for the drive volume information. Its data is persistent and lives for the life of the application. One for an 'open' file and that data remains valid once a file is 'opened'. There is no 'Close File', instead there is a flush file. After a flush you can keep using the file or discard the file info data as if the file were closed. The 'get-put' sector level does caching. There are two reasons for caching. First is that the DOS code does not have to check for unnecessary reads and writes. Second is to save on battery life. Caching is pretty simple at the level of a single buffer. The PC example is in code starting near the top of "mfc_diskioView.cpp".

    One feature of this code is there is no mult or div math. (One exception noted and will be cleaned up.) All mults and divs are done with shifts. And the compiler is smart enough to translate a val << 8 into dropping the low byte and and moving over the bytes. Likewise, a val << 9 or >> 9 is just one shift.

    The code is bare bones, just enough to get the job done. I looked to keep the proper information on the volume and files so as to hold down the math and indirection. After I sleep on this I may find I can do more to make it size and speed efficient.

    DOS Declarations

    All of the below return true if successful.


    Call this once after a micro reset, (RAM power up), to initialize the volume information.

    bool HEDsk_LoadVolumeInfo( );

    This is the 'Open' for a file. It initializes the file info for an existing file. The name is canonical, i.e., in the form of "TEST    TXT". No flags, it is open for read and write and must exist. Just 11 BYTES for the name, a trailing null is not necessary. The file pointer is set to zero.

    bool HEDsk_GetFileInfo( pHEDskFileInfo pInfo, char* lpsCanonicalName );

    Reads 'count' of BYTES into buf from the file. Moves the file pointer up by count. Reading past the end of file is undetermined.

    bool HEDsk_ReadFile( pHEDskFileInfo pInfo, BYTE* buf, WORD count );

    Writes 'count' in BYTES from buf to the file from the current file pointer. Will extend the size of the file if needed.

    bool HEDsk_WriteFile( pHEDskFileInfo pInfo, BYTE* buf, WORD count );

    Sets the file pointer to pos. No check is made to make sure pos < fileSize. The file size is available in pInfo->size.

    bool HEDsk_SeekFile( pHEDskFileInfo pInfo, DWORD pos );

    This will write off the file infromation to the drive. The file is still open and pointers are still in place as they were before the call.

    bool HEDsk_FlushFile( pHEDskFileInfo pInfo );

    This code was run on the MSP430 and wrote the card fine:

    HEDsk_LoadVolumeInfo( );

    if( HEDsk_GetFileInfo( &heFileInfo, "TEST TXT" ) )
    {
    for( j= 0; j < 100; ++j )
    {
    P1OUT ^= BIT4; // Toggle LED
    HEDsk_WriteFile( &heFileInfo, "this is a test\r\n", 16 );
    }
    HEDsk_FlushFile( &heFileInfo );
    }
    There is a folder in the project called MspCode with all the files for the micro.

    TODO

    Things that may happen in the future is to add optional code with ifdefs so files can be created and zeroed if needed. There is no handling the 'date modified' of the file. For a card that will be moved from the micro to a box this is not a real issue. But while working on the box alone the OS will not see that the file is modified and the cache may stay stale. I have had to pull the card and reinsert it to get a fresh copy of files. I tried one hack that didn't work in 'HEDsk_FlushFile', If you know one, let me know. Even if this is extended to handle FAT32, I would never look to support FAT12, I don't see the point.

    Points of Interest

    More on the MSP430 here

    History

        October 29, 2009
           Added the call 'HEDsk_FlushFile'. In the case that small writes to the file buffer are made it does not make sense to save the file info on every write.

    Thanks, Dan.