DSPI multiple Peripheral chip select

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

DSPI multiple Peripheral chip select

1,700 Views
petershih
Contributor III

Hi:

 

I am working on a custom board equipped with K66 MCU(120MHz, and 60MHz bus clock), serial Flash, Ethernet switch, and other peripherals. The purpose of serial Flash is just for data storage. The Ethernet switch is configurable through SPI interface. Both device are on SPI1 bus and I have successfully read both device ID at 500KHz baud. However I have Ethernet problem after I have some data write to serial flash. Investigate problem more detail, I found whenever SPI initialization DSPI_DRV_MasterInit() is called, the un-selected PCS will keep asserted even during data transferring. I am not sure if I utilize KSDK properly. Please let me know if you have any idea. Thank you very much.

Read serial flash ID with PCS0

yellow: PCS0 (PTB10)

green: PCS1 (PTB9)

blue: SCK (PTB11)

pink: SOUT (PTB16)

119401_119401.pngpastedImage_0.png

 

Read Ethernet switch ID with PCS1

yellow: PCS0

green: PCS1

blue: SCK

pink: SOUT

119543_119543.pngpastedImage_1.png

int main(void) {     uint32_t    int32utmp;     uint8_t        int8utmp;      /* Write your code here */     // Init hardware     hardware_init();     dbg_uart_init();      PRINTF("\r\n\nRunning SPI_Test example.");      // Configure SPI pins     configure_spi_pins(BOARD_ETHSW_SERFLASH_SPI_INSTANCE);    //configure SPI1     gpio_Init();      int32utmp = W25Q128FV_ReadID();     if (int32utmp == 0xEF4018)    printf("\r\nW25Q128FV is detected.");      /* Initialize Ethernet switch internal registers */     int8utmp = readRegisters(0);            //read family ID = 0x88     if (int8utmp == 0x88) {         printf("\r\nKSZ8863 Rev%d is detected ", (int8utmp & 0x0E)>1);     }      /* This for loop should be replaced. By default this loop allows a single stepping. */     for (;;) {      }     /* Never leave main */     return 0; }

 

In W25QxFVFlash.c

dspi_master_state_t w25Q128FV_masterState; dspi_device_t w25Q128FV_masterDevice; dspi_master_user_config_t w25Q128FV_masterUserConfig;  uint32_t W25Q128FV_ReadID(void) {     uint8_t            send_buf[5];     uint8_t            recv_buf[5];     uint32_t         result;      //GPIOE_PSOR |= 0x00000001;     result = dspicomm_w25qxf_init(DSPI_W25QxFV_INSTANCE, TRANSFER_LOW_BAUDRATE);     if (result != kStatus_DSPI_Success)    return (-1);      send_buf[0] = JEDEC_ID;     result = dspicomm_read(DSPI_W25QxFV_INSTANCE, send_buf, 1, recv_buf, 3);     dspicomm_close(DSPI_W25QxFV_INSTANCE);      result = (uint32_t)(recv_buf[1] << 16);    // Manuf ID     : Winbond             = 0xEF     result |= recv_buf[2] << 8;                // Memory Type     : SPI Serial Flash     = 0x40     result |= recv_buf[3];                   // Memory Size     : W25Q128FV         = 0x18      return result; }  int8_t dspicomm_w25qxf_init(uint32_t instance, uint32_t speed) {     dspi_status_t     dspiResult;     uint32_t         calculatedBaudRate;     SPI_Type         *dspiBaseAddr = g_dspiBase[instance];      w25Q128FV_masterUserConfig.isChipSelectContinuous = true;     w25Q128FV_masterUserConfig.isSckContinuous        = false;     w25Q128FV_masterUserConfig.pcsPolarity            = kDspiPcs_ActiveLow;     w25Q128FV_masterUserConfig.whichCtar              = kDspiCtar0;     w25Q128FV_masterUserConfig.whichPcs               = kDspiPcs0;      // Initialize master driver.     dspiResult = DSPI_DRV_MasterInit(instance,                                      &w25Q128FV_masterState,                                      &w25Q128FV_masterUserConfig);     if (dspiResult != kStatus_DSPI_Success)     {         PRINTF("\r\nERROR: Can not initialize SPI master driver!");         return -1;     }      // Setup the configuration.     w25Q128FV_masterDevice.dataBusConfig.bitsPerFrame = 8;     w25Q128FV_masterDevice.dataBusConfig.clkPhase     = kDspiClockPhase_FirstEdge;     w25Q128FV_masterDevice.dataBusConfig.clkPolarity  = kDspiClockPolarity_ActiveHigh;     w25Q128FV_masterDevice.dataBusConfig.direction    = kDspiMsbFirst;     w25Q128FV_masterDevice.bitsPerSec = speed;     dspiResult = DSPI_DRV_MasterConfigureBus(instance,                                              &w25Q128FV_masterDevice,                                              &calculatedBaudRate);     if (dspiResult != kStatus_DSPI_Success)     {         printf("\r\nERROR: failure in configuration SPI bus!");         return -1;     }      return (kStatus_DSPI_Success); }  int8_t dspicomm_close(uint32_t instance) {     dspi_status_t dspiResult;      dspiResult = DSPI_DRV_MasterDeinit(instance);     if (dspiResult != kStatus_DSPI_Success)     {         PRINTF("\r\nERROR: failure in configuration SPI bus!");         return -1;     }      return (kStatus_DSPI_Success); }  int32_t dspicomm_read(uint32_t instance, uint8_t *txData, uint32_t txSize, uint8_t *rxData, uint32_t rxSize) {     dspi_status_t     dspiResult;     uint32_t        i, tempPushr;     uint32_t         wordsTransfer = 0;      // Send/Receive the data.     dspiResult = DSPI_DRV_MasterTransfer(instance,                                          NULL,                                          txData,                                          rxData,                                          txSize+rxSize);     if (dspiResult != kStatus_DSPI_Success)     {         PRINTF("\r\nERROR: Read data transfer error!");         return (-1);     }     // Wait until the transfer is complete.     while (DSPI_DRV_MasterGetTransferStatus(instance, &wordsTransfer) == kStatus_DSPI_Busy)     {}      return rxSize; }

 

In ethSwitch.c

dspi_master_state_t ksz8863_masterState; dspi_device_t ksz8863_masterDevice; dspi_master_user_config_t ksz8863_masterUserConfig; dspi_status_t dspiResult;  uint8_t readRegisters (uint8_t addr) {     uint8_t            send_buf[5];     uint8_t            recv_buf[5];     uint32_t         result;      /* Protect SPI transaction in multitask environment */     result= dspicomm_ethsw_init(DSPI_KSZ8863_INSTANCE, TRANSFER_LOW_BAUDRATE);     if (result != kStatus_DSPI_Success)    {         return (0xFF);     }      send_buf[0] = READ_REG;     send_buf[1] = addr;      //Send and receive data.     dspicomm_ethsw_read(DSPI_KSZ8863_INSTANCE, send_buf, 2, recv_buf, 1);      dspicomm_ethsw_close(DSPI_KSZ8863_INSTANCE);      return recv_buf[2]; }  static int8_t dspicomm_ethsw_init(uint32_t instance, uint32_t speed) {     uint32_t calculatedBaudRate;      ksz8863_masterUserConfig.isChipSelectContinuous = true;     ksz8863_masterUserConfig.isSckContinuous = false;     ksz8863_masterUserConfig.pcsPolarity = kDspiPcs_ActiveLow;     ksz8863_masterUserConfig.whichCtar = kDspiCtar1;     ksz8863_masterUserConfig.whichPcs = kDspiPcs1;      // Initialize master driver.     dspiResult = DSPI_DRV_MasterInit(instance,                                      &ksz8863_masterState,                                      &ksz8863_masterUserConfig);     if (dspiResult != kStatus_DSPI_Success)     {         printf("\r\nERROR: Can not initialize master driver \n\r");         return -1;     }      // Configure bus.     ksz8863_masterDevice.dataBusConfig.bitsPerFrame = 8;     ksz8863_masterDevice.dataBusConfig.clkPhase     = kDspiClockPhase_FirstEdge;     ksz8863_masterDevice.dataBusConfig.clkPolarity  = kDspiClockPolarity_ActiveHigh;     ksz8863_masterDevice.dataBusConfig.direction    = kDspiMsbFirst;      // Configure baudrate.     ksz8863_masterDevice.bitsPerSec = TRANSFER_LOW_BAUDRATE;     dspiResult = DSPI_DRV_MasterConfigureBus(instance,                                              &ksz8863_masterDevice,                                              &calculatedBaudRate);     if (dspiResult != kStatus_DSPI_Success)     {         printf("\r\nERROR: failure in configuration bus\n\r");         return -1;     }      return (kStatus_DSPI_Success); }  static int32_t dspicomm_ethsw_read(uint32_t instance, uint8_t *txData, uint32_t txSize, uint8_t *rxData, uint32_t rxSize) {     dspi_status_t     dspiResult;     uint32_t         wordsTransfer = 0;      // Send / receive the data.     dspiResult = DSPI_DRV_MasterTransfer(instance,                                          NULL,                                          txData,                                          rxData,                                          txSize+rxSize);     if (dspiResult != kStatus_DSPI_Success)     {         printf("\r\nERROR: Read data transfer error!");         return (-1);     }     // Wait until the transfer is complete.     while (DSPI_DRV_MasterGetTransferStatus(instance, &wordsTransfer) == kStatus_DSPI_Busy)     {}      return rxSize; }  static int8_t dspicomm_ethsw_close(uint32_t instance) {     dspi_status_t dspiResult;      dspiResult = DSPI_DRV_MasterDeinit(instance);     if (dspiResult != kStatus_DSPI_Success)     {         printf("\r\nERROR: failure in configuration SPI bus!");         return -1;     }      return (kStatus_DSPI_Success); }

 

In pin_mux.c

void configure_spi_pins(uint32_t instance) {   switch(instance) {     case SPI0_IDX:                       /* HW_SPI0 */ //      /* Affects PORTA_PCR17 register */ //      PORT_HAL_SetMuxMode(PORTA,17UL,kPortMuxAlt2); //      /* Affects PORTA_PCR16 register */ //      PORT_HAL_SetMuxMode(PORTA,16UL,kPortMuxAlt2); //      /* Affects PORTA_PCR15 register */ //      PORT_HAL_SetMuxMode(PORTA,15UL,kPortMuxAlt2); //      /* Affects PORTA_PCR14 register */ //      PORT_HAL_SetMuxMode(PORTA,14UL,kPortMuxAlt2);       break;     case SPI1_IDX:                       /* HW_SPI1 */       /* Affects PORTB_PCR10 register */       PORT_HAL_SetMuxMode(PORTB,10u,kPortMuxAlt2);       /* Affects PORTB_PCR9 register */       PORT_HAL_SetMuxMode(PORTB,9u,kPortMuxAlt2);       /* Affects PORTB_PCR17 register */       PORT_HAL_SetMuxMode(PORTB,17u,kPortMuxAlt2);       /* Affects PORTB_PCR11 register */       PORT_HAL_SetMuxMode(PORTB,11u,kPortMuxAlt2);       /* Affects PORTB_PCR16 register */       PORT_HAL_SetMuxMode(PORTB,16u,kPortMuxAlt2);       break;     case SPI2_IDX:                       /* HW_SPI2 */ //      /* Affects PORTD_PCR11 register */ //      PORT_HAL_SetMuxMode(PORTD,11UL,kPortMuxAlt2); //      /* Affects PORTD_PCR15 register */ //      PORT_HAL_SetMuxMode(PORTD,15UL,kPortMuxAlt2); //      /* Affects PORTD_PCR14 register */ //      PORT_HAL_SetMuxMode(PORTD,14UL,kPortMuxAlt2); //      /* Affects PORTD_PCR12 register */ //      PORT_HAL_SetMuxMode(PORTD,12UL,kPortMuxAlt2); //      /* Affects PORTD_PCR13 register */ //      PORT_HAL_SetMuxMode(PORTD,13UL,kPortMuxAlt2);       break;     default:       break;   } }
Labels (1)
Tags (3)
0 Kudos
8 Replies

892 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Peter,

I have not idea unless you use debugger.  As you know that the code use the interrupt mechanism to transfer data. I suggest you use debugger and set a break point in ISR and check the SPIx_TXFRn register which is a copy of the SPIx_PUSHR.

Hope it can help you.

BR

Xiangjun Rong

0 Kudos

892 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Peter,

Regarding your issue that both PCS0 and PCS1 pins are driven low when you transfer SPI data, of course, it is a wrong timing, which may results in the chip damage because of MISO pin conflicting.

Regarding the reason, I suspect that you set both the PCS0 and PCS1 bits in SPIx_PUSHR(I mean the bit16 and bit17 in SPIx_PUSHR register), if you set both PCS0 and PCS1 bits when you write SPIx_PUSHR to launch a SPI transferring process, both PCS0 and PCS1 will be driven to low. Pls set only PCS0 or PCS1 bits rather than both when you write the SPIx_PUSHR register.

Hope it can help you.

BR

Xiangjun Rong

0 Kudos

892 Views
petershih
Contributor III

Hi Xiangjun:

As you can see, the source code I made all based on the KSDK and example at KSDK_1.2.0\examples\twrk65f180m\driver_examples\dspi. I didn't have any special code to manipulate chip selects. Do you mean there could be problem in KSDK regarding chip select manipulation?

You also mentioned the PCS0 and PCS1 bits in SPIx_PUSHR. Could you indicate me more detail or example how I should set this before calling DSPI_DRV_MasterTransfer()? Thanks!

0 Kudos

892 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Peter,

I think the SPI driver in SDK has issue, I pick up  the code to set PCS bits in SPI driver:

In Your code, The PCS bits are modified by two initialization function:dspicomm_w25qxf_init() and dspicomm_ethsw_init() by calling the same function DSPI_DRV_MasterInit(), the PCS bits in SPIx_PUSHR register are ORed, so both of the PCS0/PCS1 bits are set, it is wrong.

I suggest you use the following code as a workaround without modifying the original SPI driver.

  1. int8_t dspicomm_w25qxf_init(uint32_t instance, uint32_t speed) 
  2.     dspi_status_t     dspiResult; 
  3.     uint32_t         calculatedBaudRate; 
  4.     SPI_Type         *dspiBaseAddr = g_dspiBase[instance]; 
  5.  
  6.     w25Q128FV_masterUserConfig.isChipSelectContinuous = true; 
  7.     w25Q128FV_masterUserConfig.isSckContinuous        = false; 
  8.     w25Q128FV_masterUserConfig.pcsPolarity            = kDspiPcs_ActiveLow; 
  9.     w25Q128FV_masterUserConfig.whichCtar              = kDspiCtar0; 
  10.     w25Q128FV_masterUserConfig.whichPcs               = kDspiPcs0; 
  11.  
  12.     // Initialize master driver. 
  13.    SPI0_PUSHR&=~(0x3F0000);   //Rong wrote: clear all the PCS bits before initialization
  14.     dspiResult = DSPI_DRV_MasterInit(instance, 
  15.                                      &w25Q128FV_masterState, 
  16.                                      &w25Q128FV_masterUserConfig); 
  17.     if (dspiResult != kStatus_DSPI_Success) 
  18. ..........................................................
  19. }

Hope it can help you.

BR

Xiangjun Rong

  1. int8_t dspicomm_w25qxf_init(uint32_t instance, uint32_t speed) 
  2.     dspi_status_t     dspiResult; 
  3.     uint32_t         calculatedBaudRate; 
  4.     SPI_Type         *dspiBaseAddr = g_dspiBase[instance]; 
  5.  
  6.     w25Q128FV_masterUserConfig.isChipSelectContinuous = true; 
  7.     w25Q128FV_masterUserConfig.isSckContinuous        = false; 
  8.     w25Q128FV_masterUserConfig.pcsPolarity            = kDspiPcs_ActiveLow; 
  9.     w25Q128FV_masterUserConfig.whichCtar              = kDspiCtar0; 
  10.     w25Q128FV_masterUserConfig.whichPcs               = kDspiPcs0; 
  11.  
  12.     // Initialize master driver. 
  13. SPI0_PUSHR&=~(0x3F0000);   //Rong wrote: clear all the PCS bits before initialization
  14.     dspiResult = DSPI_DRV_MasterInit(instance, 
  15.                                      &w25Q128FV_masterState, 
  16.                                      &w25Q128FV_masterUserConfig); 
  17.     if (dspiResult != kStatus_DSPI_Success) 
  18. ....................................................................................
  19. }

The following is your original code:

//////////////////////////////////////

  1. int8_t dspicomm_w25qxf_init(uint32_t instance, uint32_t speed) 
  2.     dspi_status_t     dspiResult; 
  3.     uint32_t         calculatedBaudRate; 
  4.     SPI_Type         *dspiBaseAddr = g_dspiBase[instance]; 
  5.  
  6.     w25Q128FV_masterUserConfig.isChipSelectContinuous = true; 
  7.     w25Q128FV_masterUserConfig.isSckContinuous        = false; 
  8.     w25Q128FV_masterUserConfig.pcsPolarity            = kDspiPcs_ActiveLow; 
  9.     w25Q128FV_masterUserConfig.whichCtar              = kDspiCtar0; 
  10.     w25Q128FV_masterUserConfig.whichPcs               = kDspiPcs0; 
  11.  
  12.     // Initialize master driver. 
  13.     dspiResult = DSPI_DRV_MasterInit(instance, 
  14.                                      &w25Q128FV_masterState, 
  15.                                      &w25Q128FV_masterUserConfig); 
  16.     if (dspiResult != kStatus_DSPI_Success) 
  17. ////////////////////////////////////////////////////////////////////////////////////

***************************************************************************************************************************

  1. static int8_t dspicomm_ethsw_init(uint32_t instance, uint32_t speed) 
  2.     uint32_t calculatedBaudRate; 
  3.  
  4.     ksz8863_masterUserConfig.isChipSelectContinuous = true; 
  5.     ksz8863_masterUserConfig.isSckContinuous = false; 
  6.     ksz8863_masterUserConfig.pcsPolarity = kDspiPcs_ActiveLow; 
  7.     ksz8863_masterUserConfig.whichCtar = kDspiCtar1; 
  8.     ksz8863_masterUserConfig.whichPcs = kDspiPcs1; 
  9.  
  10.     // Initialize master driver. 
  11.     dspiResult = DSPI_DRV_MasterInit(instance, 
  12.                                      &ksz8863_masterState, 
  13.                                      &ksz8863_masterUserConfig); 

****************************************************************************************************************************

//The following is the driver code:

/////////////////////////////////////////////////////////////////////////////////////////////////////////

dspi_status_t DSPI_DRV_MasterInit(uint32_t instance,

                                  dspi_master_state_t * dspiState,

                                  const dspi_master_user_config_t * userConfig)

{

    uint32_t dspiSourceClock;

    dspi_status_t errorCode = kStatus_DSPI_Success;

    SPI_Type *base = g_dspiBase[instance];

    /* Clear the run-time state struct for this instance.*/

    memset(dspiState, 0, sizeof(* dspiState));

    /* Note, remember to first enable clocks to the DSPI module before making any register accesses

     * Enable clock for DSPI

     */

    CLOCK_SYS_EnableSpiClock(instance);

    /* Get module clock freq*/

    dspiSourceClock = CLOCK_SYS_GetSpiFreq(instance);

    /* Configure the run-time state struct with the DSPI source clock */

    dspiState->dspiSourceClock = dspiSourceClock;

    /* Configure the run-time state struct with the data command parameters*/

    dspiState->whichCtar = userConfig->whichCtar;  /* set the dspiState struct CTAR*/

   dspiState->whichPcs = userConfig->whichPcs;  /* set the dspiState struct whichPcs*/

    dspiState->isChipSelectContinuous = userConfig->isChipSelectContinuous; /* continuous PCS*/

    /* Initialize the DSPI module registers to default value, which disables the module */

    DSPI_HAL_Init(base);

    /* Init the interrupt sync object.*/

    OSA_SemaCreate(&dspiState->irqSync, 0);

    /* Initialize the DSPI module with user config */

    /* Set to master mode.*/

    DSPI_HAL_SetMasterSlaveMode(base, kDspiMaster);

    /* Configure for continuous SCK operation*/

    DSPI_HAL_SetContinuousSckCmd(base, userConfig->isSckContinuous);

    /* Configure for peripheral chip select polarity*/

   DSPI_HAL_SetPcsPolarityMode(base, userConfig->whichPcs, userConfig->pcsPolarity);

    /* Enable fifo operation (regardless of FIFO depth) */

    DSPI_HAL_SetFifoCmd(base, true, true);

..........................................................................................

}

void DSPI_HAL_SetPcsPolarityMode(SPI_Type * base, dspi_which_pcs_config_t pcs,

                                 dspi_pcs_polarity_config_t activeLowOrHigh)

{

    uint32_t temp;

    temp = SPI_RD_MCR_PCSIS(base);

    if (activeLowOrHigh == kDspiPcs_ActiveLow)

    {

        temp |= pcs;   //Rong wrote: because you use

    }

    else  /* kDspiPcsPolarity_ActiveHigh */

    {

        temp &= ~(unsigned)pcs;

    }

    SPI_BWR_MCR_PCSIS(base, temp);

}

0 Kudos

892 Views
petershih
Contributor III

Hi Xiangjun:

Thanks your detail investigation. I have apply the work-around code in my test project. I am not able to access PUSHR before DSPI_DRV_MasterInit(), the system jump to DefaultISR right away.

pastedImage_0.png

And also based on your investigation, the problem probably will be at MCR register instead of PUSHR. I also tried to call SPI_BWR_MCR_PCSIS(dspiBaseAddr, 0); before calling DSPI_DRV_MasterInit(), I got the same result as above. Do you have any idea what it happened? Thanks!

0 Kudos

892 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Peter,

I suspect that you use SPI1 module instead of SPI0,  the SPI0 clock is DISABLED, that is why the K66 enters Hardware Fault and leads to default ISR when you write SPI0 register, I am sorry.

Pls use the code:

  1. int8_t dspicomm_w25qxf_init(uint32_t instance, uint32_t speed) 
  2.     dspi_status_t     dspiResult; 
  3.     uint32_t         calculatedBaudRate; 
  4.     SPI_Type         *dspiBaseAddr = g_dspiBase[instance]; 
  5.  
  6.     w25Q128FV_masterUserConfig.isChipSelectContinuous = true; 
  7.     w25Q128FV_masterUserConfig.isSckContinuous        = false; 
  8.     w25Q128FV_masterUserConfig.pcsPolarity            = kDspiPcs_ActiveLow; 
  9.     w25Q128FV_masterUserConfig.whichCtar              = kDspiCtar0; 
  10.     w25Q128FV_masterUserConfig.whichPcs               = kDspiPcs0; 
  11.  
  12.     // Initialize master driver. 
  13.    SPI1_PUSHR&=~(0x3F0000);   //Rong wrote: clear all the PCS bits of SPI1 module before initialization
  14.     dspiResult = DSPI_DRV_MasterInit(instance, 
  15.                                      &w25Q128FV_masterState, 
  16.                                      &w25Q128FV_masterUserConfig); 
  17.     if (dspiResult != kStatus_DSPI_Success) 
  18. ..........................................................
  19. }
  20. Hope it can help you.
  21. BR
  22. Xiangjun Rong
0 Kudos

892 Views
petershih
Contributor III

Hi Xiangjun:

I just tried calling CLOCK_SYS_EnableSpiClock(1); before SPI1_PUSHR &= ~(0x3F0000); The system doesn't trapped into system fault, but It is still not working. I got the same result as the before. Hope you have better idea. Thanks!

0 Kudos

892 Views
petershih
Contributor III

Hi Xiangjun:

I do have code for SPI1 as you hint, but not able to clear the register and the system jump to system fault. However, you probably have good guess; since the SPI clock is enabled in DSPI_DRV_MasterInit(), I am not able to write to the PUSHR register no matter how you tried. Probably the only way is modify the SDK source code, use GPIO as PCS signal, or turn on clock and clear register before calling DSPI_DRV_MasterInit(). Thanks your support. If you have any better idea, please let me know. Thanks!

0 Kudos