SPI Read Issue on MPC5674F: Incorrect Data Received from MCP2518FD CAN Extender

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

SPI Read Issue on MPC5674F: Incorrect Data Received from MCP2518FD CAN Extender

ソリューションへジャンプ
5,188件の閲覧回数
CNarendra
Contributor III

Hello,

I have a few queries regarding the SPI read function implementation. I am attempting to communicate with a slave device (MCP2518FD CAN extender) via SPI in polling mode at 16.5 MHz.

Issue:
When reading the OSC register from the slave, the expected data is 0x60040000. Upon probing with an oscilloscope, the data on the SPI bus is correct (0x60040000). However, during the software read operation, the data observed in the debugger appears as 0x00600400 instead of the expected 0x60040000. The first byte is always received as zero during the read operation.

Scope Data below is 0x60040000

CNarendra_0-1737560240815.png

Debugger window of received data(0x00600400)

CNarendra_1-1737560325963.png

Modified Code:
To address this, I modified the code to perform a dummy read for flushing the RX FIFO immediately after writing the dummy data into the PUSH.R register. This modification resolves the issue, and the read operation now works as intended. kindly check below one

CNarendra_2-1737560370608.png

Additional Observations:

Interestingly, other slaves like FRAM and FLASH work fine without requiring the dummy read to flush the RX FIFO placement. After applying the dummy flush placement modification, these other slaves continue to work correctly without any issues, while the MCP2518FD slave now works as expected.

Question:
Is performing a dummy read to flush the RX FIFO immediately after writing dummy data into the PUSH.R register the correct approach? Are there any alternative or recommended ways to handle this scenario?

Looking forward to your guidance. 


Thanks & Regards

Narendra C

@PetrS ,#MPC5674F ,#MPC5xxx

タグ(3)
0 件の賞賛
返信
1 解決策
4,663件の閲覧回数
davidtosenovjan
NXP TechSupport
NXP TechSupport

Check status register whether you see overflow/underflow and also check whether you have enabled FIFOs.

元の投稿で解決策を見る

0 件の賞賛
返信
14 返答(返信)
5,157件の閲覧回数
PetrS
NXP TechSupport
NXP TechSupport

Hi,

you can check SR register to know how many entries are in RX FIFO.
RXFIFO can flushed using MCR[CLR_RXF].
Also do not use instantiation (.B) for flags clearing, to avoid other flags clearing too. Check chapter 3.2 of https://www.nxp.com/docs/en/engineering-bulletin/EB758.pdf for more info.

BR, Petr 

0 件の賞賛
返信
4,948件の閲覧回数
CNarendra
Contributor III

Hi @PetrS,

I have observed that I am only able to see 1 RXFIFO in the SR.RXCTR flag.

I have attempted to flush the RXFIFO using the MCR[CLR_RXF] bit and cleared the relevant flags as shown in the code below without instantiation. 

Previously, I hadn’t checked below 16.5 MHz, but after doing so, I can confirm that the SPI read fails to work at frequencies below 16.5 MHz, even after performing the dummy read (for flushing) after the clock cycle and clearing the CLR_RXF bit.

To provide more context, there is no issue when communicating with other slaves, such as FRAM or FLASH, across different frequencies. However, when communicating with the CAN Extender MCP2518FD, the SPI read fails below 16.5 MHz.

I would appreciate any insights or suggestions you might have on resolving this issue.

 

 

/**
 *
 * @name        spi_read
 *
 * @brief       Reads a sequence of bytes from the SPI interface. The function
 *              supports both polling and interrupt modes. In polling mode, it
 *              waits for the read transfer to complete before returning
 *
 *
 * @Param       p_spi_config - Pointer to the SPI configuration structure.
 * @Param       p_rx_buffer - Buffer to store the received data.
 * @Param       num_bytes - Number of bytes to read from the SPI interface.
 *
 * @return      spi_status_enum_t - Status of the SPI operation (eSPI_SUCCESS,
 *                                  eSPI_ERROR).
 *
 */

spi_status_enum_t spi_read(const spi_config_t *p_spi_config, uint8_t *p_rx_buffer,
                           uint16_t num_bytes)
{
    uint16_t pos = 0;
    uint8_t dummy;
    spi_status_enum_t status = eSPI_ERROR; // assign with error

    // Read if the SPI configuration, transmit buffer, and byte count are valid
    if ((NULL != p_spi_config) && (NULL != p_rx_buffer) && (num_bytes > 0))
    {
        // Clear any residual data in the rx fifo
       // dummy = SPI_READ_DATA(p_spi_config->port);

        // Clear RFDF Receive FIFO Drain Flag
     //   SPI_CLEAR_RX_FIFO_DRAIN_FLAG(p_spi_config->port);

        // polling mode
        if (p_spi_config->mode == eSPI_POLLING_MODE)
        {
            status = eSPI_SUCCESS; // Assume success unless error occurs

            for (pos = 0; pos < num_bytes; pos++)
            {
               // write data for clock
               SPI_WRITE_DUMMY_DATA(p_spi_config->port);

               // flush rx register ,CLR_RXF is 21st bit
               p_spi_config->port->MCR.R |= (1 << (31 - 21));

              // wait for Receive FIFO Drain Flag.
              // The bit is set while the RX FIFO is not empty
              while(!(p_spi_config->port->SR.R & (1u << (31 - 14))))
              {

              }
                // store into buffer
              p_rx_buffer[pos] = SPI_READ_DATA(p_spi_config->port);

              // clear RFDF flag , RFDF is 14 th bit
             p_spi_config->port->SR.R |= (1u << (31 - 14));

            }
        }
        else // interrupt mode
        {
            // Initialize the SPI reception
            spi_interrupt_buffer.p_rx_buffer = p_rx_buffer;
            spi_interrupt_buffer.rx_length = num_bytes;
            spi_interrupt_buffer.rx_pos = 0;
           // spi_interrupt_buffer.port = p_spi_config->port;

            // send dummy message to invoke interrupt
            SPI_WRITE_DUMMY_DATA(p_spi_config->port);
            dummy = SPI_READ_DATA(p_spi_config->port);

            // Enable RX FIFO Drain Interrupt
            SPI_ENABLE_RX_FIFO_DRAIN_INT(p_spi_config->port);
            status = eSPI_SUCCESS; // Interrupt mode assumed successful
        }
    }

    // returns spi communication status
    return status;
}

 

 



Thanks & Regards
Narendra.C

 

0 件の賞賛
返信
4,914件の閲覧回数
davidtosenovjan
NXP TechSupport
NXP TechSupport

Hi, Petr is currently on vacation.

In my opinion, there is no need to clear the RXFIFO counter during operation and always having PUSH/POP pairs is the right approach.

I would recommend checking the timing requirements of the SPI slave device in question to confirm that the settings match.

0 件の賞賛
返信
4,909件の閲覧回数
CNarendra
Contributor III

Hi @davidtosenovjan 

Should I check the Tcs2sck and Tsck2cs parameters, or are there other parameters I should consider in SPI timings? . Kindly look at attachment of  slave datasheet MCP2518FD DS.book

SPI_Characterstics.pngSPI_Timing_Diagram.pngThanks

Narendra C.

MPC5674F ,#SPI

 

 

0 件の賞賛
返信
4,854件の閲覧回数
CNarendra
Contributor III

Hi @davidtosenovjan @PetrS 

We tried adding a delay between chip select and clock, but it didn't resolve the issue. Could you provide some inputs on this?

Thanks & Regards,
Narendra.C

MPC5674F ,#SPI

タグ(2)
0 件の賞賛
返信
4,817件の閲覧回数
davidtosenovjan
NXP TechSupport
NXP TechSupport

Have you measured all four lines of SPI communication i.e. MISO, MOSI, CLK and CS?

0 件の賞賛
返信
4,793件の閲覧回数
CNarendra
Contributor III

Hi @davidtosenovjan @PetrS,

We captured SPI signals at different frequencies and attempted to read various registers, including the 32-bit OSC and 32-bit C1CON (0x000) registers. We found the C1CON register particularly useful for analysis, as all bytes have some values.

We have set a delay between frame-to-frame using the PDT and DT parameters. We observed a noticeable difference in the delay between frames at 16.5 MHz, 8.5 MHz, and 11 MHz. While the oscilloscope shows the data correctly, the software fails to capture the one byte.

Data Expected to Receive: -0x60079804

Data on SPI Bus  -0x60079804

Data received on Software below 16.5Mhz- 0x600798xy

 

 

 

 

void spi_initialize(spi_config_t *spi_config)
{
    uint8_t i = 0;

    // todo: Need to Improve this function , this is very starting point

    // Configure GPIO pins
    // CLK set to Primary Function, Output and max slew rate
    SIU.PCR[spi_config->bus_pins.sck].R = PCR_SCK;
    // MISO set to Primary Function, Input, and Weak Pullup
    SIU.PCR[spi_config->bus_pins.miso].R = PCR_MISO;
    // MOSI set to Primary Function, Output, and Max Slew Rate
    SIU.PCR[spi_config->bus_pins.mosi].R = PCR_MOSI;

    // set chip select enable
    for (i = 0; i < MAXIMUM_SLAVES; i++)
    {
        if (spi_config->chip_select[i] != 0)
        {
            SIU.PCR[spi_config->chip_select[i]].R = GPIO_PCR_WRITE;
            SIU.GPDO[spi_config->chip_select[i]].B.PDO = eCS_HIGH;
        }
    }

    if (spi_config->write_prot.has_wr_prot)
    {
        SIU.PCR[spi_config->write_prot.wr_prot].R = GPIO_PCR_WRITE;
        SIU.GPDO[spi_config->write_prot.wr_prot].B.PDO = eCS_LOW;
    }

    // Stop the DSPI interface
    spi_config->port->MCR.B.HALT = 1;

    // Configure DSPI interface
    spi_config->port->MCR.B.MSTR = 1;      // Master Mode
    spi_config->port->MCR.B.DIS_TXF = 1;   // No TX Queue
    spi_config->port->MCR.B.DIS_RXF = 1;   // No RX Queue
    spi_config->port->MCR.B.CONT_SCKE = 0; // No Continuous Clock
    spi_config->port->MCR.B.DCONF = 0;     // SPI
    spi_config->port->MCR.B.MTFE = 0;      // Modified Timing Disabled
    spi_config->port->MCR.B.PCSSE = 0;     // Unused
    spi_config->port->MCR.B.ROOE = 1;      // RX Overwrite
    spi_config->port->MCR.B.DOZE = 0;      // No Doze
    spi_config->port->MCR.B.SMPL_PT = 0;   // Sample Point

    // Configure CTAR0 (Clock and Transfer Attributes Register)
    spi_config->port->CTAR[0].B.DBR = 0;                          // No Baud Rate Doubling
    spi_config->port->CTAR[0].B.FMSZ = 7;                         // 8 Bit Frame
    spi_config->port->CTAR[0].B.CPHA = 0;                         // Capture on Rising Edge, SPI-0 Mode
    spi_config->port->CTAR[0].B.LSBFE = 0;                        // MSB First
    spi_config->port->CTAR[0].B.PCSSCK = 0;                       // PCS to SCK Delay Prescaler
    spi_config->port->CTAR[0].B.PASC = 0;                         // Last SCK to PCS delay Prescaler
    spi_config->port->CTAR[0].B.PDT = 1;                          // Frame to Frame Delay Prescaler
    spi_config->port->CTAR[0].B.PBR = 0;                          // Baud Rate Prescaler
    spi_config->port->CTAR[0].B.CSSCK = 0;                        // PCS to SCK Delay Scaler
    spi_config->port->CTAR[0].B.ASC = 0;                          // After SCK Delay Scaler
    spi_config->port->CTAR[0].B.DT = 1;                           // Frame to Frame Scaler
    spi_config->port->CTAR[0].B.BR = (uint8_t)(spi_config->baud_rate_scale); // Baud Rate Scalerspi_config

    // Calculate and verify SCK based on:
    // SCK = (fPeriph / PBR) * (1 + DBR) * (1 / BR)
    //     = (132MHz /  2) *(1 + 0) *( 1 / config->baud_rate_scale)
    // where fPeriph is the peripheral clock frequency, typically 132MHz as per absolosence board

    // Enable SPI
    spi_config->port->MCR.B.HALT = 0;
}

 

 

 

 

Command SequenceCommand SequenceREG_C1CON(0x000)@8.5MHzREG_C1CON(0x000)@8.5MHzREG_C1CON(0x000)@10.5MHzREG_C1CON(0x000)@10.5MHzREG_C1CON(0x000)@16.5MHzREG_C1CON(0x000)@16.5MHzDebug_Console@8.5MhzDebug_Console@8.5MhzDebug_Console@16.5MhzDebug_Console@16.5Mhz

Note: Other slaves, such as FRAM and Flash, are working fine in all frequencies

Kindly refer to the images below, along with the debug console outputs, for further inputs.

Thanks & regards

Narendra

MPC5674F 

0 件の賞賛
返信
4,774件の閲覧回数
CNarendra
Contributor III

Hi @davidtosenovjan,

I have continued debugging the issue and have been examining the DSPI Receive FIFO Registers (DSPI_x.RXFR[0].R) to track message entries in the RX FIFO. We can see all data correctly in both POPR.R and DSPI_x.RXFR[0].R. However, it appears that one byte—either the first or the last—is being overwritten in the buffer, which is causing the issue.

I am currently investigating the root cause, and I am uncertain whether this is due to compiler optimization or timing constraints from the SPI slave device.

Kindly refer to the attached files for further details.

Buffer_OverwrittenBuffer_OverwrittenWorking oneWorking one

 

Thanks 

Narendra .C

タグ(1)
0 件の賞賛
返信
4,757件の閲覧回数
CNarendra
Contributor III

Hi @davidtosenovjan ,

1. As part of debugging ,I added a random delay after the dummy write (for clocking), and now the read operation works correctly.

spi_status_enum_t spi_read(const spi_config_t *spi_config, volatile uint8_t *rx_buffer, uint32_t num_bytes)
{

    uint16_t pos = 0;
    uint16_t dummy;
    spi_status_enum_t spi_status = eSPI_SUCCESS;

    dummy = (uint8_t)(spi_config->port->POPR.R);

    spi_config->port->SR.B.RFDF = 1;

    if (spi_config->mode == eSPI_POLLING_MODE)
    {
        for (pos = 0; pos < num_bytes; pos++)
        {

            // write data for clock
            spi_config->port->PUSHR.R = 0x00;

            // we are adding delay 
            delay2();

           // first byte always read as 0xff . we are bypassing here
            dummy = (uint8_t)(spi_config->port->POPR.R);

            // wait for data
            while (spi_config->port->SR.B.RFDF == 0)
            {

            }

            rx_buffer[pos] = (uint8_t)(spi_config->port->POPR.R);

            spi_config->port->SR.B.RFDF = 1;

        }
    }

    return spi_status;
}


void delay2()
{
   uint64_t i = 0;
   for(i = 0 ; i < 100 ;i++)
   {
   }
}

 

 

2. However, as I mentioned earlier, if I comment out the following line:

dummy = (uint8_t)(spi_config->port->POPR.R);

the first byte always reads as 0xFF.

We are reading this 0xFF into dummy as a bypass, but the first byte consistently comes as 0xFF across all frequencies.

Kindly help us in giving inputs .This is critical one

Thanks 

Narendra .C

0 件の賞賛
返信
4,738件の閲覧回数
davidtosenovjan
NXP TechSupport
NXP TechSupport

Probably the problem is that you are doing pop operation too early after push operation. Due to that probably RxFIFO underflow happens.

Looking to my example code I did in the past with using of polling method I always did it this way:

PUSH
WAIT_UNTIL_RxFIFO_IS_NOT_EMPTY;
POP

where following macro is defined
#define WAIT_UNTIL_RxFIFO_IS_NOT_EMPTY while (!(DSPI_B.SR.B.RFDF)) {}

Example code you may donwload here:
https://community.nxp.com/t5/MPC5xxx-Knowledge-Base/Example-MPC5676R-DSPI-ext-SPI-memory-S25FL129P-C...

Mentioned SPI code snippets in dspi_S25FL129.c and .h

Hope it helps

0 件の賞賛
返信
4,704件の閲覧回数
CNarendra
Contributor III

Hi @davidtosenovjan , @PetrS 

I have implemented the suggested changes, but the issue still persists. I also used SPI_Popr_Read_Fix for analysis. The first byte received is either 0xFF or 0x00, even though the correct data is visible in the RXFIFO (debug register DSPI_A.RXFR[0].R).

The first byte in the RX FIFO is not getting updated in DSPI_A.POPR.R (shift register). I have attached a debug screenshot for reference. While using a delay and dummy read has served as a temporary workaround, we need a permanent solution.

Kindly assist us in identifying the root cause and providing a reliable fix.

 

#define PPC_NOP(x)   {uint8_t n = x; do{ PPCASM(" e_nop"); } while(n--);}

#define SPI_DUMMY_READ_DATA()              ((uint8_t)DSPI_A.POPR.R)

#define SPI_WRITE_DUMMY_DATA()              (DSPI_A.PUSHR.R = 0x00)

#define SPI_TRANSMIT(data)            \
    do {                              \
        DSPI_A.SR.B.TCF = 1;          \
        DSPI_A.PUSHR.R = (uint32_t)((uint8_t)(data) & 0xFF);  \
        while (DSPI_A.SR.B.TCF == 0); \
    } while (0)

#define SPI_RECEIVE(buffer)           \
    do {                              \
        while (DSPI_A.SR.B.RFDF == 0); \
        buffer = (uint8_t)(DSPI_A.POPR.R); \
        DSPI_A.SR.B.RFDF = 1;          \
    } while (0)


// by default we are reading only 4 byte register 
void MCP2518_Read_Data(CAN_DEV_LIST_t selectedDevice, uint8_t cmd, uint16_t address, uint8_t *p_rxbuffer, uint8_t length)
{
	uint8_t i = 0;
	uint16_t data = 0;
	uint8_t spi_tx_cmd[2] = {0};

	if(!p_rxbuffer)
	{
		 return eSPI_ERROR;
	}

	data = ( ((cmd) << 12) | ((address) & 0xFFF) );
	// pack command and address
	spi_tx_cmd[0] = ((data >>  & 0xFF);
	spi_tx_cmd[1] = data;

	  // chip select LOW
	MCP2518_Device_Select[selectedDevice]();

    // send command
    SPI_TRANSMIT(spi_tx_cmd[0]);

    // send Register Address
    SPI_TRANSMIT(spi_tx_cmd[1]);
    
    //1st byte
    SPI_WRITE_DUMMY_DATA();
    if(SPI_Popr_Read_Fix)
    {
         // adding delay for fix
	   PPC_NOP(1)
        // we are always receiving first byte as 0xff or 0x00 even we see 
        // correct data in RXFIFO(debug register DSPI_A.RXFR[0].R)
        // but DSPI_A.POPR.R shift register value is 0x00 or 0xff
        // here we are reading dummy
	   SPI_DUMMY_READ_DATA();
    }
    SPI_RECEIVE(p_rxbuffer[0]);


    // 2nd byte
    SPI_WRITE_DUMMY_DATA();
    SPI_RECEIVE(p_rxbuffer[1]);


    // 3rd byte
    SPI_WRITE_DUMMY_DATA();
    SPI_RECEIVE(p_rxbuffer[2]);


    // 4 th byte
    SPI_WRITE_DUMMY_DATA();
    SPI_RECEIVE(p_rxbuffer[3]);


    // chip select High
    MCP2518_Device_Deselect[selectedDevice]();

}

 

Spi read issueSpi read issue

First Byte in POPR.R(shift register) is not getting updated from RXFIFOFirst Byte in POPR.R(shift register) is not getting updated from RXFIFO

Spi Read WorkingSpi Read Working

Thanks

Narendra.C

MPC5674F 

0 件の賞賛
返信
4,669件の閲覧回数
davidtosenovjan
NXP TechSupport
NXP TechSupport
 

Don't use .B instance. Petr already mentioned it in the very first response (EB758). It is very important.

image.png

0 件の賞賛
返信
4,664件の閲覧回数
davidtosenovjan
NXP TechSupport
NXP TechSupport

Check status register whether you see overflow/underflow and also check whether you have enabled FIFOs.

0 件の賞賛
返信
2,840件の閲覧回数
CNarendra
Contributor III

Hi,

Issue got resolved after enabling FIFO(s) in DSPI

Thanks & regards
Narendra.C

0 件の賞賛
返信