Post Go back to editing

RSI/SD card multiple block help needed

Hi,

I'm trying to communicate with a SD card using the multiple block write command. As RSI_DATA_LGTH is 16bit width, it limits the data size to 65535, but I would like to test 64k/128k/256k and more data length. The idea is to test maximum throughput of the card, targeting 10MBytes/sec as the physical maximum of the Blackfin (RSI max clock is 25MHz).

I'm using a ADSP-BF506F EZ-KIT and have modified the power on self test code:

uint32_t sd_mmc_write_mblocks_dma_64k(uint32_t card_address, void * pSource)

{

    uint32_t error = 0;

    uint32_t i = 0;

    // DMA setup

    *pDMA1_CONFIG         = 0x0000;

    *pDMA1_START_ADDR     = pSource;

    *pDMA1_X_COUNT         = 65536 / 4;     // / 4 => 32bit words

    *pDMA1_X_MODIFY     = 0;    // repeat first word because we don't have enough internal RAM on EZ-KIT

    *pDMA1_IRQ_STATUS     = *pDMA1_IRQ_STATUS & DMA_DONE;

    *pDMA1_CONFIG         = DMAEN | WDSIZE_32 |DI_EN | SYNC;

    error = sd_mmc_send_command(SD_MMC_CMD_WRITE_MULTIPLE_BLOCK, card_address);

    // Setup data transfer  

    *pRSI_DATA_LGTH = 1024;     // 2 x 512 bytes

    *pRSI_DATA_TIMER = 0xFFFFFFFF;    // not handled for now

    // data transfer       

    for(i=0; i<64; i++)

    {

        // Start data transfer

        *pRSI_DATA_CONTROL = 0x99;    // 512 bytes block over DMA

        // wait for end of transmission

        while(!(*pRSI_STATUS & DAT_END));

        // clear status flags

        *pRSI_STATUSCL =  DAT_END | DAT_BLK_END;       

    }

    error = sd_mmc_send_command(SD_MMC_CMD_STOP_TRANSMISSION, 0);

    /* ensure DMA has completed */

   while((*pDMA1_IRQ_STATUS & DMA_DONE) != DMA_DONE);

   *pDMA1_IRQ_STATUS = *pDMA1_IRQ_STATUS & DMA_DONE;

   /* wait for the device to become ready */

   sd_mmc_get_wait_until_ready();

    return error;

}

This function should send 64k (512 bytes * 2 * 64) to the SD card. It doesn't work, the DSP get stuck into the while(!(*pRSI_STATUS & (DAT_END | DAT_BLK_END))); after the first pass (i==1).

If I test the function using the debugger step by step, it works. If a add large delay (for(j=0; j<100000; j++); between each line of the for loop, it also works.

When the DSP doesn't go out from the DAT_END, the status register value is 0, but value should be (DAT_END | DAT_BLK_END) as the RSI_DATA_CONTROL register was written just before.

Any idea?

Thanks,

Vincent

  • Hi,

    Although I am not sure if this is the actual reason why you are seeing the hang while transferring multiple blocks in a loop.

    As you have indicated from the code snippet the DMA count is different from what SD card controller is expecting for each multiple block transfer(two blocks in your case). You are programming DMA1_X_COUNT to 65536/4 while RSI_DATA_LGTH is 1024.

    Can you try to do something like this and see if it behaves any differently. Here you program the DMA count as per the number of bytes to be transferred per multiple block write. After each multiple block is finished reprogram the DMA also:

    uint32_t sd_mmc_write_mblocks_dma_64k(uint32_t card_address, void * pSource)

    {

        uint32_t error = 0;

        uint32_t i = 0;

        // DMA setup

        *pDMA1_CONFIG         = 0x0000;

        *pDMA1_START_ADDR     = pSource;

        *pDMA1_X_COUNT         = 1024 / 4;     // / 4 => 32bit words

        *pDMA1_X_MODIFY     = 0;    // repeat first word because we don't have enough internal RAM on EZ-KIT

        error = sd_mmc_send_command(SD_MMC_CMD_WRITE_MULTIPLE_BLOCK, card_address);

        // Setup data transfer  

        *pRSI_DATA_LGTH = 1024;     // 2 x 512 bytes

        *pRSI_DATA_TIMER = 0xFFFFFFFF;    // not handled for now

        // data transfer       

        for(i=0; i<64; i++)

        {

             //Start DMA

             *pDMA1_IRQ_STATUS     = *pDMA1_IRQ_STATUS & DMA_DONE;

             *pDMA1_CONFIG         = DMAEN | WDSIZE_32 |DI_EN | SYNC;

            // Start data transfer

            *pRSI_DATA_CONTROL = 0x99;    // 512 bytes block over DMA

            // wait for end of transmission

            while(!(*pRSI_STATUS & DAT_END));

            // clear status flags

            *pRSI_STATUSCL =  DAT_END | DAT_BLK_END;       

        }

        error = sd_mmc_send_command(SD_MMC_CMD_STOP_TRANSMISSION, 0);

        /* ensure DMA has completed */

       while((*pDMA1_IRQ_STATUS & DMA_DONE) != DMA_DONE);

       *pDMA1_IRQ_STATUS = *pDMA1_IRQ_STATUS & DMA_DONE;

       /* wait for the device to become ready */

       sd_mmc_get_wait_until_ready();

        return error;

    }

    Regards,

    Nabeel