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)
Read Ethernet switch ID with PCS1
yellow: PCS0
green: PCS1
blue: SCK
pink: SOUT
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; } }
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
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
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!
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.
Hope it can help you.
BR
Xiangjun Rong
The following is your original code:
//////////////////////////////////////
***************************************************************************************************************************
****************************************************************************************************************************
//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);
}
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.
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!
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:
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!
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!