KinetisSDHC.c clock setting error

UhClem

Well-known member
In KinetisSDHC.c there is a macro used to set the SDHC clock speed:
Code:
// prescale can be 2, 4, 8, 16, 32, 64, 128, 256
// divisor can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
#define SDHC_SYSCTL_DIVISOR(prescale, divisor) \
(SDHC_SYSCTL_DVS((prescale)>>1)|SDHC_SYSCTL_SDCLKFS((divisor)-1))

This invokes a couple of macros in kinetis.h:

Code:
#define SDHC_SYSCTL_SDCLKFS(n) (uint32_t)(((n) & 0xFF)<<8) // SDCLKFrequency Select
#define SDHC_SYSCTL_SDCLKFS_MASK ((uint32_t)0x0000FF00)
#define SDHC_SYSCTL_DVS(n) (uint32_t)(((n) & 0xF)<<4) // Divisor
#define SDHC_SYSCTL_DVS_MASK ((uint32_t)0x000000F0)

The problem is that the code is feeding the prescale value (a single bit set in an eight bit field) to the divisor macro (four bits) and the divisor value to the prescale macro. The result is clock frequencies are set to values that aren't predictable since operation with more than one bit set in the prescaler field is undefined.

A simple change fixes it:
Code:
#define SDHC_SYSCTL_DIVISOR(prescale, divisor) \
(SDHC_SYSCTL_SDCLKFS((prescale)>>1)|SDHC_SYSCTL_DVS((divisor)-1))
 
I agree this is an error. if i run T3.6 @180mhz, SDHC_SYSCTL is 0xE0318. 3 is illegal value for SDCLKFS. sector read time is 452 us. Manually setting to 0xE0138, then SDHC clock should be 180/2/4 (22.5 MHz) and sector read time is 427us.

I'm not sure why Paul hasn't replied. I'll try filing an issue on github
 
Sorry about the delay on this (and so many other things). My spare dev cycles are currently going into some final cleanup with the recent server move, and an ongoing project with our PCB vendor to make very minor changes on all the boards to improve manufacturability... and of course keeping up with answering questions.
 
No rest for the weary. thanks

Upon further review, I think you can improve SDHC clock values in some cases. So if F_CPU is 72mhz, one could get 24mhz SDHC clock SDCLKFS 0, and divisor 3. that is better than your 18 mhz.
 
Last edited:
Upon further review, I think you can improve SDHC clock values in some cases. So if F_CPU is 72mhz, one could get 24mhz SDHC clock SDCLKFS 0, and divisor 3. that is better than your 18 mhz.

Any chance you can tighten up some of the divisors in KinetisSDHC.c, i have a perl script that generates the following divisors
Code:
F_CPU 240000000
  400000  (375000)  div(64,10)
  25000000  (24000000)  div(1,10)
  50000000  (48000000)  div(1,5)
F_CPU 216000000
  400000  (375000)  div(64,9)
  25000000  (24000000)  div(1,9)
  50000000  (43200000)  div(1,5)
F_CPU 192000000
  400000  (400000)  div(32,15)
  25000000  (24000000)  div(1,8)
  50000000  (48000000)  div(1,4)
F_CPU 180000000
  400000  (375000)  div(32,15)
  25000000  (22500000)  div(1,8)
  50000000  (45000000)  div(1,4)
F_CPU 168000000
  400000  (375000)  div(32,14)
  25000000  (24000000)  div(1,7)
  50000000  (42000000)  div(1,4)
F_CPU 144000000
  400000  (375000)  div(32,12)
  25000000  (24000000)  div(1,6)
  50000000  (48000000)  div(1,3)
F_CPU 120000000
  400000  (375000)  div(32,10)
  25000000  (24000000)  div(1,5)
  50000000  (40000000)  div(1,3)
F_CPU 96000000
  400000  (400000)  div(16,15)
  25000000  (24000000)  div(1,4)
  50000000  (48000000)  div(1,2)
F_CPU 72000000
  400000  (375000)  div(16,12)
  25000000  (24000000)  div(1,3)
  50000000  (36000000)  div(1,2)
F_CPU 48000000
  400000  (400000)  div(8,15)
  25000000  (24000000)  div(1,2)
  50000000  (48000000)  div(1,1)
F_CPU 24000000
  400000  (400000)  div(4,15)
  25000000  (24000000)  div(1,1)
  50000000  (24000000)  div(1,1)
I guess I could modify the perl script to generate your macros ....
 
Do these actually work and produce the desired frequencies?

The datasheet says the clock prescale must be at least 2.
 
Do these actually work and produce the desired frequencies?

The datasheet says the clock prescale must be at least 2.

I confirmed a few of the configurations provided "faster" megabits/sec, but i don't have a way to actually measure the SD clock. As noted above, 0 bypasses the prescaler (e.g., prescaler =1)
 
As noted above, 0 bypasses the prescaler (e.g., prescaler =1)

This is what I was reading too and coding also without problems.
(it is only a line or so above, but on previous page)
As soon as I have access to a SDIO sniffer board (next week), I will test clock rate.
 
Last edited:
Back
Top