Browse Source

First try SD card.

Vladimir N. Shilov 2 years ago
parent
commit
219776ca1a
4 changed files with 483 additions and 2 deletions
  1. 1 0
      Makefile
  2. 303 0
      cfg/ffconf.h
  3. 1 1
      cfg/halconf.h
  4. 178 1
      src/main.c

+ 1 - 0
Makefile

@@ -111,6 +111,7 @@ include $(CHIBIOS)/tools/mk/autobuild.mk
 # Other files (optional).
 include $(CHIBIOS)/os/hal/lib/streams/streams.mk
 #include $(CHIBIOS)/os/various/shell/shell.mk
+include $(CHIBIOS)/os/various/fatfs_bindings/fatfs.mk
 
 # µGFX
 GFXLIB = C:/MCU/uGFX

+ 303 - 0
cfg/ffconf.h

@@ -0,0 +1,303 @@
+/* CHIBIOS FIX */
+#include "ch.h"
+
+/*---------------------------------------------------------------------------/
+/  FatFs Functional Configurations
+/---------------------------------------------------------------------------*/
+
+#define FFCONF_DEF	86631	/* Revision ID */
+
+/*---------------------------------------------------------------------------/
+/ Function Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_FS_READONLY	0
+/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
+/  Read-only configuration removes writing API functions, f_write(), f_sync(),
+/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
+/  and optional writing functions as well. */
+
+
+#define FF_FS_MINIMIZE	0
+/* This option defines minimization level to remove some basic API functions.
+/
+/   0: Basic functions are fully enabled.
+/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
+/      are removed.
+/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
+/   3: f_lseek() function is removed in addition to 2. */
+
+
+#define FF_USE_FIND		0
+/* This option switches filtered directory read functions, f_findfirst() and
+/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
+
+
+#define FF_USE_MKFS		0
+/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_FASTSEEK	0
+/* This option switches fast seek function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_EXPAND	0
+/* This option switches f_expand function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_CHMOD	0
+/* This option switches attribute manipulation functions, f_chmod() and f_utime().
+/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
+
+
+#define FF_USE_LABEL	0
+/* This option switches volume label functions, f_getlabel() and f_setlabel().
+/  (0:Disable or 1:Enable) */
+
+
+#define FF_USE_FORWARD	0
+/* This option switches f_forward() function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_STRFUNC	0
+#define FF_PRINT_LLI	0
+#define FF_PRINT_FLOAT	0
+#define FF_STRF_ENCODE	0
+/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
+/  f_printf().
+/
+/   0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
+/   1: Enable without LF-CRLF conversion.
+/   2: Enable with LF-CRLF conversion.
+/
+/  FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
+   makes f_printf() support floating point argument. These features want C99 or later.
+/  When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
+/  encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
+/  to be read/written via those functions.
+/
+/   0: ANSI/OEM in current CP
+/   1: Unicode in UTF-16LE
+/   2: Unicode in UTF-16BE
+/   3: Unicode in UTF-8
+*/
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_CODE_PAGE    850
+/* This option specifies the OEM code page to be used on the target system.
+/  Incorrect code page setting can cause a file open failure.
+/
+/   437 - U.S.
+/   720 - Arabic
+/   737 - Greek
+/   771 - KBL
+/   775 - Baltic
+/   850 - Latin 1
+/   852 - Latin 2
+/   855 - Cyrillic
+/   857 - Turkish
+/   860 - Portuguese
+/   861 - Icelandic
+/   862 - Hebrew
+/   863 - Canadian French
+/   864 - Arabic
+/   865 - Nordic
+/   866 - Russian
+/   869 - Greek 2
+/   932 - Japanese (DBCS)
+/   936 - Simplified Chinese (DBCS)
+/   949 - Korean (DBCS)
+/   950 - Traditional Chinese (DBCS)
+/     0 - Include all code pages above and configured by f_setcp()
+*/
+
+
+#define FF_USE_LFN		3
+#define FF_MAX_LFN		255
+/* The FF_USE_LFN switches the support for LFN (long file name).
+/
+/   0: Disable LFN. FF_MAX_LFN has no effect.
+/   1: Enable LFN with static  working buffer on the BSS. Always NOT thread-safe.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/   3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
+/  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
+/  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
+/  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
+/  be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
+/  specification.
+/  When use stack for the working buffer, take care on stack overflow. When use heap
+/  memory for the working buffer, memory management functions, ff_memalloc() and
+/  ff_memfree() exemplified in ffsystem.c, need to be added to the project. */
+
+
+#define FF_LFN_UNICODE	0
+/* This option switches the character encoding on the API when LFN is enabled.
+/
+/   0: ANSI/OEM in current CP (TCHAR = char)
+/   1: Unicode in UTF-16 (TCHAR = WCHAR)
+/   2: Unicode in UTF-8 (TCHAR = char)
+/   3: Unicode in UTF-32 (TCHAR = DWORD)
+/
+/  Also behavior of string I/O functions will be affected by this option.
+/  When LFN is not enabled, this option has no effect. */
+
+
+#define FF_LFN_BUF		255
+#define FF_SFN_BUF		12
+/* This set of options defines size of file name members in the FILINFO structure
+/  which is used to read out directory items. These values should be suffcient for
+/  the file names to read. The maximum possible length of the read file name depends
+/  on character encoding. When LFN is not enabled, these options have no effect. */
+
+
+#define FF_FS_RPATH		0
+/* This option configures support for relative path.
+/
+/   0: Disable relative path and remove related functions.
+/   1: Enable relative path. f_chdir() and f_chdrive() are available.
+/   2: f_getcwd() function is available in addition to 1.
+*/
+
+
+/*---------------------------------------------------------------------------/
+/ Drive/Volume Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_VOLUMES		1
+/* Number of volumes (logical drives) to be used. (1-10) */
+
+
+#define FF_STR_VOLUME_ID	0
+#define FF_VOLUME_STRS		"RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
+/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
+/  When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
+/  number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
+/  logical drives. Number of items must not be less than FF_VOLUMES. Valid
+/  characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
+/  compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
+/  not defined, a user defined volume string table needs to be defined as:
+/
+/  const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
+*/
+
+
+#define FF_MULTI_PARTITION	0
+/* This option switches support for multiple volumes on the physical drive.
+/  By default (0), each logical drive number is bound to the same physical drive
+/  number and only an FAT volume found on the physical drive will be mounted.
+/  When this function is enabled (1), each logical drive number can be bound to
+/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
+/  funciton will be available. */
+
+
+#define FF_MIN_SS		512
+#define FF_MAX_SS		512
+/* This set of options configures the range of sector size to be supported. (512,
+/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
+/  harddisk, but a larger value may be required for on-board flash memory and some
+/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
+/  for variable sector size mode and disk_ioctl() function needs to implement
+/  GET_SECTOR_SIZE command. */
+
+
+#define FF_LBA64		0
+/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
+/  To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
+
+
+#define FF_MIN_GPT		0x10000000
+/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and
+/  f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
+
+
+#define FF_USE_TRIM		0
+/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
+/  To enable Trim function, also CTRL_TRIM command should be implemented to the
+/  disk_ioctl() function. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_FS_TINY		0
+/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
+/  At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
+/  Instead of private sector buffer eliminated from the file object, common sector
+/  buffer in the filesystem object (FATFS) is used for the file data transfer. */
+
+
+#define FF_FS_EXFAT		1
+/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
+/  To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
+/  Note that enabling exFAT discards ANSI C (C89) compatibility. */
+
+
+#define FF_FS_NORTC		0
+#define FF_NORTC_MON	1
+#define FF_NORTC_MDAY	1
+#define FF_NORTC_YEAR	2020
+/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
+/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
+/  the timestamp function. Every object modified by FatFs will have a fixed timestamp
+/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
+/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
+/  added to the project to read current time form real-time clock. FF_NORTC_MON,
+/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
+/  These options have no effect in read-only configuration (FF_FS_READONLY = 1). */
+
+
+#define FF_FS_NOFSINFO	0
+/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
+/  option, and f_getfree() function at first time after volume mount will force
+/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.
+/
+/  bit0=0: Use free cluster count in the FSINFO if available.
+/  bit0=1: Do not trust free cluster count in the FSINFO.
+/  bit1=0: Use last allocated cluster number in the FSINFO if available.
+/  bit1=1: Do not trust last allocated cluster number in the FSINFO.
+*/
+
+
+#define FF_FS_LOCK		0
+/* The option FF_FS_LOCK switches file lock function to control duplicated file open
+/  and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
+/  is 1.
+/
+/  0:  Disable file lock function. To avoid volume corruption, application program
+/      should avoid illegal open, remove and rename to the open objects.
+/  >0: Enable file lock function. The value defines how many files/sub-directories
+/      can be opened simultaneously under file lock control. Note that the file
+/      lock control is independent of re-entrancy. */
+
+
+#define FF_FS_REENTRANT   0
+#define FF_FS_TIMEOUT     TIME_MS2I(1000)
+#define FF_SYNC_t         semaphore_t*
+/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
+/  module itself. Note that regardless of this option, file access to different
+/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
+/  and f_fdisk() function, are always not re-entrant. Only file/directory access
+/  to the same volume is under control of this function.
+/
+/   0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
+/   1: Enable re-entrancy. Also user provided synchronization handlers,
+/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
+/      function, must be added to the project. Samples are available in
+/      option/syscall.c.
+/
+/  The FF_FS_TIMEOUT defines timeout period in unit of time tick.
+/  The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
+/  SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
+/  included somewhere in the scope of ff.h. */
+
+
+
+/*--- End of configuration options ---*/

+ 1 - 1
cfg/halconf.h

@@ -135,7 +135,7 @@
  * @brief   Enables the SDC subsystem.
  */
 #if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
-#define HAL_USE_SDC                         FALSE
+#define HAL_USE_SDC                         TRUE
 #endif
 
 /**

+ 178 - 1
src/main.c

@@ -14,9 +14,13 @@
     limitations under the License.
 */
 
+#include <stdio.h>
+#include <string.h>
+
 #include "ch.h"
 #include "hal.h"
 #include "chprintf.h"
+#include "ff.h"
 #include "gfx.h"
 #include "buttons.h"
 #include "INA3221.h"
@@ -31,6 +35,12 @@
 #define INA_BUS_VALUES        EVENT_MASK(1)
 #define CHRGR_ST_CHANGE       EVENT_MASK(2)
 #define TIME_CHANGE           EVENT_MASK(3)
+#define INSERTED_EVENT        EVENT_MASK(4)
+#define REMOVED_EVENT         EVENT_MASK(5)
+
+/* Card insertion monitor. */
+#define POLLING_INTERVAL      10
+#define POLLING_DELAY         10
 
 /* Type definitions */
 typedef enum chrgr_state {
@@ -125,12 +135,19 @@ static void mode_vt_cb(virtual_timer_t *vtp, void *st);
 static void btn1_handler(const button_state_t);
 static void btn2_handler(const button_state_t);
 static void show_MenuItem(const int item);
+static void sdc_tmrfunc(virtual_timer_t *vtp, void *p);
+static void sdc_tmr_init(void *p);
+static void InsertHandler(eventid_t id); /* Card insertion event. */
+static void RemoveHandler(eventid_t id); /* Card removal event. */
+static FRESULT scan_files(BaseSequentialStream *chp, char *path);
+static void cmd_tree(BaseSequentialStream *chp, int argc, char *argv[]);
 
 /* Private variables */
 static binary_semaphore_t ina_bsem, charger_bsem;
-static virtual_timer_t mode_vt;
+static virtual_timer_t mode_vt, sdc_tmr;
 static event_source_t ina_all_event, ina_bus_event;
 static event_source_t chrgr_st_event, time_event;
+static event_source_t inserted_event, removed_event;
 static charger_state_t charger_State;
 static ina3221_ch_t charger_Channel;
 static int charger_Profile = 0;
@@ -148,6 +165,10 @@ static time_cnt_t Timer = {0}, dechTimer, chTimer;
 static btn_hndlr bha[Button_Num] = {btn1_handler, btn2_handler};
 static int menu_Active = MenuItem_1;
 static menu_colors_t menu_Colors = {Navy, Olive, Yellow, Navy};
+static unsigned cnt;
+static FATFS SDC_FS; /* FS object. */
+static bool fs_ready = false; /* FS mounted and ready.*/
+static uint8_t fbuff[1024]; /* Generic large buffer.*/
 
 /*
  * INA process thread.
@@ -335,6 +356,11 @@ int main(void) {
   gptStart(&GPTD7, &gpt_cfg);
   gptStartContinuous(&GPTD7, INA_SCAN_PERIOS_US);
 
+  /* Activates the  SDC driver 1 using default configuration. */
+  sdcStart(&SDCD1, NULL);
+  /* Activates the card insertion monitor. */
+  sdc_tmr_init(&SDCD1);
+
   /* Init charger module */
   charger_State = Stop;
   charger_Channel = INA3221_CH1;
@@ -346,10 +372,15 @@ int main(void) {
   chEvtObjectInit(&ina_bus_event);
   chEvtObjectInit(&chrgr_st_event);
   chEvtObjectInit(&time_event);
+  chEvtObjectInit(&inserted_event);
+  chEvtObjectInit(&removed_event);
+  
   chEvtRegister(&ina_all_event, &el0, 0);
   chEvtRegister(&ina_bus_event, &el1, 1);
   chEvtRegister(&chrgr_st_event, &el2, 2);
   chEvtRegister(&time_event, &el3, 3);
+  chEvtRegister(&inserted_event, &el3, 4);
+  chEvtRegister(&removed_event, &el3, 5);
 
   eventmask_t events;
   charger_state_t oldState = Stop;
@@ -578,6 +609,14 @@ int main(void) {
       chsnprintf(buf, 12, "T:%02u:%02u:%02u", Timer.hh, Timer.mm, Timer.ss);
       gdispFillStringBox(160, 123, 158, 29, buf, font2, Red, Gray, gJustifyLeft);
     }
+
+    if (events & INSERTED_EVENT) {
+      InsertHandler(0);
+    }
+
+    if (events & REMOVED_EVENT) {
+      RemoveHandler(0);
+    }
   }
 }
 
@@ -903,3 +942,141 @@ static void gpt_cb(GPTDriver *gptp) {
     chSysUnlockFromISR();
   }
 }
+
+/**
+ * @brief   Insertion monitor timer callback function.
+ *
+ * @param[in] p         pointer to the @p BaseBlockDevice object
+ *
+ * @notapi
+ */
+static void sdc_tmrfunc(virtual_timer_t *vtp, void *p) {
+  BaseBlockDevice *bbdp = p;
+
+  (void)vtp;
+
+  chSysLockFromISR();
+  if (cnt > 0) {
+    if (blkIsInserted(bbdp)) {
+      if (--cnt == 0) {
+        chEvtBroadcastI(&inserted_event);
+      }
+    }
+    else
+      cnt = POLLING_INTERVAL;
+  }
+  else {
+    if (!blkIsInserted(bbdp)) {
+      cnt = POLLING_INTERVAL;
+      chEvtBroadcastI(&removed_event);
+    }
+  }
+  chVTSetI(&sdc_tmr, TIME_MS2I(POLLING_DELAY), sdc_tmrfunc, bbdp);
+  chSysUnlockFromISR();
+}
+
+/**
+ * @brief   Polling monitor start.
+ *
+ * @param[in] p         pointer to an object implementing @p BaseBlockDevice
+ *
+ * @notapi
+ */
+static void sdc_tmr_init(void *p) {
+
+  chEvtObjectInit(&inserted_event);
+  chEvtObjectInit(&removed_event);
+  chSysLock();
+  cnt = POLLING_INTERVAL;
+  chVTSetI(&sdc_tmr, TIME_MS2I(POLLING_DELAY), sdc_tmrfunc, p);
+  chSysUnlock();
+}
+
+/*
+ * Card insertion event.
+ */
+static void InsertHandler(eventid_t id) {
+  FRESULT err;
+
+  (void)id;
+  /*
+   * On insertion SDC initialization and FS mount.
+   */
+  if (sdcConnect(&SDCD1))
+    return;
+
+  err = f_mount(&SDC_FS, "/", 1);
+  if (err != FR_OK) {
+    sdcDisconnect(&SDCD1);
+    return;
+  }
+  fs_ready = true;
+  gwinPrintf(GW1, "SD Card connected and mounted.\n");
+}
+
+/*
+ * Card removal event.
+ */
+static void RemoveHandler(eventid_t id) {
+  (void)id;
+  sdcDisconnect(&SDCD1);
+  fs_ready = false;
+  gwinPrintf(GW1, "SD Card disconnected.\n");
+}
+
+
+static FRESULT scan_files(BaseSequentialStream *chp, char *path) {
+  static FILINFO fno;
+  FRESULT res;
+  DIR dir;
+  size_t i;
+  char *fn;
+
+  res = f_opendir(&dir, path);
+  if (res == FR_OK) {
+    i = strlen(path);
+    while (((res = f_readdir(&dir, &fno)) == FR_OK) && fno.fname[0]) {
+      if (FF_FS_RPATH && fno.fname[0] == '.')
+        continue;
+      fn = fno.fname;
+      if (fno.fattrib & AM_DIR) {
+        *(path + i) = '/';
+        strcpy(path + i + 1, fn);
+        res = scan_files(chp, path);
+        *(path + i) = '\0';
+        if (res != FR_OK)
+          break;
+      }
+      else {
+        chprintf(chp, "%s/%s\r\n", path, fn);
+      }
+    }
+  }
+  return res;
+}
+
+static void cmd_tree(BaseSequentialStream *chp, int argc, char *argv[]) {
+  FRESULT err;
+  uint32_t fre_clust;
+  FATFS *fsp;
+
+  (void)argv;
+  if (argc > 0) {
+    chprintf(chp, "Usage: tree\r\n");
+    return;
+  }
+  if (!fs_ready) {
+    chprintf(chp, "File System not mounted\r\n");
+    return;
+  }
+  err = f_getfree("/", &fre_clust, &fsp);
+  if (err != FR_OK) {
+    chprintf(chp, "FS: f_getfree() failed\r\n");
+    return;
+  }
+  chprintf(chp,
+           "FS: %lu free clusters with %lu sectors (%lu bytes) per cluster\r\n",
+           fre_clust, (uint32_t)fsp->csize, (uint32_t)fsp->csize * 512);
+  fbuff[0] = 0;
+  scan_files(chp, (char *)fbuff);
+}