Menu

"SPI clock baud rate is calculated..." not making sense.

2026-07-08
6 days ago
1 2 > >> (Page 1 of 2)
  • Roger Jönsson

    Roger Jönsson - 2026-07-08

    I have been sniffing the https://gcbasic.sourceforge.io/help/_spi2mode.html -page several times, not understanding the formula (giving up, saving it for later):
    "SPI clock baud rate is calculated as INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000) + 1. Where SPI2_BAUD_RATE defaults to 4000."

    After some back and forth, I finally figured it out (I hope):
    The SPI2_BAUD_RATE is in kHz?
    But still the result isn't "SPI clock baud rate"?
    -It's the SPI2_BAUD_RATE_REGISTER figure.
    -Right?

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-08

    Was it meant to say this?:

    The SPI2_BAUD_RATE_REGISTER value is calculated as: INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000)+ 1. SPI2_BAUD_RATE defaults to 4000.

    SPI2_BAUD_RATE being in kbaud/kHz?

    Nah. Hm.

     

    Last edit: Roger Jönsson 2026-07-09
  • Roger Jönsson

    Roger Jönsson - 2026-07-09

    For an 18FxxQ84 @ 64MHz should it result in:
    64MHz/4000/2*1000+1=8.000001 MHz?

     

    Last edit: Roger Jönsson 2026-07-09
  • Anobium

    Anobium - 2026-07-09

    GCBASIC handles it

    1. Legacy PIC18F SPI (MSSP module) — the simple case

    On older PIC18Fs (e.g. 18F4550, 18F2620, 18F26K22...), SPI lives inside the MSSP module. There is only one clock source for SPI Master mode: the system clock, Fosc. You don't choose a clock source — you only choose a divider of Fosc, set by the SSPM<3:0> bits in SSPxCON1:

    Mode (SSPM bits) SCK Speed
    Fosc/4 Fastest
    Fosc/16 Medium
    Fosc/64 Slow
    Timer2 output/2 Tied to Timer2

    That's it — one register field, three or four fixed divisors, always referenced to Fosc. This maps directly to GCBASIC's legacy SPIMode options:

    • MasterFast → Fosc/4
    • Master → Fosc/16
    • MasterSlow → Fosc/64

    Simple, predictable, and there's no separate "which clock feeds SPI" question to answer.

    2. The 18FxxQ84 (and 18FxxK42 / 18xxFK83) — the modern SPI module

    These parts replace MSSP with a genuinely new SPI peripheral. It splits clocking into two independent registers:

    • SPIxCLK — picks the clock source feeding the SPI baud generator (the CLKSEL bits). Typical sources available on this family include:
    • FOSC (system clock)
    • FOSC/4
    • MFINTOSC (500 kHz internal)
    • HFINTOSC (as configured by OSCFRQ)
    • SOSC (secondary/external 32.768 kHz oscillator)
    • Timer2/4/6 match or postscaled output
    • An external reference clock

    • SPIxBAUD — an 8-bit divider applied to whichever clock SPIxCLK selected.

    The resulting SCK frequency is:

    FBAUD = FCSEL / (2 × (BAUD + 1))
    

    Where FCSEL is the frequency of whatever source SPIxCLK picked, and BAUD is the value in SPIxBAUD.

    This is a much bigger design space than the legacy MSSP: you're no longer locked to Fosc, and you can pick a source completely decoupled from your system clock (handy if you change Fosc but still want a fixed SPI rate, or if you want SPI to keep running from SOSC in a low-power mode).

    3. How GCBASIC handles it — minimum code to get SPI running

    GCBASIC deliberately hides all of the above behind the same-looking API as the legacy chips, so code is portable across families. The minimum needed is just:

    #CHIP 18F27Q84, 64
    
    #DEFINE HWSPIMode      MasterFast
    #DEFINE HWSPIClockMode SPI_SS_0 + SPI_CPOL_0 + SPI_CPHA_0
    
    SPIMode ( HWSPIMode, HWSPIClockMode )
    

    Under the hood, for the Q84/K42/FK83 family, GCBASIC:

    • Sets SPIxCLK to use the system clock (Fosc) as the source — it doesn't attempt to pick HFINTOSC, SOSC, or a timer source automatically.
    • Calculates the value it loads into SPIxBAUD using a simple approximation, keyed off the SPI_BAUD_RATE constant (default 4000, i.e. a ~4 MHz target expressed in kHz):
    Mode GCBASIC's baud calc
    MasterSlow INT( ChipMHz / INT(SPI_BAUD_RATE) / 16 * 1000 ) + 1
    Master INT( ChipMHz / INT(SPI_BAUD_RATE) / 4 * 1000 ) + 1
    MasterFast INT( ChipMHz / INT(SPI_BAUD_RATE) / 2 * 1000 ) + 1
    MasterUltraFast SPIxBAUD = 0 → maximum possible SPI clock

    You can override this in two ways:

    ' Change the target rate the formula above aims for
    #DEFINE SPI_BAUD_RATE 8000
    
    ' OR bypass the formula entirely and write SPIxBAUD directly
    #DEFINE SPI_BAUD_RATE_REGISTER 55
    

    The key difference to highlight: on legacy PIC18Fs there was one clock source and a handful of dividers — trivial to reason about. On the Q84, the hardware gives you a full clock-source mux plus an 8-bit divider — much more capable, but also more to get wrong. GCBASIC's SPIMode/MasterFast-style calls are a minimum-effort abstraction: they always drive SPI from Fosc and compute a "close enough" divider, so your code looks identical to the legacy version — but it is not exercising the Q84's ability to clock SPI from HFINTOSC, MFINTOSC, SOSC, or a timer. If you need one of those other sources, you'd have to write to SPIxCLK yourself (or via SPI_BAUD_RATE_REGISTER plus manual register pokes), since GCBASIC's built-in commands don't expose clock-source selection.

    4. Verifying what GCBASIC actually chose — use the CDF file

    Because the baud value GCBASIC computes is a compile-time approximation, it's good practice to check what actually got written, rather than trust the formula blindly. GCBASIC can emit a CDF (Conditional Debug File) during compilation:

    • Enable it via the compiler option in Prefs Editor checkbox.
    • The CDF lists the resolved constants and register values the compiler settled on for your specific #CHIP and settings — including the actual SPI1BAUD value and SPI1CLK selection used.
    • This is the fastest way to confirm your SPI clock is what you expect, especially since the demo program in the attached file even prints SPI1BAUD to the GLCD screen (GLCDPrint ( 2, 2, SPI1BAUD )) as a runtime sanity check of the same thing.

    In short: legacy PIC18F SPI = one clock source, few dividers, easy math. The 18FxxQ84 = independent clock-source mux + programmable divider, capable of much more, but GCBASIC's built-in SPIMode only drives it the simple way (from Fosc) by default — always confirm the resulting speed via the CDF file or by reading back SPI1BAUD/SPI1CLK if precise timing matters.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-09

    I wanted to know the approximate bitrate acheived with MasterFast with 18F27Q84 @64MHz and saw what I thought was a formula but I could not make out what it was doing.
    A formula where you insert a baud rate constant to get the baud rate?
    SPIxBAUD is part of the calculation to get the output baudrate, but is left out, so it's not a formula to calculate the resulting baudrate? It is just telling me that the fclock and the constant are doing something in there and that it is divided by 16, 4, 2?

    **The question is, what is this for (it doesn't give me the resulting baud rate, does it)?: **

    "SPI clock baud rate is calculated as INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000) + 1. Where SPI2_BAUD_RATE defaults to 4000."

     
  • Anobium

    Anobium - 2026-07-09

    You've read it exactly right — that formula does not give you the resulting SPI bitrate. It gives you the raw value that gets loaded into the SPIxBAUD register. To get the actual SCK frequency you have to take that number and run it back through the hardware equation.

    Step 1 — what the GCBASIC formula actually produces

    SPIxBAUD register value = INT( ChipMHz / INT(SPI_BAUD_RATE) / 2 * 1000 ) + 1
    

    SPI_BAUD_RATE is expressed in kHz (default 4000 = a 4 MHz "target"), and ChipMHz is in MHz, so the *1000 at the end is just there to convert units so both sides match — it's not a separate scaling step, it's unit correction folded into the arithmetic. Once you cancel the units, it collapses to:

    BAUD ≈ INT( Fclk / (target × 2) ) + 1
    

    For your case — 18F27Q84 @ 64 MHz, MasterFast, default SPI_BAUD_RATE = 4000:

    BAUD = INT( 64 / 4000 / 2 * 1000 ) + 1
         = INT( 8 ) + 1
         = 9
    

    So GCBASIC loads SPIxBAUD = 9. That's it — that's all the formula gives you. No frequency comes out of it directly.

    Step 2 — turn that register value into an actual bitrate

    For this, you need the real hardware equation from the SPI module (the one that involves SPIxCLK, the clock source select register, which GCBASIC leaves set to Fosc):

    FBAUD = FCSEL / (2 × (BAUD + 1))
    

    Plugging in FCSEL = 64 MHz and BAUD = 9:

    FBAUD = 64,000,000 / (2 × (9 + 1))
          = 64,000,000 / 20
          = 3.2 MHz
    

    So MasterFast on the Q84 at 64 MHz with default settings gives you ≈ 3.2 MHz SCK — not exactly the 4 MHz "target" implied by the default SPI_BAUD_RATE, because GCBASIC's +1 rounds conservatively (it always rounds toward a slower actual clock, never faster than requested).

    Why it's confusing

    The compiler doc's wording — "SPI clock baud rate is calculated as..." — is misleading. It's really describing "how the SPIxBAUD register value is calculated," not "how to calculate the resulting baud rate." The 2 in that formula isn't the divisor that ends up in your SCK output either — it's just an internal fudge factor GCBASIC uses to roughly mimic the old Fosc/2-style naming convention (MasterFast/Master/MasterSlow/2, /4, /16) inherited from legacy MSSP chips. On the Q84 that divisor doesn't map 1:1 to anything in silicon — the real divisor is 2 × (BAUD+1), computed separately.

    Quick reference table (64 MHz, Fosc as SPI clock source)

    Mode Formula divisor BAUD reg (default target) Actual SCK
    MasterSlow /16 INT(64/4000/16*1000)+1 = 2 64M / (2×3) ≈ 10.7 MHz
    Master /4 INT(64/4000/4*1000)+1 = 5 64M / (2×6) ≈ 5.3 MHz
    MasterFast /2 INT(64/4000/2*1000)+1 = 9 64M / (2×10) = 3.2 MHz
    MasterUltraFast n/a 0 (fixed) 64M / (2×1) = 32 MHz

    If you want to confirm this without doing the math by hand, generate the CDF file (conditionaldebugfile = y) — it will show you the literal SPI1BAUD value the compiler chose for your exact SPI_BAUD_RATE and clock setting, which you can then run through FBAUD = FCSEL/(2×(BAUD+1)) yourself to get the real number. Note that when the demo program prints SPI1BAUD to the GLCD, it's showing you the register value (e.g. 9), not the frequency in Hz — same distinction as above.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-09

    MasterSlow is 3 times faster than MasterFast?
    Does that make sense?

     
    • Anobium

      Anobium - 2026-07-09

      Roughly, yes. But, the calc is specific to frequency etc etc

       
  • Roger Jönsson

    Roger Jönsson - 2026-07-09

    MasterSlow being faster than MasterFast. -That is where I got stuck.
    Doesn't make sense, without an explaination.

     
  • Anobium

    Anobium - 2026-07-09

    My err in explaining. The lower the register value ( the calculation) the faster.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-11

    I got curious to see what changing HWSPIMode really did to my rolling cow picture experiment from December 2025. If adding #define HWSPIMode MASTERFAST really was the fastest way with SSD1331 (1" color GLCD). Apparently I was right back then.
    MasterSlow is considerely slower than Masterfast in updating the screen!
    (Masterultrafast gives a black screen).

    So. Does these modes mean something different with the GLCD routines, than when sending bytes more directly with FastHWSPITransfer etc? (Where you say that MasterSlow should be faster than Masterfast on 1827Q84)

     
  • Anobium

    Anobium - 2026-07-11

    Your findings are correct. Not surprised. Do not confuse what i am saying 'the lower the calculated register value the faster the clock'.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-11

    You earlier agreed to that MasterSlow is roughly 3 times faster than MasterFast and your table above Masterfast (SCK 3.2MHz) is slower than Master slow (10.7MHz).
    Still in my GLCD test Masterfast is faster than Masterslow.

     
    • Anobium

      Anobium - 2026-07-11

      I also said "my err".

      and, your findings are correct.

       
  • Roger Jönsson

    Roger Jönsson - 2026-07-11

    But you did not specify what your error was! Not easy knowing what is what. :-)

    So Masterslow is actually slower than Masterfast after all?
    AND the SCK table above was also wrong: (Masterfast SCK 3.2MHz slower than Master slow 10.7MHz)?

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-11

    I measured the SCL/SCK output (18F27Q84 @64MHz):

    Masterslow 1060ns / 0.94MHz
    Master 310ns / 3.2MHz
    Masterfast 125ns / 8MHz

    If I ask gemini or chat gpt, I sometimes get the 3.2MHz figure for Masterfast. -If I feed it the formula in the help and say its GC-basic. I can't AI:s to explain why I am seeing 8MHz.

    I'm kind of back on square one, not understanding what it going on under the GC-basic hood, but now that I have tested, I can settle with that. For now.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-11

    The CHF File says:
    FINAL/CONSTANT :SPI2BAUDRATE_SCRIPT 3 //I guess this is MASTERFAST
    FINAL/CONSTANT :SPI2BAUDRATE_SCRIPT_MASTER 9
    FINAL/CONSTANT :SPI2BAUDRATE_SCRIPT_MASTERSLOW 33

    If I multiply the constants (however they were created) by two and then add two (found by trial and error) instead of one the results are pretty much bang on:

    The first one, I guess, is MASTERFAST: 64/(6+2) =8MHz
    MASTER: 64/(18+2)= 3.2MHz
    MASTERSLOW: 64/(66+2)=0.94MHz
    (with 18F27Q84, 64MHz)

    The formula in the help can't be right (?) - as it's results in relation to the growing constants moves in the opposite direction. -Where MASTERSLOW is seemingly faster than MASTERFAST.

    ???

     

    Last edit: Roger Jönsson 2026-07-13
    • Anobium

      Anobium - 2026-07-12

      Attached the CDF file. I will review.

       
  • Anobium

    Anobium - 2026-07-13

    I will explain SPI2BAUDRATE_SCRIPT as the general rule that you can apply to the others.
    Line 11619: FINAL/CONSTANT :SPI2BAUDRATE_SCRIPT 3 FINAL/CONSTANT

    This is the end state of the specific constant after all scripts etc.

    So, look for where this is set, search for SPI2BAUDRATE_SCRIPT.

    Found at line 863: SCRIPT/AddConstant: Line 178 SPI2BAUDRATE_SCRIPT 3 C:\GCstudio\gcbasic\INCLUDE\LOWLEVEL\hwspi.h

    This shows that HWSPI.H set the constant is a script at line 178,

    Open HWSPI.H. Review line 178, code to set the constant is.

        'Calculate SPI Baud Rate for SPI2mode modules on K42 per datasheet
        SPI2BAUDRATE_SCRIPT = INT( ChipMHz / INT( SPI2_BAUD_RATE  ) / 2 * 1000) + 1
    

    So, this shows the calculation to be SPI2BAUDRATE_SCRIPT = INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000) + 1.

    The script lines before set check the SPI2_BAUD_RATE is either user set, or, system set.

    'create a constant, as this IS needed, if the user have not defined USERHASDEFINETHESPI2_BAUD_RATE = 0 IF SPI2_BAUD_RATE THEN USERHASDEFINETHESPI2_BAUD_RATE = 1 END IF IF USERHASDEFINETHESPI2_BAUD_RATE = 0 THEN SPI2_BAUD_RATE = INT(ChipMhz/4)*1000 END IF

    therefore SPI2BAUDRATE_SCRIPT = INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000) + 1 therefore 3.

    So, the calculation is INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000) + 1 as the default. You can override the default SPI2_BAUD_RATE by #DEFINE SPI2_BAUD_RATE 16000 but clock control is very crude.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-13

    Sorry. Still not understanding how the formula works.
    If I do 4000/2000+1="therefor" 3 -So?

    The formula: SPI2BAUDRATE_SCRIPT = INT( ChipMHz / INT( SPI2_BAUD_RATE ) / 2 * 1000) + 1.

    Could you please put the numbers in, including ChipMHz, so I can follow, what numbers are used, then what comes out (= the value of SPI2BAUDRATE_SCRIPT).

    And how do I arrive at 9 for MASTER or 33 for MASTERSLOW? (as stated in the CDF file)

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-13

    Not that I must know (I can use the values in the CHF-file), but it is annoying not understanding how the formula does what it is supposedly doing.

     
  • Roger Jönsson

    Roger Jönsson - 2026-07-13

    The only way I can make it work for all speeds is if I assume that SPI2_BAUD_RATE scales like:
    Masterslow:
    64/1000/2x1000+1=33
    Master:
    64/4000/2x1000+1=9
    Masterfast:
    64/16000/2x1000+1=3

     

    Last edit: Roger Jönsson 7 days ago
  • Roger Jönsson

    Roger Jönsson - 7 days ago

    Then do: SPI frequency= 64/(2x(constant+1):

    MASTERSLOW: 64/(2x(33+1))=0.94MHz
    MASTER: 64/( 2x(9 +1))= 3.2MHz
    MASTERFAST: 64/(2x(3+1)) =8MHz

    This matches my measurements!

     
  • Roger Jönsson

    Roger Jönsson - 7 days ago

    According to my findings on 18F27Q84 it is about GC-basic for some unknown reason using an odd formula to create the SPI2BAUDRATE_SCRIPT constant.

    If it instead had used the formula: SPI frequency= 64/(2x(constant+1)) to get the SPI2BAUDRATE_SCRIPT constant it could have been (with ChipMHz of 64):
    3 for MASTERFAST => SCK of 8MHz
    7 for MASTER => SCK of 4MHz -(tested #DEFINE SPI_BAUD_RATE_REGISTER 7)
    31 for MASTERSLOW => SCK of 1MHz -(tested #DEFINE SPI_BAUD_RATE_REGISTER 31)

    So if I understand this correctly, from my findings, the way to describe (atleast for 18F27Q84) would be that:

    MASTERSLOW: SPI clock baud rate=ChipMHz / (2x(SPI2BAUDRATE_SCRIPT+1)). Where SPI2BAUDRATE_SCRIPT = 33

    MASTER: SPI clock baud rate=ChipMHz / (2x(SPI2BAUDRATE_SCRIPT+1)). Where SPI2BAUDRATE_SCRIPT = 9

    MASTERFAST: SPI clock baud rate=ChipMHz / (2x(SPI2BAUDRATE_SCRIPT+1)). Where SPI2BAUDRATE_SCRIPT= 3

     

    Last edit: Roger Jönsson 7 days ago
1 2 > >> (Page 1 of 2)

Log in to post a comment.

MongoDB Logo MongoDB