Hi,
we want to use FlexSPI-QSPIB1 to talk to an FPGA and to use DMA. So I configured the FlexSPI and can use CMD_SDR to send a test command.
Then I changed to the LUT command to WRITE_SDR with one MOSI line and found, that there is an issue with the FlexSPI. The Processors reference Manual IMX8MMRM rev 2 tells, that I can fill the txFIFO before and after starting the LUT command.
I found, that the FlexSPI clocks one time and runs into timeout, when
1) I fill the txFIFO after starting FlexSPI_IPCMD_TRG(1)
2) Starting FlexSPI_IPCMD_TRG(1) and don't fill the txFIFO
with exactly the same behavior on the QSPI interface.
Then I changed to start FlexSPI_IPCMD_TRG(1) and then fill the txFIFO to send two Bytes. But now I get a trailing clock cycle without valid data, then a pause and then 15 additional clocks with proper data (I filled the txFIFO with 0x12345678) but missing last clock.
It seems, that FlexSPI generates a wrong trailing clock and therefore suppress the last data clock.
Since the content of the reference manual seems to be wrong in some things, could you help me please to remove the trailing clock, please.
Thanks and regards
Christoph
Here please find my test code:
#include "halQSpi.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
#include "MIMX8MM6_cm4.h"
#include "fsl_debug_console.h"
u32_t halQSpiModuleFreq( void )
{
u32_t u32_pllFreq = CLOCK_GetPllFreq( kCLOCK_SystemPll1Ctrl );
u32_t u32_rootPreDivider = CLOCK_GetRootPreDivider ( kCLOCK_RootQspi );
u32_t u32_rootPostDivider = CLOCK_GetRootPostDivider( kCLOCK_RootQspi );
return u32_pllFreq / 2 / u32_rootPreDivider / u32_rootPostDivider;
}
static inline u32_t halQspiSetReg( u32_t u32_reg, u32_t u32_mask, u32_t u32_val )
{
u32_reg &= ~u32_mask;
u32_reg |= u32_val;
return u32_reg;
}
static inline u32_t halQspiFlashStartAddrB1( void )
{
u32_t u32_startAddr = 0;
u32_startAddr += (u32_t)FLEXSPI->FLSHCR0[0] & FlexSPI_FLSHCR0_FLSHSZ_MASK;
u32_startAddr += (u32_t)FLEXSPI->FLSHCR0[1] & FlexSPI_FLSHCR0_FLSHSZ_MASK;
return u32_startAddr * 1024;
}
void halQSpiPrintLut( void )
{
// Unlock LUT
FLEXSPI->LUTKEY = FlexSPI_LUTKEY_KEY( 0x5AF05AF0 );
FLEXSPI->LUTCR = FlexSPI_LUTCR_UNLOCK( 1 );
// Print LUT
PRINTF( " LUT[0] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[0] );
PRINTF( " LUT[1] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[1] );
PRINTF( " LUT[2] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[2] );
PRINTF( " LUT[3] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[3] );
PRINTF( " LUT[4] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[4] );
PRINTF( " LUT[5] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[5] );
PRINTF( " LUT[6] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[6] );
PRINTF( " LUT[7] 0x%08x\r\n", (u32_t)FLEXSPI->LUT[7] );
// Lock lut
FLEXSPI->LUTKEY = FlexSPI_LUTKEY_KEY( 0x5AF05AF0 );
FLEXSPI->LUTCR = FlexSPI_LUTCR_LOCK( 1 );
}
void halQSpiPrintReg( void )
{
PRINTF( "Debug FlexSPI register:\r\n" );
PRINTF( " MCR0 0x%08x\r\n", (u32_t)FLEXSPI->MCR0 );
PRINTF( " MCR1 0x%08x\r\n", (u32_t)FLEXSPI->MCR1 );
PRINTF( " MCR2 0x%08x\r\n", (u32_t)FLEXSPI->MCR2 );
PRINTF( " AHBCR 0x%08x\r\n", (u32_t)FLEXSPI->AHBCR );
PRINTF( " INTEN 0x%08x\r\n", (u32_t)FLEXSPI->INTEN );
// PRINTF( " INTR 0x%08x\r\n", (u32_t)FLEXSPI->INTR );
// PRINTF( " LUTKEY 0x%08x\r\n", (u32_t)FLEXSPI->LUTKEY );
PRINTF( " LUTCR 0x%08x\r\n", (u32_t)FLEXSPI->LUTCR );
// PRINTF( " AHBRXBUFCR0 0x%08x\r\n", (u32_t)FLEXSPI->AHBRXBUFCR0 );
//
PRINTF( " FLSHCR0[0] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR0[0] );
PRINTF( " FLSHCR0[1] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR0[1] );
PRINTF( " FLSHCR0[2] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR0[2] );
PRINTF( " FLSHCR0[3] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR0[3] );
PRINTF( " FLSHCR1[0] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR1[0] );
PRINTF( " FLSHCR1[1] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR1[1] );
PRINTF( " FLSHCR1[2] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR1[2] );
PRINTF( " FLSHCR1[3] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR1[3] );
// PRINTF( " FLSHCR2[0] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR2[0] );
// PRINTF( " FLSHCR2[1] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR2[1] );
// PRINTF( " FLSHCR2[2] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR2[2] );
// PRINTF( " FLSHCR2[3] 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR2[3] );
//
// PRINTF( " FLSHCR4 0x%08x\r\n", (u32_t)FLEXSPI->FLSHCR4 );
PRINTF( " IPCR0 0x%08x\r\n", (u32_t)FLEXSPI->IPCR0 );
PRINTF( " IPCR1 0x%08x\r\n", (u32_t)FLEXSPI->IPCR1 );
// PRINTF( " IPCMD 0x%08x\r\n", (u32_t)FLEXSPI->IPCMD );
// PRINTF( " DLPR 0x%08x\r\n", (u32_t)FLEXSPI->DLPR );
// PRINTF( " IPRXFCR 0x%08x\r\n", (u32_t)FLEXSPI->IPRXFCR );
PRINTF( " IPTXFCR 0x%08x\r\n", (u32_t)FLEXSPI->IPTXFCR );
// PRINTF( " DLLCR[0] 0x%08x\r\n", (u32_t)FLEXSPI->DLLCR[0] );
// PRINTF( " DLLCR[1] 0x%08x\r\n", (u32_t)FLEXSPI->DLLCR[1] );
// PRINTF( " STS0 0x%08x\r\n", (u32_t)FLEXSPI->STS0 );
// PRINTF( " STS1 0x%08x\r\n", (u32_t)FLEXSPI->STS1 );
// PRINTF( " STS2 0x%08x\r\n", (u32_t)FLEXSPI->STS2 );
// PRINTF( " AHBSPNDSTS 0x%08x\r\n", (u32_t)FLEXSPI->AHBSPNDSTS );
// PRINTF( " IPRXFSTS 0x%08x\r\n", (u32_t)FLEXSPI->IPRXFSTS );
// PRINTF( " IPTXFSTS 0x%08x\r\n", (u32_t)FLEXSPI->IPTXFSTS );
// halQSpiPrintLut();
}
void halQSpiPrintStatus( void )
{
u32_t u32_regVal;
PRINTF( "FlexSPI status register:\r\n" );
PRINTF( " STS0 0x%08x\r\n", (u32_t)FLEXSPI->STS0 );
PRINTF( " STS1 0x%08x\r\n", (u32_t)FLEXSPI->STS1 );
// PRINTF( " STS2 0x%08x\r\n", (u32_t)FLEXSPI->STS2 );
// *******************************************************************
// IPCMDERRCODE - Indicates the Error Code when IP command Error detected. This field will be
// cleared when INTR[IPCMDERR] is write-1-clear(w1c).
// *******************************************************************
PRINTF( " STS1 - IPCMDERRCODE: " );
u32_regVal = ( FLEXSPI->STS1 & FlexSPI_STS1_IPCMDERRCODE_MASK ) >> FlexSPI_STS1_IPCMDERRCODE_SHIFT;
switch ( u32_regVal )
{
case 0b0000: PRINTF( "No error.\r\n" ); break;
case 0b0010: PRINTF( "IP command with JMP_ON_CS instruction used in the sequence.\r\n" ); break;
case 0b0011: PRINTF( "There is unknown instruction opcode in the sequence.\r\n" ); break;
case 0b0100: PRINTF( "Instruction DUMMY_SDR/DUMMY_RWDS_SDR used in DDR sequence.\r\n" ); break;
case 0b0101: PRINTF( "Instruction DUMMY_DDR/DUMMY_RWDS_DDR used in SDR sequence.\r\n" ); break;
case 0b0110: PRINTF( "Flash access start address exceed the whole flash address range (A1/A2/B1/B2).\r\n" ); break;
case 0b1110: PRINTF( "Sequence execution timeout.\r\n" ); break;
case 0b1111: PRINTF( "Flash boundary crossed.\r\n" ); break;
}
// *******************************************************************
// Indicates the sequence Index when IPmmand Error detected. This field will be
// INTR[IPCMDERR] is write-1-clear(w1c).
// *******************************************************************
u32_regVal = ( FLEXSPI->STS1 & FlexSPI_STS1_IPCMDERRID_MASK ) >> FlexSPI_STS1_IPCMDERRID_SHIFT;
PRINTF( " STS1 - IPCMDERRID: %d\r\n", u32_regVal );
}
void halQSpiPrintFlashSizes( void )
{
PRINTF( "Debug FlexSPI flash sizes:\r\n" );
PRINTF( " flashSize A1 0x%08x kByte\r\n", (u32_t)FLEXSPI->FLSHCR0[0] & FlexSPI_FLSHCR0_FLSHSZ_MASK );
PRINTF( " flashSize A2 0x%08x kByte\r\n", (u32_t)FLEXSPI->FLSHCR0[1] & FlexSPI_FLSHCR0_FLSHSZ_MASK );
PRINTF( " flashSize B1 0x%08x kByte\r\n", (u32_t)FLEXSPI->FLSHCR0[2] & FlexSPI_FLSHCR0_FLSHSZ_MASK );
PRINTF( " flashSize B2 0x%08x kByte\r\n", (u32_t)FLEXSPI->FLSHCR0[3] & FlexSPI_FLSHCR0_FLSHSZ_MASK );
PRINTF( " flashStartAddr B1 0x%08x\r\n", halQspiFlashStartAddrB1() );
}
bool halQSpiInit( void )
{
// *******************************************************************
// Select and enable clock
// *******************************************************************
// CLOCK_SetRootMux( kCLOCK_RootIpg, kCLOCK_QspiRootmuxSysPll1Div8 );
CLOCK_SetRootMux( kCLOCK_RootQspi, kCLOCK_QspiRootmuxSysPll1Div8 );
CLOCK_SetRootDivider( kCLOCK_RootQspi, 1U, 2U );
// CLOCK_EnableClock( kCLOCK_AhbClk );
// CLOCK_EnableClock( kCLOCK_IpgClk );
CLOCK_EnableClock( kCLOCK_Qspi );
// *******************************************************************
// Init QSPI_A pins
// *******************************************************************
IOMUXC_SetPinMux( IOMUXC_NAND_ALE_QSPI_A_SCLK, 0U );
IOMUXC_SetPinMux( IOMUXC_NAND_CE0_B_QSPI_A_SS0_B, 0U );
IOMUXC_SetPinMux( IOMUXC_NAND_DATA00_QSPI_A_DATA0, 0U );
IOMUXC_SetPinMux( IOMUXC_NAND_DATA01_QSPI_A_DATA1, 0U );
IOMUXC_SetPinMux( IOMUXC_NAND_DATA02_QSPI_A_DATA2, 0U );
IOMUXC_SetPinMux( IOMUXC_NAND_DATA03_QSPI_A_DATA3, 0U );
// *******************************************************************
// Init QSPI
// *******************************************************************
{
// MCR0
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_MDIS_MASK, FlexSPI_MCR0_MDIS( 1 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_LEARNEN_MASK, FlexSPI_MCR0_LEARNEN( 0 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_SCKFREERUNEN_MASK, FlexSPI_MCR0_SCKFREERUNEN( 0 ) );
// FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_SCKFREERUNEN_MASK, FlexSPI_MCR0_SCKFREERUNEN( 1 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_COMBINATIONEN_MASK, FlexSPI_MCR0_COMBINATIONEN( 0 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_DOZEEN_MASK, FlexSPI_MCR0_DOZEEN( 0 ) );
// FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_HSEN_MASK, FlexSPI_MCR0_HSEN( 0 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_HSEN_MASK, FlexSPI_MCR0_HSEN( 1 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_SERCLKDIV_MASK, FlexSPI_MCR0_SERCLKDIV( 4 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_ATDFEN_MASK, FlexSPI_MCR0_ATDFEN( 0 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_ARDFEN_MASK, FlexSPI_MCR0_ARDFEN( 0 ) );
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_RXCLKSRC_MASK, FlexSPI_MCR0_RXCLKSRC( 0 ) );
// MCR2
FLEXSPI->MCR2 = halQspiSetReg( FLEXSPI->MCR2, FlexSPI_MCR2_RESUMEWAIT_MASK, FlexSPI_MCR2_RESUMEWAIT( 0x20 ) );
FLEXSPI->MCR2 = halQspiSetReg( FLEXSPI->MCR2, FlexSPI_MCR2_SCKBDIFFOPT_MASK, FlexSPI_MCR2_SCKBDIFFOPT( 0 ) );
FLEXSPI->MCR2 = halQspiSetReg( FLEXSPI->MCR2, FlexSPI_MCR2_SAMEDEVICEEN_MASK, FlexSPI_MCR2_SAMEDEVICEEN( 0 ) );
FLEXSPI->MCR2 = halQspiSetReg( FLEXSPI->MCR2, FlexSPI_MCR2_CLRAHBBUFOPT_SHIFT, FlexSPI_MCR2_CLRAHBBUFOPT( 0 ) );
// AHBCR
// FLEXSPI->AHBCR = halQspiSetReg( FLEXSPI->AHBCR, FlexSPI_AHBCR_READADDROPT_MASK, FlexSPI_AHBCR_READADDROPT( 0 ) );
// FLEXSPI->AHBCR = halQspiSetReg( FLEXSPI->AHBCR, FlexSPI_AHBCR_PREFETCHEN_MASK, FlexSPI_AHBCR_PREFETCHEN( 0 ) );
// FLEXSPI->AHBCR = halQspiSetReg( FLEXSPI->AHBCR, FlexSPI_AHBCR_BUFFERABLEEN_MASK, FlexSPI_AHBCR_BUFFERABLEEN( 0 ) );
// FLEXSPI->AHBCR = halQspiSetReg( FLEXSPI->AHBCR, FlexSPI_AHBCR_CACHABLEEN_MASK, FlexSPI_AHBCR_CACHABLEEN( 0 ) );
// FLEXSPI->AHBCR = halQspiSetReg( FLEXSPI->AHBCR, FlexSPI_AHBCR_APAREN_MASK, FlexSPI_AHBCR_APAREN( 0 ) );
// Configure FLSHCRB1
// FLSHCR0, Flash size in kByte
// FLEXSPI->FLSHCR0[0] = halQspiSetReg( FLEXSPI->FLSHCR0[0], FlexSPI_FLSHCR0_FLSHSZ_MASK, FlexSPI_FLSHCR0_FLSHSZ( 8 ) );
// FLEXSPI->FLSHCR0[1] = halQspiSetReg( FLEXSPI->FLSHCR0[0], FlexSPI_FLSHCR0_FLSHSZ_MASK, FlexSPI_FLSHCR0_FLSHSZ( 8 ) );
// FLEXSPI->FLSHCR0[2] = halQspiSetReg( FLEXSPI->FLSHCR0[0], FlexSPI_FLSHCR0_FLSHSZ_MASK, FlexSPI_FLSHCR0_FLSHSZ( 8 ) );
// FLEXSPI->FLSHCR0[3] = halQspiSetReg( FLEXSPI->FLSHCR0[0], FlexSPI_FLSHCR0_FLSHSZ_MASK, FlexSPI_FLSHCR0_FLSHSZ( 8 ) );
// FLSHCR1
FLEXSPI->FLSHCR1[2] = halQspiSetReg( FLEXSPI->FLSHCR1[0], FlexSPI_FLSHCR1_CSINTERVAL_MASK, FlexSPI_FLSHCR1_CSINTERVAL( 0 ) );
FLEXSPI->FLSHCR1[2] = halQspiSetReg( FLEXSPI->FLSHCR1[0], FlexSPI_FLSHCR1_CSINTERVALUNIT_MASK, FlexSPI_FLSHCR1_CSINTERVALUNIT( 0 ) );
FLEXSPI->FLSHCR1[2] = halQspiSetReg( FLEXSPI->FLSHCR1[0], FlexSPI_FLSHCR1_CAS_MASK, FlexSPI_FLSHCR1_CAS( 0 ) );
FLEXSPI->FLSHCR1[2] = halQspiSetReg( FLEXSPI->FLSHCR1[0], FlexSPI_FLSHCR1_WA_MASK, FlexSPI_FLSHCR1_WA( 0 ) );
FLEXSPI->FLSHCR1[2] = halQspiSetReg( FLEXSPI->FLSHCR1[0], FlexSPI_FLSHCR1_TCSH_MASK, FlexSPI_FLSHCR1_TCSH( 3 ) );
FLEXSPI->FLSHCR1[2] = halQspiSetReg( FLEXSPI->FLSHCR1[0], FlexSPI_FLSHCR1_TCSS_MASK, FlexSPI_FLSHCR1_TCSS( 3 ) );
// FLSHCR2
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_CLRINSTRPTR_MASK, FlexSPI_FLSHCR2_CLRINSTRPTR( 0 ) );
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_AWRWAITUNIT_MASK, FlexSPI_FLSHCR2_AWRWAITUNIT( 0 ) );
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_AWRWAIT_MASK, FlexSPI_FLSHCR2_AWRWAIT( 0 ) );
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_ARDSEQNUM_MASK, FlexSPI_FLSHCR2_ARDSEQNUM( 0 ) );
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_AWRSEQID_MASK, FlexSPI_FLSHCR2_AWRSEQID( 0 ) );
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_ARDSEQNUM_MASK, FlexSPI_FLSHCR2_ARDSEQNUM( 0 ) );
// FLEXSPI->FLSHCR2[2] = halQspiSetReg( FLEXSPI->FLSHCR2[0], FlexSPI_FLSHCR2_ARDSEQID_MASK, FlexSPI_FLSHCR2_ARDSEQID( 0 ) );
// FLSHCR4
FLEXSPI->FLSHCR4 = halQspiSetReg( FLEXSPI->FLSHCR4, FlexSPI_FLSHCR4_WMOPT1_MASK, FlexSPI_FLSHCR4_WMOPT1( 0 ) );
FLEXSPI->FLSHCR4 = halQspiSetReg( FLEXSPI->FLSHCR4, FlexSPI_FLSHCR4_WMENA_MASK, FlexSPI_FLSHCR4_WMENA( 0 ) );
FLEXSPI->FLSHCR4 = halQspiSetReg( FLEXSPI->FLSHCR4, FlexSPI_FLSHCR4_WMENB_MASK, FlexSPI_FLSHCR4_WMENB( 0 ) );
// Set individual mode
FLEXSPI->IPCR1 = halQspiSetReg( FLEXSPI->IPCR1, FlexSPI_IPCR1_IPAREN_MASK, FlexSPI_IPCR1_IPAREN( 0 ) );
// Set sequence. ISEQNUM is the operation count n+1
FLEXSPI->IPCR1 = halQspiSetReg( FLEXSPI->IPCR1, FlexSPI_IPCR1_ISEQID_MASK, FlexSPI_IPCR1_ISEQID( 0 ) );
FLEXSPI->IPCR1 = halQspiSetReg( FLEXSPI->IPCR1, FlexSPI_IPCR1_ISEQNUM_MASK, FlexSPI_IPCR1_ISEQNUM( 0 ) );
FLEXSPI->IPTXFCR = halQspiSetReg( FLEXSPI->IPTXFCR, FlexSPI_IPTXFCR_TXDMAEN_MASK, FlexSPI_IPTXFCR_TXDMAEN( 0 ) );
// FLEXSPI->IPTXFCR = halQspiSetReg( FLEXSPI->IPTXFCR, FlexSPI_IPTXFCR_TXDMAEN_MASK, FlexSPI_IPTXFCR_TXDMAEN( 1 ) );
// Enable
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_MDIS_MASK, FlexSPI_MCR0_MDIS( 0 ) );
}
// *******************************************************************
// Configure LUT after MDIS = 0
// *******************************************************************
{
// Unlock LUT
FLEXSPI->LUTKEY = FlexSPI_LUTKEY_KEY( 0x5AF05AF0 );
FLEXSPI->LUTCR = FlexSPI_LUTCR_UNLOCK( 1 );
// Setup lut
{
u32_t u32_reg;
u32_reg = 0;
// WRITE_SDR on single line
u32_reg = FlexSPI_LUT_OPCODE0( 0x08 ) | FlexSPI_LUT_NUM_PADS0( 0 ) | FlexSPI_LUT_OPERAND0( 0 );
// WRITE_SDR on quad line
// u32_reg = FlexSPI_LUT_OPCODE0( 0x08 ) | FlexSPI_LUT_NUM_PADS0( 2 ) | FlexSPI_LUT_OPERAND0( 0 );
// CMD_SDR on single line
// u32_reg = FlexSPI_LUT_OPCODE0( 0x01 ) | FlexSPI_LUT_NUM_PADS0( 2 ) | FlexSPI_LUT_OPERAND0( 0xA5 );
// Stop
u32_reg |= FlexSPI_LUT_OPCODE1( 0x00 ) | FlexSPI_LUT_NUM_PADS1( 0 ) | FlexSPI_LUT_OPERAND1( 0 );
FLEXSPI->LUT[0] = u32_reg;
for ( int i_iterator = 1; i_iterator < FlexSPI_LUT_COUNT; ++i_iterator )
FLEXSPI->LUT[ i_iterator ] = 0;
}
// Lock lut
FLEXSPI->LUTKEY = FlexSPI_LUTKEY_KEY( 0x5AF05AF0 );
FLEXSPI->LUTCR = FlexSPI_LUTCR_LOCK( 1 );
}
// *******************************************************************
// Reset controller at last
// *******************************************************************
// halQSpiPrintReg();
FLEXSPI->MCR0 = halQspiSetReg( FLEXSPI->MCR0, FlexSPI_MCR0_SWRESET_MASK, FlexSPI_MCR0_SWRESET( 1 ) );
// halQSpiPrintReg();
// halQSpiPrintLut();
return true;
}
void halQSpiTest( void )
{
// Set watermark to ( n + 1 ) * 64 Bit
FLEXSPI->IPTXFCR = halQspiSetReg( FLEXSPI->IPTXFCR, FlexSPI_IPTXFCR_TXWMRK_MASK, FlexSPI_IPTXFCR_TXWMRK( 0 ) );
// *******************************************************************
// Clear fifo, MUST be done to delete rest data from previous transfer
// *******************************************************************
{
// Clear fifo
FLEXSPI->IPTXFCR = halQspiSetReg( FLEXSPI->IPTXFCR, FlexSPI_IPTXFCR_CLRIPTXF_MASK, FlexSPI_IPTXFCR_CLRIPTXF( 1 ) );
// Wait until fifo empty
while ( ! ( FLEXSPI->INTR & FlexSPI_INTR_IPTXWE_MASK ) );
}
PRINTF( " INTR pre0 0x%08x\r\n", (u32_t)FLEXSPI->INTR );
// *******************************************************************
// Configure transmit
// *******************************************************************
// Set flash start address without base address
// FLEXSPI->IPCR0 = halQspiSetReg( FLEXSPI->IPCR0, FlexSPI_IPCR0_SFAR_MASK, FlexSPI_IPCR0_SFAR( halQspiFlashStartAddrB1() ) ); // didn't work
FLEXSPI->IPCR0 = halQspiSetReg( FLEXSPI->IPCR0, FlexSPI_IPCR0_SFAR_MASK, FlexSPI_IPCR0_SFAR( 0 ) );
// Read / program data size in Bytes
FLEXSPI->IPCR1 = halQspiSetReg( FLEXSPI->IPCR1, FlexSPI_IPCR1_IDATSZ_MASK, FlexSPI_IPCR1_IDATSZ( 2 ) );
// halQSpiPrintReg();
// halQSpiPrintFlashSizes();
halQSpiPrintStatus();
PRINTF( " INTR pre1 0x%08x\r\n", (u32_t)FLEXSPI->INTR );
// *******************************************************************
// Start transfer
// *******************************************************************
FLEXSPI->IPCMD = FlexSPI_IPCMD_TRG( 1 );
// INTR = 0x040
PRINTF( " INTR post 0x%08x\r\n", (u32_t)FLEXSPI->INTR );
for ( int i_burst = 0; i_burst < 2; ++i_burst )
{
// Wait until fifo empty
while ( ! ( FLEXSPI->INTR & FlexSPI_INTR_IPTXWE_MASK ) );
// Fill data to tx fifo.
for ( int i_iterator = 0; i_iterator < 8; ++i_iterator )
FLEXSPI->TFDR[ i_iterator ] = 0x12345678;
// Start transfer
FLEXSPI->INTR = FlexSPI_INTR_IPTXWE_MASK;
}
// *******************************************************************
// Start transfer - didn't work. One clock cycle, then stopping until timeout
// *******************************************************************
// FLEXSPI->IPCMD = FlexSPI_IPCMD_TRG( 1 );
for ( int i_iterator = 0; i_iterator < 10; ++i_iterator )
PRINTF( " INTR post 0x%08x\r\n", (u32_t)FLEXSPI->INTR );
halQSpiPrintStatus();
// Wait until ip command is done
// while( FLEXSPI->INTR & FlexSPI_INTR_IPCMDDONE_MASK );
}
Thanks and regards
Christoph
Hi Jimmy,
I am using SDK 2.8. The FlexSPI works since some days. The processor reference manual is incomplete, the Linux driver is a better reference: https://elixir.bootlin.com/linux/v5.9-rc7/source/drivers/spi/spi-nxp-fspi.c
The only thing which didn't work is the addressing nxp_fspi_select_mem() of the driver.
-Christoph
Hi Jimmy,
SDK 2.8. But it works since some days with exception of the address selection. I used the Linux driver from newest Linux kernel as reference.
The main problem was, that I MUST send a command before sending data. Then some other things may also be wrong, I've rearranged like the Linux kernel driver.
Only the Address selection didn't work. The Linux kernel configures all four QSPI chip sizes to zero, then changes the address of the only one which have to be addressed to the chip size and then writes the address the IPCR0 register.
For me I left the FLSHCR 0 - 3 registers untouched and write zero to IPCR0. This currently works.
Which version of SDK are you using?