10 years, 3 months ago.

spi.frequency for KL25Z

I write spi.frequency(1000000); in my program and compile it. but I get 500KHz SPI frequency. Is it bug or my Logic analyzer is broken???

Hello Behdad Khoshin,

there was this question asked 4 months ago, here's the link [http://mbed.org/questions/1485/spifrequency-for-KL25Z/]

Look at prescaler registers, and see if it's possible to generate 1MHz, report back.

Regards,
0xc0170

posted by Martin Kojtal 08 Jan 2014

Hi , My BR register is 0x23 it means spr=3 and sppr=2 which is correct for 1Mhz but logic analyzor shows 5Hz ! I am interfacing it with CC1101 . Thanks

posted by Behdad Khoshbin 08 Jan 2014

Made a pull request to the mbed github library to change:

uint32_t PCLK = 48000000u;
into:
uint32_t PCLK = SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);

Slightly slower than hardcoded, but it should always return the proper frequency, also with different clock setups.

Since I am not that familiar with github I kinda accidently included it in my previous pull request, I think :P. I am fairly certain this change is now also included in the pull request.

It probably also needs to change for the KL46Z and KL05Z.

posted by Erik - 08 Jan 2014

2 Answers

10 years, 3 months ago.

@Last comment: Nop, with your numbers you get 500kHz. Weird part for me is mainly that recently I was working at SPI with SD cards, and I am fairly certain the time it took to write a block was pretty close to what I was expecting (and that was written with DMA, so no mbed driver overhead, while the mbed driver was used to set the baudrate).

Anyway, from the code:

void spi_frequency(spi_t *obj, int hz) {
    uint32_t error = 0;
    uint32_t p_error = 0xffffffff;
    uint32_t ref = 0;
    uint8_t  spr = 0;
    uint8_t  ref_spr = 0;
    uint8_t  ref_prescaler = 0;
 
    // bus clk
    uint32_t PCLK = 48000000u;
    uint8_t prescaler = 1;
    uint8_t divisor = 2;
 
    for (prescaler = 1; prescaler <= 8; prescaler++) {
        divisor = 2;
        for (spr = 0; spr <= 8; spr++, divisor *= 2) {
            ref = PCLK / (prescaler*divisor);
            if (ref > (uint32_t)hz)
                continue;
            error = hz - ref;
            if (error < p_error) {
                ref_spr = spr;
                ref_prescaler = prescaler - 1;
                p_error = error;
            }
        }
    }
 
    // set SPPR and SPR
    obj->spi->BR = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf);
}

Now if I am not mistaken the problem here, besides that for some reason PCLK is hardcoded to be 48MHz instead of just using the SystemCoreClock, is that 48MHz is the SystemCoreClock. While from the user manual:

Quote:

The input to this prescaler is the bus rate clock (BUSCLK).

And the bus clock rate of the KL25Z is 24MHz.

So someone correct me if I made a mistake here somewhere, but it looks to me like PCLK should be 48MHz / the bus-core ratio which is given in SIM->CLKDIV1 (might as well make it scale properly with clock rate). If soonish no one else has done it I will fix it and upload to github.

Could someone else with a KL25Z and a logic analyzer verify this btw?

Accepted Answer

Hello,

I was just looking at this issue yesterday while working on K20 port, had problems also with prescalers and noticed that bus clock is a clock for SPI but KL ports are using system clock. Have you tested it with bus clock?

I believe you pinpointed that issue, I can fix this on all KL ports, if you don't mind. Let me know.

Regards,
0xc0170

posted by Martin Kojtal 09 Jan 2014

I checked the numbers with bus clock on the KL25. This fix is now also comitted to fhr other KL's on github.

posted by Erik - 09 Jan 2014
10 years, 3 months ago.

Hi All, I did a quick test of the SPI bitrate for the KL25Z and it seems to be wrong. You get about 50% of the selected value.

#include "mbed.h"

DigitalOut myled(LED1);

SPI spi(PTD2, PTD3, PTD1);
DigitalOut CS(PTD0);

int main() {
    
    myled = 1;
    CS = 1;
    
    spi.format(8, 0);          
//    spi.frequency(100000);    
//    spi.frequency(500000);    
    spi.frequency(1000000);
 
        
    while(1) {
      CS=0;
      spi.write(0xAA);
      spi.write(0x81);
      CS=1;        
      wait_us(5);      
    }
}

Result for 100000:

/media/uploads/wim/screenshot_100khz.jpg

Actual bitrate is 46.5 KHz

Result for 500000: /media/uploads/wim/screenshot_500khz.jpg Actual bitrate is 250 KHz

Result for 1000000: /media/uploads/wim/screenshot_1mhz.jpg Actual bitrate is 500 KHz

Probable cause is mix-up between the KL25Z 48MHz SystemCoreClock and the bus clock rate of 24MHz.