SAM3U SD card writing speed

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

Hi guys,

 

I'm using a SAM3U-EK devkit to write a 16KB buffer to a SD card however I'm a bit disappointed with the speed results that I'm getting when writing from the SAM to the SD card (~0.41 MB/s).

In theory, since the HSMCI clock is at 50 MHz (~half sys clock. Main clock at 96MHz) and I'm using 4 datalines, I could get up to 25MB/s. This will never happen due to protocol overhead. When writing to the SD card over USB using the SAM, I'm getting writings speeds up to 17 MB/s (for big files) and around 4MB/s for 16KB files.

 

I'm using the ASF libraries and my code is based on one of the examples that uses a file system provided by atmel. I'm using the f_write function to write the buffer.

 

Think this could be related to the fact that the library is writing one block of 512 bytes to the SD card at a time. I see that it's also possible to perform multi block write operations.

What's the easiest way of enabling this multi block when writing a big buffer (16KB) to the SD card using the ASF libraries? Any thoughts?

 

Regards,

Joao

This topic has a solution.
Last Edited: Tue. May 30, 2017 - 09:38 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Hi guys,

 

Think I found the problem. I've made some changes to the ASF library and a minor change to the third party FATFS. With these changes I'm able to write a 16KB buffer from RAM to a file in the SD card in 4.7 ms (~3.4 MB/s).

I'm going to leave here the changes I made for future reference. I'm not sure if there was any reason why the blocks were being written one at a time instead of using the Multiblock command. This seems to be working for me at the moment.

 

In diskio.c, the function disk_write calls ram_2_memory that was being used to write one sector at a time. Therefore, I replaced this for a multi_ram_2_memory function. Modified function looks like this:

DRESULT disk_write(BYTE drv, BYTE const *buff, DWORD sector, BYTE count)
{
	#if ACCESS_MEM_TO_RAM
	uint8_t uc_sector_size = mem_sector_size(drv);
	uint32_t ul_last_sector_num;

	if (uc_sector_size == 0) {
		return RES_ERROR;
	}

	/* Check valid address */
	mem_read_capacity(drv, &ul_last_sector_num);
	if ((sector + count * uc_sector_size) >
	(ul_last_sector_num + 1) * uc_sector_size) {
		return RES_PARERR;
	}

	/* Write the data */
	if (multi_ram_2_memory(drv, sector, buff, count) !=	CTRL_GOOD)
	{
		return RES_ERROR;
	}

	return RES_OK;

	#else
	return RES_ERROR;
	#endif
}

 

Then, in ctrl_access.c created the multi_ram_2_memory function (don't forget to extern it in ctrl_access.h):

Ctrl_status multi_ram_2_memory(U8 lun, U32 addr, const void *ram, U8 n_blocks)
{
	Ctrl_status status;
	U8 i;
	#if MAX_LUN==0
	UNUSED(lun);
	#endif

	if (!Ctrl_access_lock()) return CTRL_FAIL;

	memory_start_write_action(n_blocks);
	
	
	status = sd_mmc_multi_ram_2_mem(lun,addr,ram,n_blocks);

	memory_stop_write_action();

	Ctrl_access_unlock();

	return status;
}

 

And finally in sd_mmc_mem.c created the function sd_mmc_multi_ram_2_mem. Just like in the function sd_mmc_ram_2_mem, the sd_mmc_init_write_blocks routine is called which evaluates the number of blocks being written to send the SD command SDMMC_CMD24_WRITE_BLOCK or SDMMC_CMD25_WRITE_MULTIPLE_BLOCK. The problem was that the ASF function sd_mmc_ram_2_mem sets the number of blocks to a fixed value of 1 (and therefore never making use of the write multiple block). The modified version looks like this:

Ctrl_status sd_mmc_multi_ram_2_mem(uint8_t slot, uint32_t addr, const void *ram, uint8_t nb_sector)
{
	uint8_t i=0;

	switch (sd_mmc_init_write_blocks(slot, addr, nb_sector)) {
		case SD_MMC_OK:
		break;
		case SD_MMC_ERR_NO_CARD:
		return CTRL_NO_PRESENT;
		default:
		return CTRL_FAIL;
	}
	
	for (i=0; i< nb_sector;i++ )
	{
		if (SD_MMC_OK != sd_mmc_start_write_blocks(ram+SD_MMC_BLOCK_SIZE*i, 1)) {
			return CTRL_FAIL;
		}
		if (SD_MMC_OK != sd_mmc_wait_end_of_write_blocks(false)) {
			return CTRL_FAIL;
		}
		
	}
	
	return CTRL_GOOD;
}

 

Regards,

Joao

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

Thanks Joao!

I've just came across this 1-block limit in the ASF code, which might be the cause of my problem writing to the SD-Card.
Currently I'm writing 256 byte long blocks, every 3 mSec (44.1 KHz mono audio). The 500KB/sec I got seems satisfactory, but, every 0.918 seconds (~80KB) I get a glitch and miss 2 blocks.
I wanted to write several blocks at once, and see if this solves the problem or at least makes it more scarce (I just need a few seconds of clean audio).

Thanks for posting a patch, will try it today/tomorrow.

Thanks

Koby