Simple DataLogger for STM32F4-Discovery

This forum is about you. Feel free to discuss anything is related to embedded and electronics, your awesome projects, your ideas, your announcements, not necessarily related to ChibiOS but to embedded in general. This forum is NOT for support.
User avatar
Fede
Posts: 37
Joined: Thu Nov 08, 2012 8:30 pm
Location: Milano

Simple DataLogger for STM32F4-Discovery

Postby Fede » Fri Jan 04, 2013 4:58 pm

Hi all,

I would like to create a simple data logger for F4-Discovery Board using MMC over SPI Driver.
I only need to write some string into a file!
I've found some examples for other hardware so I "wrote" (maybe I've copied and pasted!) just an "ugly" draft...

Code: Select all

 
#include <string.h>
#include "ch.h"
#include "hal.h"
#include "chsprintf.h"
#include "chprintf.h"
#include "evtimer.h"
#include "ff.h"

#define POLLING_INTERVAL                10
#define POLLING_DELAY                   10

static VirtualTimer tmr;  // Card monitor timer
static unsigned cnt;     // Debounce counter
static EventSource inserted_event, removed_event; // Card event sources

static FRESULT scan_files(BaseSequentialStream *chp, char *path) {
  FRESULT res;
  FILINFO fno;
  DIR dir;
  int i;
  char *fn;

#if _USE_LFN
  fno.lfname = 0;
  fno.lfsize = 0;
#endif
  res = f_opendir(&dir, path);
  if (res == FR_OK) {
    i = strlen(path);
    for (;;) {
      res = f_readdir(&dir, &fno);
      if (res != FR_OK || fno.fname[0] == 0)
        break;
      if (fno.fname[0] == '.')
        continue;
      fn = fno.fname;
      if (fno.fattrib & AM_DIR) {
        path[i++] = '/';
        strcpy(&path[i], fn);
        res = scan_files(chp, path);
        if (res != FR_OK)
          break;
        path[--i] = 0;
      }
      else {
        chprintf(chp, "%s/%s\r\n", path, fn);
      }
    }
  }
  return res;
}


static void tmrfunc(void *p) {
  BaseBlockDevice *bbdp = p;

  /* The presence check is performed only while the driver is not in a
     transfer state because it is often performed by changing the mode of
     the pin connected to the CS/D3 contact of the card, this could disturb
     the transfer.*/
  blkstate_t state = blkGetDriverState(bbdp);
  chSysLockFromIsr();
  if ((state != BLK_READING) && (state != BLK_WRITING)) {
    /* Safe to perform the check.*/
    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(&tmr, MS2ST(POLLING_DELAY), tmrfunc, bbdp);
  chSysUnlockFromIsr();
}

static void tmr_init(void *p) {

  chEvtInit(&inserted_event);
  chEvtInit(&removed_event);
  chSysLock();
  cnt = POLLING_INTERVAL;
  chVTSetI(&tmr, MS2ST(POLLING_DELAY), tmrfunc, p);
  chSysUnlock();
}

 // MMC card insertion event.
static void InsertHandler(eventid_t id) {
  FRESULT err;

  (void)id;
 
 //On insertion MMC initialization and FS mount.
   if (mmcConnect(&MMCD1)) {
    return;
  }
  err = f_mount(0, &MMC_FS);
  if (err != FR_OK) {
    mmcDisconnect(&MMCD1);
    return;
  }
  fs_ready = TRUE;
}


 // MMC card removal event.
static void RemoveHandler(eventid_t id) {

  (void)id;
  mmcDisconnect(&MMCD1);
  fs_ready = FALSE;
}


/*===========================================================================*/
/* FatFs related.                                                            */
/*===========================================================================*/

FATFS MMC_FS; // brief FS object
MMCDriver MMCD1; //  MMC driver instance.
static bool_t fs_ready = FALSE; // FS mounted and ready

/* Maximum speed SPI configuration (18MHz, CPHA=0, CPOL=0, MSb first).*/
static SPIConfig hs_spicfg = {NULL, IOPORT2, GPIOB_SPI2NSS, 0};                // GPIOB_SPI2NSS is not defined for F4

/* Low speed SPI configuration (281.250kHz, CPHA=0, CPOL=0, MSb first).*/
static SPIConfig ls_spicfg = {NULL, IOPORT2, GPIOB_SPI2NSS,                      // GPIOB_SPI2NSS is not defined for F4
                              SPI_CR1_BR_2 | SPI_CR1_BR_1};

/* MMC/SD over SPI driver configuration.*/
static MMCConfig mmccfg = {&SPID2, &ls_spicfg, &hs_spicfg};

/* Generic large buffer.*/
uint8_t fbuff[1024];


int main (void){

halInit();
chSysInit();
sdStart(&SD2, NULL); // Activates the serial driver 2 using the driver default configuration.

//Initializes the MMC driver to work with SPI2.
palSetPadMode(IOPORT2, GPIOB_SPI2NSS, PAL_MODE_OUTPUT_PUSHPULL);   // GPIOB_SPI2NSS is not defined for F4
palSetPad(IOPORT2, GPIOB_SPI2NSS);                                                           // GPIOB_SPI2NSS is not defined for F4
mmcObjectInit(&MMCD1);
mmcStart(&MMCD1, &mmccfg);
//Activates the card insertion monitor.
tmr_init(&MMCD1);

// and NOW???

return 0;
}


I'm a beginner of "FatFS" so maybe it's all wrong or maybe someone has a small and simple example to post here...
Thank you very much in advance
Fede

User avatar
Giovanni
Site Admin
Posts: 14455
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Simple DataLogger for STM32F4-Discovery

Postby Giovanni » Fri Jan 04, 2013 6:31 pm

Hi,

Your is a broad question, in ChibiOS there are several demo applications that show how to integrate FatFS and ChibiOS, we could help if you have integration problems. In general, in order to start with your project you should first port one of the demos (for example the STM32F103 one) to the STM32F4-Discovery and verify that the demo works AS-IS, don't try to make changes, just verify that everything work after fixing differences.
Basically you have to change the Makefile (see an STM32F4xx demo Makefile for differences) and to main.c.

After the demo is working you could also check the FatFS forum for usage examples, here you can find the documentation and the discussion forum: http://elm-chan.org/fsw/ff/00index_e.html

If you have more specific questions regarding the integration between FatFS and ChibiOS feel free to ask here.

BTW, if somebody already made an MMC demo for the F4-Discovery please post here.

Giovanni

User avatar
Fede
Posts: 37
Joined: Thu Nov 08, 2012 8:30 pm
Location: Milano

Re: Simple DataLogger for STM32F4-Discovery

Postby Fede » Fri Jan 04, 2013 8:23 pm

Hi giovanni,
your answers are always helpful!
Tomorrow i'll try to port that example to STM32F4, and if it will works fine I will post here...
Thank you so much for your kind reply.

Fede

if somebody already made an MMC demo for the F4-Discovery please post here

User avatar
Fede
Posts: 37
Joined: Thu Nov 08, 2012 8:30 pm
Location: Milano

Re: Simple DataLogger for STM32F4-Discovery

Postby Fede » Sat Jan 05, 2013 2:57 pm

Hi, all

the enclosed folder contains the project modified to work with STM32F4Discovery. It works exactly like the ARMCM3-STM32F103ZG-FATFS demo with a few changes (serial tx is PA02 & serial rx is PA03). Obviously if I send "tree" command, this message is shown : "File System not mounted"...
In fact, my question is: How do I physically connect the SD-shield to the board?
I think that I've to use SPI3 (SPI1 & SPI2 is already used for accel. & mic.), isn't it?

in general for SD in SPI mode we have:

SD PIN_________SD FUNCTION_________F4Discovery_____pin
pin1___________CS__________________SPI3_NSS________PA15 ?
pin2___________DI__________________SPI3_MOSI_______PB5 ?
pin3___________GND________________GND
pin4___________VDD________________+3v3
pin5___________SCLK_______________SPI3_SCK________PB3 ?
pin7___________DO_________________SPI3_MISO_______PB4 ?

I think it's useful to many people, so what do you think about it?
Thank you all in advance!
Fede

Code: Select all

// main.c
#include <stdio.h>
#include <string.h>
#include "ch.h"
#include "hal.h"
#include "test.h"
#include "shell.h"
#include "evtimer.h"
#include "chprintf.h"
#include "ff.h"

/*===========================================================================*/
/* Card insertion monitor.                                                   */
/*===========================================================================*/

#define POLLING_INTERVAL                10
#define POLLING_DELAY                   10

/**
 * @brief   Card monitor timer.
 */
static VirtualTimer tmr;

/**
 * @brief   Debounce counter.
 */
static unsigned cnt;

/**
 * @brief   Card event sources.
 */
static EventSource inserted_event, removed_event;

/**
 * @brief   Insertion monitor timer callback function.
 *
 * @param[in] p         pointer to the @p BaseBlockDevice object
 *
 * @notapi
 */
static void tmrfunc(void *p) {
  BaseBlockDevice *bbdp = p;

  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(&tmr, MS2ST(POLLING_DELAY), tmrfunc, bbdp);
  chSysUnlockFromIsr();
}

/**
 * @brief   Polling monitor start.
 *
 * @param[in] p         pointer to an object implementing @p BaseBlockDevice
 *
 * @notapi
 */
static void tmr_init(void *p) {

  chEvtInit(&inserted_event);
  chEvtInit(&removed_event);
  chSysLock();
  cnt = POLLING_INTERVAL;
  chVTSetI(&tmr, MS2ST(POLLING_DELAY), tmrfunc, p);
  chSysUnlock();
}

/*===========================================================================*/
/* FatFs related.                                                            */
/*===========================================================================*/

/**
 * @brief FS object.
 */
FATFS SDC_FS;

/* FS mounted and ready.*/
static bool_t fs_ready = FALSE;

/* Generic large buffer.*/
uint8_t fbuff[1024];

static FRESULT scan_files(BaseSequentialStream *chp, char *path) {
  FRESULT res;
  FILINFO fno;
  DIR dir;
  int i;
  char *fn;

#if _USE_LFN
  fno.lfname = 0;
  fno.lfsize = 0;
#endif
  res = f_opendir(&dir, path);
  if (res == FR_OK) {
    i = strlen(path);
    for (;;) {
      res = f_readdir(&dir, &fno);
      if (res != FR_OK || fno.fname[0] == 0)
        break;
      if (fno.fname[0] == '.')
        continue;
      fn = fno.fname;
      if (fno.fattrib & AM_DIR) {
        path[i++] = '/';
        strcpy(&path[i], fn);
        res = scan_files(chp, path);
        if (res != FR_OK)
          break;
        path[--i] = 0;
      }
      else {
        chprintf(chp, "%s/%s\r\n", path, fn);
      }
    }
  }
  return res;
}

/*===========================================================================*/
/* Command line related.                                                     */
/*===========================================================================*/

#define SHELL_WA_SIZE   THD_WA_SIZE(2048)
#define TEST_WA_SIZE    THD_WA_SIZE(256)

static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
  size_t n, size;

  (void)argv;
  if (argc > 0) {
    chprintf(chp, "Usage: mem\r\n");
    return;
  }
  n = chHeapStatus(NULL, &size);
  chprintf(chp, "core free memory : %u bytes\r\n", chCoreStatus());
  chprintf(chp, "heap fragments   : %u\r\n", n);
  chprintf(chp, "heap free total  : %u bytes\r\n", size);
}

static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
  static const char *states[] = {THD_STATE_NAMES};
  Thread *tp;

  (void)argv;
  if (argc > 0) {
    chprintf(chp, "Usage: threads\r\n");
    return;
  }
  chprintf(chp, "    addr    stack prio refs     state time\r\n");
  tp = chRegFirstThread();
  do {
    chprintf(chp, "%.8lx %.8lx %4lu %4lu %9s %lu\r\n",
            (uint32_t)tp, (uint32_t)tp->p_ctx.r13,
            (uint32_t)tp->p_prio, (uint32_t)(tp->p_refs - 1),
            states[tp->p_state], (uint32_t)tp->p_time);
    tp = chRegNextThread(tp);
  } while (tp != NULL);
}

static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
  Thread *tp;

  (void)argv;
  if (argc > 0) {
    chprintf(chp, "Usage: test\r\n");
    return;
  }
  tp = chThdCreateFromHeap(NULL, TEST_WA_SIZE, chThdGetPriority(),
                           TestThread, chp);
  if (tp == NULL) {
    chprintf(chp, "out of memory\r\n");
    return;
  }
  chThdWait(tp);
}

static void cmd_tree(BaseSequentialStream *chp, int argc, char *argv[]) {
  FRESULT err;
  uint32_t clusters;
  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("/", &clusters, &fsp);
  if (err != FR_OK) {
    chprintf(chp, "FS: f_getfree() failed\r\n");
    return;
  }
  chprintf(chp,
           "FS: %lu free clusters, %lu sectors per cluster, %lu bytes free\r\n",
           clusters, (uint32_t)SDC_FS.csize,
           clusters * (uint32_t)SDC_FS.csize * (uint32_t)MMCSD_BLOCK_SIZE);
  fbuff[0] = 0;
  scan_files(chp, (char *)fbuff);
}

static const ShellCommand commands[] = {
  {"mem", cmd_mem},
  {"threads", cmd_threads},
  {"test", cmd_test},
  {"tree", cmd_tree},
  {NULL, NULL}
};

static const ShellConfig shell_cfg1 = {
  (BaseSequentialStream *)&SD2,                  // was &SD1
  commands
};

/*===========================================================================*/
/* Main and generic code.                                                    */
/*===========================================================================*/

/*
 * SD 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(0, &SDC_FS);
  if (err != FR_OK) {
    sdcDisconnect(&SDCD1);
    return;
  }
  fs_ready = TRUE;
}

/*
 * SD card removal event.
 */
static void RemoveHandler(eventid_t id) {

  (void)id;
  sdcDisconnect(&SDCD1);
  fs_ready = FALSE;
}

/*
 * LEDs blinker thread, times are in milliseconds.
 */
static WORKING_AREA(waThread1, 128);
static msg_t Thread1(void *arg) {

  (void)arg;
  chRegSetThreadName("blinker");
  while (TRUE) {
    palClearPad(GPIOD, GPIOD_LED3);     //mod
    palSetPad(GPIOD, GPIOD_LED4);       //mod
    chThdSleepMilliseconds(250);
    palClearPad(GPIOD, GPIOD_LED4);     //mod
    palSetPad(GPIOD, GPIOD_LED5);       //mod
    chThdSleepMilliseconds(250);
    palClearPad(GPIOD, GPIOD_LED5);     //mod
    palSetPad(GPIOD, GPIOD_LED6);       //mod
    chThdSleepMilliseconds(250);
    palClearPad(GPIOD, GPIOD_LED6);     //mod
    palSetPad(GPIOD, GPIOD_LED3);       //mod
    chThdSleepMilliseconds(250);
  }
}

/*
 * Application entry point.
 */
int main(void) {
  static const evhandler_t evhndl[] = {
    InsertHandler,
    RemoveHandler
  };
  Thread *shelltp = NULL;
  struct EventListener el0, el1;

  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  halInit();
  chSysInit();

  /*
   * Activates the serial driver 1 and SDC driver 1 using default
   * configuration.
   */
  sdStart(&SD2, NULL);      // change from SD1
  palSetPadMode(GPIOA, 2, PAL_MODE_ALTERNATE(7));    //added
  palSetPadMode(GPIOA, 3, PAL_MODE_ALTERNATE(7));    //added

  sdcStart(&SDCD1, NULL);

  /*
   * Shell manager initialization.
   */
  shellInit();

  /*
   * Activates the card insertion monitor.
   */
  tmr_init(&SDCD1);

  /*
   * Creates the blinker thread.
   */
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);

  /*
   * Normal main() thread activity, in this demo it does nothing except
   * sleeping in a loop and listen for events.
   */
  chEvtRegister(&inserted_event, &el0, 0);
  chEvtRegister(&removed_event, &el1, 1);
  while (TRUE) {
    if (!shelltp)
      shelltp = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO);
    else if (chThdTerminated(shelltp)) {
      chThdRelease(shelltp);    /* Recovers memory of the previous shell.   */
      shelltp = NULL;           /* Triggers spawning of a new shell.        */
    }
    chEvtDispatch(evhndl, chEvtWaitOneTimeout(ALL_EVENTS, MS2ST(500)));
  }
}


STM32F407_FATFS.tgz
(31.78 KiB) Downloaded 618 times

User avatar
Fede
Posts: 37
Joined: Thu Nov 08, 2012 8:30 pm
Location: Milano

Re: Simple DataLogger for STM32F4-Discovery

Postby Fede » Tue Jan 08, 2013 12:24 pm

Guys, 91 views and 0 replies? please! ;)

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: Simple DataLogger for STM32F4-Discovery

Postby Tectu » Tue Jan 08, 2013 4:33 pm

Hello Fede,

Here's how an SD card socket is connected on one of my boards using SPI. There are no other pullup or pulldown resistors. The labels go directly to the pins of the MCU. The pins SD_CD and SD_CS are GPIOs. You have to give the information of the CS pin and port in your SPI config structure.
Also, you don't need the connections of pin 10 to 12 on the socket. These are only to check if a card has been inserted or if it's write protected.

rsz_1capture.png
rsz_1capture.png (68.34 KiB) Viewed 13025 times


Things to consider:
  • Make sure the PAL stuff is configured correctly (Output PushPull for the CS pin and alternative for the SPI pins)
  • In case of you don't have any pin where the socket tells you if a card has been inserted, make sure you wait a little bit after powerup because the card needs some initialisation time as well - or simply connect a switch you can manually use (I recommend this)
  • Make sure your SPI frequencies aren't too high. Lower them if all the poins from above didn't help at all
  • What SD card are you using? Newer SD cards have problems that they don't support the SPI interface properly anymore. For example, 8 out of 10 SD cards I have here didn't work that way, but all of them work with SDIO.
  • What toolchain are you using? Like many other ChibiOS people, I had some issues with mine. I highly recommend using this one. It even comes with precompiled binaries for Linux, Mac OSX and Windows.


I hope this helps somehow.

~ Tectu

User avatar
Fede
Posts: 37
Joined: Thu Nov 08, 2012 8:30 pm
Location: Milano

Re: Simple DataLogger for STM32F4-Discovery

Postby Fede » Tue Jan 08, 2013 5:32 pm

Many thanks Tectu, ok I will use the same SPI2 (PB12 PB13 PB14 PB15)... now hardware is setup, next step software!
I'm using this toolchain: arm-none-eabi v4.6 on xubuntu OS... no problem "for now"!
Thanks a lot,
Fede

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: Simple DataLogger for STM32F4-Discovery

Postby Tectu » Tue Jan 08, 2013 5:44 pm

Does that means that it works now? o0
Also, it dosen't matter which SPI you use as long as you configure it correctly. Also, I used an STM32F103 for that pic above, but that shouldn't matter at all.

Keep me up to date.


~ Tectu

User avatar
Fede
Posts: 37
Joined: Thu Nov 08, 2012 8:30 pm
Location: Milano

Re: Simple DataLogger for STM32F4-Discovery

Postby Fede » Tue Jan 08, 2013 5:58 pm

No I don't have built the hardware yet! :) but I think (I hope) that your schematic will work fine!
Fede

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: Simple DataLogger for STM32F4-Discovery

Postby Tectu » Tue Jan 08, 2013 6:11 pm

By the way, you don't need the transistor stuff as well. Just connect pin 4 of your SD card socket to +3.3V.


~ Tectu


Return to “User Projects”

Who is online

Users browsing this forum: No registered users and 8 guests