[STM32GENERIC] SDIO DMA

Discussions about the STM32generic core
User avatar
Pito
Posts: 1593
Joined: Sat Mar 26, 2016 3:26 pm
Location: Rapa Nui

Re: [STM32GENERIC] SDIO DMA

Post by Pito » Wed May 17, 2017 7:27 pm

With the Sandisk CL10 it works "somehow" in 4bit mode so I added the first 4bits copy test result:
SDIO 1bit and 4bit Copy.JPG
SDIO 1bit and 4bit Copy.JPG (59.61 KiB) Viewed 355 times
With 42MHz SDIO clk it throws errors:

Code: Select all

Use a freshly formatted SD for best performance.
Type any character to start

Opening the read file..
Opening the write file..
Reading and Writing..
HAL_SD_WriteBlocks Error: 5
HAL_SD_WriteBlocks Error: 3
HAL_SD_WriteBlocks Error: 16
HAL_SD_WriteBlocks Error: 5
HAL_SD_WriteBlocks Error: 3
HAL_SD_WriteBlocks Error: 16
HAL_SD_WriteBlocks Error: 3
HAL_SD_WriteBlocks Error: 3
..
HAL_SD_WriteBlocks Error: 3
Pukao Hats Cleaning Services Ltd.

victor_pv
Posts: 1681
Joined: Mon Apr 27, 2015 12:12 pm

Re: [STM32GENERIC] SDIO DMA

Post by victor_pv » Wed May 17, 2017 8:45 pm

stevestrong wrote:Extract from F4 errata sheet:

Code: Select all

2.12 SDIO peripheral limitations
2.12.1 SDIO HW flow control
Description
When enabling the HW flow control by setting bit 14 of the SDIO_CLKCR register to ‘1’,
glitches can occur on the SDIOCLK output clock resulting in wrong data to be written into
the SD/MMC card or into the SDIO device. As a consequence, a CRC error will be reported
to the SD/SDIO MMC host interface (DCRCFAIL bit set to ‘1’ in SDIO_STA register).
Workaround
None.
Note: Do not use the HW flow control. Overrun errors (Rx mode) and FIFO underrun (Tx mode)
should be managed by the application software.
Conclusion: Do not use the HW flow control.
Yeah I read about that, but currently I do not know if sdfat manages any kind of errors or just fails, so I wanted to see if with HW Flow control we would get the CL10 card detected and start writing, even if it failed the hash. But in Pito's test it did not work any better.
I think we need to add at least a basic error management and retries in our layer, since the HAL SDIO drive does not provide error management (it does report, but doesn't retry).
From what I have read, I think we need to confirm before reads or writes that the card is ready to actually accept data. And once a write is completed, read the card status and confirm there were no errors, and retry if needed.
But perhaps SDFat already provides for some retry. It's kind of complicated to track it all with so many layers.

Regarding SdioEX. Basically what it adds is support for multiblock writes. The SdFat library uses a single 512byte cache. That is 1 block. So to write 10 consecutive blocks, SdioEX does this:
1-Send starting LBA to the card, and the command for multiblock write.
2.-Sends a block and return
3.- Sdfat calls the driver for another write, the drive check if the lba is the consecutive one.
4.-If so, the drive writes the new block without sending any command or address to the card.
5.- Repeat from step 3 until the LBA to write to is not consecutive, in which case send a command to stop multiblock write and start from step 1.

The HAL currently does not do that, every write implies sending command and address to the card, wait for the card to accept them, then send 1 block. Next write even if consecutive LBA address is used, will result in the whole process again.
The HAL does not provide for sending multiple blocks one by one. You can send a block of say 2KB at once, but since SdFat writes always in blocks of 512 because that is the size of the buffer, it results in single block addressing and write each time.
We could copy the parts we need from the HAL and modify for allowing multiblock writes as the SdioEX, but I wonder how much that would break compatibility between series...

victor_pv
Posts: 1681
Joined: Mon Apr 27, 2015 12:12 pm

Re: [STM32GENERIC] SDIO DMA

Post by victor_pv » Wed May 17, 2017 11:00 pm

Pito wrote: With 42MHz SDIO clk it throws errors:

Code: Select all

Use a freshly formatted SD for best performance.
Type any character to start

Opening the read file..
Opening the write file..
Reading and Writing..
HAL_SD_WriteBlocks Error: 5
HAL_SD_WriteBlocks Error: 3
HAL_SD_WriteBlocks Error: 16
HAL_SD_WriteBlocks Error: 5
HAL_SD_WriteBlocks Error: 3
HAL_SD_WriteBlocks Error: 16
HAL_SD_WriteBlocks Error: 3
HAL_SD_WriteBlocks Error: 3
..
HAL_SD_WriteBlocks Error: 3
Those are timeout, FIFO underrun, and illegal command errors:
SD_CMD_RSP_TIMEOUT = (3U),
SD_TX_UNDERRUN = (5U),
SD_ILLEGAL_CMD = (16U),

danieleff
Posts: 336
Joined: Thu Sep 01, 2016 8:52 pm
Location: Hungary
Contact:

Re: [STM32GENERIC] SDIO DMA

Post by danieleff » Thu May 18, 2017 4:03 am

victor_pv wrote:From what I have read, I think we need to confirm before reads or writes that the card is ready to actually accept data. And once a write is completed, read the card status and confirm there were no errors, and retry if needed.
But perhaps SDFat already provides for some retry. It's kind of complicated to track it all with so many layers.
I am not sure which function to call to "confirm before reads or writes that the card is ready to actually accept data". If there is one, yes, do it. Also yes to do a few retries.
victor_pv wrote: The HAL does not provide for sending multiple blocks one by one. You can send a block of say 2KB at once, but since SdFat writes always in blocks of 512 because that is the size of the buffer, it results in single block addressing and write each time.
We could copy the parts we need from the HAL and modify for allowing multiblock writes as the SdioEX, but I wonder how much that would break compatibility between series...
HAL: The last parameter of HAL_SD_ReadBlocks/HAL_SD_WriteBlocks is the number of blocks.
SdFat-beta: BaseBlockDriver.readBlocks/writeBlocks also has a version with number of blocks parameter.

victor_pv
Posts: 1681
Joined: Mon Apr 27, 2015 12:12 pm

Re: [STM32GENERIC] SDIO DMA

Post by victor_pv » Thu May 18, 2017 4:33 am

danieleff wrote:
victor_pv wrote:From what I have read, I think we need to confirm before reads or writes that the card is ready to actually accept data. And once a write is completed, read the card status and confirm there were no errors, and retry if needed.
But perhaps SDFat already provides for some retry. It's kind of complicated to track it all with so many layers.
I am not sure which function to call to "confirm before reads or writes that the card is ready to actually accept data". If there is one, yes, do it. Also yes to do a few retries.
victor_pv wrote: The HAL does not provide for sending multiple blocks one by one. You can send a block of say 2KB at once, but since SdFat writes always in blocks of 512 because that is the size of the buffer, it results in single block addressing and write each time.
We could copy the parts we need from the HAL and modify for allowing multiblock writes as the SdioEX, but I wonder how much that would break compatibility between series...
HAL: The last parameter of HAL_SD_ReadBlocks/HAL_SD_WriteBlocks is the number of blocks.
SdFat-beta: BaseBlockDriver.readBlocks/writeBlocks also has a version with number of blocks parameter.
Daniel the difference is that SdioEX will send a multiblock write command, then send 512 bytes.
If the next write LBA is in sequence, will send another 512 bytes (without sending a new LBA or a stop command), and so on, until an LBA out of sequence is sent, or a read.

If that happens, the SdioEX will sent a command 12 to stop the writes, and send the new LBA.
The advantage is that if you sent let's say 64KB in consecutive blocks, you only send 1 command to the Card.
With the HAL if you do a send for 64KB, the sdfat library will break it down in blocks, it sends command, then writes, then send stop command, the another write (which will involve sending command, lba, data, stop...).
It's more overhead than what the SdioEX has for sequential blocks. On random access the performance should be more similar, but since we are testing with the bench sketch that will read and write large sequential files, the SdioEX method provides for less overhead.

danieleff
Posts: 336
Joined: Thu Sep 01, 2016 8:52 pm
Location: Hungary
Contact:

Re: [STM32GENERIC] SDIO DMA

Post by danieleff » Thu May 18, 2017 5:27 am

OK I see what you mean. Yes, copy parts of HAL code, and use that. As you said it might break different series, so as default use `#define sdioex sdio`, and for F4 use parts of the F4 HAL. This way it will work. And for other series, only do this is somebody can actually test.

But first concentrate on the error.

User avatar
Pito
Posts: 1593
Joined: Sat Mar 26, 2016 3:26 pm
Location: Rapa Nui

Re: [STM32GENERIC] SDIO DMA

Post by Pito » Thu May 18, 2017 9:00 am

It would be great if someone else did the tests with SDIO too.
Here is the "COPY TEST" I published on this forum a year back - here the version with SDIO.
Simply copy a file of "any size" to the Sdcard, rename it to "test_in.bin". After the running the sketch it copies the test_in.bin into the "test_out.bin".
Compare the hashes to check whether the copy went well.
Note: you want Victor's SDIO lib files from here
https://github.com/victorpv/STM32GENERI ... s/SDIO/src
https://github.com/victorpv/STM32GENERI ... 07VE/Bench
Also you need SdFat lib too.

Code: Select all

/*
 SDcard SDIO example - Copy Test - copy binaries 
 Buffer of BUFSIZE bytes is used for writing.
 You have to place a binary called "test_in.bin" on the SDcard and run the sketch.
 You will get the "test_out.bin" after the copy finishes.
 Pito 5/2016, no warranties of any kind
 Pito 5/2017, no warranties of any kind 
 */
#include "SDIO.h"
#include "STM32SdFatSdio.h"

STM32SdFatSdio sd;
SdFile myFileIn;
SdFile myFileOut;

#define BUFSIZE 32*1024

// Serial output stream
ArduinoOutStream cout(Serial);

void setup() {
  Serial.begin(115200);
   delay(1000);
   cout << F("\nUse a freshly formatted SD for best performance.\n");
  // Discard any input.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);
  
  Serial.println("Type any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
  
  if (!sd.begin()) {
    sd.initErrorHalt();
  }  
    Serial.println("*************************************************");
    Serial.println("Opening the read file..");
  // open the file for Read
  if (!myFileIn.open("test_in.bin", O_RDONLY)) {
    sd.errorHalt("opening test_in.bin for Read failed");
  }
  
  Serial.println("Opening the write file..");
  // open the file for Write
  if (!myFileOut.open("test_out.bin", O_WRITE | O_CREAT)) {
    sd.errorHalt("opening test_out.bin for Write failed");
  }
  
  // Read from myFileIn and write to myFileOut via a Buffer
  Serial.println("Reading and Writing..");
  uint8_t buf[BUFSIZE];
  uint32_t nr;
  uint32_t t = millis();
  while ((nr = myFileIn.read(buf, BUFSIZE)) > 0) {
    if (nr < BUFSIZE){
                  myFileOut.write(buf, nr);  }
        else {
              myFileOut.write(buf, BUFSIZE);  }
  }
  t = millis() - t;
  // close the files
  myFileIn.close();
  myFileOut.close();
  Serial.println("*************************************************");
  Serial.print("Done in ");
  Serial.print(t);
  Serial.print(" msecs");
}

void loop() {
}
Pukao Hats Cleaning Services Ltd.

stevestrong
Posts: 1747
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: [STM32GENERIC] SDIO DMA

Post by stevestrong » Thu May 18, 2017 9:42 am

Can someone please provide a binary file for black F407VE board? Then I would test it, too.

stevestrong
Posts: 1747
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: [STM32GENERIC] SDIO DMA

Post by stevestrong » Thu May 18, 2017 9:47 am

Btw, in the errata sheet there are several other SDIO-related issues which would force the software to:

Code: Select all

Workaround
The CCRCFAIL bit in the SDIO_STA register shall be ignored by the software. CCRCFAIL
must be cleared by setting CCRCFAILC bit of the SDIO_ICR register after reception of the
response to the CMD5 command.
and

Code: Select all

Workaround
None. A configuration with the NEGEDGE bit equal to ‘1’ should not be used
and

Code: Select all

Workaround
After sending the write command (RW_MULTIPLE_REGISTER or
RW_MULTIPLE_BLOCK), the application must check that the card is not busy by polling the
BSY bit of the ATA status register using the FAST_IO (CMD39) command before enabling
the data state machine.
and

Code: Select all

[3 x period(PCLK2) + 3 x period(SDIOCLK)] >= (32 / (BusWidth)) x period(SDIO_CK)
Workaround
Avoid the above-mentioned clock frequency relationship, by:
• Incrementing the APB frequency
• or decreasing the transfer bandwidth
• or reducing SDIO_CK frequency
Have all these been respected in the actual version?

danieleff
Posts: 336
Joined: Thu Sep 01, 2016 8:52 pm
Location: Hungary
Contact:

Re: [STM32GENERIC] SDIO DMA

Post by danieleff » Thu May 18, 2017 10:26 am

Given that for example readBlocks just calls HAL_SD_ReadBlocks and thats it, I hope those issues are fixed in HAL. (except maybe clock setup).

Which reminds me, there are actually newer HAL firmware versions for the series, so I will upgrade them when I get home; that may help too.

Post Reply