SAMA5: Some improvements to the HSCMI card removal/insertion logic

This commit is contained in:
Gregory Nutt 2013-08-11 11:13:11 -06:00
parent d6264c2c1f
commit dd3c682443
6 changed files with 156 additions and 65 deletions

View File

@ -2438,8 +2438,8 @@ static void sam_callback(void *arg)
{ {
/* Yes.. queue it */ /* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); fllvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
(void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0); (void)work_queue(LPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
} }
else else
{ {
@ -2551,7 +2551,7 @@ void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot)
priv->cdstatus &= ~SDIO_STATUS_PRESENT; priv->cdstatus &= ~SDIO_STATUS_PRESENT;
} }
fvdbg("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus); fllvdbg("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus);
/* Perform any requested callback if the status has changed */ /* Perform any requested callback if the status has changed */

View File

@ -2704,8 +2704,8 @@ static void sam_callback(void *arg)
{ {
/* Yes.. queue it */ /* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); fllvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
(void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0); (void)work_queue(LPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
} }
else else
{ {
@ -2931,7 +2931,7 @@ void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot)
priv->cdstatus &= ~SDIO_STATUS_PRESENT; priv->cdstatus &= ~SDIO_STATUS_PRESENT;
} }
fvdbg("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus); fllvdbg("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus);
/* Perform any requested callback if the status has changed */ /* Perform any requested callback if the status has changed */

View File

@ -1045,6 +1045,45 @@ Configurations
Application Configuration -> NSH Library Application Configuration -> NSH Library
CONFIG_NSH_ARCHINIT=y : NSH board-initialization CONFIG_NSH_ARCHINIT=y : NSH board-initialization
Using the SD card:
1) If you try mounting an SD card with nothing in the slot, the
mount will fail:
nsh> mount -t vfat /dev/mmcsd1 /mnt/sd1
nsh: mount: mount failed: 19
NSH can be configured to provide errors as strings instead of
numbers. But in this case, only the error number is reported.
The error numbers can be found in nuttx/include/errno.h:
#define ENODEV 19
#define ENODEV_STR "No such device"
So the mount command is saying that there is no device or, more
correctly, that there is no card in the SD card slot.
2) Inserted the SD card. Then the mount should succeed.
nsh> mount -t vfat /dev/mmcsd1 /mnt/sd1
nsh> ls /mnt/sd1
/mnt/sd1:
atest.txt
nsh> cat /mnt/sd1/atest.txt
This is a test
3) Before removing the card, you must umount the file system. This
is equivalent to "ejecting" or "safely removing" the card on
Windows: It flushes any cached data to the card and makes the SD
card unavailable to the applications.
nsh> mount -t vfat /dev/mmcsd1 /mnt/sd1
It is now safe to remove the card. NuttX provides into callbacks
that can be used by an application to automatically unmount the
volume when it is removed. But those callbacks are not used in
this configuration.
STATUS: STATUS:
2013-7-19: This configuration (as do the others) run at 396MHz. 2013-7-19: This configuration (as do the others) run at 396MHz.
The SAMA5D3 can run at 536MHz. I still need to figure out the The SAMA5D3 can run at 536MHz. I still need to figure out the
@ -1063,7 +1102,7 @@ Configurations
2013-7-31: Using delay loop calibration from the hello configuration. 2013-7-31: Using delay loop calibration from the hello configuration.
That configuration runs out of internal SRAM and, as a result, this That configuration runs out of internal SRAM and, as a result, this
configuration needs to be recalibrated. configuration should be recalibrated.
2013-8-3: SDRAM configuration and RAM test usage have been verified 2013-8-3: SDRAM configuration and RAM test usage have been verified
and are functional. I note some issues; occassionally, SDRAM is and are functional. I note some issues; occassionally, SDRAM is
@ -1080,6 +1119,18 @@ Configurations
2013-8-10: Basic HSCMI1 functionality (with DMA) has been verified. 2013-8-10: Basic HSCMI1 functionality (with DMA) has been verified.
Most testing is needed to assure that this is a stable solution. Most testing is needed to assure that this is a stable solution.
2013-8-11: HSMCI0 is more finicky. Usually there is no card
communcation and I get timeouts. But if I remove and re-insert the
card it few times, sometimes communication is successfully and the
card behaves normally. I suspected an electro-mechanical issue but
but now think there is more to the problem than that.
2013-8-11: I see another problem doing card insertion and card removal
testing. When there is a lot of debug output, the system locks up.
I have traced to this the debug output itself. The debug output
from the device driver interferes with normal serial port operation
and prevents NSH from receiving data. There is no issue when the
debug output is suppressed and card insertial and removal works as
expected (at least on the HSMCI1 microSD slot).
ostest: ostest:
This configuration directory, performs a simple OS test using This configuration directory, performs a simple OS test using

View File

@ -93,46 +93,45 @@
/**************************************************************************** /****************************************************************************
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
/* This structure holds information unique to one HSMCI peripheral */ /* This structure holds static information unique to one HSMCI peripheral */
struct sam_hsmci_info_s struct sam_hsmci_state_s
{ {
struct sdio_dev_s *hsmci; /* R/W device handle */
pio_pinset_t pincfg; /* Card detect PIO pin configuratin */ pio_pinset_t pincfg; /* Card detect PIO pin configuratin */
uint8_t irq; /* Interrupt number (same as pid) */ uint8_t irq; /* Interrupt number (same as pid) */
uint8_t slotno; /* Slot number */
bool cd; /* TRUE: card is inserted */
xcpt_t handler; /* Interrupt handler */ xcpt_t handler; /* Interrupt handler */
struct sdio_dev_s **hsmci; /* R/W device handle */
}; };
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
/* Retained HSMCI driver handles for use by interrupt handlers */ /* HSCMI device state */
#ifdef CONFIG_SAMA5_HSMCI0
static struct sdio_dev_s *g_hsmci0;
#endif
#ifdef CONFIG_SAMA5_HSMCI1
static struct sdio_dev_s *g_hsmci1;
#endif
/* HSCMI device characteristics */
#ifdef CONFIG_SAMA5_HSMCI0 #ifdef CONFIG_SAMA5_HSMCI0
static int sam_hsmci0_cardetect(int irq, void *regs); static int sam_hsmci0_cardetect(int irq, void *regs);
static const struct sam_hsmci_info_s g_hsmci0_info = static struct sam_hsmci_state_s g_hsmci0 =
{ {
PIO_MCI0_CD, IRQ_MCI0_CD, sam_hsmci0_cardetect, &g_hsmci0 .pincfg = PIO_MCI0_CD,
.irq = IRQ_MCI0_CD,
.slotno = 0,
.handler = sam_hsmci0_cardetect,
}; };
#endif #endif
#ifdef CONFIG_SAMA5_HSMCI1 #ifdef CONFIG_SAMA5_HSMCI1
static int sam_hsmci1_cardetect(int irq, void *regs); static int sam_hsmci1_cardetect(int irq, void *regs);
static const struct sam_hsmci_info_s g_hsmci1_info = static struct sam_hsmci_state_s g_hsmci1 =
{ {
PIO_MCI1_CD, IRQ_MCI1_CD, sam_hsmci1_cardetect, &g_hsmci1 .pincfg = PIO_MCI1_CD,
.irq = IRQ_MCI1_CD,
.slotno = 1,
.handler = sam_hsmci1_cardetect,
}; };
#endif #endif
@ -141,47 +140,86 @@ static const struct sam_hsmci_info_s g_hsmci1_info =
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: sam_hsmci0_cardetect and sam_hsmci1_cardetect * Name: sam_cardinserted_internal
*
* Description:
* Check if a card is inserted into the selected HSMCI slot
*
****************************************************************************/
bool sam_cardinserted_internal(struct sam_hsmci_state_s *state)
{
bool inserted;
/* Get the state of the PIO pin */
inserted = sam_pioread(state->pincfg);
fllvdbg("Slot %d inserted: %s\n", state->slotno, inserted ? "NO" : "YES");
return !inserted;
}
/****************************************************************************
* Name: sam_hsmci_cardetect, sam_hsmci0_cardetect, and sam_hsmci1_cardetect
* *
* Description: * Description:
* Card detect interrupt handlers * Card detect interrupt handlers
* *
****************************************************************************/ ****************************************************************************/
static int sam_hsmci_cardetect(struct sam_hsmci_state_s *state)
{
/* Get the current card insertion state */
bool cd = sam_cardinserted_internal(state);
/* Has the card detect state changed? */
if (cd != state->cd)
{
/* Yes... remember that new state and inform the HSMCI driver */
state->cd = cd;
/* Report the new state to the SDIO driver */
sdio_mediachange(state->hsmci, cd);
}
return OK;
}
#ifdef CONFIG_SAMA5_HSMCI0 #ifdef CONFIG_SAMA5_HSMCI0
static int sam_hsmci0_cardetect(int irq, void *regs) static int sam_hsmci0_cardetect(int irq, void *regs)
{ {
sdio_mediachange(g_hsmci0, sam_cardinserted(0)); return sam_hsmci_cardetect(&g_hsmci0);
return OK;
} }
#endif #endif
#ifdef CONFIG_SAMA5_HSMCI1 #ifdef CONFIG_SAMA5_HSMCI1
static int sam_hsmci1_cardetect(int irq, void *regs) static int sam_hsmci1_cardetect(int irq, void *regs)
{ {
sdio_mediachange(g_hsmci1, sam_cardinserted(1)); return sam_hsmci_cardetect(&g_hsmci1);
return OK;
} }
#endif #endif
/**************************************************************************** /****************************************************************************
* Name: sam_hsmci_info * Name: sam_hsmci_state
* *
* Description: * Description:
* Initialize HSMCI PIOs. * Initialize HSMCI PIOs.
* *
****************************************************************************/ ****************************************************************************/
static const struct sam_hsmci_info_s *sam_hsmci_info(int slotno) static struct sam_hsmci_state_s *sam_hsmci_state(int slotno)
{ {
const struct sam_hsmci_info_s *info = NULL; struct sam_hsmci_state_s *state = NULL;
#ifdef CONFIG_SAMA5_HSMCI0 #ifdef CONFIG_SAMA5_HSMCI0
#ifdef CONFIG_SAMA5_HSMCI1 #ifdef CONFIG_SAMA5_HSMCI1
if (slotno == 0) if (slotno == 0)
#endif #endif
{ {
info = &g_hsmci0_info; state = &g_hsmci0;
} }
#ifdef CONFIG_SAMA5_HSMCI1 #ifdef CONFIG_SAMA5_HSMCI1
else else
@ -190,11 +228,11 @@ static const struct sam_hsmci_info_s *sam_hsmci_info(int slotno)
#ifdef CONFIG_SAMA5_HSMCI1 #ifdef CONFIG_SAMA5_HSMCI1
{ {
info = &g_hsmci1_info; state = &g_hsmci1;
} }
#endif #endif
return info; return state;
} }
/**************************************************************************** /****************************************************************************
@ -211,27 +249,27 @@ static const struct sam_hsmci_info_s *sam_hsmci_info(int slotno)
int sam_hsmci_initialize(int slotno, int minor) int sam_hsmci_initialize(int slotno, int minor)
{ {
const struct sam_hsmci_info_s *info; struct sam_hsmci_state_s *state;
int ret; int ret;
/* Get the HSMI description */ /* Get the static HSMI description */
info = sam_hsmci_info(slotno); state = sam_hsmci_state(slotno);
if (!info) if (!state)
{ {
fdbg("No info for slotno %d\n", slotno); fdbg("No state for slotno %d\n", slotno);
return -EINVAL; return -EINVAL;
} }
/* Initialize card-detect and write-protect PIOs */ /* Initialize card-detect and write-protect PIOs */
sam_configpio(info->pincfg); sam_configpio(state->pincfg);
/* Mount the SDIO-based MMC/SD block driver */ /* Mount the SDIO-based MMC/SD block driver */
/* First, get an instance of the SDIO interface */ /* First, get an instance of the SDIO interface */
*info->hsmci = sdio_initialize(slotno); state->hsmci = sdio_initialize(slotno);
if (!*info->hsmci) if (!state->hsmci)
{ {
fdbg("Failed to initialize SDIO slot %d\n", slotno); fdbg("Failed to initialize SDIO slot %d\n", slotno);
return -ENODEV; return -ENODEV;
@ -239,7 +277,7 @@ int sam_hsmci_initialize(int slotno, int minor)
/* Now bind the SDIO interface to the MMC/SD driver */ /* Now bind the SDIO interface to the MMC/SD driver */
ret = mmcsd_slotinitialize(minor, *info->hsmci); ret = mmcsd_slotinitialize(minor, state->hsmci);
if (ret != OK) if (ret != OK)
{ {
fdbg("Failed to bind SDIO to the MMC/SD driver: %d\n", ret); fdbg("Failed to bind SDIO to the MMC/SD driver: %d\n", ret);
@ -248,14 +286,17 @@ int sam_hsmci_initialize(int slotno, int minor)
/* Configure card detect interrupts */ /* Configure card detect interrupts */
sam_pioirq(info->pincfg); sam_pioirq(state->pincfg);
(void)irq_attach(info->irq, info->handler); (void)irq_attach(state->irq, state->handler);
sam_pioirqenable(info->irq);
/* Then inform the HSMCI driver if there is or is not a card in the slot. */ /* Then inform the HSMCI driver if there is or is not a card in the slot. */
sdio_mediachange(*info->hsmci, sam_cardinserted(slotno)); state->cd = sam_cardinserted_internal(state);
sdio_mediachange(state->hsmci, state->cd);
/* Enable card detect interrupts */
sam_pioirqenable(state->irq);
return OK; return OK;
} }
@ -269,23 +310,20 @@ int sam_hsmci_initialize(int slotno, int minor)
bool sam_cardinserted(int slotno) bool sam_cardinserted(int slotno)
{ {
const struct sam_hsmci_info_s *info; struct sam_hsmci_state_s *state;
bool inserted;
/* Get the HSMI description */ /* Get the HSMI description */
info = sam_hsmci_info(slotno); state = sam_hsmci_state(slotno);
if (!info) if (!state)
{ {
fdbg("No info for slotno %d\n", slotno); fdbg("No state for slotno %d\n", slotno);
return false; return false;
} }
/* Get the state of the PIO pin */ /* Return the state of the PIO pin */
inserted = sam_pioread(info->pincfg); return sam_cardinserted_internal(state);
fvdbg("Slot %d inserted: %s\n", slotno, inserted ? "NO" : "YES");
return !inserted;
} }
/**************************************************************************** /****************************************************************************

View File

@ -2231,6 +2231,7 @@ static void mmcsd_mediachange(FAR void *arg)
SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED);
} }
mmcsd_givesem(priv); mmcsd_givesem(priv);
} }

View File

@ -289,7 +289,8 @@ static int uart_putxmitchar(FAR uart_dev_t *dev, int ch, bool oktoblock)
* Name: uart_irqwrite * Name: uart_irqwrite
************************************************************************************/ ************************************************************************************/
static inline ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t buflen) static inline ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer,
size_t buflen)
{ {
ssize_t ret = buflen; ssize_t ret = buflen;
@ -321,9 +322,9 @@ static inline ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer,
static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen) size_t buflen)
{ {
FAR struct inode *inode = filep->f_inode; FAR struct inode *inode = filep->f_inode;
FAR uart_dev_t *dev = inode->i_private; FAR uart_dev_t *dev = inode->i_private;
ssize_t nread = buflen; ssize_t nwritten = buflen;
bool oktoblock; bool oktoblock;
int ret; int ret;
char ch; char ch;
@ -473,13 +474,13 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer,
* interrupted transfer. * interrupted transfer.
*/ */
if (buflen < nread) if (buflen < nwritten)
{ {
/* Some data was transferred. Return the number of bytes that /* Some data was transferred. Return the number of bytes that
* were successfully transferred. * were successfully transferred.
*/ */
nread -= buflen; nwritten -= buflen;
} }
else else
{ {
@ -487,7 +488,7 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer,
* The VFS layer will set the errno value appropriately). * The VFS layer will set the errno value appropriately).
*/ */
nread = ret; nwritten = ret;
} }
break; break;
@ -500,7 +501,7 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer,
} }
uart_givesem(&dev->xmit.sem); uart_givesem(&dev->xmit.sem);
return nread; return nwritten;
} }
/************************************************************************************ /************************************************************************************