- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The SPI Master control component does not work properly.
If I have an SPI Master component in my design, properly connected to some I/O Pins and try to send an Array of data to it, even if the size of the array easily fits into the defined buffer, then the SPI Component drops the SS line between each byte being output.
I believe that this is a bug in the implementation of the component.
The SS line should not be dropped bewteen bytes, as this signals the end of the transmission to the slave.
It makes it impossible to do sequential writes or reads to slave devices.
There are two possible work arounds that I can see:
1. Manually control the SS I/O Pin, but this is always going to be sub-optimal and some slave devices may not like the timing.
2. Manually disable / re-enable the TXInterrupt - but I do not think this will work, if using a buffer bigger than 4 bytes, then the SPIM_WriteTxData() method forcibly re-enables the interrupt anyway. And SPIM_PutArray() calls SPIM_WriteTxData().
So the SPI Master control does not work as intended unless you manually control the SS line. To do that you'd need to add an OR gate and an extra Output Pin (without hardware connection) or Control register to your design.
Having looked at the generated source I believe I can see what is happening...
When you use SPIM_PutArray() to write a numebr of bytes over SPI, it calls SPIM_WriteTxData() which in turn enables the TX Interrupt. The TX Interrupt fires and transfers the byte out the SPI Master. It then looks to see if there is any more data in the buffer - if not, then it releases the SS line. This happens while SPIM_PutArray() is still trying to write data into the buffer, but happens so quickly that it outruns the PutArray loop and the SS line gets released while data is still being added to the output buffer.
The fix would be to not call SPIM_TxWriteData until the buffer had been filled. If the array is to big to fit into the buffer, then as much as possible should be copied in, then an OVERFLOW error bit should be set and an error result returned (or, like POSIX writes) the actual number of bytes added to the buffer should be returned. Only when SPIM_PutArray() is done adding to the buffer should the TX Interrupt be enabled.
Regards,
Kenny.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Kenny,
I would strongly suggest to have Cypress informed about that issue. Can you please create a MyCase and support them with your tested projects?
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Bob
Sorry for the delay in replying - the email notification only arrived this morning.
Yes I will create a MyCase with some demo code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Another workaround is tor educe the SPI clock frequency. That increases the time it takes to write out data over SPI, giving the ISR more time to re-fill the TX buffer.
I think the next version of the SPI master data sheet will state that this is a known problem (and AFAIK there are no real workarounds).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you @hli
I think a good solution would be to have a SPIM_WriteArray(...) method that is non-blocking, returns the number of bytes actually added to the buffer, and doesn't start the TX Interrupt until it returns. The user can then poll the TX Status registers to see when the last byte has been trasnferred.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tep. This worked for me. Too bad this "feature" is not clearly stated in the manual...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Does somebody have simple SPI Master main.c code where Cypress kit CY8CKIT-042-BLE sends one byte to a accelerometer and receives one byte back? There are many functions in the SPI.c code and I don't know which ones to use. So far I have:
#include <project.h>
int main()
{
CyGlobalIntEnable; /* Enable global interrupts. */
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
SPIM_Start();
for(;;)
{
/* Place your application code here. */
SPIM_WriteTxData(0xF1u);
SPIM_WriteTxData(0xF1u);
SPIM_WriteTxData(0xF1u);
}
}
In the debugger I'd place a breakpoint on the third write thus there would be two writes, first one to write the address/read request into the slave and the second one to actually receive requested register content from the slave. The first write will also force the slave to empty its transmision register with whatever was there from before, correct?
Don't I need a loop to know when Master Rx register is full?
Any other function missing, enable etc?
In the part, do you use internal or external clock? I connect a clock to the SPI Master in the schematic.
Just trying to read/write to accelerometer for now with the kit connected via USB cable to the PC.
Thank you!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For every bit (byte) you send via SPI you receive one bit (bate) back.
SPIM_WriteTxData(0xF1u); returns before the byte is sent, there is a transmit buffer (and a receive buffer). Only when the Tx buffer is full the write function will wait.
As a consequence you will have to wait for a complete transmission before you will have received your data.
Depending on the type of SPI you used (SCB or UDB based) there are functions to check how many bytes are in the receive buffer
"The first write will also force the slave to empty its transmision register with whatever was there from before, correct?" Not quite.
You have to clear the input buffer yourself using the appropriate API. The output buffer will be emptied when the last byte is transmitted.
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Bob,
My SPI interface is also not working. I am trying to connect a CYBLE-022001 to an MCP3551 ADC using an SCB configured as a SPI master.
I am getting no proper communication, when I measure the SS pin it is never getting asserted low,
I've attached a workspace archive...could you please take a look and offer some advice about where I am going wrong
for(;;)
{
SPI_ss0_m_Write(0);
while( SPI_miso_m_Read()){
SPI_ss0_m_Write(0);
}
SPI_SpiUartWriteTxData(0x00);
CyDelayUs(1);
SPI_SpiUartWriteTxData(0x00);
CyDelayUs(1);
SPI_SpiUartWriteTxData(0x00);
CyDelayUs(01);
c.ab[2]= SPI_SpiUartReadRxData();
c.ab[1]= SPI_SpiUartReadRxData();
c.ab[0]= SPI_SpiUartReadRxData();
c.ab[3] =0x00;
SPI_ss0_m_Write(1);
SPI_SpiUartClearRxBuffer();
sprintf(Buffer,"Reaading :- %d", c.value);
UART_UartPutString(Buffer);
UART_UartPutString("\r\n");
while(SPI_SpiIsBusBusy());
CyDelay(1000);
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content