DSPI abnormal timing between frames

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

DSPI abnormal timing between frames

Jump to solution
766 Views
petershih
Contributor III

Hi:

 

I am working on a custom board equipped with K66 MCU(120MHz, and 60MHz bus clock), serial Flash, and other peripherals. The purpose of serial Flash is just for data storage. I have successfully read the device JEDEC ID through DSPI bus 1 (20MHz baud). However, based on the scope observation, the delay between 8-bit frames are too long (approximately  3.2us). Please refer to the following scope screenshot,

Yellow signal: PCS0 on DSPI1,

Green signal: CLK,

Blue signal: SOUT, and

Pink signal: SIN.

113649_113649.pngpastedImage_0.png

I would like to have minimum delay between transfer by setting delay with DSPI_HAL_SetDelay() function. Based on the calculation,

PCSSCK=0, CSSCk=0 --> tcsc=(1/60M)*1*2=33.3ns

PASS=0, ASC=0, tasc=(1/60M)*1*2=33.3ns

PDT=0, DT=0, tdt=(1/60M)*1*2=33.3ns

113650_113650.jpgpastedImage_21.jpg

 

I have verified the register has been correct set to zero before calling transfer. Based on the reference manual, the delay between transfer should be tasc+tcsc or maybe even none. However, I have 3.2us between transfer. This is too much away from specification. I wonder if any thing wrong in my code. Please let me know if you have idea or recommendation. Thank you very much.

 

The following are source code for my test:

int main(void) {     uint32_t    int32utmp;      /* 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("\nW25Q128FV is detected.");      /* This for loop should be replaced. By default this loop allows a single stepping. */     for (;;) {     }     /* Never leave main */     return 0; }

 

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_HIGH_BAUDRATE);     GPIOE_PCOR |= 0x00000001;     if (result != kStatus_DSPI_Success)    return (-1);      send_buf[0] = JEDEC_ID;     GPIOE_PSOR |= 0x00000001;     result = dspicomm_read(DSPI_W25QxFV_INSTANCE, send_buf, 1, recv_buf, 3);     GPIOE_PCOR |= 0x00000001;     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;          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; //    }      // The original DSPI_DRV_MasterConfigureBus() routine takes about 30us to complete.     // The following initialization takes only about 2.5us     dspi_master_state_t * dspiState = (dspi_master_state_t *)g_dspiStatePtr[instance];     SPI_Type *base = g_dspiBase[instance];      SPI_BWR_CTAR_DBR(base, dspiState->whichCtar, 0x01);    //DBR = 1     SPI_BWR_CTAR_PBR(base, dspiState->whichCtar, 0x01);    //PBR = 1     SPI_BWR_CTAR_BR(base, dspiState->whichCtar, 0x00);    //BR = 0, Baud = (fp/PBR)*[(1+DBR)/BR] = (60M/3)*[(1+1)/2] = 20MHz      SPI_BWR_CTAR_FMSZ(base, dspiState->whichCtar, (w25Q128FV_masterDevice.dataBusConfig.bitsPerFrame - 1));     SPI_BWR_CTAR_CPOL(base, dspiState->whichCtar, w25Q128FV_masterDevice.dataBusConfig.clkPolarity);     SPI_BWR_CTAR_CPHA(base, dspiState->whichCtar, w25Q128FV_masterDevice.dataBusConfig.clkPhase);     SPI_BWR_CTAR_LSBFE(base, dspiState->whichCtar, w25Q128FV_masterDevice.dataBusConfig.direction);      DSPI_HAL_SetDelay(base, dspiState->whichCtar, 0x00, 0x00, kDspiPcsToSck);        //PCSSCK=0, CSSCK=0, Tcsc=(1/60M)*1*2=32ns     DSPI_HAL_SetDelay(base, dspiState->whichCtar, 0x00, 0x00, kDspiLastSckToPcs);    //PASC=0, ASC=0, Tasc=(1/60M)*1*2=32ns     DSPI_HAL_SetDelay(base, dspiState->whichCtar, 0x00, 0x00, kDspiAfterTransfer);    //PDT=0, DT=0, Tdt=(1/60M)*1*2=32ns      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_write(uint32_t instance, uint8_t *data, uint32_t size) {     dspi_status_t     dspiResult;     uint32_t         wordsTransfer = 0;      // Send the data.     dspiResult = DSPI_DRV_MasterTransfer(instance,                                          NULL,                                          data,                                          NULL,                                          size);     if (dspiResult != kStatus_DSPI_Success)     {         PRINTF("\r\nERROR: Write data transfer error!");         return (-1);     }     // Wait until the transfer is complete.     while (DSPI_DRV_MasterGetTransferStatus(instance, &wordsTransfer) == kStatus_DSPI_Busy)     {}      return size; }  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         wordsTransfer = 0;      // Send 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; }
Labels (1)
Tags (2)
0 Kudos
1 Solution
467 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Peter,

Regarding your question, for the K66, the PTE0 is multiplexed with the other peripherals as following:

Pin assignment:PTE0, ADC1_SE4a,SPI1_PCS1, UART1_TX, SDHC0_D1, TRACE_CLKOUT,I2C1_SDA RTC_CLKOUT.

From your code, it seems that you set the PTE0 pin as GPIO output and toggle it in software. If you use the pin PTE0 as SPI1_PCS1, you should not set the PTE0 as GPIO by setting the MUX bits of PORTE_PCR0 as ALT1, you should set the MUX bits of PORTE_PCR0 as ALT2 so that the SPI1 module can drive the PTE2 automatically.

Of course, you are right that the PDT/DT bits in SPIx_CTARn determine the interval between two SPI transfer. If you do not call the SDK function and write the SPIx_PUSHR register directly, I think the interval between two transfer will be very short which is based on the DT/PTD mechanism. I have checked your code, I think the code is okay, but the SDK is a high level function, the DSPI_DRV_MasterTransfer() function just put the data to an internal buffer, the code efficiency is low, which leads to the interval is long. If you require the speed of SPI, I suggest you write register directly without calling SDK function.

Hope it can help you.

BR

Xiangjun Rong

View solution in original post

0 Kudos
2 Replies
468 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Peter,

Regarding your question, for the K66, the PTE0 is multiplexed with the other peripherals as following:

Pin assignment:PTE0, ADC1_SE4a,SPI1_PCS1, UART1_TX, SDHC0_D1, TRACE_CLKOUT,I2C1_SDA RTC_CLKOUT.

From your code, it seems that you set the PTE0 pin as GPIO output and toggle it in software. If you use the pin PTE0 as SPI1_PCS1, you should not set the PTE0 as GPIO by setting the MUX bits of PORTE_PCR0 as ALT1, you should set the MUX bits of PORTE_PCR0 as ALT2 so that the SPI1 module can drive the PTE2 automatically.

Of course, you are right that the PDT/DT bits in SPIx_CTARn determine the interval between two SPI transfer. If you do not call the SDK function and write the SPIx_PUSHR register directly, I think the interval between two transfer will be very short which is based on the DT/PTD mechanism. I have checked your code, I think the code is okay, but the SDK is a high level function, the DSPI_DRV_MasterTransfer() function just put the data to an internal buffer, the code efficiency is low, which leads to the interval is long. If you require the speed of SPI, I suggest you write register directly without calling SDK function.

Hope it can help you.

BR

Xiangjun Rong

0 Kudos
467 Views
petershih
Contributor III

Hi Xiangjun:

Thanks your feedback!

The PTE0 is used as GPIO for output to scope for debug purpose, not for SPI1. I have no problem with SPI1 signals.

Based on your feedback, I have tried to send data by writing to PUSHR register without calling KSDK, it gives me the best situation 760ns between transfer, which is much better than before. I think it will be OK for my system.

pastedImage_0.png

I also tried to implement based on eDMA in KSDK, it gives me pretty good 67ns between transfer. However, the initialization takes 45us to complete. I will assume it will be good for large quantity of data transfer, not for 4 bytes data transfer.

pastedImage_1.png

Thanks your help.

Peter Shih

0 Kudos