main.c
上传用户:wybzxr
上传日期:2020-02-23
资源大小:263k
文件大小:20k
源码类别:

单片机开发

开发平台:

C/C++

  1. /*
  2.  * Copyright (c) 2006-2008 by Roland Riegel <feedback@roland-riegel.de>
  3.  *
  4.  * This file is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License version 2 as
  6.  * published by the Free Software Foundation.
  7.  */
  8. #include <string.h>
  9. #include <avr/pgmspace.h>
  10. #include <avr/sleep.h>
  11. #include "fat.h"
  12. #include "fat_config.h"
  13. #include "partition.h"
  14. #include "sd_raw.h"
  15. #include "sd_raw_config.h"
  16. #include "uart.h"
  17. #define DEBUG 1
  18. /**
  19.  * mainpage MMC/SD card example application
  20.  *
  21.  * This project is a small test application which implements read and write
  22.  * support for MMC, SD and SDHC cards.
  23.  *
  24.  * It includes
  25.  * - low-level link sd_raw MMC, SD and SDHC read/write routines endlink
  26.  * - link partition partition table support endlink
  27.  * - a simple link fat FAT16/FAT32 read/write implementation endlink
  28.  *
  29.  * section circuit The circuit
  30.  * The curcuit board is a self-made and self-soldered board consisting of a single
  31.  * copper layer and standard DIL components, except of the MMC/SD card connector.
  32.  *
  33.  * The connector is soldered to the bottom side of the board. It has a simple
  34.  * eject button which, when a card is inserted, needs some space beyond the connector
  35.  * itself. As an additional feature the connector has two electrical switches
  36.  * to detect wether a card is inserted and wether this card is write-protected.
  37.  * 
  38.  * I used two microcontrollers during development, the Atmel ATmega8 with 8kBytes
  39.  * of flash, and its pin-compatible alternative, the ATmega168 with 16kBytes flash.
  40.  * The first one is the one I started with, but when I implemented FAT16 write
  41.  * support, I ran out of flash space and switched to the ATmega168. For FAT32, an
  42.  * ATmega328 is required.
  43.  * 
  44.  * section pictures Pictures
  45.  * image html pic01.jpg "The circuit board used to implement and test this application."
  46.  * image html pic02.jpg "The MMC/SD card connector on the soldering side of the circuit board."
  47.  *
  48.  * section software The software
  49.  * The software is written in pure standard ANSI-C. Sure, it might not be the
  50.  * smallest or the fastest one, but I think it is quite flexible.
  51.  *
  52.  * I implemented a simple command prompt which is accessible via the UART at 9600 Baud. With
  53.  * commands similiar to the Unix shell you can browse different directories, read and write
  54.  * files, create new ones and delete them again. Not all commands are available in all
  55.  * software configurations.
  56.  * - <tt>cat <file></tt>n
  57.  *   Writes a hexdump of <file> to the terminal.
  58.  * - <tt>cd <directory></tt>n
  59.  *   Changes current working directory to <directory>.
  60.  * - <tt>disk</tt>n
  61.  *   Shows card manufacturer, status, filesystem capacity and free storage space.
  62.  * - <tt>init</tt>n
  63.  *   Reinitializes and reopens the memory card.
  64.  * - <tt>ls</tt>n
  65.  *   Shows the content of the current directory.
  66.  * - <tt>mkdir <directory></tt>n
  67.  *   Creates a directory called <directory>.
  68.  * - <tt>rm <file></tt>n
  69.  *   Deletes <file>.
  70.  * - <tt>sync</tt>n
  71.  *   Ensures all buffered data is written to the card.
  72.  * - <tt>touch <file></tt>n
  73.  *   Creates <file>.
  74.  * - <tt>write <file> <offset></tt>n
  75.  *   Writes text to <file>, starting from <offset>. The text is read
  76.  *   from the UART, line by line. Finish with an empty line.
  77.  *
  78.  * htmlonly
  79.  * <p>
  80.  * The following table shows some typical code sizes in bytes, using the 20061101 release with malloc()/free():
  81.  * </p>
  82.  *
  83.  * <table border="1" cellpadding="2">
  84.  *     <tr>
  85.  *         <th>layer</th>
  86.  *         <th>code size</th>
  87.  *         <th>static RAM usage</th>
  88.  *     </tr>
  89.  *     <tr>
  90.  *         <td>MMC/SD (read-only)</td>
  91.  *         <td align="right">1576</td>
  92.  *         <td align="right">0</td>
  93.  *     </tr>
  94.  *     <tr>
  95.  *         <td>MMC/SD (read-write)</td>
  96.  *         <td align="right">2202</td>
  97.  *         <td align="right">517</td>
  98.  *     </tr>
  99.  *     <tr>
  100.  *         <td>Partition</td>
  101.  *         <td align="right">418</td>
  102.  *         <td align="right">0</td>
  103.  *     </tr>
  104.  *     <tr>
  105.  *         <td>FAT16 (read-only)</td>
  106.  *         <td align="right">3834</td>
  107.  *         <td align="right">0</td>
  108.  *     </tr>
  109.  *     <tr>
  110.  *         <td>FAT16 (read-write)</td>
  111.  *         <td align="right">7932</td>
  112.  *         <td align="right">0</td>
  113.  *     </tr>
  114.  * </table>
  115.  *
  116.  * <p>
  117.  * The static RAM in the read-write case is used for buffering memory card
  118.  * access. Without this buffer, implementation would have been much more complicated.
  119.  * </p>
  120.  * 
  121.  * <p>
  122.  * Please note that the numbers above do not include the C library functions
  123.  * used, e.g. malloc()/free() and some string functions. These will raise the
  124.  * numbers somewhat if they are not already used in other program parts.
  125.  * </p>
  126.  * 
  127.  * <p>
  128.  * When opening a partition, filesystem, file or directory, a little amount
  129.  * of dynamic RAM is used, as listed in the following table. Alternatively,
  130.  * the same amount of static RAM can be used.
  131.  * </p>
  132.  *
  133.  * <table border="1" cellpadding="2">
  134.  *     <tr>
  135.  *         <th>descriptor</th>
  136.  *         <th>dynamic/static RAM</th>
  137.  *     </tr>
  138.  *     <tr>
  139.  *         <td>partition</td>
  140.  *         <td align="right">17</td>
  141.  *     </tr>
  142.  *     <tr>
  143.  *         <td>filesystem</td>
  144.  *         <td align="right">26</td>
  145.  *     </tr>
  146.  *     <tr>
  147.  *         <td>file</td>
  148.  *         <td align="right">51</td>
  149.  *     </tr>
  150.  *     <tr>
  151.  *         <td>directory</td>
  152.  *         <td align="right">47</td>
  153.  *     </tr>
  154.  * </table>
  155.  * 
  156.  * endhtmlonly
  157.  *
  158.  * section adaptation Adapting the software to your needs
  159.  * The only hardware dependent part is the communication
  160.  * layer talking to the memory card. The other parts like partition table and FAT
  161.  * support are completely independent, you could use them even for managing
  162.  * Compact Flash cards or standard ATAPI hard disks.
  163.  *
  164.  * By changing the MCU* variables in the Makefile, you can use other Atmel
  165.  * microcontrollers or different clock speeds. You might also want to change
  166.  * the configuration defines in the files fat_config.h, partition_config.h,
  167.  * sd_raw_config.h and sd-reader_config.h. For example, you could disable
  168.  * write support completely if you only need read support.
  169.  * 
  170.  * section bugs Bugs or comments?
  171.  * If you have comments or found a bug in the software - there might be some
  172.  * of them - you may contact me per mail at feedback@roland-riegel.de.
  173.  *
  174.  * section acknowledgements Acknowledgements
  175.  * Thanks go to Ulrich Radig, who explained on his homepage how to interface
  176.  * MMC cards to the Atmel microcontroller (http://www.ulrichradig.de/).
  177.  * I adapted his work for my circuit. Although this is a very simple
  178.  * solution, I had no problems using it.
  179.  * 
  180.  * section copyright Copyright 2006-2008 by Roland Riegel
  181.  * This program is free software; you can redistribute it and/or modify it under
  182.  * the terms of the GNU General Public License version 2 as published by
  183.  * the Free Software Foundation (http://www.gnu.org/copyleft/gpl.html).
  184.  * At your option, you can alternatively redistribute and/or modify the following
  185.  * files under the terms of the GNU Lesser General Public License version 2.1
  186.  * as published by the Free Software Foundation (http://www.gnu.org/copyleft/lgpl.html):
  187.  * - byteordering.c
  188.  * - byteordering.h
  189.  * - fat.c
  190.  * - fat.h
  191.  * - fat_config.h
  192.  * - partition.c
  193.  * - partition.h
  194.  * - partition_config.h
  195.  * - sd_raw.c
  196.  * - sd_raw.h
  197.  * - sd_raw_config.h
  198.  * - sd-reader_config.h
  199.  */
  200. static uint8_t read_line(char* buffer, uint8_t buffer_length);
  201. static uint32_t strtolong(const char* str);
  202. static uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry);
  203. static struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name); 
  204. static uint8_t print_disk_info(const struct fat_fs_struct* fs);
  205. int main()
  206. {
  207.     /* we will just use ordinary idle mode */
  208.     set_sleep_mode(SLEEP_MODE_IDLE);
  209.     /* setup uart */
  210.     uart_init();
  211.     while(1)
  212.     {
  213.         /* setup sd card slot */
  214.         if(!sd_raw_init())
  215.         {
  216. #if DEBUG
  217.             uart_puts_p(PSTR("MMC/SD initialization failedn"));
  218. #endif
  219.             continue;
  220.         }
  221.         /* open first partition */
  222.         struct partition_struct* partition = partition_open(sd_raw_read,
  223.                                                             sd_raw_read_interval,
  224.                                                             sd_raw_write,
  225.                                                             sd_raw_write_interval,
  226.                                                             0
  227.                                                            );
  228.         if(!partition)
  229.         {
  230.             /* If the partition did not open, assume the storage device
  231.              * is a "superfloppy", i.e. has no MBR.
  232.              */
  233.             partition = partition_open(sd_raw_read,
  234.                                        sd_raw_read_interval,
  235.                                        sd_raw_write,
  236.                                        sd_raw_write_interval,
  237.                                        -1
  238.                                       );
  239.             if(!partition)
  240.             {
  241. #if DEBUG
  242.                 uart_puts_p(PSTR("opening partition failedn"));
  243. #endif
  244.                 continue;
  245.             }
  246.         }
  247.         /* open file system */
  248.         struct fat_fs_struct* fs = fat_open(partition);
  249.         if(!fs)
  250.         {
  251. #if DEBUG
  252.             uart_puts_p(PSTR("opening filesystem failedn"));
  253. #endif
  254.             continue;
  255.         }
  256.         /* open root directory */
  257.         struct fat_dir_entry_struct directory;
  258.         fat_get_dir_entry_of_path(fs, "/", &directory);
  259.         struct fat_dir_struct* dd = fat_open_dir(fs, &directory);
  260.         if(!dd)
  261.         {
  262. #if DEBUG
  263.             uart_puts_p(PSTR("opening root directory failedn"));
  264. #endif
  265.             continue;
  266.         }
  267.         
  268.         /* print some card information as a boot message */
  269.         print_disk_info(fs);
  270.         /* provide a simple shell */
  271.         char buffer[24];
  272.         while(1)
  273.         {
  274.             /* print prompt */
  275.             uart_putc('>');
  276.             uart_putc(' ');
  277.             /* read command */
  278.             char* command = buffer;
  279.             if(read_line(command, sizeof(buffer)) < 1)
  280.                 continue;
  281.             /* execute command */
  282.             if(strcmp_P(command, PSTR("init")) == 0)
  283.             {
  284.                 break;
  285.             }
  286.             else if(strncmp_P(command, PSTR("cd "), 3) == 0)
  287.             {
  288.                 command += 3;
  289.                 if(command[0] == '')
  290.                     continue;
  291.                 /* change directory */
  292.                 struct fat_dir_entry_struct subdir_entry;
  293.                 if(find_file_in_dir(fs, dd, command, &subdir_entry))
  294.                 {
  295.                     struct fat_dir_struct* dd_new = fat_open_dir(fs, &subdir_entry);
  296.                     if(dd_new)
  297.                     {
  298.                         fat_close_dir(dd);
  299.                         dd = dd_new;
  300.                         continue;
  301.                     }
  302.                 }
  303.                 uart_puts_p(PSTR("directory not found: "));
  304.                 uart_puts(command);
  305.                 uart_putc('n');
  306.             }
  307.             else if(strcmp_P(command, PSTR("ls")) == 0)
  308.             {
  309.                 /* print directory listing */
  310.                 struct fat_dir_entry_struct dir_entry;
  311.                 while(fat_read_dir(dd, &dir_entry))
  312.                 {
  313.                     uint8_t spaces = sizeof(dir_entry.long_name) - strlen(dir_entry.long_name) + 4;
  314.                     uart_puts(dir_entry.long_name);
  315.                     uart_putc(dir_entry.attributes & FAT_ATTRIB_DIR ? '/' : ' ');
  316.                     while(spaces--)
  317.                         uart_putc(' ');
  318.                     uart_putdw_dec(dir_entry.file_size);
  319.                     uart_putc('n');
  320.                 }
  321.             }
  322.             else if(strncmp_P(command, PSTR("cat "), 4) == 0)
  323.             {
  324.                 command += 4;
  325.                 if(command[0] == '')
  326.                     continue;
  327.                 
  328.                 /* search file in current directory and open it */
  329.                 struct fat_file_struct* fd = open_file_in_dir(fs, dd, command);
  330.                 if(!fd)
  331.                 {
  332.                     uart_puts_p(PSTR("error opening "));
  333.                     uart_puts(command);
  334.                     uart_putc('n');
  335.                     continue;
  336.                 }
  337.                 /* print file contents */
  338.                 uint8_t buffer[8];
  339.                 uint32_t offset = 0;
  340.                 while(fat_read_file(fd, buffer, sizeof(buffer)) > 0)
  341.                 {
  342.                     uart_putdw_hex(offset);
  343.                     uart_putc(':');
  344.                     for(uint8_t i = 0; i < 8; ++i)
  345.                     {
  346.                         uart_putc(' ');
  347.                         uart_putc_hex(buffer[i]);
  348.                     }
  349.                     uart_putc('n');
  350.                     offset += 8;
  351.                 }
  352.                 fat_close_file(fd);
  353.             }
  354.             else if(strcmp_P(command, PSTR("disk")) == 0)
  355.             {
  356.                 if(!print_disk_info(fs))
  357.                     uart_puts_p(PSTR("error reading disk infon"));
  358.             }
  359. #if FAT_WRITE_SUPPORT
  360.             else if(strncmp_P(command, PSTR("rm "), 3) == 0)
  361.             {
  362.                 command += 3;
  363.                 if(command[0] == '')
  364.                     continue;
  365.                 
  366.                 struct fat_dir_entry_struct file_entry;
  367.                 if(find_file_in_dir(fs, dd, command, &file_entry))
  368.                 {
  369.                     if(fat_delete_file(fs, &file_entry))
  370.                         continue;
  371.                 }
  372.                 uart_puts_p(PSTR("error deleting file: "));
  373.                 uart_puts(command);
  374.                 uart_putc('n');
  375.             }
  376.             else if(strncmp_P(command, PSTR("touch "), 6) == 0)
  377.             {
  378.                 command += 6;
  379.                 if(command[0] == '')
  380.                     continue;
  381.                 struct fat_dir_entry_struct file_entry;
  382.                 if(!fat_create_file(dd, command, &file_entry))
  383.                 {
  384.                     uart_puts_p(PSTR("error creating file: "));
  385.                     uart_puts(command);
  386.                     uart_putc('n');
  387.                 }
  388.             }
  389.             else if(strncmp_P(command, PSTR("write "), 6) == 0)
  390.             {
  391.                 command += 6;
  392.                 if(command[0] == '')
  393.                     continue;
  394.                 char* offset_value = command;
  395.                 while(*offset_value != ' ' && *offset_value != '')
  396.                     ++offset_value;
  397.                 if(*offset_value == ' ')
  398.                     *offset_value++ = '';
  399.                 else
  400.                     continue;
  401.                 /* search file in current directory and open it */
  402.                 struct fat_file_struct* fd = open_file_in_dir(fs, dd, command);
  403.                 if(!fd)
  404.                 {
  405.                     uart_puts_p(PSTR("error opening "));
  406.                     uart_puts(command);
  407.                     uart_putc('n');
  408.                     continue;
  409.                 }
  410.                 int32_t offset = strtolong(offset_value);
  411.                 if(!fat_seek_file(fd, &offset, FAT_SEEK_SET))
  412.                 {
  413.                     uart_puts_p(PSTR("error seeking on "));
  414.                     uart_puts(command);
  415.                     uart_putc('n');
  416.                     fat_close_file(fd);
  417.                     continue;
  418.                 }
  419.                 /* read text from the shell and write it to the file */
  420.                 uint8_t data_len;
  421.                 while(1)
  422.                 {
  423.                     /* give a different prompt */
  424.                     uart_putc('<');
  425.                     uart_putc(' ');
  426.                     /* read one line of text */
  427.                     data_len = read_line(buffer, sizeof(buffer));
  428.                     if(!data_len)
  429.                         break;
  430.                     /* write text to file */
  431.                     if(fat_write_file(fd, (uint8_t*) buffer, data_len) != data_len)
  432.                     {
  433.                         uart_puts_p(PSTR("error writing to filen"));
  434.                         break;
  435.                     }
  436.                 }
  437.                 fat_close_file(fd);
  438.             }
  439.             else if(strncmp_P(command, PSTR("mkdir "), 6) == 0)
  440.             {
  441.                 command += 6;
  442.                 if(command[0] == '')
  443.                     continue;
  444.                 struct fat_dir_entry_struct dir_entry;
  445.                 if(!fat_create_dir(dd, command, &dir_entry))
  446.                 {
  447.                     uart_puts_p(PSTR("error creating directory: "));
  448.                     uart_puts(command);
  449.                     uart_putc('n');
  450.                 }
  451.             }
  452. #endif
  453. #if SD_RAW_WRITE_BUFFERING
  454.             else if(strcmp_P(command, PSTR("sync")) == 0)
  455.             {
  456.                 if(!sd_raw_sync())
  457.                     uart_puts_p(PSTR("error syncing diskn"));
  458.             }
  459. #endif
  460.             else
  461.             {
  462.                 uart_puts_p(PSTR("unknown command: "));
  463.                 uart_puts(command);
  464.                 uart_putc('n');
  465.             }
  466.         }
  467.         /* close file system */
  468.         fat_close(fs);
  469.         /* close partition */
  470.         partition_close(partition);
  471.     }
  472.     
  473.     return 0;
  474. }
  475. uint8_t read_line(char* buffer, uint8_t buffer_length)
  476. {
  477.     memset(buffer, 0, buffer_length);
  478.     uint8_t read_length = 0;
  479.     while(read_length < buffer_length - 1)
  480.     {
  481.         uint8_t c = uart_getc();
  482.         if(c == 0x08 || c == 0x7f)
  483.         {
  484.             if(read_length < 1)
  485.                 continue;
  486.             --read_length;
  487.             buffer[read_length] = '';
  488.             uart_putc(0x08);
  489.             uart_putc(' ');
  490.             uart_putc(0x08);
  491.             continue;
  492.         }
  493.         uart_putc(c);
  494.         if(c == 'n')
  495.         {
  496.             buffer[read_length] = '';
  497.             break;
  498.         }
  499.         else
  500.         {
  501.             buffer[read_length] = c;
  502.             ++read_length;
  503.         }
  504.     }
  505.     return read_length;
  506. }
  507. uint32_t strtolong(const char* str)
  508. {
  509.     uint32_t l = 0;
  510.     while(*str >= '0' && *str <= '9')
  511.         l = l * 10 + (*str++ - '0');
  512.     return l;
  513. }
  514. uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
  515. {
  516.     while(fat_read_dir(dd, dir_entry))
  517.     {
  518.         if(strcmp(dir_entry->long_name, name) == 0)
  519.         {
  520.             fat_reset_dir(dd);
  521.             return 1;
  522.         }
  523.     }
  524.     return 0;
  525. }
  526. struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
  527. {
  528.     struct fat_dir_entry_struct file_entry;
  529.     if(!find_file_in_dir(fs, dd, name, &file_entry))
  530.         return 0;
  531.     return fat_open_file(fs, &file_entry);
  532. }
  533. uint8_t print_disk_info(const struct fat_fs_struct* fs)
  534. {
  535.     if(!fs)
  536.         return 0;
  537.     struct sd_raw_info disk_info;
  538.     if(!sd_raw_get_info(&disk_info))
  539.         return 0;
  540.     uart_puts_p(PSTR("manuf:  0x")); uart_putc_hex(disk_info.manufacturer); uart_putc('n');
  541.     uart_puts_p(PSTR("oem:    ")); uart_puts((char*) disk_info.oem); uart_putc('n');
  542.     uart_puts_p(PSTR("prod:   ")); uart_puts((char*) disk_info.product); uart_putc('n');
  543.     uart_puts_p(PSTR("rev:    ")); uart_putc_hex(disk_info.revision); uart_putc('n');
  544.     uart_puts_p(PSTR("serial: 0x")); uart_putdw_hex(disk_info.serial); uart_putc('n');
  545.     uart_puts_p(PSTR("date:   ")); uart_putw_dec(disk_info.manufacturing_month); uart_putc('/');
  546.                                    uart_putw_dec(disk_info.manufacturing_year); uart_putc('n');
  547.     uart_puts_p(PSTR("size:   ")); uart_putdw_dec(disk_info.capacity / 1024 / 1024); uart_puts_p(PSTR("MBn"));
  548.     uart_puts_p(PSTR("copy:   ")); uart_putw_dec(disk_info.flag_copy); uart_putc('n');
  549.     uart_puts_p(PSTR("wr.pr.: ")); uart_putw_dec(disk_info.flag_write_protect_temp); uart_putc('/');
  550.                                    uart_putw_dec(disk_info.flag_write_protect); uart_putc('n');
  551.     uart_puts_p(PSTR("format: ")); uart_putw_dec(disk_info.format); uart_putc('n');
  552.     uart_puts_p(PSTR("free:   ")); uart_putdw_dec(fat_get_fs_free(fs)); uart_putc('/');
  553.                                    uart_putdw_dec(fat_get_fs_size(fs)); uart_putc('n');
  554.     return 1;
  555. }
  556. #if FAT_DATETIME_SUPPORT
  557. void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec)
  558. {
  559.     *year = 2007;
  560.     *month = 1;
  561.     *day = 1;
  562.     *hour = 0;
  563.     *min = 0;
  564.     *sec = 0;
  565. }
  566. #endif