2011-10-26 07:11 AM
Hi again guys,
I have previously had some issues with the SDIO that have been fixed. Recently I moved my SDIO test application into my large application and have been having a strange issue writing to the power register. I have a work around in place to get the power register set, but it seems to be causing issues further along such as not being able to enable the clock either. Here is a snippit of the function that initializes my SDIO...SD_Error DIL_SDIO_Power_On ( void )
{
SD_Error errorstatus = SD_OK;
uint32_t response = 0;
uint32_t count = 0;
uint32_t validvoltage = 0;
uint32_t SDType = SD_STD_CAPACITY;
/* Power ON Sequence -----------------------------------------------------*/
/* Configure the SDIO peripheral */
/* SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) */
/* on STM32F2xx devices, SDIOCLK is fixed to 48MHz */
/* SDIO_CK for initialization should not exceed 400 KHz */
SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init ( &SDIO_InitStructure );
/* Set Power State to ON */
SDIO_SetPowerState ( SDIO_PowerState_ON );
/* Enable SDIO Clock */
SDIO_ClockCmd ( ENABLE ); The issue I am having is when SDIO_SetPowerState is called is simply write to the power register using the following.... SDIO->POWER &= PWR_PWRCTRL_MASK;
SDIO->POWER |= SDIO_PowerState;
The problem is the register is not being set. If I comment out the first line in SetPowerState ( SDIO->POWER &= PWR_PWRCTRL_MASK;) the register does get set. How important is this line? It is part of the stm32f2xx library so I am wary about commenting it out. ( #define PWR_PWRCTRL_MASK ((uint32_t)0xFFFFFFFC) ) From what I understand it is just clearing out the first 2 bits of the register before writing to it. In the reference manual it shows all other bits as reserved always reading 0. So why is it important to preserve these bits? Does this seem weird to anyone? Has anyone ever seen this issue? Suggestions? Advice? Thanks, Brad EDIT 1: The Problem is worse than I thought. Something must be going wrong prior to setting the power state and the clock enable. as neither are happening. The code is identical to what i have had previously. I am currently lost and will update if I find a solution.
2011-10-26 08:42 AM
Hi Brad,
I ran into the exact same issue on another new ST part with SDIO. I couldn't get the bits to set and commented out the first line of SDIO_SetPowerState and things started to work. The newer version of the ST library for that part (STM32L152) had the same change I made so I assume the FW engineers at ST think that's the correct way of doing it.The current version of the 20x library still has both lines so it must work for ST's test cases, not sure why it sometimes fails. I'm using that code on my 207 project and everything is fine but had to make the change for my 152 project. I'll ping the ST guys to see what I can find out.As to your other problem, not sure why you now can't enable either clock or power. I've kept the init sequence ST has in their example and carried it over to my projects:- GPIO/RCC setup- SDIO_DeInit (which is essentially a reset of the SDIO peripheral)- NVIC setup- SD_PowerOnThat sequence has always worked on the F1xx parts, the F2xx parts and started working on the L152 when I removed the first line of the SDIO_SetPowerState.Andrew2011-10-26 08:54 AM
Thanks for your response Andrew.
In my SDIO Init my order was: -NVIC setup -Setting up periphals -DeInit -PowerOn I moved my NVIC just to give it a shot with no changes. Unfortunately there is no update for the f2xx library as of now. But yeah, I can get the power register to set by removing that line. But the call to SDIO_ClockCmd ( ENABLE ); is not settign my clock bit in CLKCR. ( but the SDIO_Init will set the ClockDiv bits ) Does not make sense how the below code is not setting the register. It is almost like it is locked or read only. *(__IO uint32_t *) CLKCR_CLKEN_BB = (uint32_t)NewState;2011-10-27 07:35 AM
I just remembered another thing - I've seen the clock not come on when the 48MHz clock driving the SDIO_CK clock (the one going out to the card) is not on.
I was confused about the way the SDIO_CK clock is generated and had to look at the clock tree. As it turns out, SDIO_CK is generated from a 48MHz clock that's also used for things like USB. Here's a snippet from the manual:All peripheral clocks are derived from the system clock (SYSCLK) except for:
�? The USB OTG FS clock (48 MHz), the random analog generator (RNG) clock
(≤ 48 MHz) and the SDIO clock (≤ 48 MHz) which are coming from a specific output of
PLL (PLL48CLK)
In one instance we were playing around with power-savings and turned the clock down and turned the PLL off. At that point SDIO stopped switching on the clock. We had to reenable the PLL and set the div/mult values to regenerate the 48MHz.Have you checked whether you have the PLL set up correctly to generate the 48MHz clock at the point in time where you try to enable the SDIO clock? Andrew2011-10-27 09:20 AM
Andrew,
Funny thing is I was getting on to share with everyone that my PLL was not configured properly. Thanks for all your help.. I got ahold of the clock configuration spreadsheet and got it going. Cheers, Brad2011-12-05 04:37 PM
Hi Brad & Andrew,
Thanks very much for this (month-old) thread - I had the same problem on a STM32F205 and although it was a low-priority problem, eventually I got tired of it and decided to fix it. It was the exact same thing you've described below - the problem with the SDIO_SetPowerState() function. I believe the reason the function does this: SDIO->POWER &= PWR_PWRCTRL_MASK; SDIO->POWER |= SDIO_PowerState; is because the function is used both to turn on the power, and also to turn it off. Simply commenting out the first line would prevent it from being able to turn off the power (I think). An alternate fix to the function might be something like: if (SDIO_PowerState == SDIO_PowerState_ON) SDIO->POWER |= SDIO_PowerState; else SDIO->POWER &= PWR_PWRCTRL_MASK; FYI, the definitions of ON and OFF are: #define SDIO_PowerState_OFF ((uint32_t)0x00000000) #define SDIO_PowerState_ON ((uint32_t)0x00000003) #define PWR_PWRCTRL_MASK ((uint32_t)0xFFFFFFFC) This change seems to work. Edit: The root cause is the documentation for the SDIO_POWER register clearly states: At least seven HCLK clock periods are needed between two write accesses to this register