yrakcaz
Posts: 3
Joined: Thu Nov 27, 2014 3:50 pm

[BARE-METAL][SDC/EMMC] How to access it properly??

Tue Dec 16, 2014 10:59 am

Hi everybody,

Firstable, I'm sorry for my English which I know is not very well.
I know that there are too many topics about it, but I can't find out my way in anyone of them, so I hope it will be the good (last) one...

So, I'm trying to write a little and simple OS (educational purpose) for my raspberry, the code is here if needed : https://github.com/yrakcaz/RasPiK/
What I'd like to do now is just to retrieve some data from SD card, just read something on it. I've tried everything I found on the internet but nothing seems to work : I'd just like to have a sign from the sd card, like an "sd_init" function which returns SUCCESS or anything like that...

Does someone have an example of it, which could be integrable directly on my OS, just for "test the sd card" before to write a real driver?

Thanks a lot to anyone who will answer this question, I'm on it for a few weeks and I begin to lose hope...

Cordially.

--

yrakcaz

hldswrth
Posts: 108
Joined: Mon Sep 10, 2012 4:14 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Tue Dec 16, 2014 11:48 am

Initialising the SD card through the EMMC interface is unfortunately not a simple process. There's a sequence of commands and responses which you need to go through to establish the card type, speed, voltage etc. before you can read and write. I've written my own SD card driver which uses the EMMC interface. I'll attach the code although its not standalone as-is as it depends on my log macros and other functions, but hopefully it will help you understand what's required to get this to work.
Attachments
sdcard.zip
Bare metal SD card driver using EMMC interface
(13.59 KiB) Downloaded 390 times

yrakcaz
Posts: 3
Joined: Thu Nov 27, 2014 3:50 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Tue Dec 16, 2014 12:47 pm

Thank you so much for this fast answer hldswrth!

I will try to use it to build my own one, but before that I've just a few questions about your method :

-> Could you please explain your gpio initialization sequence? I already saw it on other projects, and I don't understand everything (I'm speaking about your sdInitGPIO() function and the two lines marked "Check GPIO 47 status")..

-> I see that you make a difference between virtual and physical memory, I didn't do that for the moment on my OS, do you think that using raw addresses for EMMC device could corrupt it?

-> I see also that you make a difference between waitMicro and waitCycle into your code, why did you need to do that?

I really know that my questions are basics but I prefer to understand everything before writing thousand lines for nothing...
Thanks!

Regards.

--

yrakcaz

hldswrth
Posts: 108
Joined: Mon Sep 10, 2012 4:14 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Thu Dec 18, 2014 1:09 pm

-> Could you please explain your gpio initialization sequence? I already saw it on other projects, and I don't understand everything (I'm speaking about your sdInitGPIO() function and the two lines marked "Check GPIO 47 status")..

GPIO 47 is the SD "card detect" which tells me whether there is a card present or if one has been removed and inserted.

-> I see that you make a difference between virtual and physical memory, I didn't do that for the moment on my OS, do you think that using raw addresses for EMMC device could corrupt it?

Using the raw addresses is fine. In my OS I have a 2GB/2GB split for user and kernel memory so I map the registers to a range above 0x80000000. If you #define P2V_DEV(X) (X) that gives the values without MMU enabled.

-> I see also that you make a difference between waitMicro and waitCycle into your code, why did you need to do that?

Timing was one of the hardest bits to get right. waitCycle is for a very small wait of a number of instructions when a register is set or read, whereas waitMicro is for a longer wait where a response is being waited for from the card.

moizumi
Posts: 5
Joined: Fri Jan 06, 2017 5:12 am

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Mon Feb 06, 2017 5:52 am

Hello, hldswrth

I recently started Raspbery Pi bare metal programming, and found your EMMC code very very useful. I am using it in my project with a little modification to fit into my environment.
What is the copyright type of this code?
Is it OK to upload my project that include this to github or other public spaces? Any condition?
hldswrth wrote:Initialising the SD card through the EMMC interface is unfortunately not a simple process. There's a sequence of commands and responses which you need to go through to establish the card type, speed, voltage etc. before you can read and write. I've written my own SD card driver which uses the EMMC interface. I'll attach the code although its not standalone as-is as it depends on my log macros and other functions, but hopefully it will help you understand what's required to get this to work.

LdB
Posts: 550
Joined: Wed Dec 07, 2016 2:29 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Mon Feb 06, 2017 4:46 pm

If he doesn't answer you (the repo hasn't been touched in 2 years) it is just a wrapper around John Cronin's emmc.c, which you will find in that source (master/src/drivers/imports/emmc.c). That is a public release and the wrapper is fairly trivial and would be a fairly simple rewrite.

The original source is
https://github.com/jncronin/rpi-boot/blob/master/emmc.c

Be aware that code has a couple of bugs/departures from the standard which you can download from http://www.sdcard.org called partA2_300.pdf

The first one you will probably run into is during SD card initialization on CMD3

Step 33 of the initialization from the standard says
(33) CMD3 is issued to get RCA. If the RCA number is 0, the Host should issue CMD3 again

You might want to look at what the code does, I had a lot of trouble with certain SD cards on that.

If I recall the 10 bit clock divider code doesn't work correctly if you change the EMMC clock speed either, I changed it to a fls (first last set) bit operation to setup a correct power2 divisor calc.

The USB disk access on John Cronin's site was a little more robust and not a bad start point if you want to go down that track.

moizumi
Posts: 5
Joined: Fri Jan 06, 2017 5:12 am

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Tue Feb 07, 2017 4:45 pm

Thank you for letting me know about the John Cronin's work. It's another nice source.
But, I have difficulty finding the association between John's code and hldswrth's code. At least, it doesn't look like trivial difference.
Anyway, I need to read both codes a little more to understand the behavior.

LdB
Posts: 550
Joined: Wed Dec 07, 2016 2:29 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Wed Feb 08, 2017 2:44 pm

They are the same code it just looks different because one got made linear... how do I know well lets look at some bugs

In this procedure "static int sdResetCard( int resetType )" in hldswrth's code it has this line

Code: Select all

*EMMC_CONTROL2 = 0;
That is a read only register in version 2 card it's not supposed to be written look at partA2_200.pdf offset 003C detail ... It's clearly labelled ROC. Only in version 3 cards does the top bit of it become writable again partA2_300.pdf offset 003E is the writable bit. You can get both the version 2 and version 3 pdf's from http://www.sdcard.org if you don't have them

In John Cronnins code he does exactly the same thing

Code: Select all

// Clear control2
mmio_write(emmc_base + EMMC_CONTROL2, 0);
That isn't even that registers name it's (Auto CMD Error Status Register) on SD 2 spec. John was the one who seems to have given it that name from the Host Control 2 Register name of offset 3E on SD spec 3. Ok lets put that as just coincidence. Note the correct safe way to play with that is read it change the bits and write it back again in case they define more bits as writable in future and only on a version 3 card. I would suggest blindly writing zero at it isn't a really good idea.

If you look at the low speed clock setup "static int sdSetClock( int freq )" in hldswrth's code
It's got the same crazy clock divider code immediately above it called "static int sdGetClockDivider( int freq )"
If you look hldswrth has commented that it's dorked and it is because it's derived off John Cronnins code. Go and look at John code called "sd_get_clock_divider(uint32_t base_clock, uint32_t target_rate)"

What is wrong with John's code well first the clock frequency to the SD on the Pi is 41.66666Mhz, John thinks it is 100Mhz. I will cut John some slack on that because back in the early days I believe it was different until problem with corruption forced a firmware fix from what I have read off the Pi firmware forum. All that assumes you haven't got a config.txt file that plays with the values and in that case the SD CARD clock frequency will be the 250Mhz GPU clock divided by 6 = 41.666666Mhz

The second part of John's problem is he thinks the divider is 10bits .. it is only 10 bits on a version 3 SD card. On a version 2 SD card it's only 8 bits and only 1 bit can be set at a time. Again refer to the detail on partA2_200.pdf and compare to partA2_300.pdf.

The final part of the problem is in the attempt to get a power2 divisor he botches it totally. The easiest way to do that properly is to round up a Find Last Set (FSL) bit operation. However it's pretty well not needed the divisor you want is pretty much always 128. If someone has tweaked the clock up up the only other real choice is 256 the maximum value you can set on a SD version 2 I/F card. The 128 divisor gives you a low speed setup at 325Khz the only real choice you have. On a version 2 card even at high speed the selection gets pretty brutal (I will leave you to work that one out). Only a version 3 I/F card do you have a little more flexibility and a few more divisors to work with if you know the new register bits to set. Hence hldswrth reached the correct conclusion about his code and that was just by luck as he seems to think its 10bits (max 1024)

Code: Select all

  // For V2, the divider is supposed to be a power of 2
  // For V3, the divider is a multiple of 2, with a value of 0 indicating 1.
  // TODO: currently only V2 algorithm appears to work.
There are few more bugs in John's code with certain commands, like there is a horror one that sends you into a deadloop. I got so familiar with them I can pick code derived off/or incorporating John's work very quickly. There is definitely some novel stuff in hldswrth's code and John released his code to the public, so there is no real issue here.

If I get time this week I will add some commented patches to the code, if you want to use it ... up to you.

LdB
Posts: 550
Joined: Wed Dec 07, 2016 2:29 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Wed Feb 08, 2017 4:34 pm

Oh just for house keeping the code for rounding up a divisor to power 2 you need the two functions

A quick implementation of fls_long, there is no point is shorting it on an ARM6+ it will be 32 bit register anyhow

Code: Select all

int fls_long (unsigned long x) {
     int r = 32;
     if (!x)  return 0;
     if (!(x & 0xffff0000u)) {
         x <<= 16;
         r -= 16;
     }
     if (!(x & 0xff000000u)) {
       x <<= 8;
       r -= 8;
    }
    if (!(x & 0xf0000000u)) {
      x <<= 4;
      r -= 4;
   }
   if (!(x & 0xc0000000u)) {
      x <<= 2;
      r -= 2;
   }
   if (!(x & 0x80000000u)) {
     x <<= 1;
     r -= 1;
   }
   return r;
 }
Then the function that uses it to round the divisor up

Code: Select all

unsigned long roundup_pow_of_two (unsigned long x) {
   return 1UL << fls_long(x - 1);
}
41,666,666 / 400000 = 104 and roundup_pow_of_two(104) should give you 128 all being well, but you only need the fls result to shift the bit for the register :-)

PS: Asking for the EMMC frequency from the mailbox is pointless on baremetal it will always return 250Mhz because as per the mailbox clock standard (All clocks are the base clocks for those peripherals, e.g. 3MHz for UART, 50/100MHz for EMMC, not the dividers applied using the peripheral.). The standard divisor of the EMMC is 6 (it has to be an even number) unless you yourself went and change it and then you open up the whole corruption issue.

moizumi
Posts: 5
Joined: Fri Jan 06, 2017 5:12 am

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Fri Feb 10, 2017 6:05 am

LdB,
thanks a lot. It seems like I was very lucky that the code was working with my SDCARD.
Also, your another comment about mailbox returning base clock is very helpful. I had some puzzling moments in the past. (I don't remember exactly which clock, but I do remember some return values didn't make sense.)

I'd really love to see your code, if it is not too much trouble for you.

LdB
Posts: 550
Joined: Wed Dec 07, 2016 2:29 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Fri Feb 10, 2017 3:18 pm

Quote: thanks a lot. It seems like I was very lucky that the code was working with my SDCARD.
No it was 50/50 .. it worked in a manner on about half my 40 or so cards.

Okay I will prep that code dump to happen ... will need to be next week I have a lot on my plate.

I have run over that code in the meantime ... beyond a raft of possible minor stuff there are three major problems with that code you need to be aware of because they will happen .. I guarantee it.

1.) The Pi can't do anything but 3.3V it doesn't and can't do 1.8V drop down. The code checks the card can do drop down and then goes into code to command the card to go to low voltage. The moment that happens you will lose contact to the SD card. The author seems convinced there is some undocumented ability but (A.) it doesn't work on any Pi I have and (B) I can find no source except him that thinks there is some undocumented feature. So lets say I need to be convinced a Pi can do low voltage drop down. What I have found is the Pi1 will do UHS-I 3.3volt double access mode (where it read/writes on positive and negative edges) but strangely the Pi2 and 3 won't. I wondered if he ran across that and didn't recognize it because his code had the other problem it was Pi1 only with those register addresses.

To stop fix that in the meantime in the function sdSwitchVoltage() just add these two lines at the top. It just gives you a warning into logs if you have them turned on and bails you out without doing anything to continue on. Beyond the return message he doesn't check the card actually did the dropdown and it has no effect on any future code.

Code: Select all

static int sdSwitchVoltage()  {
  LOG_DEBUG("EMMC: Pi does not support switch voltage, fixed at 3.3volt\n");
  return SD_OK;
2.) Please remove that write zero to Control2 register I highlighted. If you have a SD CARD which has auto preset tuning that line of code merrily turns it off on Bit 15. I warned you it wasn't a good idea.

3.) Finally the patch to the code for the clock frequency you have the FLS code above. I changed code to using uint32 as I had it on 64bit mode you can just change them back to normal int, I was too lazy to change when I cut and pasted.

Code: Select all

/* Get the clock divider for the given requested frequency.
 * This is calculated relative to the SD base clock.
 */
static uint32_t sdGetClockDivider ( uint32_t freq ) {
	uint32_t divisor;
	uint32_t closest = 41666666 / freq;					// Pi SD frequency is always 41.66667Mhz on baremetal
	uint32_t shiftcount = fls_long(closest - 1);		// Get the raw shiftcount
	if (shiftcount > 0) shiftcount--;					// Note the offset of shift by 1 (look at the spec)
	if (shiftcount > 7) shiftcount = 7;					// It's only 8 bits maximum on HOST_SPEC_V2
	if (sdHostVer > HOST_SPEC_V2) divisor = closest;	// Version 3 take closest
		else divisor = (1 << shiftcount);				// Version 2 take power 2
	
	if (divisor <= 2) {									// Too dangerous to go for divisor 1 unless you test
		divisor = 2;									// You can't take divisor below 2 on slow cards
		shiftcount = 0;									// Match shift to above just for debug notification
	}

	LOG_DEBUG("Divisor selected = %lu, pow 2 shift count = %lu\n", divisor, shiftcount);
	uint32_t hi = 0;
	if (sdHostVer > HOST_SPEC_V2) hi = (divisor & 0x300) >> 2; // Only 10 bits on Hosts specs above 2
    uint32_t lo = (divisor & 0x0ff);					// Low part always valid
    uint32_t cdiv = (lo << 8) + hi;						// Join and roll to position
	return cdiv;										// Return cdiv
}
Finally there is a thing which I just found bizarre and puzzling with the ReadWrite sending in a real address and then pulling back a sector that addressed by rolling the address down by 9 (effectively doing a divid 512) to give you the appropriate sector and then doing weird access to the data. I don't get it .. you have to read/write a whole block anyhow why fiddle around like that. Every normal person runs a simple sector buffer and does the buffer work themselves the performance was horrible. Anyhow I just dispensed with the real address and made it a sector number you requested and it just dropped straight into any normal code off a PC that uses INT13 disk access which expects sector number.

moizumi
Posts: 5
Joined: Fri Jan 06, 2017 5:12 am

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Sun Feb 19, 2017 7:44 pm

LdB,
thanks. I have removed Control2.
Right now, I am trying to implement clock divisor. I think I need to make it work with other places (I change EMMC clock in another place. So, it may be interfering.) I am studying your advice and the document.

BTW, Here is the link to my project.
https://github.com/moizumi99/RPiHaribote
It's a porting of an educational OS called Haribote, which is popular among OS learners in my home country.

hldswrth
Posts: 108
Joined: Mon Sep 10, 2012 4:14 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Thu Mar 16, 2017 11:13 am

Apologies for the late post. Just for the record the code I posted was entirely my own work and not derived from anyone else's emmc library. If there are similarities in the way the registers are accessed and divisors calculated its most likely because that was in the documentation or posted in this forum as part of discussions on how to get the interface working.

The code was intended to provide some detailed guidance on at least how I got it working for myself. I'm happy for anyone to use the code as-is - as disucssed above there are likely shortcomings, I have only used it on a Pi 1 model B and a limited number of cards.

LdB
Posts: 550
Joined: Wed Dec 07, 2016 2:29 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Thu Mar 16, 2017 12:13 pm

Thanks for the clarification and he is obviously using it and very happy, so that will make him doubly happy. I pass that on in case he misses this post to do so.

It was a pretty fair effort on your behalf, and I know I found some bugs but that doesn't detract from the scale of work you did. You code was concise and well documented and is easy for people to follow and learn from.

Yeah the documentation was fun wasn't it .. I know I spent about 4 days on my storage scope on the Pi socket checking everything when I did my assembler library.

moizumi
Posts: 5
Joined: Fri Jan 06, 2017 5:12 am

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Fri Mar 17, 2017 5:06 am

Hi, hldswrth
Thank you for the confirmation. I knew it was posted a few years ago, and that there was little chance you noticed. But, I am happy to get the confirmation. Now I can use the code without worrying. Also, I'd like to let you know that it's working on my Pi Zero as well as on Pi B+. https://github.com/moizumi99/RPiHaribot ... e/sdcard.c

LdB,
Thank you for following up.
I had some other tasks and choirs in the past few weeks, and haven't finished going through the docs that you referred yet. But, I will find time and work on them soon!

hldswrth
Posts: 108
Joined: Mon Sep 10, 2012 4:14 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Fri Oct 06, 2017 4:58 pm

Another necro of this thread, apologies but my question is directly related to the discussion above.
I would really like to understand the setting of the clock divisor and so far I've still not got it.
I've tried updating my code as described here and there are some things I still don't understand or can get to work.

Mailbox returns 100Mhz for SD base clock, not 250Mhz or 41.6Mhz. How am I supposed to know the magic number of 41.6Mhz, and is that ever likely to change at any point? What's the point of the mailbox interface if the value it returns bears no resemblance to reality?

Even given that, with a card that has 2 for sd host version (which I believe indicates Spec V3) the divisor from the above code comes out as 104. Setting that as the divisor value, or 128, just does not work at all. The first command send to the card after the reset never gets a response. The only two values I have ever got to work are 15 and 2. 15 doesn't make much sense for a slow speed setting but anything greater does not work for me.

Does the code linked above work with a divisor value of 104 or 128?

I'm wondering if this is possibly related to using very old (2012) firmware, however I've tried to use more up to date firmware and my O/S fails to boot with it at all - and I'm not sure I want to have to debug that unless I really have to.

LdB
Posts: 550
Joined: Wed Dec 07, 2016 2:29 pm

Re: [BARE-METAL][SDC/EMMC] How to access it properly??

Sun Oct 08, 2017 4:48 am

On old firmware the SD Card clock was 104Mhz. They changed it because they had SD card corruption issues .. you can follow it on the firmware or raspbian threads
https://github.com/raspberrypi/linux/issues/467
http://lkml.iu.edu/hypermail/linux/kern ... 03366.html

ghollingworth => Actually the driver chooses a value of 1/6 resulting in a frequency of 41MHz .. .AKA 250/6 = 41Mhz.
P33M => As explained, this is required to work around a bug with the hardware.
Eric Anholt =>The other is EMMC, which according to the docs was supposed to be in the 50-100Mhz
range, but it turns out the firmware needed to change to running it at the 250Mhz core clock speed to avoid a bug in clock domain crossing.

So that change occured somewhere in 2013-15. So as per the that thread there is 100Mhz SD clock on old firmware and now what we call 50 Mhz clock (which is actually 41Mhz post that change). The 41Mhz clock is why the SD card speed flattens out to 20Mbs on the Pi. On the old firmware you can get 40Mbs but you run the SD card corruption issue which is a hardware bug. You can get around the bug but that is a whole other story.

You can change it by changing the speed of the GPU clock or changing the divisor. However they also stated the divisor can only be an even number (2,4,6,8, etc). The number we might have liked is 5 but it is illegal. I don't know the background to why.

However for clarity on the current up todate firmware if you divid whatever speed the Pi mailbox returns for the EMMC clock and divid it by 6 you will have the real SD card clock speed if you haven't altered the divisor from the bootloader.

Return to “Bare metal”

Who is online

Users browsing this forum: wh7qq and 3 guests