PSOC5LP SPIM using DMA, rxBuffer not receiving the correct data

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
KahHou
Level 1
Level 1
10 sign-ins 5 sign-ins First reply posted

Hai, 

I would need some help on transferring data by SPI Master with DMA.

Sending data works very well, all the data in txBuffer is sent.

However, I do not receive the data that I am expecting from the slave.

 

I am expecting a lot of 0x8000 and some measures in the table rxBuffer : 


 

However, I received a lot of 0x0000 and some measures that do not really make sense to me in the table rxBuffer when I read the table in debug mode :

Here is the configuration of my SPI and DMA : 

KahHou_1-1622018050634.png

KahHou_2-1622018066804.png

 

Hardware request is "Level" because rx interrupt is always at high level.

Attached below is my project, does anyone have an idea what can cause this ? 

0 Likes
1 Solution
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

KahHou,

I'm still in the process of debugging your issue.  I'm a bit confused.

Confusion #1:

Your main() function has this flow:

int main(void)
{
    uint8 i = 0u;
    CyGlobalIntEnable; /* Enable global interrupts. */
    
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    SPIM_Start();
    //Clock_1_Start();
    VDAC8_1_Start();
    Opamp_1_Start();
    
    SPIM_Write_and_Read(0xE800, &dummy_data);
...  Many other SPIM_Write_and_Read() calls 
    CyDelayUs(20);       

/* Here you start the DMA for the Tx and Rx of SPIM */
    DmaTxConfiguration();
    DmaRxConfiguration();
    
    CyDmaChEnable(rxChannel, STORE_TD_CFG_ONCMPLT);
    CyDmaChEnable(txChannel, STORE_TD_CFG_ONCMPLT);

/* After this point, there is no definitive proof that SPIM_RX will receive ANY further data */
    
    while (0u == (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE))
    {}

    while(1)
    {
        for(i=0; i <18; i++)
        {
            dataconvert[i] = rxBuffer[i];
        }
    }    
}

The confusion is I cannot see where the DMA is being used given that I have no evidence of further SPIM_RX input from an external device.

Confusion #2

Is the data that you show in the memory window in the debug session with mostly 0x00s, from the reading of the SPIM_RX BEFORE the configuring and enabling the DMA?

If so, I can see why this is happening.

The DMA for Rx is not loading rxBuffer[].  The buffer you are reading is the default data in non-initialized RAM.

Confusion #3

You have the function:

void SPIM_Write_and_Read(uint16_t writeData, uint16_t * readData)
{
    SPIM_WriteTxData(writeData);  /* You are NOT checking to make sure */
                                  /* the Tx FIFO is not full. */
                                  /*  This could overwrite the last byte of data */
    SPIM_ClearFIFO();  /* This call clears BOTH the Tx and Rx FIFO buffers */
    *readData = SPIM_ReadRxData();  /* Because the Rx FIFO is cleared */
                                    /* in the previous line, this call */
                                    /* has no real purpose */
}

Potential issues:

  • Calling SPIM_WriteRxData() does check if the FIFO is not full.  If the FIFO is full, the data will be forced into the last byte of the FIFO.
  • You call SPIM_ClearFIFO().   This will clear the Tx and Rx FIFOs.  If you are trying to send a multi-byte command sequence to a remote SPI slave, you will be clearing (setting to 0x00) any SPI bytes in the FIFO.  The command sequence will be wrong.  
    Additionally if you are expecting Rx data from the SPI slave, you have effectively erased this before you go to read the data.  Recommendation:  Eliminate this call.  Good coding should make this unnecessary.
  • As stated in the previous issue, the Rx data read should always be 0x00.

 

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
5 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

KahHou,

You've selected "Enable Rx Internal Interrupt".  This actually causes an internal interrupt to be executed when the Rx FIFO is not empty.  You don't want that.   Deselect the "Enable Rx Internal Interrupt" check box.

Here is a snip from the datasheet regarding this parameter.

Enable TX / RX Internal Interrupt
The Enable TX / RX Internal Interrupt options allow you to use the predefined Tx and Rx ISRs of the SPI Master component, or supply your own custom ISRs. If enabled, you may add your own code to these predefined ISRs if small changes are required.  If the internal interrupt is deselected, you may supply an external interrupt component with custom code connected to the interrupt outputs of the SPI Master.

Although you can supply your own ISR component you can also provide your own DMA component as you did.

See if this helps.

Another thing I noticed.  To access the Rx FIFO data, you are using SPIM_BSPIM_sR16_Dp_u0__F1_REG instead of SPIM_RXDATA_PTR.  Is there a reason?   Although in this particular instance they are equivalent, SPIM_RXDATA_PTR is the 'safer' choice.  SPIM_RXDATA_PTR will remain true as long as your component name remains the same.  However SPIM_BSPIM_sR16_Dp_u0__F1_REG may not be true if later you add components and the Application build phase changes the UDB location of your SPIM component.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Thanks for your reply, and yes, it helps, deselecting RX Internal Interrupt is what I have done. As for the SPIM_BSPIM_sR16_Dp_u0__F1_REG , I saw in another thread that if I want to use SPI 16 bits, I should use this address.

 

0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

KahHou,

I don't have your HW (obviously).  What would happen if I program my CY8CKIT-059 with your code and route the SPIM Tx pin to the Rx pin?  What should I expect to receive?

I'm trying to find a practical way to debug your issue on my HW.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

KahHou,

I'm still in the process of debugging your issue.  I'm a bit confused.

Confusion #1:

Your main() function has this flow:

int main(void)
{
    uint8 i = 0u;
    CyGlobalIntEnable; /* Enable global interrupts. */
    
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    SPIM_Start();
    //Clock_1_Start();
    VDAC8_1_Start();
    Opamp_1_Start();
    
    SPIM_Write_and_Read(0xE800, &dummy_data);
...  Many other SPIM_Write_and_Read() calls 
    CyDelayUs(20);       

/* Here you start the DMA for the Tx and Rx of SPIM */
    DmaTxConfiguration();
    DmaRxConfiguration();
    
    CyDmaChEnable(rxChannel, STORE_TD_CFG_ONCMPLT);
    CyDmaChEnable(txChannel, STORE_TD_CFG_ONCMPLT);

/* After this point, there is no definitive proof that SPIM_RX will receive ANY further data */
    
    while (0u == (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE))
    {}

    while(1)
    {
        for(i=0; i <18; i++)
        {
            dataconvert[i] = rxBuffer[i];
        }
    }    
}

The confusion is I cannot see where the DMA is being used given that I have no evidence of further SPIM_RX input from an external device.

Confusion #2

Is the data that you show in the memory window in the debug session with mostly 0x00s, from the reading of the SPIM_RX BEFORE the configuring and enabling the DMA?

If so, I can see why this is happening.

The DMA for Rx is not loading rxBuffer[].  The buffer you are reading is the default data in non-initialized RAM.

Confusion #3

You have the function:

void SPIM_Write_and_Read(uint16_t writeData, uint16_t * readData)
{
    SPIM_WriteTxData(writeData);  /* You are NOT checking to make sure */
                                  /* the Tx FIFO is not full. */
                                  /*  This could overwrite the last byte of data */
    SPIM_ClearFIFO();  /* This call clears BOTH the Tx and Rx FIFO buffers */
    *readData = SPIM_ReadRxData();  /* Because the Rx FIFO is cleared */
                                    /* in the previous line, this call */
                                    /* has no real purpose */
}

Potential issues:

  • Calling SPIM_WriteRxData() does check if the FIFO is not full.  If the FIFO is full, the data will be forced into the last byte of the FIFO.
  • You call SPIM_ClearFIFO().   This will clear the Tx and Rx FIFOs.  If you are trying to send a multi-byte command sequence to a remote SPI slave, you will be clearing (setting to 0x00) any SPI bytes in the FIFO.  The command sequence will be wrong.  
    Additionally if you are expecting Rx data from the SPI slave, you have effectively erased this before you go to read the data.  Recommendation:  Eliminate this call.  Good coding should make this unnecessary.
  • As stated in the previous issue, the Rx data read should always be 0x00.

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

For Confusion #1 : 

I thought that these two lines is starting the DMA, and so DMA should be putting all the data that came in inside the rxBuffer; 

    CyDmaChEnable(rxChannel, STORE_TD_CFG_ONCMPLT);
    CyDmaChEnable(txChannel, STORE_TD_CFG_ONCMPLT);

 or are you talking about something like, SPIM_ReadRxStatus / SPIM_GetRxBufferSize to ensure that there is data coming in ? In this case, maybe I have misunderstood DMA's function, because with the configuration, my slave is supposed to respond, and so DMA should be able to take all his response.

 

For Confusion #2 :

The data that I show in memory window is the data that I get AFTER configuring and enabling my DMA, I have tried to initialized my rxBuffer with 0x1234, at the end, I still get 0x0000, this proves that DMA has changed my rxBuffer but not with the data that i expected.

 

For confusion #3 :

Exactly, I have solved my problem, and the problem came from this function.

Actually, I am new to SPI so I don't really know what are the "procedures" to send and receive SPI data.

I was thinking about sending my data, by using SPIM_WriteTxData();

Then SPIM_ClearFIFO to clear whatever data that is on the miso line, 

And since I have cleared the miso line, I will now read miso line by SPIM_ReadRxData, which should be the response from my slave.

Until now, I still don't know what are the "procedures" or "precautions" to take when I need to send, and receive SPI data, like when to check FIFO or clear Buffer. I would be glad if you can give me an example more or less universal so that the next time when I use SPI, I would have the "precautions" or the correct "procedures"

 

So, I have removed the function SPIM_Write_and_Read(), since this method doesn't work.

I have used DMA to send all the SPI data that I need to configure my slave, and it worked.

 

Thank you very much.

 

Kah Hou

 

 

0 Likes