SD Good Code
SD Good Code
1 //###########################################################################
2 //
3 // FILE: sd_card.c
4 //
5 // TITLE: Example program for reading files from an SD card.
6 //
7 //! \addtogroup cpu01_example_list
8 //! <h1>SD card using FAT file system (sd_card)</h1>
9 //!
10 //! This example application demonstrates reading a file system from
11 //! an SD card. It makes use of FatFs, a FAT file system driver.
12 //!
13 //! For additional details about FatFs, see the following site:
14 //! http://elm-chan.org/fsw/ff/00index_e.html
15 //!
16 //! The application may be operated via a serial terminal attached to
17 //! UART0. The RS232 communication parameters should be set to 115,200 bits
18 //! per second, and 8-n-1 mode. When the program is started a message will be
19 //! printed to the terminal. Type ``help'' for command help.
20 //!
21 //
22 //###########################################################################
23 // $TI Release: F2837xD Support Library v210 $
24 // $Release Date: Tue Nov 1 14:46:15 CDT 2016 $
25 // $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
26 // http://www.ti.com/ ALL RIGHTS RESERVED $
27 //###########################################################################
28
29 //
30 // Included Files
31 //
32 #include "F28x_Project.h"
33 #include <string.h>
34 #include "inc/hw_ints.h"
35 #include "inc/hw_memmap.h"
36 #include "inc/hw_types.h"
37 #include "driverlib/interrupt.h"
38 #include "driverlib/sysctl.h"
39 #include "driverlib/systick.h"
40 #include "utils/cmdline.h"
41 #include "utils/uartstdio.h"
42 #include "utils/ustdlib.h"
43 #include "third_party/fatfs/src/ff.h"
44 #include "third_party/fatfs/src/diskio.h"
45
46 //
47 // Defines
48 //
49 #define PATH_BUF_SIZE 80 // Defines the size of the buffers that hold the
50 // path, or temporary data from the SD card.
51 // There are two buffers allocated of this size.
52 // The buffer size must be large enough to hold
53 // the longest expected full path name,
54 // including the file name, and a trailing null
55 // character.
56 #define CMD_BUF_SIZE 64 // Defines the size of the buffer that holds
57 // the command line.
58 #define FRESULT_ENTRY(f) { (f), (# f) } // A macro to make it easy to
59 // add result codes to the table
60 #define NAME_TOO_LONG_ERROR 1 // Error reasons returned
61 #define OPENDIR_ERROR 2 // by ChangeDirectory().
62 #define NUM_FRESULT_CODES (sizeof(g_sFresultStrings) / sizeof(tFresultString))
Page 1
sd_card.c
Page 2
sd_card.c
125 FRESULT_ENTRY(FR_INVALID_OBJECT),
126 FRESULT_ENTRY(FR_MKFS_ABORTED)
127 };
128
129 const char *g_ppcDirListStrings[NUM_LIST_STRINGS]; // Storage for the filename
130 // listbox widget string
131 // table.
132
133 //
134 // Storage for the names of the files in the current directory. Filenames
135 // are stored in format "(D) filename.ext" for directories or
136 // "(F) filename.ext" for files.
137 //
138 char g_pcFilenames[NUM_LIST_STRINGS][MAX_FILENAME_STRING_LEN];
139
140 //
141 // Storage for the strings which appear in the status box at the bottom of the
142 // display.
143 //
144 char g_pcStatus[NUM_STATUS_STRINGS][MAX_STATUS_STRING_LEN];
145
146 //
147 // Storage for the status listbox widget string table.
148 //
149 const char *g_ppcStatusStrings[NUM_STATUS_STRINGS] =
150 {
151 g_pcStatus[0],
152 g_pcStatus[1],
153 g_pcStatus[2],
154 g_pcStatus[3],
155 g_pcStatus[4],
156 g_pcStatus[5]
157 };
158 unsigned long g_ulStatusStringIndex = 0;
159
160 //
161 // Forward declarations for functions called by the widgets used in the user
162 // interface.
163 //
164 static FRESULT ChangeToDirectory(char *pcDirectory, unsigned long *pulReason);
165 static const char *StringFromFresult(FRESULT fresult);
166
167 //
168 // Function Prototypes
169 //
170 extern void UARTStdioIntHandler(void);
171
172 //
173 // StringFromFresult - This function returns a string representation of an
174 // error code that was returned from a function call to
175 // FatFs. It can be used for printing human readable
176 // error messages.
177 //
178 static const char *
179 StringFromFresult(FRESULT fresult)
180 {
181 unsigned int uIdx;
182
183 //
184 // Enter a loop to search the error code table for a matching
185 // error code.
186 //
Page 3
sd_card.c
Page 4
sd_card.c
249 ulFileCount = 0;
250 ulDirCount = 0;
251 ulItemCount = 0;
252
253 //
254 // Give an extra blank line before the listing.
255 //
256 UARTprintf("\n");
257
258 //
259 // Enter loop to enumerate through all directory entries.
260 //
261 for(;;)
262 {
263 //
264 // Read an entry from the directory.
265 //
266 fresult = f_readdir(&g_sDirObject, &g_sFileInfo);
267
268 //
269 // Check for error and return if there is a problem.
270 //
271 if(fresult != FR_OK)
272 {
273 return(fresult);
274 }
275
276 //
277 // If the file name is blank, then this is the end of the
278 // listing.
279 //
280 if(!g_sFileInfo.fname[0])
281 {
282 break;
283 }
284
285 //
286 // Print the entry information on a single line with formatting
287 // to show the attributes, date, time, size, and name.
288 //
289 UARTprintf("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9u %s\n",
290 (g_sFileInfo.fattrib & AM_DIR) ? (uint32_t)'D' : (uint32_t)'-',
291 (g_sFileInfo.fattrib & AM_RDO) ? (uint32_t)'R' : (uint32_t)'-',
292 (g_sFileInfo.fattrib & AM_HID) ? (uint32_t)'H' : (uint32_t)'-',
293 (g_sFileInfo.fattrib & AM_SYS) ? (uint32_t)'S' : (uint32_t)'-',
294 (g_sFileInfo.fattrib & AM_ARC) ? (uint32_t)'A' : (uint32_t)'-',
295 (uint32_t)((g_sFileInfo.fdate >> 9) + 1980),
296 (uint32_t)((g_sFileInfo.fdate >> 5) & 15),
297 (uint32_t)(g_sFileInfo.fdate & 31),
298 (uint32_t)((g_sFileInfo.ftime >> 11)),
299 (uint32_t)((g_sFileInfo.ftime >> 5) & 63),
300 (uint32_t)(g_sFileInfo.fsize),
301 g_sFileInfo.fname);
302
303 //
304 // Add the information as a line in the listbox widget.
305 //
306 if(ulItemCount < NUM_LIST_STRINGS)
307 {
308 usprintf(g_pcFilenames[ulItemCount], "(%c) %12s",
309 (g_sFileInfo.fattrib & AM_DIR) ? 'D' : 'F',
310 g_sFileInfo.fname);
Page 5
sd_card.c
311 }
312
313 //
314 // If the attribute is directory, then increment the directory count.
315 //
316 if(g_sFileInfo.fattrib & AM_DIR)
317 {
318 ulDirCount++;
319 }
320 //
321 // Otherwise, it is a file. Increment the file count, and
322 // add in the file size to the total.
323 //
324 else
325 {
326 ulFileCount++;
327 ulTotalSize += g_sFileInfo.fsize;
328 }
329
330 //
331 // Move to the next entry in the item array we use to populate the
332 // list box.
333 //
334 ulItemCount++;
335
336 //
337 // Wait for the UART transmit buffer to empty.
338 //
339 // UARTFlushTx(false);
340 }
341
342 //
343 // Print summary lines showing the file, dir, and size totals.
344 //
345 UARTprintf("\n%4u File(s),%10u bytes total\n%4u Dir(s)",
346 ulFileCount, ulTotalSize, ulDirCount);
347
348 //
349 // Get the free space.
350 //
351 fresult = f_getfree("/", &ulTotalSize, &pFatFs);
352
353 //
354 // Check for error and return if there is a problem.
355 //
356 if(fresult != FR_OK)
357 {
358 return(fresult);
359 }
360
361 //
362 // Display the amount of free space that was calculated.
363 //
364 UARTprintf(", %10uK bytes free\n", ulTotalSize * pFatFs->sects_clust / 2);
365
366 //
367 // Wait for the UART transmit buffer to empty.
368 //
369 // UARTFlushTx(false);
370
371 //
372 // Made it to here, return with no errors.
Page 6
sd_card.c
373 //
374 return(0);
375 }
376
377 //
378 // ChangeToDirectory - This function implements the "cd" command. It takes an
379 // argument that specifies the directory to make the
380 // current working directory. Path separators must use a
381 // forward slash "/". The argument to cd can be one of the
382 // following:
383 // * root ("/")
384 // * a fully specified path ("/my/path/to/mydir")
385 // * a single directory name that is in the current
386 // directory ("mydir")
387 // * parent directory ("..")
388 // It does not understand relative paths, so don't try
389 // something like this: ("../my/new/path")
390 // Once the new directory is specified, it attempts to open
391 // the directory to make sure it exists. If the new path
392 // is opened successfully, then the current working
393 // directory (cwd) is changed to the new path. In cases of
394 // error, the pulReason parameter will be written with one
395 // of the following values:
396 //
397 static FRESULT
398 ChangeToDirectory(char *pcDirectory, unsigned long *pulReason)
399 {
400 unsigned int uIdx;
401 FRESULT fresult;
402
403 //
404 // Copy the current working path into a temporary buffer so
405 // it can be manipulated.
406 //
407 strcpy(g_cTmpBuf, g_cCwdBuf);
408
409 //
410 // If the first character is /, then this is a fully specified
411 // path, and it should just be used as-is.
412 //
413 if(pcDirectory[0] == '/')
414 {
415 //
416 // Make sure the new path is not bigger than the cwd buffer.
417 //
418 if(strlen(pcDirectory) + 1 > sizeof(g_cCwdBuf))
419 {
420 *pulReason = NAME_TOO_LONG_ERROR;
421 return(FR_OK);
422 }
423 //
424 // If the new path name (in argv[1]) is not too long, then
425 // copy it into the temporary buffer so it can be checked.
426 //
427 else
428 {
429 strncpy(g_cTmpBuf, pcDirectory, sizeof(g_cTmpBuf));
430 }
431 }
432 //
433 // If the argument is .. then attempt to remove the lowest level
434 // on the CWD.
Page 7
sd_card.c
435 //
436 else if(!strcmp(pcDirectory, ".."))
437 {
438 //
439 // Get the index to the last character in the current path.
440 //
441 uIdx = strlen(g_cTmpBuf) - 1;
442
443 //
444 // Back up from the end of the path name until a separator (/)
445 // is found, or until we bump up to the start of the path.
446 //
447 while((g_cTmpBuf[uIdx] != '/') && (uIdx > 1))
448 {
449 //
450 // Back up one character.
451 //
452 uIdx--;
453 }
454
455 //
456 // Now we are either at the lowest level separator in the
457 // current path, or at the beginning of the string (root).
458 // So set the new end of string here, effectively removing
459 // that last part of the path.
460 //
461 g_cTmpBuf[uIdx] = 0;
462 }
463 //
464 // Otherwise this is just a normal path name from the current
465 // directory, and it needs to be appended to the current path.
466 //
467 else
468 {
469 //
470 // Test to make sure that when the new additional path is
471 // added on to the current path, there is room in the buffer
472 // for the full new path. It needs to include a new separator,
473 // and a trailing null character.
474 //
475 if(strlen(g_cTmpBuf) + strlen(pcDirectory) + 1 + 1 > sizeof(g_cCwdBuf))
476 {
477 *pulReason = NAME_TOO_LONG_ERROR;
478 return(FR_INVALID_OBJECT);
479 }
480 //
481 // The new path is okay, so add the separator and then append
482 // the new directory to the path.
483 //
484 else
485 {
486 //
487 // If not already at the root level, then append a /
488 //
489 if(strcmp(g_cTmpBuf, "/"))
490 {
491 strcat(g_cTmpBuf, "/");
492 }
493
494 //
495 // Append the new directory to the path.
496 //
Page 8
sd_card.c
Page 9
sd_card.c
Page 10
sd_card.c
621 // First, check to make sure that the current path (CWD), plus
622 // the file name, plus a separator and trailing null, will all
623 // fit in the temporary buffer that will be used to hold the
624 // file name. The file name must be fully specified, with path,
625 // to FatFs.
626 //
627 if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
628 {
629 UARTprintf("Resulting path name is too long\n");
630 return(0);
631 }
632
633 //
634 // Copy the current path to the temporary buffer so it can be manipulated.
635 //
636 strcpy(g_cTmpBuf, g_cCwdBuf);
637
638 //
639 // If not already at the root level, then append a separator.
640 //
641 if(strcmp("/", g_cCwdBuf))
642 {
643 strcat(g_cTmpBuf, "/");
644 }
645
646 //
647 // Now finally, append the file name to result in a fully specified file.
648 //
649 strcat(g_cTmpBuf, argv[1]);
650
651 //
652 // Open the file for reading.
653 //
654 fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_READ);
655
656 //
657 // If there was some problem opening the file, then return
658 // an error.
659 //
660 if(fresult != FR_OK)
661 {
662 return(fresult);
663 }
664
665 //
666 // Enter a loop to repeatedly read data from the file and display it,
667 // until the end of the file is reached.
668 //
669 do
670 {
671 //
672 // Read a block of data from the file. Read as much as can fit
673 // in the temporary buffer, including a space for the trailing null.
674 //
675 fresult = f_read(&g_sFileObject, g_cTmpBuf, sizeof(g_cTmpBuf) - 1,
676 &usBytesRead);
677
678 //
679 // If there was an error reading, then print a newline and
680 // return the error to the user.
681 //
682 if(fresult != FR_OK)
Page 11
sd_card.c
683 {
684 UARTprintf("\n");
685 return(fresult);
686 }
687
688 //
689 // Null terminate the last block that was read to make it a
690 // null terminated string that can be used with printf.
691 //
692 g_cTmpBuf[usBytesRead] = 0;
693
694 //
695 // Print the last chunk of the file that was received.
696 //
697 UARTprintf("%s", g_cTmpBuf);
698
699 //
700 // Continue reading until less than the full number of bytes are
701 // read. That means the end of the buffer was reached.
702 //
703 }
704 while(usBytesRead == sizeof(g_cTmpBuf) - 1);
705
706 //
707 // Return success.
708 //
709 return(0);
710 }
711
712 //
713 // Cmd_help - This function implements the "help" command. It prints a simple
714 // list of the available commands with a brief description.
715 //
716 int
717 Cmd_help(int argc, char *argv[])
718 {
719 tCmdLineEntry *pEntry;
720
721 //
722 // Print some header text.
723 //
724 UARTprintf("\nAvailable commands\n");
725 UARTprintf("------------------\n");
726
727 //
728 // Point at the beginning of the command table.
729 //
730 pEntry = &g_psCmdTable[0];
731
732 //
733 // Enter a loop to read each entry from the command table. The
734 // end of the table has been reached when the command name is NULL.
735 //
736 while(pEntry->pcCmd)
737 {
738 //
739 // Print the command name and the brief description.
740 //
741 UARTprintf("%s%s\n", pEntry->pcCmd, pEntry->pcHelp);
742
743 //
744 // Advance to the next entry in the table.
Page 12
sd_card.c
745 //
746 pEntry++;
747 }
748
749 //
750 // Return success.
751 //
752 return(0);
753 }
754
755 //
756 // This is the table that holds the command names, implementing functions,
757 // and brief description.
758 //
759 tCmdLineEntry g_psCmdTable[] =
760 {
761 { "help", Cmd_help, " : Display list of commands" },
762 { "h", Cmd_help, " : alias for help" },
763 { "?", Cmd_help, " : alias for help" },
764 { "ls", Cmd_ls, " : Display list of files" },
765 { "chdir", Cmd_cd, ": Change directory" },
766 { "cd", Cmd_cd, " : alias for chdir" },
767 { "pwd", Cmd_pwd, " : Show current working directory" },
768 { "cat", Cmd_cat, " : Show contents of a text file" },
769 { 0, 0, 0 }
770 };
771
772 //
773 // __error__ - The error routine that is called if the driver library
774 // encounters an error.
775 //
776 #ifdef DEBUG
777 void
778 __error__(char *pcFilename, unsigned long ulLine)
779 {
780 }
781 #endif
782
783 //
784 // ConfigureUART - Configure the UART and its pins. This must be called
785 // before UARTprintf().
786 //
787 void
788 ConfigureUART(void)
789 {
790 //
791 // Enable UART0
792 //
793 SysCtlPeripheralEnable(SYSCTL_PERIPH_SCI1);
794
795 //
796 // Configure GPIO Pins for UART mode.
797 //
798 EALLOW;
799 GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 1;
800 GpioCtrlRegs.GPAPUD.bit.GPIO28 = 0;
801 GpioCtrlRegs.GPAQSEL2.bit.GPIO28 = 3;
802 GpioCtrlRegs.GPADIR.bit.GPIO28 = 0;
803
804 GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 1;
805 GpioCtrlRegs.GPAPUD.bit.GPIO29 = 0;
806 GpioCtrlRegs.GPADIR.bit.GPIO29 = 1;
Page 13
sd_card.c
807 EDIS;
808
809 //
810 // Initialize the UART for console I/O.
811 //
812 UARTStdioConfig(0, 115200, SysCtlLowSpeedClockGet(SYSTEM_CLOCK_SPEED));
813 }
814
815 //
816 // Main - It performs initialization, then runs a command processing loop to
817 // read commands from the console.
818 //
819 int
820 main(void)
821 {
822 int nStatus;
823 FRESULT fresult;
824
825 //
826 // Set the clocking to run from the PLL at 50MHz
827 //
828 SysCtlClockSet(SYSCTL_OSCSRC_OSC2 | SYSCTL_PLL_ENABLE | SYSCTL_IMULT(10) |
829 SYSCTL_SYSDIV(2));
830 SysCtlAuxClockSet(SYSCTL_OSCSRC_OSC2 | SYSCTL_PLL_ENABLE |
831 SYSCTL_IMULT(12) | SYSCTL_SYSDIV(2)); //60 MHz
832
833 #ifdef _FLASH
834 //
835 // Copy time critical code and Flash setup code to RAM
836 // This includes the following functions: InitFlash();
837 // The RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart
838 // symbols are created by the linker. Refer to the device .cmd file.
839 //
840 memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
841
842 //
843 // Call Flash Initialization to setup flash waitstates
844 // This function must reside in RAM
845 //
846 InitFlash();
847 #endif
848
849 //
850 // Initialize interrupt controller and vector table
851 //
852 InitPieCtrl();
853 InitPieVectTable();
854
855 //
856 // Set the system tick to fire 100 times per second.
857 //
858 SysTickInit();
859 SysTickPeriodSet(SysCtlClockGet(SYSTEM_CLOCK_SPEED) / 100);
860 SysTickIntRegister(SysTickHandler);
861 SysTickIntEnable();
862 SysTickEnable();
863
864 //
865 // Enable Interrupts
866 //
867 IntMasterEnable();
868
Page 14
sd_card.c
869 //
870 // Configure UART0 for debug output.
871 //
872 ConfigureUART();
873
874 //
875 // Print hello message to user.
876 //
877 UARTprintf("\n\nSD Card Example Program\n");
878 UARTprintf("Type \'help\' for help.\n");
879
880 //
881 // Mount the file system, using logical disk 0.
882 //
883
884
885 WORD bw;
886 fresult = f_mount(0, &FatFs);
887 fresult = f_open(&Fil, "arun.txt", FA_WRITE | FA_CREATE_ALWAYS);
888
889
890
891
892
893 fresult = f_lseek(&g_sFileObject,4);
894 fresult = f_write(&Fil, "test", 4, &bw);
895 f_sync(&Fil);
896
897
898
899
900 //fresult = f_mount(0, &g_sFatFs);
901 if(fresult != FR_OK)
902 {
903 UARTprintf("f_mount error: %s\n", StringFromFresult(fresult));
904 return(1);
905 }
906
907 //
908 // Enter an (almost) infinite loop for reading and processing commands from
909 // the user.
910 //
911 while(1)
912 {
913 //
914 // Print a prompt to the console. Show the CWD.
915 //
916 UARTprintf("\n%s> ", g_cCwdBuf);
917
918 //
919 // Get a line of text from the user.
920 //
921 UARTgets(g_cCmdBuf, sizeof(g_cCmdBuf));
922
923 //
924 // Pass the line from the user to the command processor.
925 // It will be parsed and valid commands executed.
926 //
927 nStatus = CmdLineProcess(g_cCmdBuf);
928
929 //
930 // Handle the case of bad command.
Page 15
sd_card.c
931 //
932 if(nStatus == CMDLINE_BAD_CMD)
933 {
934 UARTprintf("Bad command!\n");
935 }
936 //
937 // Handle the case of too many arguments.
938 //
939 else if(nStatus == CMDLINE_TOO_MANY_ARGS)
940 {
941 UARTprintf("Too many arguments for command processor!\n");
942 }
943
944 //
945 // Otherwise the command was executed. Print the error
946 // code if one was returned.
947 //
948 else if(nStatus != 0)
949 {
950 UARTprintf("Command returned error code %s\n",
951 StringFromFresult((FRESULT)nStatus));
952 }
953 }
954 }
955
956 //
957 // End of file
958 //
959
Page 16