ASF SD Card driver problem for ATMEL SAMV71 Micro running Reliance Edge and FreeRTOS

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I am currently attempting to run some speed tests provided by Datalight (vendors of the Reliance Edge File System). I have therefore integrated FreeRTOS, Reliance Edge and ASF SD card drivers together onto a SAMV71 Xplained board.

The result is that I have a Reliance Edge File system running from an SD card. This has been all good... But I have found that the ASF SD/MMC driver code only appears to function correctly if all the data is written to the card using a multi-block-transfer (SD card CMD25). I find that a single block transfer (CMD24) seems to result in a response timeout (MAXLAT exceeded). I have not chased this down further and am living with multi-block transfers only.

 

Is there a reason that CMD24 might not work and CMD25 work just fine?

 

Many thanks,

 

Paul.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I am now also getting problems with multi block transfers too (when the amount of data passed by a single multi-block transfer exceeds a certain quantity of data). 

 

I have chased this down a bit further with the aid of the Atmel Studio debugger and a scope.

 

Here is the sequence of events:

- I can see that the Micro sends SD card command CMD25.

- I can see that lots of data is transferred using the DAT0 ->DAT3 lines and the CLK line is going up and down nicely (the ASF driver is using SD 4 line parallel data interface - not SPI)

- At the end of a single multi-block transfer, I can see the Micro sends CMD12 (Stop transfer). All good so far.

- At this point, I can see the DAT0 line go low... According to my reading, this is good and is the SD Card telling the Micro that the data is being committed to the underlying media.

- Around 4 to 5ms later, DAT0 goes high (released by SD card)... again, this sounds good: data commit has finished.

- However, despite DAT0 going high, the HSMCI_SR register has the NOTBUSY set low... I don't understand this... as I read the SAMV71 datasheet, NOTBUSY should follow DAT0.

- Now the code is stuck in the following code loop (ASF code):

 

/**
 * \brief Wait the end of busy signal on data line
 *
 * \param hw       The pointer to MCI hardware instance
 * \return true if success, otherwise false
 */
static bool _mci_wait_busy(const void *const hw)
{
	uint32_t busy_wait = 0xFFFFFFFF;
	uint32_t sr;

	ASSERT(hw);

	do {
		sr = hri_hsmci_read_SR_reg(hw);
		if (busy_wait-- == 0) {
			_mci_reset(hw);
			return false;
		}
	} while (!((sr & HSMCI_SR_NOTBUSY) && ((sr & HSMCI_SR_DTIP) == 0)));
	return true;
}

The loop continues for a very long time (until busy_wait hits 0)... The reason is that HSMCI_SR_NOTBUSY is false.... Any ideas why?

 

I can see references elsewhere in the code to what looks like chip errata Ref !MMC7 and !SD19... Are there a lot of SD related problems with this chip? I have looked at the chip errata:  http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_E70_S70_V70_V71_Family_Errata_DS80000767D.pdf. I can't see any problems with the HSMCI device listed and the references !MMC7 and !SD19 are not mentioned.

 

Thanks,

 

Paul.

Last Edited: Fri. Dec 6, 2019 - 01:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Hi All, 

 

My investigation here continues:

 

As I said above, the ASF driver does manage to send data to the SD card using the multi-block write type sequencing (CMD25 & CMD12). It works reliably when the number of blocks transferred is low (4). In this case, the scope shows the following activity:

 

Sucessful multi-clock transmission

 

However, when the number of blocks is much higher, things seem to go wrong at the end of the transfer:

 

A few things to note... when things go wrong... the CMDIO line as active close to the DAT0 going low... not sure if this is linked to the problem?

 

During the multi-block transfer where this problem occurs, the code runs through the following ASF function:

 

/**
 * \brief Send a command
 *
 * \param hw         The pointer to MCI hardware instance
 * \param cmdr       CMDR resgister bit to use for this command
 * \param cmd        Command definition
 * \param arg        Argument of the command
 *
 * \return true if success, otherwise false
 */
static bool _mci_send_cmd_execute(const void *const hw, uint32_t cmdr, uint32_t cmd, uint32_t arg)
{
	uint32_t sr;
	ASSERT(hw);

	cmdr |= HSMCI_CMDR_CMDNB(cmd) | HSMCI_CMDR_SPCMD_STD;
	if (cmd & MCI_RESP_PRESENT) {
		cmdr |= HSMCI_CMDR_MAXLAT;
		if (cmd & MCI_RESP_136) {
			cmdr |= HSMCI_CMDR_RSPTYP_136_BIT;
		} else if (cmd & MCI_RESP_BUSY) {
			cmdr |= HSMCI_CMDR_RSPTYP_R1B;
		} else {
			cmdr |= HSMCI_CMDR_RSPTYP_48_BIT;
		}
	}
	if (cmd & MCI_CMD_OPENDRAIN) {
		cmdr |= HSMCI_CMDR_OPDCMD_OPENDRAIN;
	}

	hri_hsmci_write_ARGR_reg(hw, arg);
	hri_hsmci_write_CMDR_reg(hw, cmdr);

	/* Wait end of command */
	do {
		sr = hri_hsmci_read_SR_reg(hw);
		if (cmd & MCI_RESP_CRC) {
			if (sr
			    & (HSMCI_SR_CSTOE | HSMCI_SR_RTOE | HSMCI_SR_RENDE | HSMCI_SR_RCRCE | HSMCI_SR_RDIRE
			       | HSMCI_SR_RINDE)) {
				_mci_reset(hw);
				return false;
			}
		} else {
			if (sr & (HSMCI_SR_CSTOE | HSMCI_SR_RTOE | HSMCI_SR_RENDE | HSMCI_SR_RDIRE | HSMCI_SR_RINDE)) {
				_mci_reset(hw);
				return false;
			}
		}
	} while (!(sr & HSMCI_SR_CMDRDY));

	if (cmd & MCI_RESP_BUSY) {
		if (!_mci_wait_busy(hw)) {
			return false;
		}
	}
	return true;
}

In the final invocation of this function (when the problem occurs), the code never exits _mci_wait_busy(hw) having sent CMD12 and having the response from the SD, as I explained above HSMCI_SR_NOTBUSY is false forever?!? 

 

Any ideas ASF community... your help is much appreciated ;)

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Aha...

 

I have narrowed things down now... The problem seems timing related.... I have found that the code works more reliably if I insert a delay here (between the write to the CMDR register and the read of the SR register - see the vTaskDelay() function call)

 

/**
 * \brief Send a command
 *
 * \param hw         The pointer to MCI hardware instance
 * \param cmdr       CMDR resgister bit to use for this command
 * \param cmd        Command definition
 * \param arg        Argument of the command
 *
 * \return true if success, otherwise false
 */
static bool _mci_send_cmd_execute(const void *const hw, uint32_t cmdr, uint32_t cmd, uint32_t arg)
{
	uint32_t sr;
	ASSERT(hw);

	cmdr |= HSMCI_CMDR_CMDNB(cmd) | HSMCI_CMDR_SPCMD_STD;
	if (cmd & MCI_RESP_PRESENT) {
		cmdr |= HSMCI_CMDR_MAXLAT;
		if (cmd & MCI_RESP_136) {
			cmdr |= HSMCI_CMDR_RSPTYP_136_BIT;
		} else if (cmd & MCI_RESP_BUSY) {
			cmdr |= HSMCI_CMDR_RSPTYP_R1B;
		} else {
			cmdr |= HSMCI_CMDR_RSPTYP_48_BIT;
		}
	}
	if (cmd & MCI_CMD_OPENDRAIN) {
		cmdr |= HSMCI_CMDR_OPDCMD_OPENDRAIN;
	}

	hri_hsmci_write_ARGR_reg(hw, arg);
	hri_hsmci_write_CMDR_reg(hw, cmdr);

	vTaskDelay(100);

	/* Wait end of command */
	do {
		sr = hri_hsmci_read_SR_reg(hw);
		if (cmd & MCI_RESP_CRC) {
			if (sr
			    & (HSMCI_SR_CSTOE | HSMCI_SR_RTOE | HSMCI_SR_RENDE | HSMCI_SR_RCRCE | HSMCI_SR_RDIRE
			       | HSMCI_SR_RINDE)) {
				_mci_reset(hw);
				return false;
			}
		} else {
			if (sr & (HSMCI_SR_CSTOE | HSMCI_SR_RTOE | HSMCI_SR_RENDE | HSMCI_SR_RDIRE | HSMCI_SR_RINDE)) {
				_mci_reset(hw);
				return false;
			}
		}
	} while (!(sr & HSMCI_SR_CMDRDY));

	if (cmd & MCI_RESP_BUSY) {
		if (!_mci_wait_busy(hw)) {
			return false;
		}
	}
	return true;
}

 

Is this ringing any bells for anyone yet?

Last Edited: Mon. Dec 9, 2019 - 02:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok... Now I am getting somewhere....

 

According to the SAMV71 datasheet (Atmel-44003E-ATARM-SAM V71-Datasheet_12-Oct-16), Figures 40-12 and 40-10: the end of the transfer is determined by polling for the XFRDONE bit within the HSMCI Status register. This is at odds with the ASF driver which polls 2 bits NOTBUSY and DTIP.

 

The ASF technique does not work under all circumstances. I have therefore changed this code:

 

/**
 * \brief Wait the end of busy signal on data line
 *
 * \param hw       The pointer to MCI hardware instance
 * \return true if success, otherwise false
 */
static bool _mci_wait_busy(const void *const hw)
{
	uint32_t busy_wait = 0xFFFFFFFF;
	uint32_t sr;

	ASSERT(hw);

	do {
		sr = hri_hsmci_read_SR_reg(hw);
		if (busy_wait-- == 0) {
			_mci_reset(hw);
			return false;
		}
	} while (!((sr & HSMCI_SR_NOTBUSY) && ((sr & HSMCI_SR_DTIP) == 0)));
	return true;
}

 

to read like this:

 

/**
 * \brief Wait the end of busy signal on data line
 *
 * \param hw       The pointer to MCI hardware instance
 * \return true if success, otherwise false
 */
static bool _mci_wait_busy(const void *const hw)
{
	uint32_t busy_wait = 0xFFFFFFFF;
	uint32_t sr;

	ASSERT(hw);

	do {
		sr = hri_hsmci_read_SR_reg(hw);
		if (busy_wait-- == 0) {
			_mci_reset(hw);
			return false;
		}
	} while (!(sr & HSMCI_SR_XFRDONE));
	return true;

 

It now appears to be working more reliably.... Does this constitute a bug in the ASF code?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Moderators (or anyone else),

 

How do I report a bug? I can see a reference to a bugzilla portal on avrfreaks but the link took me to microchip support... Should bugs be reported that way?

 

Thanks,

 

Paul.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

https://microchipsupport.force.com/s/

 

Create a support case for the bug. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have now created a Microchip case here:

 

https://microchipsupport.force.com/s/case/5003l00000y1gaIAAQ/detail

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have similar problem on ATSAME70Q21B.

Reading from SD sometimes hangs after 30min to some hours.

If I reset the SD hangs after some seconds. I have to switch off everything and wait some minutes before start again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, have you tried the above fix to the function _mci_wait_busy?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, my software doesn't hangs in mci_wait_busy, it seems a problem even more strange.

For some reason my SAM E70 hangs when I drive 24bit of parallel data on pins of PORTC all together...