Hi:
I am working on a custom board equipped with K66 MCU, 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. However, based on the scope observation, the delay between the chip enable (PCS) to clock (CLK) is too long (approximately 39us). Please refer to the following scope screenshot,
Yellow signal: PCS0 on DSPI1,
Green signal: SIN,
Blue signal: CLK, and
Pink signal: SOUT.
Based on the datasheet, the delay between the PCS to the first raising clock can be adjusted by bit15-12 PCS to SCK Delay Scaler in the SPIx_CTARn register. The delay is calculated by tcsc=(1/fp)*PCSSCK*CSSCK. I have K66 running at 120MHz clock and the system speed is 60MHz. That means the minimum delay should be (1/60M)*1*2=32ns.
The software development is based on KDS3.0 and KSDK1.2. I don't have any special delay settings (DSPI_DRV_MasterSetDelay()) in the source code, and I have verified the PCSSCK=00 and CSSCK=1 in the CTAR1 from DSPI1, which should be (1/60M)*1*4=64ns. This value, initial set from DSPI_HAL_SetDelay(base, userConfig->whichCtar, 0, 1, kDspiPcsToSck) in the DSPI_DRV_MasterInit(), doesn't match the signal I saw on the scope. I wonder if I misunderstand somewhere. Is any way I can short the time between the PCS and the 1st CLK? Please let me know if you have any idea or recommendation. Thanks!
#include <stdio.h> #include "main.h" #include "ethSwitch.h" #include "W25QxFVFlashDriver.h" //----------------------------------------------------------------------- // Function Prototypes //----------------------------------------------------------------------- void main_task(uint32_t param); void task_example(task_param_t param); void gpio_Init(void); //----------------------------------------------------------------------- // Constants //----------------------------------------------------------------------- #define MAIN_TASK 8U const TASK_TEMPLATE_STRUCT MQX_template_list[] = { { MAIN_TASK, main_task, 0xC00, 20, "main_task", MQX_AUTO_START_TASK}, { 0L, 0L, 0L, 0L, 0L, 0L } }; #define TASK_EXAMPLE_PRIO 6U #define TASK_EXAMPLE_STACK_SIZE 1024U //----------------------------------------------------------------------- // Macros //----------------------------------------------------------------------- OSA_TASK_DEFINE(task_example, TASK_EXAMPLE_STACK_SIZE); //----------------------------------------------------------------------- // Main Function //----------------------------------------------------------------------- void main_task(uint32_t param) { uint32_t int32utmp; osa_status_t result = kStatus_OSA_Error; printf("\n\nRunning the SPIFFS project."); // Configure SPI pins configure_spi_pins(BOARD_ETHSW_SERFLASH_SPI_INSTANCE); //configure SPI1 for Ethernet switch gpio_Init(); /* Initialize Ethernet Switch KSZ8895RQ */ OSA_TimeDelay(100); //wait for Ethernet switch ready Initialize_EthSW(); int32utmp = W25Q128FV_ReadID(); if (int32utmp == 0xEF4018) printf("\nW25Q128FV is detected."); OSA_Init(); // result = OSA_TaskCreate(task_example, // (uint8_t *)"example", // TASK_EXAMPLE_STACK_SIZE, // task_example_stack, // TASK_EXAMPLE_PRIO, // (task_param_t)0, // false, // &task_example_task_handler); // if (result != kStatus_OSA_Success) // { // printf("Failed to create example task\r\n"); // return; // } OSA_Start(); for (;;) // Forever loop { OSA_TimeDelay(100); //500ms delay } } //----------------------------------------------------------------------- // Task Functions //----------------------------------------------------------------------- // //void task_example(task_param_t param) //{ // printf("\r\nHellow World.\r\n"); // // while(1) // { // __asm("NOP"); // } //} void gpio_Init(void) { gpio_output_pin_user_config_t outputPinConfig; outputPinConfig.pinName = kGpioC5; outputPinConfig.config.outputLogic = 1; outputPinConfig.config.slewRate = kPortSlowSlewRate; outputPinConfig.config.isOpenDrainEnabled = false; outputPinConfig.config.driveStrength = kPortLowDriveStrength; GPIO_DRV_OutputPinInit(&outputPinConfig); outputPinConfig.pinName = kGpioC6; outputPinConfig.config.outputLogic = 1; outputPinConfig.config.slewRate = kPortSlowSlewRate; outputPinConfig.config.isOpenDrainEnabled = false; outputPinConfig.config.driveStrength = kPortLowDriveStrength; GPIO_DRV_OutputPinInit(&outputPinConfig); }
uint32_t W25Q128FV_ReadID(void) { uint8_t send_buf[5]; uint8_t recv_buf[5]; uint32_t result; result = dspicomm_w25qxf_init(DSPI_W25QxFV_INSTANCE, TRANSFER_HIGH_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; w25Q128FV_masterUserConfig.isChipSelectContinuous = true; w25Q128FV_masterUserConfig.isSckContinuous = false; w25Q128FV_masterUserConfig.pcsPolarity = kDspiPcs_ActiveLow; w25Q128FV_masterUserConfig.whichCtar = kDspiCtar1; 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; } // /* Configure timing delays 200ns, it is optional, useful for slower peripheral diveces or "fine tune" SPI timings */ // uint32_t delayInNanosec = 200; // uint32_t calculatedDelay; // /* Set pcs to sck delay */ // DSPI_DRV_MasterSetDelay(instance, kDspiPcsToSck, delayInNanosec, &calculatedDelay); // /* Set last sck to pcs delay */ // DSPI_DRV_MasterSetDelay(instance, kDspiLastSckToPcs, delayInNanosec, &calculatedDelay); // /* Set delay after transfer */ // DSPI_DRV_MasterSetDelay(instance, kDspiAfterTransfer, delayInNanosec, &calculatedDelay); /* SPI use interrupt, must be installed in MQX and file fsl_dspi_irq.c must not be included in project */ int32_t IRQNumber = g_dspiIrqId[instance]; _int_install_isr(IRQNumber, (INT_ISR_FPTR)DSPI_DRV_MasterIRQHandler, (void*)instance); 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); } uint32_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; }
Solved! Go to Solution.
Hello Peter Shih:
What is the value of the macro TRANSFER_HIGH_BAUDRATE in your code? And the value of JEDEC_ID?
I tried to recreate your issue using a random SPI bus frequency of 1 MHz, but I only see a delay between PCS and CLK of 60 ns. See the pictures below (value 0x54 instead of your JEDEC_ID):
The only difference is that I did not use MQX, but I think that should not make any difference in this case.
Regards!
Jorge Gonzalez
Hi Jorge:
I just got chance to review this problem. The communication baud rate is 20MHz. I redo the test based on MQX or non-MQX with KSDK, I had similar result as you have for tcsc.
However, Here I have another problem. I will post it on the different discussion. Thank you very much!
Hello Peter Shih:
What is the value of the macro TRANSFER_HIGH_BAUDRATE in your code? And the value of JEDEC_ID?
I tried to recreate your issue using a random SPI bus frequency of 1 MHz, but I only see a delay between PCS and CLK of 60 ns. See the pictures below (value 0x54 instead of your JEDEC_ID):
The only difference is that I did not use MQX, but I think that should not make any difference in this case.
Regards!
Jorge Gonzalez