WMXZ-EU / uSDFS

uSD File system based on ELM-CHaN generic FAT system
28 stars 13 forks source link

m_sdhc_baudrate caculation wrong #5

Open manitou48 opened 7 years ago

manitou48 commented 7 years ago

line 467 in sdhc.c (cosmetic?) is in error me thinks. it reads m_sdhc_baudrate=F_CPU/((1<<minpresc)*(mindiv+1));

but minpresc is not a shift value, it should be minpresc << 1 BUT, that is not quite right either, because if minpresc is 0, you want the multiplier to be 1, so maybe int tmp = minpresc << 1; if (tmp == 0) tmp = 1; m_sdhc_baudrate=F_CPU/(tmp*(mindiv+1));

WMXZ-EU commented 7 years ago

I believe that the following code should be correct

// get dividers from requested baud rate 
    uint32_t aux=F_CPU;
    uint32_t ii=0,jj=1;
    uint32_t baudrate=kbaudrate*1000;

    while(aux/(16*(1<<ii))>baudrate) ii++;
    while(aux/(jj*(1<<ii))>baudrate) jj++;

    uint32_t minpresc=ii;
    uint32_t mindiv=jj-1;

    m_sdhc_baudrate=F_CPU/((1<<minpresc) * (mindiv+1));

    // Change dividers
    sysctl = SDHC_SYSCTL & 
            (~ (SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DVS_MASK));
    SDHC_SYSCTL = sysctl | 
            (SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_SDCLKFS(minpresc) | SDHC_SYSCTL_DVS(mindiv));

presc is a single bit and div is a number

This includes the (untested case) that presc = 0 is valid input and that presc=0 does not prevent div to be effective. The way I calculate is if F_CPU=96 Mhz and baudrate is 3 kHz then ii=1 and jj=16 presc=1 and div = 15 and therefore 96MHz/((1<<presc)*(div+1)) = 3kHz

Can you agree?

manitou48 commented 7 years ago

You chose a convenient example where ii is 1. the minpresc in the register should have values of 0, 1,2,4,8,16 32 ... your current example, i don't think will set the register value correctly

what will you get with CPU 96mhz and target baudrate 400K, 96000000/(16*15) = 400000 register: prescale value 8, divisor value 14 On Tue, Jan 17, 2017 at 12:09:21PM -0800, WMXZ-EU wrote:

I believe that the following code should be correct

// get dividers from requested baud rate 
  uint32_t aux=F_CPU;
  uint32_t ii=0,jj=1;
  uint32_t baudrate=kbaudrate*1000;

  while(aux/(16*(1<<ii))>baudrate) ii++;
  while(aux/(jj*(1<<ii))>baudrate) jj++;

  uint32_t minpresc=ii;
  uint32_t mindiv=jj-1;

  m_sdhc_baudrate=F_CPU/((1<<minpresc) * (mindiv+1));

  // Change dividers
  sysctl = SDHC_SYSCTL & 
          (~ (SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DVS_MASK));
  SDHC_SYSCTL = sysctl | 
          (SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_SDCLKFS(minpresc) | SDHC_SYSCTL_DVS(mindiv));

presc is a single bit and div is a number

This includes the (untested case) that presc = 0 is valid input and that presc=0 does not prevent div to be effective. The way I calculate is if F_CPU=96 Mhz and baudrate is 3 kHz then ii=1 and jj=16 presc=1 and div = 15 and therefore 96MHz/((1<<presc)*(div+1)) = 3kHz

Can you agree?

-- You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/WMXZ-EU/uSDFS/issues/5#issuecomment-273284489

-- Tom Dunigan thdunigan@gmail.com http://tnlandforms.us