This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

  • TI Thinks Resolved

MSP432P401R: SPI clock very rounded at 16 MHz - why?

Intellectual 780 points

Replies: 16

Views: 1678

Part Number: MSP432P401R

Hi forum members,

I have run into a problem running the eUSCI_B0 module of the MSP432 at 16 MHz, and need your help and advice.

I am using DriverLib to configure a 3-wire SPI interface, which is connected to two devices. Each device has its own chip select, which I enable before communicating and then disable after communicating.

However, when we got new boards, I began having frequent problems reading a chip ID register from one of the devices. After digging deeper and checking the SPI clock with an oscilloscope, I was amazed that we ever were able to communicate over the SPI bus at all, with either the older or newer hardware.

As you can see from the attached oscilloscope image, the SCLK at 16 MHz is extremely rounded, and in fact does not appear to make it all the way down to ground before starting to rise again. A comparison of the same signal on the older board and the new board shows no discernible difference in shape or level of SCLK.

As an experiment, I reduced the SCLK to 12 MHz. The resulting SCLK waveform is also attached. The shape is still extremely rounded, but at least it does get down toward ground. Also, the reading of the chip ID no longer seems to fail at the lower speed. However, the signal quality still looks so bad that I am reluctant to call this fixed.

Has anyone else seen rounded SCLK's, or SCLK's that do not seem to go all the way to ground? I am wondering if I could have something misconfigured in the setup of the eUSCI_B0.

For reference, here is my initialization code. The processor has already been ramped up to 48MHz using the DC-DC converter, and SMCLK is running at 48MHz.

My module configuration is set up to select SPI_B0, with a desired clock of 8MHz initially, SMCLK as the clock source, SPI mode 0, MSB first, and 3-pin operation mode. SPISettings is just a C++ wrapper around that, with a constructor with default values. I have to communicate with one device at a lower speed initially (8 MHz), and later ramp the speed up to 16 MHz once that part has been configured via a call to MAP_SPI_changeMasterClock(), where desiredSPIFrequency is 16*1000000u (16MHz):

    SPISettings SPIsettings;    // Static instance of SPI settings (see constructor below for default values)
    
    // Constructs SPI settings to configure eUSCI_B0
    SPISettings(
        SPIInstance moduleInstance  = SPI_B0,
        uint32_t    spiClock        = 8000000u,
        SPIClkSrc   clockSrc        = SPI_CLK_SMCLK,
        SPIMode     dataMode        = SPI_MODE0,
        SPIBitOrder bitOrder        = SPI_MSB_FIRST,
        SPIPinMode  pinMode         = SPI_3PIN
        )
    {
        moduleInstance_ = moduleInstance;
        spiMasterConfig_.selectClockSource = clockSrc;

        if (SPI_CLK_SMCLK == clockSrc)
        {
            spiMasterConfig_.clockSourceFrequency = MAP_CS_getSMCLK();
        }
        else
        {
            spiMasterConfig_.clockSourceFrequency = MAP_CS_getACLK();
        }

        spiMasterConfig_.desiredSpiClock = spiClock;
        spiMasterConfig_.msbFirst = bitOrder;

        switch (dataMode)
        {
            case SPI_MODE0:
                spiMasterConfig_.clockPhase = EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
                spiMasterConfig_.clockPolarity = EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
                break;
            case SPI_MODE1:
                spiMasterConfig_.clockPhase = EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
                spiMasterConfig_.clockPolarity = EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
                break;
            case SPI_MODE2:
                spiMasterConfig_.clockPhase = EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
                spiMasterConfig_.clockPolarity = EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
                break;
            case SPI_MODE3:
                spiMasterConfig_.clockPhase = EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
                spiMasterConfig_.clockPolarity = EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
                break;
            default:
                // Bad SPI mode - error
                ErrorHandler::FatalError(ErrorHandler::ErrorNumber::INVALID_SPI_MODE_ERROR, __FILE__, __LINE__);
                break;
        }

        spiMasterConfig_.spiMode = pinMode;
    }

    // Sets up eUSCI_B0 in 3-wire SPI mode 0, MSB first, at 8MHz initially
    void InitSpiBus()
    {
        // Set up the SPI pins
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(SPI_SCLK_PORT,
            SPI_SCLK_PIN | SPI_MOSI_PIN | SPI_MISO_PIN, GPIO_PRIMARY_MODULE_FUNCTION);

        // Configure SPI in 3-wire master mode
        MAP_SPI_initMaster(SPIsettings.moduleInstance_, &SPIsettings.spiMasterConfig_);

        // Enable the SPI module
        MAP_SPI_enableModule(SPIsettings.moduleInstance_);
    }

    // To change SPI clock rate
    void ChangeClock(uint32_t desiredSPIFrequency)
    {
        SPIsettings.spiMasterConfig_.desiredSpiClock = desiredSPIFrequency;
        MAP_SPI_changeMasterClock(SPIsettings.moduleInstance_,
                                  SPIsettings.spiMasterConfig_.clockSourceFrequency,
                                  SPIsettings.spiMasterConfig_.desiredSpiClock);
    }

After initializing the SPI bus, I can see that P1SEL1 = 0x00 and P1SEL0 = 0xE0, which indicates that the Primary Module Function has been selected on P1.7 (MISO), P1.6 (MOSI), and P1.5 (SCLK). In eUSCI_B0, I can see that UCB0CTLW0 is set to 0xA980, which selects SMCLK as the clock source, synchronous mode, 3-pin SPI, master mode, 8 bit data, MSB first, inactive state low and data captured on 1st edge of clock and changed on following edge of clock. Also, UCB0BRW is set to 0x0006 initially, which makes sense for 8 MHz operation with 48MHz on SMCLK.

After the clock speed has been increased, UCB0BRW is 0x0003, which makes sense for 16 MHz from a 48 MHz SMCLK.

Do any of you know why SCLK might look so rounded, and especially why it does not appear to switch all the way to ground at 16MHz? Is there a drive strength or other configuration setting that I am missing? Do I also need to set the P1DIR register so that SCLK and MOSI are outputs and MISO is an input, or are those values overridden by the Primary Module Function selection? None of the DriverLib examples I've seen changed the P1DIR register.

Please help - lots of pressure to find a solution quickly. I sincerely appreciate your time and advice!

Scott

  • In reply to Scott Whitney80914:

    Sorry, I don't know any trick for getting 16MHz out of a 24MHz input clock, and we only get power-of-2 dividers on the DCO.

    I also don't know what the origin of the clock limitation is. I suppose if it's e.g. temperature or voltage and you'll always be running your system in a lab with regulated Vcc you can get away with it. Before I noticed the limit, I blissfully ran at 48MHz (20C/3.3V) without evident problems. (But I'm in the Research department.)

    I'm not sure I understand what you mean by "impact the timing relationships". Since BRCLK is divided on entry to the USCI, I imagine all that happens at the resulting BITCLK rate.
  • In reply to Bruce McKenney47378:

    Thanks Bruce,

    Yes, power of 2 divisors (or undivided) on the DCO certainly make sense.  Sorry to misdirect the conversation by asking about something that obviously wouldn't work!

    I've also been running at room temperature, Vcc=3.3V, with a 48MHz SMCLK at 16MHz SPI clock for quite a while, but then a new batch of boards was built, and we ran into problems reading a known chip ID from a part on the bus.  Further investigation showed that the SPI clock was staying high for about 2 SMCLKs and low for 1, so the SPI clock's duty cycle was not 50%.  This also meant that when data is changed on the falling edge of the SPI clock (in SPI mode 0), it didn't always look like the data on MISO or MOSI was fully settled before being latched on the next rising edge of SPI clock.  It appears that we got "lucky" with the earlier batch of boards.

    A quick software change to reduce the SPI clock to 12MHz got us back a 50% duty cycle SPI clock, and there was plenty of setup time for MISO/MOSI to stabilize before the next rising clock edge.  And that was still done with SMCLK at 48MHz.

    To be safe, I will need to make a change to the SMCLK to 16MHz and try running the SPI at 16MHz.  That should produce a 50% duty cycle SPI clock too.  The fallback would be to use an SMCLK of 24MHz and SPI clock of 12MHz, which would also provide a 50% duty cycle, while allowing devices on the SPI bus more time to settle MISO/MOSI before the next rising clock edge.  Not as desirable as 16MHz due to lots of data being sent to a SPI graphics controller (FT800).

    In short, due to various (bad) examples and not digesting all the fine print in the Technical Reference Manual, I did not know that I was running the SMCLK out of spec, and will need to make a change.

    Thanks again for your input and advice.  Best regards!

    Scott

  • In reply to Chris Sterzik:

    Hi Chris,

    Can you clarify what you mean in your last paragraph: "Just as a side note, if you are going to be sending a stream of SPI data you will end up with 'gaps' in the datastream unless you make the SMCLK faster than the spiclk. If you make them the same, then you will see the extra cycle it takes to move the byte from the transmit buffer into the shift register."

    Gaps would not be good. The data is all 8-bit chunks, and I'm not sure what would need to be done to handle an extra cycle... Do you have an example waveform showing the difference between an SMCLK faster than the SPI clock, and the SMCLK equal to the SPI clock?

    Thanks!

    Scott
  • In reply to Scott Whitney80914:

    Scott,

       I have tried to highlight the move from the transmit buffer to the shift register here:

    The following settings provided the waveform below:

    MCLK = 32Mhz

    SMCLK = 16Mhz

    SPICLK = 16Mhz

    The SPI output clock is suspended for the move so that the output data is not corrupted.  Hope that helps.

    Chris

  • In reply to Chris Sterzik:

    Hi Chris,

    Thank you for the example.  If I understand this correctly, then there isn't any impact on software, just a delay between one SPI packet and the next?

    Also, I notice that you have MCLK = 32 MHz.  If we want to run at 48 MHz, is it possible to create an SMCLK that runs at 16 MHz?  Or am I limited to factors of 2 for divisors (or no division).  I do understand that the SMCLK should not be greater than 24 MHz, and if I want SPI to run at 16 MHz, then I will need to use an SMCLK at 16 MHz to get the correct clock rate.

    A less attractive and slower option is to run MCLK at 48 MHz, SMCLK at 24 MHz, and then the SPI clock at 12 MHz, but this will slow down the data transfer to/from our FT800 graphics controller.  I'd like to run the SPI bus at 16 MHz, but do not want to do so at the expense of running the entire system slower than 48 MHz.

    Can you please clarify whether it is possible to generate a 16 MHz SMCLK while still running the system at 48 MHz?

    Many thanks for your patience and help.  There's a lot of capability to this part, along with a good amount of complexity!

    Scott

  • In reply to Scott Whitney80914:

    You are correct, it is just the delay between packets (bytes).

    The dividers are limited to factors of 2 in the Clock system, www.ti.com/.../slau356h.pdf .

    I do not think it is possible to run a 16Mhz SPI with only a 48Mhz clock source. An alternative would be to provide two separate clock sources. For example use HFXT at 48Mhz and then the DCO at 16Mhz (or vice-versa) and supply MCLK from the 48Mhz source and SMCLK from the 16Mhz source.

    Regards,
    Chris

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.