BSP430  20141115
Board Support Package for MSP430 microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
FatFs on an EXP430F5529

FatFs is a very nice FAT file system implementation suitable for SD cards and external memory.

The MSP-EXP430F5529 happens to have a micro SD card peripheral.

The bridge is in the bsp430mmc.c file, which is a lightly modified version of the generic example that came with the FatFs sample package before sometime in 2013 when it was removed (post R0.09b).

This has been tested with R0.09 and R0.10 versions of FatFS. By default it will expect R0.10, which includes an API change. If you are using an older release (e.g. R0.09b) you need to tell the source code, because there's no usable information in the FatFS headers. Add EXT_CPPFLAGS=-DFATFS_IS_PRE_R0_10=1 to the make command line.

bsp430mmc.c

Only the BSP430-specific elements of this file are extracted here. The first block is the initialization code:

/* Include BSP430 material first, which will include msp430.h. */
#include <bsp430/serial.h>
#include <bsp430/clock.h>
#ifndef BSP430_MMC_FAST_HZ
#define BSP430_MMC_FAST_HZ 8000000UL
#endif /* BSP430_MMC_FAST_HZ */
/* Wrapper to ensure FATFS_IS_PRE_R0_10 is defined. This supports an
* API change at R0.10. */
#include "ff_compat.h"
#include "diskio.h" /* Common include file for FatFs and disk I/O layer */
/* FatFS R0.10a removed these defines. */
#ifndef CT_MMC
/* MMC card type flags (MMC_GET_TYPE) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK 0x08 /* Block addressing */
#endif /* CT_MMC */
/*-------------------------------------------------------------------------*/
/* Platform dependent macros and functions needed to be modified */
/*-------------------------------------------------------------------------*/
#define APP_SD_CS_PORT_HPL xBSP430hplLookupPORT(APP_SD_CS_PORT_PERIPH_HANDLE)
static hBSP430halSERIAL sdspi;
/* Following BSP430/POSIX conventions, this returns 0 if successful,
* -1 on error. */
static int
configureSPIforSD (int fastp)
{
unsigned int init_spi_divisor;
volatile sBSP430hplPORT * miso_port = xBSP430hplLookupPORT(APP_SD_MISO_PORT_PERIPH_HANDLE);
/* We'll drive the SPI device using SMCLK. For initialization, we
* need to stay below 400 kHz, and have chosen 380 kHz in case of
* clock variances. After initialization, we can go faster. */
if (fastp) {
init_spi_divisor = uiBSP430serialSMCLKPrescaler(BSP430_MMC_FAST_HZ);
} else {
init_spi_divisor = uiBSP430serialSMCLKPrescaler(380000UL);
}
/* SPI divisor must not be zero */
if (0 == init_spi_divisor) {
init_spi_divisor = 1;
}
/* Close the device if we already opened it. */
if (sdspi) {
(void)iBSP430serialClose(sdspi);
}
/* For some SD cards, need MISO pullup, or so we're told. Do that
* first, hoping the platform peripheral configuration won't destroy
* it. */
miso_port->dir &= ~APP_SD_MISO_PORT_BIT;
BSP430_PORT_HPL_SET_REN(miso_port, APP_SD_MISO_PORT_BIT, BSP430_PORT_REN_PULL_UP);
/* Configure SPI. Probably ought to have a way to return an error
* code. Note: Per http://elm-chan.org/docs/mmc/mmc_e.html use SPI
* mode 0 (CPOL=CPHA=0 via UCCKPH). */
sdspi = hBSP430serialOpenSPI(hBSP430serialLookup(APP_SD_SPI_PERIPH_HANDLE),
UCSSEL__SMCLK, init_spi_divisor);
/* Configure the chip-select port. */
APP_SD_CS_PORT_HPL->sel &= ~APP_SD_CS_PORT_BIT;
APP_SD_CS_PORT_HPL->out |= APP_SD_CS_PORT_BIT;
APP_SD_CS_PORT_HPL->dir |= APP_SD_CS_PORT_BIT;
return (0 != sdspi) ? 0 : -1;
}
#define INIT_PORT() configureSPIforSD(0)
#define REINIT_PORT_FAST() configureSPIforSD(1)
#define DLY_US(n_) BSP430_CORE_DELAY_CYCLES(((n_) * BSP430_CLOCK_NOMINAL_MCLK_HZ)/1000000)
#define CS_H() do { APP_SD_CS_PORT_HPL->out |= APP_SD_CS_PORT_BIT; } while (0)
#define CS_L() do { APP_SD_CS_PORT_HPL->out &= ~APP_SD_CS_PORT_BIT; } while (0)

The second block is the SPI transmit/receive infrastructure:

/*-----------------------------------------------------------------------*/
/* Transmit bytes to the card (bitbanging) */
/*-----------------------------------------------------------------------*/
static
void xmit_mmc (
const BYTE* buff, /* Data to be sent */
UINT bc /* Number of bytes to send */
)
{
(void)iBSP430spiTxRx_rh(sdspi, buff, bc, 0, 0);
}
/*-----------------------------------------------------------------------*/
/* Receive bytes from the card (bitbanging) */
/*-----------------------------------------------------------------------*/
static
void rcvr_mmc (
BYTE *buff, /* Pointer to read buffer */
UINT bc /* Number of bytes to receive */
)
{
(void)iBSP430spiTxRx_rh(sdspi, NULL, 0, bc, buff);
}

There are a couple other enhancements to detect when the SPI interface configuration failed, but otherwise the driver is unmodified from ChaN's generic one.

main.c

#include <bsp430/clock.h>
#include <bsp430/serial.h>
#include <stdio.h>
/* msp430.h headers define DIR which will conflict with the structure
* definition from FatFS. */
#undef DIR
#include "diskio.h"
#include "ff.h"
/* Get definitions for FATFS_IS_PRE_R0_10 and other flags that
* accommodate API changes. */
#include "ff_compat.h"
char buffer[1024];
void main ()
{
unsigned int reset_flags;
unsigned long reset_causes;
int rv;
FATFS fso;
DIR dir_obj;
FILINFO finfo;
{
unsigned int sysrstiv;
/* Record all the reset causes */
reset_causes = 0;
while (0 != ((sysrstiv = uiBSP430sysSYSRSTGenerator_ni(&reset_flags)))) {
reset_causes |= 1UL << (sysrstiv / 2);
}
}
cprintf("\nBUILD " __DATE__ " " __TIME__ "\n");
cprintf("FatFS Revision ID: %lu\n", (unsigned long)_FATFS);
cprintf("System reset bitmask %lx; causes:\n", reset_causes);
{
int bit = 0;
while (bit < (8 * sizeof(reset_causes))) {
if (reset_causes & (1UL << bit)) {
}
++bit;
}
}
cputtext("System reset included:");
if (reset_flags & BSP430_SYS_FLAG_SYSRST_BOR) {
cputtext(" BOR");
}
if (reset_flags & BSP430_SYS_FLAG_SYSRST_LPM5WU) {
cputtext(" LPM5WU");
}
if (reset_flags & BSP430_SYS_FLAG_SYSRST_POR) {
cputtext(" POR");
}
if (reset_flags & BSP430_SYS_FLAG_SYSRST_PUC) {
cputtext(" PUC");
}
cputchar('\n');
cprintf("Set core voltage gets %d\n", rv);
#if (FATFS_IS_PRE_R0_10 - 0)
rv = f_mount(0, &fso);
#else /* Pre R0.10 */
rv = f_mount(&fso, "", 1);
#endif /* Pre R0.10 */
cprintf("mount gets %d\n", rv);
if (FR_OK == rv) {
rv = f_opendir(&dir_obj, "/");
cprintf("opendir gets %d\n", rv);
}
while (FR_OK == rv) {
rv = f_readdir(&dir_obj, &finfo);
if (FR_OK != rv) {
break;
}
if (0 == finfo.fname[0]) {
break;
}
cprintf("%s %lu %u %u %#x\n", finfo.fname, finfo.fsize, finfo.fdate, finfo.ftime, finfo.fattrib);
}
{
FIL fil_obj;
/* Append a boot log message to the file BOOT.LOG. NB: This had
* failed with version combinations prior to FatFs 0.9b and BSP430
* 20130427. */
rv = f_open(&fil_obj, "0:BOOT.LOG", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
cprintf("Boot log open returned %d\n", rv);
if (FR_OK == rv) {
UINT nbytes = -1;
rv = f_read(&fil_obj, buffer, sizeof(buffer), &nbytes);
cprintf("Read boot log %u got %d with %u read\n",
(unsigned int)sizeof(buffer), rv, nbytes);
if (0 == rv) {
buffer[nbytes] = 0;
cputs("Contents:");
cputs(buffer);
}
rv = f_lseek(&fil_obj, f_size(&fil_obj));
cprintf("Seek to end got %d\n", rv);
if (FR_OK == rv) {
int nb = snprintf(buffer, sizeof(buffer), "Booted build " __DATE__ " " __TIME__ "\n");
UINT nw;
rv = f_write(&fil_obj, buffer, nb, &nw);
cprintf("write %u got %d nw %u\n", nb, rv, nw);
}
f_close(&fil_obj);
}
}
#if (FATFS_IS_PRE_R0_10 - 0)
f_mount(0, NULL);
#else /* Pre R0.10 */
f_mount(NULL, NULL, 1);
#endif /* Pre R0.10 */
cprintf("Exiting application\n");
}

bsp430_config.h

/* Use a crystal if one is installed. Much more accurate timing
* results. */
#define BSP430_PLATFORM_BOOT_CONFIGURE_LFXT1 1
/* Application does output: support spin-for-jumper */
#define configBSP430_PLATFORM_SPIN_FOR_JUMPER 1
/* Support console output */
#define configBSP430_CONSOLE 1
/* Monitor uptime and provide generic ACLK-driven timer */
#define configBSP430_UPTIME 1
/* Explicitly require SPI via serial abstraction */
#define configBSP430_SERIAL_ENABLE_SPI 1
/* SD card is on USCI B1, which by default is port-mapped to P4 */
#define configBSP430_HAL_USCI5_B1 1
#define APP_SD_SPI_PERIPH_HANDLE BSP430_PERIPH_USCI5_B1
/* For some SD cards/holders, MISO may need to be pulled up. Normally
* SPI doesn't require this so the pin configuration doesn't do it.
* Unfortunately we don't provide a way to introspect into the
* specific pins and ports used by the peripheral handle, so we need
* to hard-code this, and on the exp430f5529 MISO is on P4.2 */
#define configBSP430_HPL_PORT4 1
#define APP_SD_MISO_PORT_PERIPH_HANDLE BSP430_PERIPH_PORT4
#define APP_SD_MISO_PORT_BIT BIT2
/* The chip select for the SD card is on P3.7 */
#define configBSP430_HPL_PORT3 1
#define APP_SD_CS_PORT_PERIPH_HANDLE BSP430_PERIPH_PORT3
#define APP_SD_CS_PORT_BIT BIT7
/* MMC SD requires that the dummy byte that cues a read be 0xFF */
#define BSP430_SERIAL_SPI_READ_TX_BYTE(i_) 0xFF
/* Get platform defaults */

Makefile

PLATFORM ?= exp430f5529
TEST_PLATFORMS=exp430f5529
AUX_CPPFLAGS = -Ifatfs/src
MODULES=$(MODULES_PLATFORM)
MODULES += $(MODULES_UPTIME)
MODULES += $(MODULES_CONSOLE)
MODULES += $(MODULES_SERIAL)
MODULES += periph/sys
MODULES += periph/pmm
SRC=bsp430mmc.c main.c fatfs/src/ff.c
include $(BSP430_ROOT)/make/Makefile.common