SPI0_PCS0 never goes idle on FRDM-K22F

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI0_PCS0 never goes idle on FRDM-K22F

587 Views
tntodorov
Contributor I

Hello,

I am testing out SPI communication to a weird SPI eeprom, which requires the first frame (command) be 12 bits/clock cycles and any subsequent data frames be 8 bit long. I like how the DSPI with the different Ctars gives me this flexibility

I have the FRDM-K22F dev board, which I use with MCUXpresso 11.4.1 and SDK_2.10.0 for FRDM-K22F, which I built just the other day. I adapted the SDK example dspi_interrupt_b2b_master, however for my test I am only sending data, so I can see with my logic analyzer, if the different bits per frame requirement for command and data are satisfied (it is!).

The problem I am having is that PCS0 is always low - it never idles. I populated the RF connector on my dev board, and the uSHCD is not populated. I also looked on the schematic, if there are any external pull-down resistors, but there aren't any. Quite the opposite - the accelerometer sensor on board has a 10k external pull-up (R36, schematic pdf, page 5) on this pin. I also created a separate pin configuration function for the SPI0 pins, and it is the only one called, uSDHC and accel pin init functions are not called on board initialization. Here is (most) of my code:

main.c (full):

/**
 * @file    MK22F51212_dpsi_test001.c
 * @brief   Application entry point.
 */
#include <stdio.h>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "MK22F51212.h"
#include "fsl_debug_console.h"
/* TODO: insert other include files here. */
#include "fsl_dspi.h"

/* TODO: insert other definitions and declarations here. */
#define TRANSFER_BAUDRATE           1000000UL

volatile bool     xferComplete;
volatile uint32_t xferTxCountAddr;
volatile uint32_t xferTxCountData;
volatile uint32_t xferCommandAddress;
volatile uint32_t xferCommandData;
uint32_t          xferFifoSize;
uint16_t          spiTxAddr   = 0x0c00;
uint8_t           spiTxData[] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };


void SPI0_IRQHandler(void)
{
    uint32_t tmpmasterTxCount = xferTxCountData;
    uint32_t tmpmasterCommand = xferCommandData;
    uint32_t tmpmasterAddrcmd = xferCommandAddress;

//    if (tmpmasterRxCount < TRANSFER_SIZE) {
//        while (DSPI_GetStatusFlags(SPI0) & kDSPI_RxFifoDrainRequestFlag) {
//            spiTxData[tmpmasterRxCount] = DSPI_ReadData(SPI0);
//            ++masterRxCount;
//            tmpmasterRxCount = masterRxCount;
//
//            DSPI_ClearStatusFlags(SPI0, kDSPI_RxFifoDrainRequestFlag);
//
//            if (tmpmasterRxCount == sizeof(spiTxData)) { break; }
//        }
//    }

    if (xferTxCountAddr < 1) {
        while ((DSPI_GetStatusFlags(SPI0) & kDSPI_TxFifoFillRequestFlag) && (xferTxCountAddr < xferFifoSize)) {
            if (xferTxCountAddr < 1) {
                SPI0->PUSHR = tmpmasterAddrcmd | spiTxAddr;
                xferTxCountAddr++;
            } else { break; }

            /* Try to clear the TFFF; if the TX FIFO is full this will clear */
            DSPI_ClearStatusFlags(SPI0, kDSPI_TxFifoFillRequestFlag);
        }
    }

    if (tmpmasterTxCount < sizeof(spiTxData)) {
        while ((DSPI_GetStatusFlags(SPI0) & kDSPI_TxFifoFillRequestFlag)) { // && (tmpmasterTxCount < xferFifoSize)) { // ((tmpmasterTxCount - tmpmasterRxCount) < xferFifoSize)) {
            if (tmpmasterTxCount < sizeof(spiTxData)) {
                SPI0->PUSHR = tmpmasterCommand | spiTxData[tmpmasterTxCount];
                ++xferTxCountData;
                tmpmasterTxCount = xferTxCountData;
            } else { break; }

            /* Try to clear the TFFF; if the TX FIFO is full this will clear */
            DSPI_ClearStatusFlags(SPI0, kDSPI_TxFifoFillRequestFlag);
        }
    }

    /* Check if we're done with this transfer.*/
    if ((tmpmasterTxCount == sizeof(spiTxData))) { // && (tmpmasterRxCount == TRANSFER_SIZE)) {
        xferComplete = true;
        /* Complete the transfer and disable the interrupts */
        DSPI_DisableInterrupts(SPI0, kDSPI_RxFifoDrainRequestInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable);
    }

    SDK_ISR_EXIT_BARRIER;
}

int main(void) {

    /* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitBootPeripherals();
#ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
    /* Init FSL debug console. */
    BOARD_InitDebugConsole();
#endif

    PRINTF("Hello World\n");

    dspi_master_config_t cmd, data;
    cmd.whichCtar                                = kDSPI_Ctar0;
    cmd.ctarConfig.baudRate                      = TRANSFER_BAUDRATE;
    cmd.ctarConfig.bitsPerFrame                  = 12U;
    cmd.ctarConfig.cpol                          = kDSPI_ClockPolarityActiveHigh;
    cmd.ctarConfig.cpha                          = kDSPI_ClockPhaseFirstEdge;
    cmd.ctarConfig.direction                     = kDSPI_MsbFirst;
    cmd.ctarConfig.pcsToSckDelayInNanoSec        = 1000000000U / TRANSFER_BAUDRATE;
    cmd.ctarConfig.lastSckToPcsDelayInNanoSec    = 1000000000U / TRANSFER_BAUDRATE;
    cmd.ctarConfig.betweenTransferDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;

    cmd.whichPcs           = kDSPI_Pcs0;
    cmd.pcsActiveHighOrLow = kDSPI_PcsActiveLow;

    cmd.enableContinuousSCK        = false;
    cmd.enableRxFifoOverWrite      = false;
    cmd.enableModifiedTimingFormat = false;
    cmd.samplePoint                = kDSPI_SckToSin0Clock;

    DSPI_MasterInit(SPI0, &cmd, CLOCK_GetFreq(DSPI0_CLK_SRC));

    data.whichCtar                                = kDSPI_Ctar1;
    data.ctarConfig.baudRate                      = TRANSFER_BAUDRATE;
    data.ctarConfig.bitsPerFrame                  = 8U;
    data.ctarConfig.cpol                          = kDSPI_ClockPolarityActiveHigh;
    data.ctarConfig.cpha                          = kDSPI_ClockPhaseFirstEdge;
    data.ctarConfig.direction                     = kDSPI_MsbFirst;
    data.ctarConfig.pcsToSckDelayInNanoSec        = 1000000000U / TRANSFER_BAUDRATE;
    data.ctarConfig.lastSckToPcsDelayInNanoSec    = 1000000000U / TRANSFER_BAUDRATE;
    data.ctarConfig.betweenTransferDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;

    data.whichPcs           = kDSPI_Pcs0;
    data.pcsActiveHighOrLow = kDSPI_PcsActiveLow;

    data.enableContinuousSCK        = false;
    data.enableRxFifoOverWrite      = false;
    data.enableModifiedTimingFormat = false;
    data.samplePoint                = kDSPI_SckToSin0Clock;

    DSPI_MasterInit(SPI0, &data, CLOCK_GetFreq(DSPI0_CLK_SRC));

    EnableIRQ(SPI0_IRQn);

    dspi_command_data_config_t spiCommandAddr;
    spiCommandAddr.isPcsContinuous    = true;
    spiCommandAddr.whichCtar          = kDSPI_Ctar0;
    spiCommandAddr.whichPcs           = kDSPI_Pcs0;
    spiCommandAddr.isEndOfQueue       = false;
    spiCommandAddr.clearTransferCount = false;
    xferCommandAddress                = DSPI_MasterGetFormattedCommand(&spiCommandAddr);

    dspi_command_data_config_t spiCommandData;
    spiCommandData.isPcsContinuous    = true;
    spiCommandData.whichCtar          = kDSPI_Ctar1;
    spiCommandData.whichPcs           = kDSPI_Pcs0;
    spiCommandData.isEndOfQueue       = false;
    spiCommandData.clearTransferCount = false;
    xferCommandData                   = DSPI_MasterGetFormattedCommand(&spiCommandData);

    xferFifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(SPI0);


    /* Enter an infinite loop, just incrementing a counter. */
    while (true) {
        xferTxCountAddr = xferTxCountData = 0;
        xferComplete                      = false;

        DSPI_StopTransfer(SPI0);
        DSPI_FlushFifo(SPI0, true, true);
        DSPI_ClearStatusFlags(SPI0, (uint32_t)kDSPI_AllStatusFlag);

        /*Fill up the master Tx data*/
        while (DSPI_GetStatusFlags(SPI0) & kDSPI_TxFifoFillRequestFlag) {
            if (xferTxCountAddr < 1) {
                DSPI_MasterWriteData(SPI0, &spiCommandAddr, spiTxAddr);
                ++xferTxCountAddr;
            } else { break; }

            /* Try to clear the TFFF; if the TX FIFO is full this will clear */
            DSPI_ClearStatusFlags(SPI0, kDSPI_TxFifoFillRequestFlag);
        }

        while (DSPI_GetStatusFlags(SPI0) & kDSPI_TxFifoFillRequestFlag) {
            if (xferTxCountData < sizeof(spiTxData)) {
                DSPI_MasterWriteData(SPI0, &spiCommandData, spiTxData[xferTxCountData]);
                ++xferTxCountData;
            } else { break; }

            /* Try to clear the TFFF; if the TX FIFO is full this will clear */
            DSPI_ClearStatusFlags(SPI0, kDSPI_TxFifoFillRequestFlag);
        }

        /*Enable master RX interrupt*/
        DSPI_EnableInterrupts(SPI0, kDSPI_RxFifoDrainRequestInterruptEnable);
        DSPI_StartTransfer(SPI0);

        /* Wait 1st round transfer complete */
        while (!xferComplete) { }

        printf("Transfer complete\r\n");

        DSPI_StopTransfer(SPI0);
        DSPI_FlushFifo(SPI0, true, true);
        DSPI_ClearStatusFlags(SPI0, (uint32_t)kDSPI_AllStatusFlag);

        __asm volatile ("nop");
    }
    return 0 ;
}

 

The pin init functions:

void BOARD_InitBootPins(void)
{
    BOARD_InitPins();
    BOARD_InitDEBUG_UARTPins();
    BOARD_InitSPI0Pins();
}

void BOARD_InitPins(void)
{
    CLOCK_EnableClock(kCLOCK_PortA);
    PORT_SetPinMux(PORTA, 2U, kPORT_MuxAlt7); // trace_swo
    PORTA->PCR[2] = ((PORTA->PCR[2] &
                      /* Mask bits to zero which are setting */
                      (~(PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_ISF_MASK)))
                     | PORT_PCR_PS(kPORT_PullDown)
                     | PORT_PCR_PE(kPORT_PullDisable));
}

void BOARD_InitSPI0Pins(void)
{
    /* Port C Clock Gate Control: Clock enabled */
    CLOCK_EnableClock(kCLOCK_PortC);
    /* Port D Clock Gate Control: Clock enabled */
    CLOCK_EnableClock(kCLOCK_PortD);

    /* PORTC4 (pin 49) is configured as SPI0_PCS0 */
    PORT_SetPinMux(BOARD_SPI0_CS_PORT, BOARD_SPI0_CS_PIN, kPORT_MuxAlt2);

//    PORTC->PCR[4] = ((PORTC->PCR[4] &
//                      /* Mask bits to zero which are setting */
//                      (~(PORT_PCR_PS_MASK | PORT_PCR_DSE_MASK | PORT_PCR_ISF_MASK)))
//
//                     /* Drive Strength Enable: High drive strength is configured on the corresponding pin, if pin
//                      * is configured as a digital output. */
//                     | PORT_PCR_DSE(kPORT_HighDriveStrength)
//
//                     /* Pull Select: Internal pullup resistor is enabled on the corresponding pin, if the
//                      * corresponding PE field is set. */
//                     | PORT_PCR_PS(kPORT_PullUp));

    /* PORTD1 (pin 58) is configured as SPI0_SCK */
    PORT_SetPinMux(BOARD_SPI0_SCK_PORT, BOARD_SPI0_SCK_PIN, kPORT_MuxAlt2);

    /* PORTD2 (pin 59) is configured as SPI0_SOUT */
    PORT_SetPinMux(BOARD_SPI0_MOSI_PORT, BOARD_SPI0_MOSI_PIN, kPORT_MuxAlt2);
}

 

It does not matter, if I enable or disable the internal pull-up on PCS0 - the result remains unchanged. My expectation was that when I call DSI_MasterInit(...) in main.c, the CS pin would be configured as requested. And if not at that point, then a call to DSI_StopTransfer(...) would bring the CS line to idle state.

My expectations were unfortunately not fulfilled.

Am I missing something? Do I have an error in my code? The communication looks perfect on my scope otherwise... I attached 2 screenshot with my capture and my pin configuration in the IDE for more info.

Thanks in advance for any help - it is greatly appreciated!

0 Kudos
1 Reply

559 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi @tntodorov ,

What's the PCS voltage when run over DSPI_MasterInit()? It should be 3.3v.

 

Regards,

Jing

0 Kudos