- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I note a gap between each byte in an array being sent over SPI (using 5LP SPIM component).
Is there a way to prevent this? I assume that it is caused by software polling to see when byte has been sent.
My code is sending and receiving an array and can be blocking until all bytes have been sent.
I have seen DMA used but would this be useful mainly when you want to continue processing other commands while SPI is being sent.
Maybe I should be using an interrupt and checking the the flag instead of reading SPI status between each byte?
Thanks
- Labels:
-
PSoC 5 Device Programming
-
PSoC 5LP
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Have you tried SPIM_PutArray() function?
For sending an array it might be better.
We had some discussion using that function in the topic below.
Although the topic is for PSoC 4, PSoC 5LP's SPM also has
void SPIM_PutAttry(const uint8 buffer[], uint8 byteCount) ;
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am still a bit lost. Is the requirement to load the first byte only used for Slave but master does not need to do it and do I need to check SPI is ready before sending or do I do as below
int readfromspi(uint16 headerLength, const uint8 *headerBuffer, uint32 readlength, uint8 *readBuffer)
{
int i=0;
CS_Write(0);
SPIM_PutArray( headerBuffer, headerLength ); //Send Read command to device
while(!(SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)){}; //wait till sent //wait till all bytes sent
SPIM_PutArray( readBuffer, readlength ); //read all bytes by sending dummy bytes
while(!(SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)){}; //wait till sent
for(i=0; i<(int)readlength; i++) //get received data from Spi received buffer
{
readBuffer = SPIM_ReadRxData();
}
SPIM_ClearRxBuffer();
CS_Write(1);
return 0;
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
> I am still a bit lost. Is the requirement to load the first byte only used for Slave
> but master does not need to do it and do I need to check SPI is ready
> before sending or do I do as below
I'm sorry your English is too difficult for me.
Would you make your sentence shorter and separate topic in each sentence?
I think that you are talking about the SPIS specification.
Yes, SPIS put 0 for the first byte, so if we want to have our data from the first byte
we needed to re-wind the pointer then fill the data from the first byte.
Although this is stated in the Datasheet, I'd rather call it a bug.
Are you planning to use SPIS, too?
Then you need to care this "feature", but otherwise you don't have to care about it.
Now my question is by using SPIM_PutArray(), was the gap you were hoping to get rid of taken care of?
Or is/are there still gap between each byte?
> ... or do I do as below
As I don't know about the slave connected to your SPIM, I can not predict the behavior of the slave
but I would add
SPIM_ClearRxBuffer() ;
before receiving the result.
And depending on the slave, may be we need to add some delay between
sending header and receiving the result.
So I would modify readfromspi() referring the previous topic something like
=====================
/* note this is an "IDEA SKETCH" and has not been tested */
int readfromspi(uint16 headerLength, const uint8 *headerBuffer, uint32 readlength, uint8 *readBuffer)
{
int i = 0 ;
uint8_t rxBufSz ;
SPIM_ClearRxBuffer() ;
SPIM_ClearTxBuffer() ;
/* Start transfer */
SPIM_PutArray( headerBuffer, headerLength );
/* Wait for the end of the transfer. In SPI, the number of transmitted data
elements has to be equal to the number of received data elements. */
rxBufSz = SPIM_GetRxBufferSize();
while( headerLength != rxBufSz ) {
rxBufSz = SPIM_GetRxBufferSize();
}
/* may be we need to allow some time for the slave to prepare data */
SPIM_ClearRxBuffer() ;
SPIM_PutArray(readBuffer, readlength);
while(readlength != rxBufSz ) {
rxBufSz = SPIM_GetRxBufferSize();
}
for (i = 0 ; i < readlength ; i++ ) {
mRxBuffer = SPIM_ReadRxData() ;
}
return 0 ;
}
=====================
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This code cause the micro to lock up at first getRxBufferSize.
I am surprised how few examples or tutorials I can find for SPI on the PSOC. Some are simple send 1 byte and receive 1 byte and some using DMA. Some of the examples clear the buffers during the routine and others don't and the datasheet does not appear to stipulate what MUST be done for proper transfer.
I cannot find any decent examples showing how to read a block of data from an external device. The PSOC 4 did have an example for FRAM but it was clearing the buffers every read or write and waiting for each write to end before continuing and resulting in gaps between digits.
For your example, are you assuming the buffer size is set to 4 in the component and not using the internal circular buffer?
I also looked around for any decent ebooks for PSOC but could not find much at all.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
> This code cause the micro to lock up at first getRxBufferSize.
That is not a good sign, but probably it's
SPIM_PutArray( headerBuffer, headerLength );
who triggered the problem.
> I am surprised how few examples or tutorials I can find for SPI on the PSOC.
I totally agree with you. Meantime, the behavior of SPI(M) needs to be adjusted depending on the behavior of the Slave and there are many different behavior(s) from different Slaves, so unless you specify the Slave, it it impossible to specify the exact behavior of a Master.
> For your example, are you assuming the buffer size is set to 4 in the component and not using the internal circular buffer?
In the previous discussion we were assuming 16.
I suppose that the SPIM_PutArray() assumes that the Buffer size is bigger or equal to the length of the buffer to be sent.
So I wonder how big is your headerLength and readlength?
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think I need to use DMA to get rid of the delays. Are there any "simple" tutorials that show how to get data from SPI to array in memory and visa versa?
The packet sizes for the data are specified in the calling routines and are different for various parts of the application so I need to be able to start the DMA each time with different number of bytes to send and receive.
Also, the function using the DMA needs to stay in the routine until received bytes are loaded in the receive buffer before returning.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm sorry for could not be a help.
> I think I need to use DMA to get rid of the delays.
> Are there any "simple" tutorials that show how to get data from SPI to array in memory and visa versa?
I, myself do not know such tutorial nor application notes,
there may be some though.
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do you know how I can get help from Cypress Technical Support? The support has gone and now referred just to the forum but I cannot get the answers I need or appropriate documentation.
The most hopeful info I found was a post by Bob. I am attempting to rearrange it to suit as per the code below but not sure if this will work.
I am not sure whether you just write data to the tx buffer and it automatically sends (So, for example: If I was reading from external SPI ram device should I simply set CS low, write the command bytes and dummy bytes for read and then once tx is done I can assume all received data is in the buffer ready to use?
I have not used DMA before. I assume once set up it is the writing to data buffer that triggers the send and then receive happens as incoming data arrives at spi device.
Also not sure what I need to call to update the Buffer size (in my attempt below I have re-called the configuration with buffer size as a parameter. But not sure if all I really need to do is write to this line
CyDmaTdSetConfiguration(txTD, bufLength*sizeof(DataItem), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR);
#include <project.h>
void DmaTxConfiguration(uint8 bufLength);
void DmaRxConfiguration(uint8 bufLength);
/* DMA Configuration for DMA_TX */
#define DMA_TX_BYTES_PER_BURST (sizeof(DataItem))
#define DMA_TX_REQUEST_PER_BURST (1u)
#define DMA_TX_SRC_BASE (CYDEV_SRAM_BASE)
#define DMA_TX_DST_BASE (CYDEV_PERIPH_BASE)
/* DMA Configuration for DMA_RX */
#define DMA_RX_BYTES_PER_BURST (sizeof(DataItem))
#define DMA_RX_REQUEST_PER_BURST (1u)
#define DMA_RX_SRC_BASE (CYDEV_PERIPH_BASE)
#define DMA_RX_DST_BASE (CYDEV_SRAM_BASE)
#define BUFFER_SIZE (8u)
#define STORE_TD_CFG_ONCMPLT (1u)
#if(SPIM_USE_SECOND_DATAPATH)
typedef uint16 DataItem; // Set this to uint8 or uint16
#else
typedef uint8 DataItem;
#endif
/* Variable declarations for DMA_TX*/
uint8 txChannel;
uint8 txTD;
/* Variable declarations for DMA_RX */
uint8 rxChannel;
uint8 rxTD;
DataItem txBuffer [BUFFER_SIZE] = {0x0u};
DataItem rxBuffer[BUFFER_SIZE] = {0};
void SendSpi(uint8 numBytes){
uint8 i;
DmaTxConfiguration(numBytes);
DmaRxConfiguration(numBytes);
txBuffer[0] = 0x01;
txBuffer[1] = 0x02;
txBuffer[2] = 0x03;
while (0u == (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE))
{
}
//At this point rxBuffer holds all receive data??
}
int main()
{
uint8 i;
SPIM_Start();
CyDmaChEnable(rxChannel, STORE_TD_CFG_ONCMPLT);
CyDmaChEnable(txChannel, STORE_TD_CFG_ONCMPLT);
for(;;)
{
SendSpi(3);
CyDelay(100);
}
}
void DmaTxConfiguration(uint8 bufLength)
{
txChannel = DMA_TX_DmaInitialize(DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST,
HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE));
txTD = CyDmaTdAllocate();
CyDmaTdSetConfiguration(txTD, bufLength*sizeof(DataItem), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR);
CyDmaTdSetAddress(txTD, LO16((uint32)txBuffer), LO16((uint32) SPIM_TXDATA_PTR));
CyDmaChSetInitialTd(txChannel, txTD);
}
void DmaRxConfiguration(uint8 bufLength)
{
rxChannel = DMA_RX_DmaInitialize(DMA_RX_BYTES_PER_BURST, DMA_RX_REQUEST_PER_BURST,
HI16(DMA_RX_SRC_BASE), HI16(DMA_RX_DST_BASE));
rxTD = CyDmaTdAllocate();
CyDmaTdSetConfiguration(rxTD, bufLength*sizeof(DataItem), CY_DMA_DISABLE_TD, TD_INC_DST_ADR);
CyDmaTdSetAddress(rxTD, LO16((uint32)SPIM_RXDATA_PTR), LO16((uint32)rxBuffer));
CyDmaChSetInitialTd(rxChannel, rxTD);
}
/* [] END OF FILE */
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
> Do you know how I can get help from Cypress Technical Support?
> The support has gone and now referred just to the forum but I cannot get the answers I need or appropriate documentation.
I will try to send a message to the Community Manager to contact you about accessing the Technical Support.
(BTW, I am not a Cypress Employee, though)
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The DMA method will be effective only if the number of bytes is fixed. Otherwise also you can use it. However if you want to chnag eth enumber of bytes very frequently it migh not be an effective way. For changing the number of bytes you will need to disable the DMA channel and then reconfigure the DMA.
Can you please have a look at the thread: Problem SPI with DMA
Thanks,
Hima
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your response Hima,
I will try the approach given in the link you provided.
The small delay at start or end of entire function is ok as long as I can run the transfer at max. rate without gaps, it should be fine
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hima,
I attached the files in the wrong forum. I replied to your post for the branching problem but it should have been here. The only issue right now is the speed to spi transactions.
Attached are my project, information regarding speed of spi transfer and a snippet from the datasheet showing spi timing diagram.
I need max. rate spi with no inter-digit gaps.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello David,
As per the expectation there will not be inter byte delay if you have data in the RX buffer all the time. If DMA is able to load the data at the rate at which the data is being sent. The maximum data rate is application specific mostly as the the main factor limiting the maximum data rate between the master and slave is the round trip path delay.
DMA transfer will happen faster if the drq is configured as level triggered and the Tx Rx flags are configured as given in the code example "SPIM_Example" in PSoC Creator. We do not have a characterised value to give since this is more application dependent.
Are you facing inter byte delay even after implementing DMA based transfer?
Thanks,
Hima
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hima,
The DMA has removed the inter-byte delay. The routines appear to be working ok now. Except the application is not reliable. For my prototype, I have long wires dangling between the PSOC and the device and I suspect I am getting poor transfer as a result. However, It the waveforms look good on the Logic Analyzer.
I have designed a PCB with the 5LP right next to the device to keep tracks short and will try it on the new board.
If I still have trouble I would be interested in finding someone (happy to pay them if needed) to send the small test PCB and Code and ask them to help me debug my application. Do you know anyone I could approach or a link where I could request?
Thanks