Using ECSPI from the i.MX8MM Cortex-M4

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

Using ECSPI from the i.MX8MM Cortex-M4

Jump to solution
1,911 Views
wonk-andy
Contributor II

I am having trouble using the ECSPI from the Cortex-M4 of the i.MX8MM with the functions available in fsl_ecspi.c. 

Eventually, I need to communicate with complex ADC and DAC devices.  To try and simplify things to prove the interface I have gone back to an SPI flash device and trying to read the manufacturer ID.  The flash data sheet shows the following diagram:

Screenshot 2023-05-25 at 14.05.00.pngLooking at the SPI bus on a logic analyser I don't ever seem to see any data coming from the device.  I appear to have 4 bytes being written to the slave device and the CS# going high then low between each byte being sent.

The setup of the ESCPI controller is as per the SDK sample:

/* Master config:
* masterConfig.channel = kECSPI_Channel0;
* masterConfig.burstLength = 8;
* masterConfig.samplePeriodClock = kECSPI_spiClock;
* masterConfig.baudRate_Bps = TRANSFER_BAUDRATE;
* masterConfig.chipSelectDelay = 0;
* masterConfig.samplePeriod = 0;
* masterConfig.txFifoThreshold = 1;
* masterConfig.rxFifoThreshold = 0;
*/

ECSPI_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Bps = TRANSFER_BAUDRATE;

ECSPI_MasterInit(EXAMPLE_ECSPI_MASTER_BASEADDR, &masterConfig, ECSPI_MASTER_CLK_FREQ);

Anyone got any ideas how I make this work?

-Andy.

 

Tags (2)
0 Kudos
1 Solution
1,828 Views
AldoG
NXP TechSupport
NXP TechSupport

Hi,

Thank you for sharing more information, from the piece of code you have shared and the analyzer image, it seems that the output you're seeing after 0x9f are random stuff because you have set a datasize of 4.
masterXfer.dataSize = 4;

Since only the first byte have a value the other 3 bytes will be dummy data, and you could see this in the ecspi driver located at: SDK_2_11_0_EVK-MIMX8MM\devices\MIMX8MM6\drivers\fsl_ecspi.c

while (xfer->dataSize > 0UL)
    {
        /* ECSPI will transmit and receive at the same time, if txData is NULL,
         * instance will transmit dummy data, the dummy data can be set by user.
         * if rxData is NULL, data will be read from RX FIFO buffer, but the
         * data will be ignored by driver.
         * Note that, txData and rxData cannot be both NULL.
         */
        state = ECSPI_WriteBlocking(base, xfer->txData, dataCounts);
        if (kStatus_Success != state)
        {
            return state;
        }
        if (NULL != xfer->txData)
        {
            xfer->txData += dataCounts;
        }
        state = ECSPI_ReadBlocking(base, xfer->rxData, dataCounts);
        if (kStatus_Success != state)
        {
            return state;
        }
        if (NULL != xfer->rxData)
        {
            xfer->rxData += dataCounts;
        }

        xfer->dataSize -= dataCounts;
    }

Also, if you need the SS to stay active, you'll need to have SS_CTL clear and after looking into the driver code this is not supported, but that does not mean it could not be added on your side, you may refer to the reference manual for more information on this:

AldoG_1-1685480024190.png

Please refer to the fsl_ecspi.c function:
void ECSPI_SetChannelConfig(ECSPI_Type *base, ecspi_channel_source_t channel, const ecspi_channel_config_t *config)

Best regards,
Aldo.

View solution in original post

0 Kudos
10 Replies
1,869 Views
wonk-andy
Contributor II

Hi @AldoG 

Let me try to explain better...

The ECSPI interface is being configured as per the driver/ecspi/polling_b2b_transfer/master example in the SDK (I have SDK v2.11.0).  I then run the following code to try to query the SPI flash for it's manufacturer ID:

uint32_t ulTxBuf[1] = { 0 };  // One byte to send for read ID
uint32_t ulRxBuf[3] = { 0 }; // Three bytes returned.
 
ulTxBuf[0] = 0x9f; // Read ID cmd/
 
masterXfer.txData = ulTxBuf;
masterXfer.rxData = ulRxBuf;
masterXfer.dataSize = 4;
masterXfer.channel = kECSPI_Channel0;
ECSPI_MasterTransferBlocking(ECSPI2, &masterXfer);
 
The output on the logic analyser shows:
 
Screenshot 2023-05-26 072333.png
 
I'm seeing 4 bytes being sent on MOSI (the top trace) which is the correct 0x9f byte followed by three random values, nothing ever on MISO and the slave select / enable pin (channel 2) is transitioning high then low again after every byte sent.
 
What I am expecting is the 0x9f being sent on MOSI, three bytes 0x1f, 0x45, and 0x01 being received on MISO and the enable pin to stay low the whole transfer.
 
-Andy.
 
-Andy.
0 Kudos
1,829 Views
AldoG
NXP TechSupport
NXP TechSupport

Hi,

Thank you for sharing more information, from the piece of code you have shared and the analyzer image, it seems that the output you're seeing after 0x9f are random stuff because you have set a datasize of 4.
masterXfer.dataSize = 4;

Since only the first byte have a value the other 3 bytes will be dummy data, and you could see this in the ecspi driver located at: SDK_2_11_0_EVK-MIMX8MM\devices\MIMX8MM6\drivers\fsl_ecspi.c

while (xfer->dataSize > 0UL)
    {
        /* ECSPI will transmit and receive at the same time, if txData is NULL,
         * instance will transmit dummy data, the dummy data can be set by user.
         * if rxData is NULL, data will be read from RX FIFO buffer, but the
         * data will be ignored by driver.
         * Note that, txData and rxData cannot be both NULL.
         */
        state = ECSPI_WriteBlocking(base, xfer->txData, dataCounts);
        if (kStatus_Success != state)
        {
            return state;
        }
        if (NULL != xfer->txData)
        {
            xfer->txData += dataCounts;
        }
        state = ECSPI_ReadBlocking(base, xfer->rxData, dataCounts);
        if (kStatus_Success != state)
        {
            return state;
        }
        if (NULL != xfer->rxData)
        {
            xfer->rxData += dataCounts;
        }

        xfer->dataSize -= dataCounts;
    }

Also, if you need the SS to stay active, you'll need to have SS_CTL clear and after looking into the driver code this is not supported, but that does not mean it could not be added on your side, you may refer to the reference manual for more information on this:

AldoG_1-1685480024190.png

Please refer to the fsl_ecspi.c function:
void ECSPI_SetChannelConfig(ECSPI_Type *base, ecspi_channel_source_t channel, const ecspi_channel_config_t *config)

Best regards,
Aldo.

0 Kudos
1,794 Views
wonk-andy
Contributor II

Hi @AldoG 

Thanks for the additional information.

Can I just confirm that in order to keep the SS signal active I need to set the SS_CTL bit to be 0?

Looking at the Reference Manual and the source code for ECSPI_MasterInit() then it looks like currently that bit is being ignored as the SMC bit in ECSPI_CONREG is set to 1. 

I'm guessing that means that I need to modify ECSPI_MasterInit() to make the SMC bit configurable and if SMC bit is cleared then the transfers need to be initiated by setting the XCH bit.

Can you confirm all of the above is correct.

-Andy.

 

0 Kudos
1,787 Views
AldoG
NXP TechSupport
NXP TechSupport

Hello,

Yes, you're correct

Best regards,
Aldo.

0 Kudos
1,725 Views
wonk-andy
Contributor II

Hi @AldoG 

Apologies for re-opening this but I have made all of the changes that I anticipated to the ECSPI functions in the SDK but I cannot get the SPI interface to work.

When I try to initiate the transfer, I am never seeing the slave select signal go low.  I have added some debug to ECSPI_MasterTransferBlocking() to look at the contents of the SPI registers and they appear correct.

DEBUG : In ECSPI_MasterTransferBlocking
DEBUG : Selected SPI channel 0
DEBUG : burstLength = 8, dataCounts = 1
DEBUG : CONREG = 0x00704511
DEBUG : CONFIGREG = 0x00010100
DEBUG : INTREG = 0x00000000
DEBUG : STATREG = 0x00000003
DEBUG : PERIODREG = 0x00000000

Immediately after that debug is output I have the following added code:

if ((base->CONREG & ECSPI_CONREG_SMC_MASK) == 0)
{
base->CONREG |= ECSPI_CONREG_XCH(1);
}
 

Any idea what I have missed?

 

-Andy.

0 Kudos
1,884 Views
AldoG
NXP TechSupport
NXP TechSupport

Hello,

I do not understand clearly which part is not responding, I believe it is the slave right?
 
I think it would be better to try an ECSPI example, i.e. b2b_transfer so you could see the SPI bus with you analyzer.

Best regards,
Aldo.

0 Kudos
1,553 Views
maryellenmclaug
Contributor II

I am using i.MX8MP and Cortex M7 and I have the same issue that the SS is not going low for multiple bursts.   The comments in fsl_ecspi.h 

*! SS_CTL
* 0b0000..In master mode - only one SPI burst will be transmitted.
* 0b0001..In master mode - Negate Chip Select (SS) signal between SPI bursts. Multiple SPI bursts will be
* transmitted. The SPI transfer will automatically stop when the TXFIFO is empty.
* 0b0000..In slave mode - an SPI burst is completed when the number of bits received in the shift register is
* equal to (BURST LENGTH + 1). Only the n least-significant bits (n = BURST LENGTH[4:0] + 1) of the first
* received word are valid. All bits subsequent to the first received word in RXFIFO are valid.
* 0b0001..Reserved
*/
 
Since my SPI is a master, it makes me think I need to set SS_CTL to 0x01, not zero, for multiple bursts.
My SPI CS is still low for each byte and not for the full data being sent.  So my slave doesnt see that as a full message.  Any help would be appreciated.
 

 

0 Kudos
1,488 Views
gabper3x
Contributor II

I also have same issue on M4.

Any configurations are not effective I thought.

The best is configuring independent GPIO as Chip Select if possible.

0 Kudos
1,477 Views
maryellenmclaug
Contributor II

Hi - I followed wonky-andy's advice and it worked.  To note, the 32 bit transfer, it only used the bottom byte of every 32bits. Also was not what I was expecting. But this has solved my issue.  Something wrong with their driver and their examples don't use the SPI interface fully so is decieving.

Good luck.

 

1,541 Views
wonk-andy
Contributor II

I never did manage to get this to work properly using the chip select pin (SS0) configured as part of the ECSPI interface. 

To work around it, I configure the pin as a GPIO:

gpio_pin_config_t xGpioConfig = { kGPIO_DigitalOutput, 1, kGPIO_NoIntmode };

IOMUXC_SetPinMux(IOMUXC_ECSPI1_MISO_ECSPI1_MISO, 0U);
IOMUXC_SetPinConfig(IOMUXC_ECSPI1_MISO_ECSPI1_MISO, 
                    IOMUXC_SW_PAD_CTL_PAD_DSE(6U) | 
                    IOMUXC_SW_PAD_CTL_PAD_HYS_MASK);

IOMUXC_SetPinMux(IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI, 0U);
IOMUXC_SetPinConfig(IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI, 
                    IOMUXC_SW_PAD_CTL_PAD_DSE(6U) | 
                    IOMUXC_SW_PAD_CTL_PAD_HYS_MASK);

IOMUXC_SetPinMux(IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK, 0U);
IOMUXC_SetPinConfig(IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK, 
                    IOMUXC_SW_PAD_CTL_PAD_DSE(6U) | 
                    IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
                    IOMUXC_SW_PAD_CTL_PAD_PE_MASK);

IOMUXC_SetPinMux(IOMUXC_ECSPI1_SS0_GPIO5_IO09, 0U);
GPIO_PinInit(GPIO3, 19, &xGpioConfig);
 
I have then written a wrapper function to handle the SPI transfer which in effect does the following:

Set CS_GPIO low
Call ECSPI_MasterTransferBlocking() for the write part of the SPI transaction with a null rxData buffer
If needed, call ECSPI_MasterTransferBlocking() for the read part of the SPI transaction with a null txData buffer
Set CS_GPIO high
 
-Andy,
0 Kudos