This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Jacinto 5 - cannot get SPI to work

Other Parts Discussed in Thread: SYSCONFIG

I am trying to get SPI to work on the jac5eco board (jacinto 5).

First I used the test setting (SYST), put the module into test mode, hooked the output to an oscilloscope and toggled the chip select signal to see if I could get something out at all. That worked.

Now I have tried to set up as basic a transmit case that I can but it is not working as expected, the chip select never happens.

However the transmission done bit (EOT) gets set. The manual however also says I should check the bit TXS in the CHxSTAT reg.

From manual:

"Wait until end of transfer? MCSPI_CHxSTAT[2:1] = 0x2"

EOT is bit 2 and TXS is bit 1. 

When reading the register the value is 6 which means TXS is also set which means register is empty. 

I find the info here a bit hard to read, isn't that actually correct? 

Is it also correct that the TXS and RXS bit mean different things, 0 is full for one and empty for the other or is that an error in the manual?

From the jac5eco manual, SPRUHF4C_DRA62x, this is the procedure for setup and transmit:

void Spi_Hw_Init( const Spi_ConfigType *ConfigPtr )
{
	uint32 resetDone = FALSE;

	mapHwRegs();

    for (uint32 i = 0; i < SPI_NBR_HW_UNITS; i++)
    {
    	*(Spi_HwRegs[i].MCSPI_SYSCONFIG) |= (MCSPI_SOFTRESET << MCSPI_SOFTRESET_OFFSET);
    }

#ifdef DEBUG_CHECK_SETUP
    uint32 regValPreSYS, regValPreMODCTL;
    regValPreSYS = *Spi_HwRegs[1].MCSPI_SYSCONFIG;
    regValPreMODCTL = *Spi_HwRegs[1].MCSPI_MODULCTRL;
#endif

    while (!resetDone)
    {
    	resetDone = 1;

    	for (uint32 i = 0; i < SPI_NBR_HW_UNITS; i++)
    	{
    		resetDone &= ((*(Spi_HwRegs[i].MCSPI_SYSSTATUS) & MCSPI_RESETDONE_MASK) ==
    		    			MCSPI_RESETDONE_MASK);
    	}
    }

    for (uint32 i = 0; i < SPI_NBR_HW_UNITS; i++)
    {
        Spi_Hw_InitController(i);
    }

    for (uint32 j = 0; j < SPI_EXT_DEVICES_CNT; j++)
    {
        setupExternalDevice(&ConfigPtr->SpiExternalDevice[j]);
    }

#ifdef DEBUG_CHECK_SETUP
    uint32 regValPostSYS, regValPostMODCTL;
    regValPostSYS = *Spi_HwRegs[1].MCSPI_SYSCONFIG;
    regValPostMODCTL = *Spi_HwRegs[1].MCSPI_MODULCTRL;
#endif
}


void Spi_Test_Transmit(void)
{
	/* SPI Transmit Mode Initialization */

	/* Transmit mode and word length. */
	Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF |= (
			(MCSPI_TRM_TRANSMIT_ONLY_MODE << MCSPI_TRM_OFFSET) |
			(8 << MCSPI_WL_OFFSET)
			);

	/* Master already set so need to do it again. */
	//*Spi_HwRegs[1].MCSPI_MODULCTRL |= (0 << MCSPI_MS_OFFSET);

	/* Enable channel. */
	MCSPI_CHAN_ENABLE(Spi_HwRegs[1].MCSPI_CHn[0]);

	/* Channels activated low during active state (EPOL) */
	Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF |= (1 << 6);

	/* Clock held high during active state (POL) */
	Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF |= 0 << 1;

	/* Data latched on odd-numbered edges of the SPI clock */
	Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF |= 0 << 0;

	/* Reset the status bits. */
	// Datasheet actually write 1 to reset so here is a contradiction.
	*Spi_HwRegs[1].MCSPI_IRQSTATUS = 0;



	/* Transmit-Only Procedure – Polling Method */

	uint32 statRegVal = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnSTAT;
	uint32 txReg = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn;

	// Put the data in the tx reg
	Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn = 0xA5A5A5A5;

	/* Start the channel. (Already done...) */
	MCSPI_CHAN_ENABLE(Spi_HwRegs[1].MCSPI_CHn[0]);

	statRegVal = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnSTAT;
	txReg = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn;

	while ((Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnSTAT & 6) != 4)
	{
		statRegVal = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnSTAT;
		txReg = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn;
	};

	MCSPI_CHAN_DISABLE(Spi_HwRegs[1].MCSPI_CHn[0]);

	while (1) {};
}

  • Should the Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn reg be emptied as the bytes are sent?
  • Some more code and info:



    void Spi_Hw_InitController( uint32 hwUnit )
    {
    /* The following registers do not need any changes:
    * MCSPI_HL_REV - Only information.
    * MCSPI_HL_HWINFO - Only information.
    * MCSPI_HL_SYSCONFIG - Only information.
    * MCSPI_REVISION - Only information
    * MCSPI_SYSSTATUS - Reset status is the only thing that can be read.
    * MCSPI_IRQSTATUS - Only status, no settings.
    * MCSPI_WAKEUPENABLE - Only applicable in slave mode, thus
    * we do not need to anything.
    * MCSPI_SYST - Only applicable in system test mode.
    *
    * Unsure:
    * MCSPI_XFERLEVEL - Applicable when using FIFOs.
    * MCSPI_DAFTX - Will not be used?
    * MCSPI_DAFRX - Will not be used?
    */

    Spi_Hw_DisableInterrupt(hwUnit);

    /* System configuration register setup:
    * Reserved (bits 31-10) = 0
    * CLOCKACTIVITY (bits 9-8) = 0 (OCP and Functional clocks may be switched off.)
    * Reserved (bits 7-5) = 0
    * SIDLEMODE (bits 4-3) = 2 (Idle request ignored)
    * ENAWAKEUP (bit 2) = 1 (Wakeup capability is enabled.)
    * SOFTRESET (bit 1) = 0 (Normal mode)
    * AUTOIDLE (bit 0) = 1 (Automatic OCP clock gating strategy is applied.)
    */
    *Spi_HwRegs[hwUnit].MCSPI_SYSCONFIG = (
    (2 << 3) |
    (1 << 2) |
    1
    );

    /* Module control register setup
    * Reserved (bits 31-9) = 0
    * FDAA (bit 8) = 0 (FIFO data managed by MCSPI_TX(i) and MCSPI_RX(i) registers.)
    * MOA (bit 7) = 0 (?) (Multiple word access disabled)
    * INITDLY (bits 6-4) = 0 (No delay for first SPI transfer)
    * SYSTEM_TEST (bit 3) = 0 (Functional mode)
    * MS (bit 2) = 0 (Master)
    * PIN34 (bit 1) = 0 (SPI_SCS[n] used as chip select)
    * SINGLE (bit 0) = 0 (More than one channel will be used in master mode.)
    */
    *Spi_HwRegs[hwUnit].MCSPI_MODULCTRL = 0;
    }

    static void setupExternalDevice(const struct Spi_ExternalDevice *ePtr)
    {
    MCSPI_CHn_Type *MCSPI_CHn = &Spi_HwRegs[ePtr->SpiHwUnit].MCSPI_CHn[ePtr->SpiCsIdentifier];

    /* Initial settings for the MCSPI_CHnCTRL register:
    * Reserved (bits 31-16) = 0
    * EXTCLK (bits 15-8) = 0 (Not used if CLKG in MCSPI_CHnCONF is set to 0.)
    * Reserved (bits 7-1) = 0
    * EN (bit 0) = 0 (Set to inactive and activate when it is used.
    * If it is not inactive some settings cannot be set in MCSPI_CHnCONF.)
    */
    MCSPI_CHn->MCSPI_CHnCTRL = 0;

    /* Initial settings for the MCSPI_CHnCONF register:
    * Reserved (bits 31-30) = 0
    * CLKG (bit 29) = 0 (Clock granularity of power of 2)
    * FFER (bit 28) = 0 (The buffer is not used to receive data.)
    * FFEW (bit 27) = 0 (The buffer is not used to transmit data.)
    * TCS (bits 26-25) = ? (TODO: Hardcoded 0 for now, will figure this out later.)
    * SBPOL (bit 24) = 0 (Ignored because of SBE.)
    * SBE (bit 23) = 0 (Default SPI transfer length as specified by WL bit field.)
    * SPIENSLV (bits 22-21) = 0 (This only applies in slave mode and is thus irrelevant)
    * FORCE (bit 20) = 0 (Write to this after setup to force it into nonactive state.)
    * TURBO (bit 19) = 0 (Turbo is deactivated (recommended for single SPI word transfer).)
    *
    * IS, DPE1 and DPE0 are settings for what should be MISO and MOSI.
    * IS (bit 18) = ? (TODO: 0 - Setting SPI_D[0] for reception and setting SPI_D[1] for transmission, figure out later what is best.)
    * DPE1 (bit 17) = ? (TODO: 0 - use for transmission)
    * DPE0 (bit 16) = ? (TODO: 1 - do not use for transmission, see IS.)
    *
    * DMAR (bit 15) = 0 (TODO: DMA read request is disabled.)
    * DMAW (bit 14) = 0 (TODO: DMA write request is disabled.)
    * TRM (bits 13-12) = 0 (TODO: Transmit and receive mode.)
    * WL (bits 11-7) = 7 (Setting to 8 (write 7 to reg) by default, this will be changed when transmitting anyway (Spi_ChannelConfig->SpiDataWidth).)
    * EPOL (bit 6) = Chip select polarity. Writing 1 to EPOL means active low.
    * CLKD (bits 5-2) = ? (TODO: Calculate with the help of Spi_ExternalDevice->SpiBaudrate. Set to 0 for now.)
    * POL (bit 1) = ? (TODO: Spi_ExternalDevice->SpiCsPolarity?)
    * PHA (bit 0) = 0 (TODO: What is preferrable? Arbitrarily setting to 0 for now.)
    */
    MCSPI_CHn->MCSPI_CHnCONF = (
    (SPI_DEFAULT_WORD_SIZE_8_BITS << MCSPI_WL_OFFSET) |
    ((!ePtr->SpiCsPolarity) << MCSPI_EPOL_OFFSET) |
    ((!ePtr->SpiCsPolarity) << MCSPI_POL_OFFSET)
    );
    }

    void Spi_Hw_Init( const Spi_ConfigType *ConfigPtr )
    {
    uint32 resetDone = FALSE;

    mapHwRegs();

    for (uint32 i = 0; i < SPI_NBR_HW_UNITS; i++)
    {
    *(Spi_HwRegs[i].MCSPI_SYSCONFIG) |= (MCSPI_SOFTRESET << MCSPI_SOFTRESET_OFFSET);
    }

    while (!resetDone)
    {
    resetDone = 1;

    for (uint32 i = 0; i < SPI_NBR_HW_UNITS; i++)
    {
    resetDone &= ((*(Spi_HwRegs[i].MCSPI_SYSSTATUS) & MCSPI_RESETDONE_MASK) ==
    MCSPI_RESETDONE_MASK);
    }
    }

    for (uint32 i = 0; i < SPI_NBR_HW_UNITS; i++)
    {
    Spi_Hw_InitController(i);
    }

    for (uint32 j = 0; j < SPI_EXT_DEVICES_CNT; j++)
    {
    setupExternalDevice(&ConfigPtr->SpiExternalDevice[j]);
    }
    }

    void Spi_Test_InitTxRxMode(void)
    {
    uint32 regVal;
    uint32 regMask = ~(
    (3 << MCSPI_TRM_OFFSET) |
    (0x1F << MCSPI_WL_OFFSET)
    );

    /* Transmit mode and word length. */
    regVal = Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF & regMask;

    Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF = regVal | (
    (MCSPI_TRM_TRANSMIT_AND_RECEIVE_MODE << MCSPI_TRM_OFFSET) |
    (7 << MCSPI_WL_OFFSET)
    );

    /* Master already set so need to do it again. */

    //enableMcSpiChannel(1, 0);
    disableMcSpiChannel(1, 0);

    /* Channels activated low during active state (EPOL) */
    Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF |= (1 << 6);

    /* Clock held high during active state (POL) */
    Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF &= ~(1 << 1);

    /* Data latched on odd-numbered edges of the SPI clock (PHA) */
    Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnCONF &= ~(1 << 0);

    /* Reset the status bits. */
    // Datasheet actually write 1 to reset so here is a contradiction.
    *Spi_HwRegs[1].MCSPI_IRQSTATUS = 0;
    //*Spi_HwRegs[1].MCSPI_IRQSTATUS = 0xFFFFFFFF;
    }

    /**
    * @brief Transmit-and-Receive Procedure With Word Count – Polling Method.
    */
    void Spi_Test_TxAndRx(void)
    {
    enableMcSpiChannel(1, 0);

    Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn = 0xA5A5A5A5;

    while ((Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnSTAT & 7) != 3) {};

    disableMcSpiChannel(1, 0);

    while (1) {};
    }




    What happens is that "Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_CHnSTAT & 7)" is 7 and not 3. However that means the EOT bit is set which must be correct. It makes sense with 7/0b111 since that means EOT+TX_empty+RX_full.

    The MCSPI_IRQSTATUS register says 5 after I step over the line "Spi_HwRegs[1].MCSPI_CHn[0].MCSPI_TXn = 0xA5A5A5A5;".

    "A5" is transferred to the MCSPI_RXn reg as it should be. However that also happens in transmit only mode, that must be wrong...?

    I do not get a chip select signal when I connect my oscilloscope.
  • So i got SPI to work but I think the instructions are not correct in the reference manual. It says the EOT bit should not be set when using Transmit-Receive mode which seems wrong and it does get set when you run it as described in the reference manual.

    The ref manual I use is:
    Jac5eco - SPRUHF4C_DRA62x

  • Hi Staffan,

    Staffan Johansson said:
    I think the instructions are not correct in the reference manual. It says the EOT bit should not be set when using Transmit-Receive mode

    Where exactly you have found this statement in the DRA62x/J5Eco TRM?

    Staffan Johansson said:
    The ref manual I use is:
    Jac5eco - SPRUHF4C_DRA62x

    This one is correct for DRA62x/J5Eco/DM811x/TI811x device. You can also explore the McSPI linux kernel driver source code:

    BR
    Pavel

  • Chapter: 21.2.12.2.1.4 Transmit-and-Receive Procedure - Polling Method

    Wait until transmit/receive word? MCSPI_CHxSTAT[2:0] = 0x3

    That would mean EOT should be 0...

  • Staffan,

    Yes, that might be TRM mistake. You are using SPI word transfer without using FIFO/buffer, right? See sections:

    21.2.3.3 Master Transmit and Receive Mode
    21.2.4.3 Slave Transmit-and-Receive Mode

    In both cases (Master or Slave), the EOT bit is used when there is no FIFO/buffer used.

    See also the below e2e thread, it might also be in help:
    e2e.ti.com/.../409945

    BR
    Pavel
  • Hi Pavel,
    Is there any method to control spi to read/write certain address using UART debug?
    My device is J5eco which should be similar to ti814x

    BR,
    Eason
  • Eason,

    Check with "sf read" and "sf write" commands. More info in the below wiki:

    processors.wiki.ti.com/.../TI811X_PSP_UBOOT_User_Guide

    BR
    Pavel