Re: CY8CPROTO-062-4343w SD card

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
Rakshith
Moderator
Moderator
Moderator
250 likes received 1000 replies posted 750 replies posted

Hello RoDu_4468516​,

The resistor R62 is not populated by default in the CY8CPROTO-062-4343W Kit. So, pin P12_1 cannot be used as the Card Detect pin. Maybe that is where you are getting stuck.

I created a quick project to use the SDHC block of CY8CPROTO-062-4343W board. The project writes a block of data into the SD Card and then reads it back. Please let me know if this is helpful.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
1 Solution

Hi Rakshith,

it was also quite easy to increase SDHC buffer in Modus 2.0 from 64KB to 448KB.

One just had to change SDHC mode from default in syhal_sdhc.c ADMA2 to SDMA.

It seems to be that ADMA2 has 64KB limit, but SDMA has not. Thus, switching the

mode automatically allows to use larger buffer to boost data rate. To change this

setting one just  can override the library function where it is set cyhal_sdhc_init()

with another function that has required SDHC mode inside (SDMA). Perhaps, this is

not an universal solution because some function of the library may change their

behavior with SDMA. I did not test this. However, read/write works just perfect:

Starting write the 1st 448K block

Duration: 13523 us, Data rate: 33.924 MBps

Starting write the 2nd 448K block

Duration: 13523 us, Data rate: 33.924 MBps

Starting read the 1st 448K block

Duration: 10520 us, Data rate: 43.608 MBps

Starting read the 2nd 448K block

Duration: 10520 us, Data rate: 43.608 MBps

Interestingly, but cy_sd_host.c library in Modus 2.0 has only tiny improvements

comparatively to library in Modus 1.1. Necessity to reinitialize the card after each

operation in my code in Modus 1.1 was caused by some omissions.

In fact, SDHC works equally well in Modus 1.1 and 2.0, but Modus 2.0 adds

convenient high level library cyhal_sdhc that is lucking in 1.1.

Now the question about SDHC performance is closed completely.

Thank you very much for your help.

Happy programming!

Alexei

View solution in original post

18 Replies
AlVy_2459421
Level 4
Level 4
25 replies posted 10 replies posted 5 replies posted

Hi  RakshithM,

great thanks!

The coder works as it should. However, the maximal block size that the library allows to transmit at once is 64 Kbytes. Perhaps, one can switch from DMA to DMAC in the library to remove this limitation, as it seems to be the limitation of used DMA and not of SD standard. Am I right? Another limitation that I have found seems more critical. Current example works at SD clock 25 MHz that brings theoretical limit of bandwidth 12.5 MBps. However, I have found that with 53248 byte blocks and 100MHz at DMA controller and processor cores the baud rate can be 7.64 MBps. This is not bad, but more is better. To increase baud rate I increased clock from 25 MHz to 50 MHz. To do this I changed the divider in the configurator of the clock that goes to SDIO1 to have 100 MHz instead of 50 MHz in your example. However, this was not sufficient and I introduced the following code after SDIO initialization but before memory writing command:

Cy_SD_Host_SetBusSpeedMode(SDHC1,CY_SD_HOST_BUS_SPEED_SDR50,&sdHostContext);

            //CY_SD_HOST_BUS_SPEED_SDR50 -> 100MHz - works with 3V3 and 1.8V IO in Modus 1.1 with one sector transfer

            //CY_SD_HOST_BUS_SPEED_SDR25 -> 50MHz - works here

Cy_SD_Host_SdCardChangeClock(SDHC1, CY_SD_HOST_CLK_50M);                            //this is needed - works without previous settings

                                                           //at 25M and 50M, but does not work with 100M, also with previous line here

Cy_SysLib_Delay(1/*msec*/); //my addition

To make these functions working I overridden one of them in the beginning and introduced one fake variable:

cy_stc_sd_host_context_t sdHostContext;

/*******************************************************************************

* Function Name: Cy_SD_Host_SdCardChangeClock

****************************************************************************//**

*

*  Changes the Host controller SD clock.

*

* \param *base

*     The SD host registers structure pointer.

*

* \param frequency

*     The frequency in Hz.

*

* \return \ref cy_en_sd_host_status_t

*

*******************************************************************************/

static cy_en_sd_host_status_t Cy_SD_Host_SdCardChangeClock(SDHC_Type *base, uint32_t frequency)

{

    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;

    uint32_t               clkDiv;

    uint32_t               clockInput = 100000000;//CY_SD_HOST_PERI_FREQUENCY;

    //CY_ASSERT_L2(CY_SD_HOST_IS_FREQ_VALID(frequency)); //not needed?

    if (NULL != base)

    {

        clkDiv = (clockInput / frequency) >> 1UL;

        Cy_SD_Host_DisableSdClk(base);

        ret = Cy_SD_Host_SetSdClkDiv(base, (uint16_t)clkDiv);

        Cy_SD_Host_EnableSdClk(base);

    }

    return ret;

}

This addition indeed increased clock from 25 to 50 MHz. This was checked by oscilloscope.

The data rate of mentioned above packets also increased up to 10.71 MBps. This is not bad, but shows existence of essential time loss for each 53248 byte data packet while its transmission time 4.97 ms can be considered as 2.15 ms of "pure" transmission time at 25MBps + 2.82 ms of wasted time because of some overhead. This is basically the reason why it may be beneficial to switch to larger packets.

However, the main my problem was that when I tried to switch to 100 MHz clock by the command

Cy_SD_Host_SdCardChangeClock(SDHC1, CY_SD_HOST_CLK_100M); 

writing to SD card was blocked. I could see 100MHz clock by oscilloscope, but this example did not work. Thus, any hint what should be changed can be helpful. Perhaps, some part of my added code does not work as expected (i.e.

Cy_SD_Host_SetBusSpeedMode(SDHC1,CY_SD_HOST_BUS_SPEED_SDR50,&sdHostContext);).

I would like to note that similar (but slightly different) code in ModusToolbox 1.1 allows to read/write one sector (512 bytes) at 100 MHz clock using the same hardware, but there is some other omission that did not allow to read/write several sectors at once.

I plan to take a look at both my codes in Modus 1.1 and 2.0, but if you have an idea how to run your example at 100MHz clock, this would be very helpful.

0 Likes
RoDu_4468516
Level 1
Level 1

Hello RakshithM

Thank you so much for the example!  Occasionally when I'm doing a large number of consecutive writes, I start getting nonzero return codes. 

Using the macros:

result = cyhal_sdhc_write(&_sdhc_object, a, (uint8_t*)b, &block_count);

if(result != 0) {

    uint8_t type = CY_RSLT_GET_TYPE(result);

    uint16_t module_id = CY_RSLT_GET_MODULE(result);

    uint16_t error_code = CY_RSLT_GET_CODE(result);

    printf("blocks written: %u, type %u, module %u, %u \n", block_count, module_id, error_code);

}

I end up with the following:

type 0, module 2, error_code 134231568

Does anyone have any idea what could be causing this?  It seems to be occurring randomly.

Thanks again

0 Likes

Hi RoDu,

I have a guess that SD card may need some time for processing commands and when the next command is coming, it may be busy and can't respond, or responds with an unexpected format. As a quick hack you can try to introduce delays between commands just for testing purposes. Another idea is to wrap a writing command into a cycle: do counter++; {write command} while (bad response && counter<counterMax). Another way is to find in SD documentation how to check card ready status and poll it in a loop before each writing command.

Hope this can help. It would be nice if you could give a feedback what fixed this problem for you.

Alexei

0 Likes

I would like to correct my previous comments.

SDHC has its own DMA engine. It has no relation to mentioned DMA and DMAC general-purpose controllers.

Why this example did not work in my hands with blocks above 64 Kbytes, I don't know.

However, I patched my old code in Modus 1.1 environment. I tested blocks as large as 384 KBytes without any issues.

Transmission of one such block with 100 MHz SD clock took 12 ms.

Thus, sustained data rate was 32.768 MBps. This is not bad.

Interestingly to note, testing of Octal SPI data rate at 50 MHz clock and DMAC gave a very similar value 32.576 MBps.

However, the block size was much smaller - 12900 bytes.

Please let me know if you know how to get higher data rates at SDHC or Octal SPI.

Good luck with coding!

Alexei

0 Likes

Hello

I thought the same as you but I tried putting a

while(cyhal_sdhc_is_busy(sdhc_obj))

{

     Cy_SysLib_Delay(1000);   //might as well start large

}

After every one of my reads and writes.  Now instead of failed reads and writes I end up with randomly occurring never ending loops where that function never resolves to false.

0 Likes

Hi AlVy_2459421​, RoDu_4468516​,

Thank you for your valuable inputs.

RoDu_4468516​, Can you please share your project? I was unable to reproduce your issue. I was able to write 51200 bytes without any issue or data loss. Also, cyhal_sdhc_is_busy(sdhc_obj) is not necessary.This function is useful on an async call to wait for the transaction to complete.

AlVy_2459421

In the PSoC 6 MCU: CY8C62x8, CY8C62xA Architecture TRM, it is mentioned that SDHC supports only 50 MHz at 3.3 V signalling. I was also able to change the clock speed only upto 50 MHz (after changing the clock divider to 1 in Device Configurator). Can you please share the code that you used to change the clock to 100 MHz? Also, SDHC supports only 4-bit bus interface.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
0 Likes
lock attach
Attachments are accessible only for community members.

Hi Rakshith,

thank you for your reply and 50 MHz mode testing. Indeed, in accordance with SD specification, high baud rates need 1.8V IO supply. However, as I noted in the attached PDF file, 100 MHz mode can work at 3.3V, although this is out of specification. Indeed, I run all my tests at modified board. Modifications are described in the file attached.

I plan to check that my code works fine with the original board, and than I shall share it.

Yes, Cypress SDHC supports only 4-bit bus. I used Octal SPI to connect FPGA that provided a test signal.

In the very last technical processor specification SDHC speed is limited by 80MHz, whereas in the original release is was 100MHz.

Perhaps, there is sense in this, because if SDHC limits data rate internally at about 32.768MBps, both 80 and 100 MHz clock modes will have identical data rate at the end limited by SDHC internal architecture. However, 32.768MBps limit is my measure, it was not declared officially. May be, the speed limit can be lifted by switching from SDMA to ADMA, but I did not test this. I used SDMA only.

With best regards,

Alexei

lock attach
Attachments are accessible only for community members.

Hi Rakshith,

finally, I have tested my code with the original non-modified CY8CPROTO-062-4343W.

It works. The attached project is done in Modus 1.1.

When the program starts with the inserted memory card, the following information is displayed in the

terminal window (115200 bps, 8-n-1):

"UART initialization complete

SDHC 100MHz code example started

Here 1MB = 1,000,000 bytes

Random values to put in the first sectors of two 384*1024-byte blocks: 49 15

Write duration of 384*1024-byte blocks in microseconds: 13032 12037

Write data rates:  30.173 32.667 MBps

Mean+/-Std:  31.420+/-1.764 MBps

Read duration of 384*1024-byte blocks in microseconds: 8787 8785

Read data rates:  44.750 44.760 MBps

Mean+/-Std:  44.755+/-0.007 MBps

SD Write/Read OK"

Now I shall give some explanations.

The program writes two 384*1024-byte blocks one after another starting from zero sector of SD card

inserted in SDHC1. Then, the program reads these two blocks and checks that they are OK.

True random number generator is used to generate starting values that are written in the first sectors

of the first and the second blocks respectively. One value is written in all 512 bytes of one sector. Values

are incremented by 1 at each sector (with return to 0 after 255).

To measure duration of operations 32-bit timer is clocked by 1MHz signal to get 1 us accuracy.

As it is seen, writing speed was about 31.420 MBps and reading speed - 44.755 MBps.

Interestingly, reading speed is close to theoretical maximum at 100 MHz, i.e. 50 MBps.

Thus, having 100MHz clock has some advantage, for instance, against 80 MHz clock.

Now about problems and non-fixed issues of the attached code:

1. MicroSD card compatibility. The code was tested with Samsung Evo Plus 128GB memory card

  (white-red color). However, there were some problems with Lexar 633x 32GB memory card

  (black-blue color). Thus, it seems to be that there are some omissions in the code.

2. Necessity to re-initialize memory card after 384*1024-byte block operation.

    It has been found that the second block is not written properly if the card is not initialized the second

    time after the first block. This is a big issue that should be solved. Initialization of the card requires

    very significant time and it should be done only once at the beginning, and not after each operation.

    Now card re-initialization looks like:

 

Cy_SD_Host_InitCard(SDHC1, &SDHC1_card_cfg, &sdHostContext);

Cy_SD_Host_SetBusSpeedMode(SDHC1,CY_SD_HOST_BUS_SPEED_SDR50,&sdHostContext);  

Cy_SD_Host_SdCardChangeClock(SDHC1, CY_SD_HOST_CLK_100M);

As you can see, the attached code is not polished. It should be improved to be practically useful.

If you shall test this code, please let me know with what types of memory cards it works, and with what does not.

Ideas directed towards elimination of memory card re-initialization are also very welcome.

Interestingly, but Modus 2.0 code uploaded by you does not have issues (1) and (2). One can write one 64K block after

another, and read both blocks without SD card re-initialization. However, the unpleasant restrains are: 50MHz

bus frequency limit, and 64K block size limit. Both restrains drastically decrease throughput.

With best regards,

Alexei

Just for comparison, SDHC rates  obtained with Modus 2.0, 64K block, 50MHz bus (25 MBps peak throughput):

Starting write the 1st 64K block

Duration: 5016 us, Data rate: 13.065 MBps

Starting write the 2nd 64K block

Duration: 5015 us, Data rate: 13.068 MBps

Starting read the 1st 64K block

Duration: 3514 us, Data rate: 18.650 MBps

Starting read the 2nd 64K block

Duration: 3515 us, Data rate: 18.645 MBps

With best regards,

Alexei

lock attach
Attachments are accessible only for community members.

Hi Rakshith,

It has happened that activation of 100MHz mode of SDHC in Modus 2.0 is very easy to do.

The singe thing that was needed is selection of low voltage signaling in configuration:

const cyhal_sdhc_config_t sdhc_config = {false, true, false, 4};    //the second - low voltage signaling.

However, physical powering of IO by 1.8V is not necessary. Just the driver should "know" that

low voltage signaling is allowed.

Thus, the whole SDHC configuration looks as:

const cyhal_sdhc_config_t sdhc_config = {false, true, false, 4};    //the second - low voltage signaling.

rslt = cyhal_sdhc_init(&sdhc_obj, &sdhc_config, cmd, clk, dat0, dat1, dat2, dat3, dat4, dat5, dat6, dat7, card_detect, io_volt_sel,                                                                  card_if_pwren, card_mech_writeprot, led_ctl, emmc_reset);

Cy_SD_Host_SetBusSpeedMode(SDHC1,CY_SD_HOST_BUS_SPEED_SDR50,&sdHostContext);

Cy_SD_Host_SdCardChangeClock(SDHC1, CY_SD_HOST_CLK_100M);  

I modified your example by adding writing/reading of two 64KB blocks with timing.

Now the program output looks as:

Starting write the 1st 64K block

Duration: 3515 us, Data rate: 18.645 MBps

Starting write the 2nd 64K block

Duration: 3515 us, Data rate: 18.645 MBps

Starting read the 1st 64K block

Duration: 2013 us, Data rate: 32.556 MBps

Read_buff value in 0 = 7

Read_buff value in 5120 = 7

Read_buff value in 10240 = 7

Read_buff value in 15360 = 7

Read_buff value in 20480 = 7

Read_buff value in 25600 = 7

Read_buff value in 30720 = 7

Read_buff value in 35840 = 7

Read_buff value in 40960 = 7

Read_buff value in 46080 = 7

Read_buff value in 51200 = 7

Read_buff value in 56320 = 7

Read_buff value in 61440 = 7

Starting read the 2nd 64K block

Duration: 2013 us, Data rate: 32.556 MBps

Read_buff value in 0 = 8

Read_buff value in 5120 = 8

Read_buff value in 10240 = 8

Read_buff value in 15360 = 8

Read_buff value in 20480 = 8

Read_buff value in 25600 = 8

Read_buff value in 30720 = 8

Read_buff value in 35840 = 8

Read_buff value in 40960 = 8

Read_buff value in 46080 = 8

Read_buff value in 51200 = 8

Read_buff value in 56320 = 8

Read_buff value in 61440 = 8

As it is seen, writing data rate increased ~1.5 times relatively to 50 MHz clock and constituted 18.645 MBps.

Reading speed also increased about 1.5 times and reached 32.556 MBps.

The code in Modus 2.0 making this output is attached.

These data rates are not bad for many applications, but I need writing of at least 26 MBps!

This could be easily achieved by increasing block size 6x from 64K to 384K.

However, it seems to be difficult in Modus 2.0. Unfortunately, 64K limit stays in the description of the library:

PSoC 6 Peripheral Driver Library: SD Host (SD Host Controller)

Whether it is possible to rise this limit is not clear.

Any advises concerning how to do this are more than welcome.

May be, you can contact developers that wrote this library with this question?

One of possible approaches is to use ADMA3 that allows to transmit several blocks in one DMA request.

Thus, one can transmit 6 blocks of 64KB. However, it is not clear how fast this transfer could be.

Perhaps, single transfer of one 384KB block could be better.

Another option is to patch old Modus 1.1 code to remove secondary SD card initializations.

However, one also should look how to do this. Any advises are welcome.

With best regards,

Alexei

Hi Rakshith,

it was also quite easy to increase SDHC buffer in Modus 2.0 from 64KB to 448KB.

One just had to change SDHC mode from default in syhal_sdhc.c ADMA2 to SDMA.

It seems to be that ADMA2 has 64KB limit, but SDMA has not. Thus, switching the

mode automatically allows to use larger buffer to boost data rate. To change this

setting one just  can override the library function where it is set cyhal_sdhc_init()

with another function that has required SDHC mode inside (SDMA). Perhaps, this is

not an universal solution because some function of the library may change their

behavior with SDMA. I did not test this. However, read/write works just perfect:

Starting write the 1st 448K block

Duration: 13523 us, Data rate: 33.924 MBps

Starting write the 2nd 448K block

Duration: 13523 us, Data rate: 33.924 MBps

Starting read the 1st 448K block

Duration: 10520 us, Data rate: 43.608 MBps

Starting read the 2nd 448K block

Duration: 10520 us, Data rate: 43.608 MBps

Interestingly, but cy_sd_host.c library in Modus 2.0 has only tiny improvements

comparatively to library in Modus 1.1. Necessity to reinitialize the card after each

operation in my code in Modus 1.1 was caused by some omissions.

In fact, SDHC works equally well in Modus 1.1 and 2.0, but Modus 2.0 adds

convenient high level library cyhal_sdhc that is lucking in 1.1.

Now the question about SDHC performance is closed completely.

Thank you very much for your help.

Happy programming!

Alexei

Hello AlVy_2459421​,

Thank you for the extensive testing. It is a great learning and will definitely help anyone who wants to use the SDHC driver.

As you have rightly observed some APIs are not available in the HAL SDHC Driver. There is an internal ticket created and our development team is working on creating HAL APIs to use all the features of SDHC block.

In one of your posts, you have mentioned -

However, physical powering of IO by 1.8V is not necessary. Just the driver should "know" that

low voltage signaling is allowed.

I did try giving the configuration to enable low voltage signaling and without any modifications, the SDHC initialization fails.

With low voltage signaling enabled -

pastedImage_2.png

With low voltage signaling disabled -

pastedImage_3.png

I have set 2 breakpoints, one for when the initialization fails and the other when the initialization succeeds. Can you please let me know if this is right and if this matches with your observations?

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
0 Likes

Hi Rakshith,

thank  you for your comments.

As you did not specify in which code did you make these changes, I supposed that you used your SDHC example.

I placed these changes in this code and did not observed any improper behavior. I.e., my Samsung 128GB Evo Plus microSD card (white-red color) was properly initialized. I used the original CY8PROTO-062-4343W, i.e. without any hardware changes.

Then I have tested the following microSD cards:

Lexar 633x 32GB, black-blue: does NOT work

Samsung 32GB, white-light blue: OK

Samsung 4GB, white-light blue: OK

Samsung Pro 8GB, black: does NOT work

SanDisk Mobile Ultra 8GB, black: OK

SanDisk Ultra 8GB, red-blue: does NOT work

SanDisk Ultra 16GB, red-blue: does NOT work

Thus, from 8 tested cards 4 did not work (50%).

Then I retested cards that did not work in my modified CY8PROTO-062-4343W board with 1.8V signalling support, and 100MHz, and 448KB block in SDMA mode.

Also, with the proper changes in software to support 3.3V/1.8V switching by the SDHC driver. Results:

Lexar 633x 32GB, black-blue: OK

Samsung Pro 8GB, black: does NOT work

SanDisk Ultra 8GB, red-blue: does NOT work

SanDisk Ultra 16GB, red-blue: does NOT work

This is somewhat surprising because all these cards should support 1.8V signaling and high data rates:

Samsung Pro 8GB should have reading up to 70 MBps, writing up to 20 MBps.

SanDisk Ultra 8GB has speed up to 48 MBps or 320X.

SanDisk Ultra 16GB has speed up to 98 MBps or 653X.

May be, there are some small omissions like luck of delays that are needed.

However, I don't have time for testing such things.

Then I tested these remaining cards without low-voltage indication, i.e. with the original settings

const cyhal_sdhc_config_t sdhc_config = {false, false, false, 4};

in your code (with ADMA2 mode):

Samsung Pro 8GB, black: OK

SanDisk Ultra 8GB, red-blue: OK

SanDisk Ultra 16GB, red-blue: OK

Thus, the conclusion is that current low-voltage support is not universal, as it does not work with some (old and weak?) memory cards (Samsung Pro 8GB, black; SanDisk Ultra 8GB, red-blue; SanDisk Ultra 16GB, red-blue).

The default original mode is OK for all cards.

Also, some cards (Lexar 633x 32 GB black-blue) need real physical 1.8V signaling to work properly with the low-voltage setting.

This is basically, in accordance with the SD specification.

Concluding, one can use low-voltage signaling, and should use it for 100MHz mode, but some memory cards can have difficulties with it, even in spite of the fact that they formally should support low-voltage and high-frequency modes.

Could you please indicate what type of microSD card did you use in the failed test?

It seems to be that your card just fell into unlucky 50% cards that don't work in the tested configuration.

Good luck!

Alexei

lock attach
Attachments are accessible only for community members.

Problem with 100MHz clock in SDHC0 in Modus 2.0, omission in Help example around function Cy_SD_Host_Write()

Hi Rakshith,

I have tested SDHC0 because SDHC1 shares clock with Octal SPI. I can't rise clock at Octal SPI above 40-50 MHz for the reason of long wiring . Thus, I decided to switch to SDHC0 that has separate clock. The WiFi transmitter normally connected to SDHC0 in CY8CPROTO-062-4343W was disconnected from SDHC, and microSD socket was attached. However, this switching did not go as smoothly  as it should. I was able co configure SDHC0 for frequencies up to 50 MHz, but failed to make SDHC0 running at 100 MHz in Modus 2.0. The reason of this is unknown. Enabling of low voltage that helped before with SDHC1 did not help now with SDHC0. However, SDHC0 works perfectly at 100 MHz in Modus 1.1. Thus, the problem is in logic in Modus 2.0 code, and not in a bad electrical connection. I tried to look at the library code, but have found nothing.

As the same time I completely fixed my code in Modus 1.1. It has happened that Cypress Help example had a very serious omission:

command Cy_SD_Host_ClearNormalInterruptStatus(SDHC1, CY_SD_HOST_XFER_COMPLETE); that should terminate every write/read operation was omitted after the command Cy_SD_Host_Write. Please see screen shot attached. In fact, this command should stay after write command exactly in the same way how it stays after the read command:

ret = Cy_SD_Host_Write(SDHC0, &data, &sdHostContext);  /* Write data to the card. */

        if (CY_SD_HOST_SUCCESS == ret)

        {

            while (CY_SD_HOST_XFER_COMPLETE != (Cy_SD_Host_GetNormalInterruptStatus(SDHC0) & CY_SD_HOST_XFER_COMPLETE))

            {

                /* Wait for the data-transaction complete event. */

            }

            /* Clear the data-transaction complete event. */

            Cy_SD_Host_ClearNormalInterruptStatus(SDHC0, CY_SD_HOST_XFER_COMPLETE);

        }

After fixing this issue mentioned earlier secondary SD card initializations became unnecessary.

Now Modus 1.1 code is useful.

Resuming, Modus 1.1 code works with SDHC0 and SDHC1 at 100 MHz,

but Modus 2.0 code works in my hands with SDHC0 at 50 MHz and with SDHC1 at 100 MHz.

For the time being I can use Modus 1.1, but in the future it would be nice to have Modus 2.0 because of its WiFi support. 

All the best,

Alexei

0 Likes

Hi AlVy_2459421,

Thank you for the detailed explanation.

I tested the code with the 2 available SD Cards -

1. SanDisk Ultra 16GB Class 10 (red and grey)

2. SanDisk 8GB Class 4 (black)

Both of these cards failed.

Regarding the code example, I will direct your query to the internal team and they will look into it and update the code example once they evaluate the issue.

In MTB 2.0 code are you using PDL or HAL to initialize/change speed of SDHC0?

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B

Hi Rakshith,

thank you for sharing information about the cards.

I also tested card 1 with the same negative result.

I just named this card red-blue because grey color was slightly bluish.

My SanDisk 8GB black had even lower class 2, but it worked.

Thus, it seems to be that there is no direct link between card performance and compatibility.

Thank you for intention to update on-line example. This will help other people.

I tried HAL to initialize SDHC0, and both PDL and HAL for switch the clock.

However, to try PDL initialization approach may be a good idea.

Both PDL and HAL approaches switch the clock, but some other settings in SDHC0 occurred incompatible

with 100 MHz clock and this causes the trouble.

In HAL clock is switched at the end of cyhal_sdhc_init() by the command

cyhal_sd_host_sdcardchangeclock()

In PDL this is done by two mentioned earlier commands.

Please let me know if you will find a way to make SDHC0 working at 100 MHz in Modus 2.0.

Originally I was thinking to use announced PSoC 64 that should combine BLE with large memory and strong peripheral devices of PSoC 62. However, release of this line seems to be delayed and now I have to look for an alternative solution to have PsSoc 62 + "something". The radio part can be from other vendors, for instance, Ambiq micro Apollo 3BLE or Nordic, but it also can be from Cypress, for instance, CYW20719. However, even if the radio chip will be from Cypress, its code still should be debugged separately. Thus, may be there will be no real benefit to go for CYW20719. Or will it be a big help to have two project in the same Modus environment? How convenient is Modus for Bluetooth/WiFi projects now? What are the alternatives?

With best regards,

Alexei

0 Likes

Hi AlVy_2459421,

The reason behind asking for a complete PDL usage is that there might be internal HAL checks for SDHC0 as only 50 MHz clock is needed for WiFi applications. You should be able to reuse the same code that is used in MTB 1.1 (along with some changes in the Device Configurator) as both use PDL . For a detailed guide to port projects from MTB 1.1 to MTB 2.0 please refer to this KBA - Migrating from ModusToolbox v1.1 to v2.x

Please let us know the results.

Regarding your second query, can you please create a new thread in ModusToolbox space so that the query can be tracked? One of the Cypress Application Engineer will be handling your query.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B

Hi Rakshith,

I did not try migration to Modus 2.0 yet, but I have found out how to address in ADMA2 mode more than 64 KB memory. Thus, all comments below concerns Modus 1.1, but they probably can be applied to Modus 2.0. As you remember, I already reported that SDMA in SDHC0  and SDHC1 works with the data blocks up to 512 KB. De facto, the restrain is even more severe: this data block should fit in the first 512 KB of RAM space. Thus, declaration of this block should be placed as early as possible inside the program to fall into this area. This is usually not a great deal. However, if the program is using both SDHCs, and if the first controller uses the whole first 512 KB, there is just no space for the buffer of the second controller. This was basically the moving force to take a look  at ADMA2 that in theory should be able to aggregate data from several independent distributed in RAM arrays to be placed in one transmission (read or write) command.

First of all, it has been found that RAM buffer for ADMA2 can be placed in any RAM region, not only in the first 512KB. Second, it has been found that it is possible with a very tiny modification of Cy_SD_Host_Write() and Cy_SD_Host_Read() commands in the file cy_sd_host.c to transmit several memory blocks, but each of them should not exceed 64KB. This is basically a big step ahead, because it allows to use the second 512KB RAM region for the second SDHC module, or make almost 1 MB buffer for one SDHC module.

How to do this?

1. Replace this piece of code (A) in Cy_SD_Host_Write() and in Cy_SD_Host_Read() with a pointer (B) to the "data" structure in which instead of a pointer to data (data.data = <data>.) stays a pointer to the structure (DMA descriptor table) determined in the user code (data.data = <DMA descriptor table>):

(A):

                length = CY_SD_HOST_BLOCK_SIZE * config->numberOfBlocks;

                aDmaDescriptTbl[0] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | // Attr Valid

                                     (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) |   // Attr End

                                     (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) |   // Attr Int

                                     (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |

                                     (length << CY_SD_HOST_ADMA_LEN_POS);     // Len

                aDmaDescriptTbl[1] = (uint32_t)config->data;

                // The address of the ADMA descriptor table.

                dataConfig.data = (uint32_t*)&aDmaDescriptTbl[0];

(B):

               dataConfig.data = (uint32_t*)config->data;

As you see, the problem of the code (A) is that only one area is addressed, and if this area is limited by 64KB, this function will never reach high throughput. One can either create automatically multiple chain descriptors when user requests a buffer larger than 64KB in this functions, or just do as I did - to accept a pointer to the description table specified in the user code. It seems to be that the last is more universal and more flexible.

2. In the user code instead of passing a pointer to data array in the data structure that is an argument in the functions Cy_SD_Host_Write() and Cy_SD_Host_Read() (A), I put a reference to the descriptor table (B):

(A):

     data.data = (uint32_t*)B0;  // Pointer to the data to write and then to read.

(B):

        #define SizeFull     (128UL)     //maximal number of sectors in ADMA2 transfer, 64KB

        #define NFull         (NSectors/SizeFull)    //number of complete 64KB blocks in B0 array

        #define SizeRest     (NSectors-NFull*SizeFull)   //number of sectors in the last non-complete block

        //data.data = (uint32_t*)B0;    //This can be removed when overridden later

        uint8_t* P_BLOCK_ADMA[NFull+1];    //array of pointers to block starts

        //Init array of pointers

        for (i=0; i<NFull+1; i++)    {

                  P_BLOCK_ADMA = &B0[CY_SD_HOST_BLOCK_SIZE*SizeFull*i];

               }

        #define My_ADMA2_DESCR_SIZE  ((NFull+1UL)*2)

        uint32_t aDmaDescriptTbl[My_ADMA2_DESCR_SIZE];

        uint32_t length;

                        length = CY_SD_HOST_BLOCK_SIZE * SizeFull;

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

                        {

                        aDmaDescriptTbl[2*i] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | // Attr Valid

                                             (0UL << CY_SD_HOST_ADMA_ATTR_END_POS) |   // Attr End

                                             (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) |   // Attr Int

                                             (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |

                                             (length << CY_SD_HOST_ADMA_LEN_POS);     // Len

                        aDmaDescriptTbl[2*i+1] =  P_BLOCK_ADMA;

                        }

                        length = CY_SD_HOST_BLOCK_SIZE * SizeRest;

                        aDmaDescriptTbl[2*NFull] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | // Attr Valid

                                             (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) |   // Attr End

                                             (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) |   // Attr Int

                                             (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |

                                             (length << CY_SD_HOST_ADMA_LEN_POS);     // Len

                        aDmaDescriptTbl[2*NFull+1] = P_BLOCK_ADMA[NFull];

                        // The address of the ADMA descriptor table.

                        data.data = (uint32_t*)&aDmaDescriptTbl[0];

As it is easy to see, now we can write several 64K blocks in one DMA request. Thus we can transmit up to whole 1MB RAM at once.

Of course, the question is how fast we can transmit data in this patched or "real" ADMA2 comparatively with SDMA.

With blocks about 448*1024 bytes ADMA2 data rate in writing was slightly smaller than in SDMA and constituted 33.061 MBps whereas SDMA had 33.924 MBps. However, this difference 3% could be just an error of measurement. Reading rates were almost identical: 43.520 MBps in ADMA2 and 43.608 MBps in SDMA.

In the next step I increased the buffer up to 988*1024 bytes, i.e. almost up to the whole 1024KB RAM. This leaded to writing rate 36.656 MBps and reading rate 44.766 MBps. Here 1MB is 1,000,000 bytes. These are the highest rates that I was able to get in PSoC 6. As one can see, increasing buffer size 2x from ~0.5 MB to ~1MB increased writing rate ~10%. This is not a lot, but can be important in some cases. More essential advantage of current realization of ADMA2 against current realization of SDMA is that the first is capable to work with RAM  above lowest 512KB.

With best regards, Alexei