- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am currently working on a project that controls an external device using SPI.
When I attempt to write data to some locations in the external SPI device and read them back, the program locks up in the read routine by jumping to CyPmHviLviRestore()?
Could this be a pointer issue? This is my calling code
void TestSpi(void){
uint8 dataA[20] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
uint8 dataB[20];
dwt_writetodevice(0x21,0, 20,dataA);
dwt_readfromdevice(0x21,0,20,dataB);
asm("nop");
}
The code doing the work is here
int readfromspi(uint16 headerLength, const uint8 *headerBuffer, uint32 readlength, uint8 *readBuffer)
{
int i=0;
volatile uint8 rxbuf[4];
CS_Write(0);
for(i=0; i<headerLength; i++)
{
SPIM_WriteTxData(headerBuffer); //write command to device
while(!(SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)){}; //wait till sent
readBuffer = SPIM_ReadRxData() ; //read any received data
}
for(i=0; i<(int)readlength; i++)
{
SPIM_WriteTxData(0x00); //dummy write for each byte to read
while(!(SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)){}; //wait till each byte done
readBuffer = SPIM_ReadRxData();
rxbuf = readBuffer;
}
CS_Write(1);
return 0;
}
Thanks
Solved! Go to Solution.
- Labels:
-
PSoC 5LP
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Bragadeesh,
I really appreciate you have taken the time to dig into the code and find this.
The code was written by third party and I am porting it to PSOC.
Line 80 does not make sense, it should be if number of bytes >= RX_BUF_LEN (which is 12 bytes) because that line will always only process rx_buffer and should never have 1024 bytes.
I have changed the spi routine to use the DMA (adopted from another forum post) now and managed to get rid of the inter-digit gaps. (snippet below), Will also take a look at clock divider, I did not realize the actual divider value was supplied value + 1.
The code below looks good on logic analyzer but in the main look it sometimes gets wrong values from spi when running at 16MHz. I thing the hardware is causing this because I have quite long wires dangling around between the PSOC 5 kit and the device. I will lay up a PCB with short tracks and test again.I am able to supply the slave device if anyone is willing to help run through and check the code with device connected.
int readfromspi(uint16 headerLength, const uint8 *headerBuffer, uint32 readLength, uint8 *readBuffer)
{
const uint8_t DMA_REQUEST_PER_BURST = 1;
const uint8_t DMA_BYTES_PER_BURST = 1;
uint8_t DMA_Rx_Chan = 0;
uint8_t DMA_Tx_Chan = 0;
uint8_t DMA_Rx_TD[1] = {0};
uint8_t DMA_Tx_TD[1] = {0};
uint8 size;
uint8 tx_data[50];
uint8 rx_data[50];
size = headerLength + readLength;
memcpy(tx_data,headerBuffer, headerLength);
memcpy(tx_data + headerLength, readBuffer, readLength);
// Allocate DMA Channels
DMA_Rx_Chan = DMA_Rx_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST,
HI16(CYDEV_PERIPH_BASE), HI16(CYDEV_SRAM_BASE));
DMA_Tx_Chan = DMA_Tx_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST,
HI16(CYDEV_SRAM_BASE), HI16(CYDEV_PERIPH_BASE));
// Allocate TDs
DMA_Rx_TD[0] = CyDmaTdAllocate();
DMA_Tx_TD[0] = CyDmaTdAllocate();
CyDmaTdSetConfiguration(DMA_Rx_TD[0], size, CY_DMA_DISABLE_TD, CY_DMA_TD_INC_DST_ADR);
CyDmaTdSetConfiguration(DMA_Tx_TD[0], size, CY_DMA_DISABLE_TD, CY_DMA_TD_INC_SRC_ADR);
CyDmaTdSetAddress(DMA_Rx_TD[0], LO16((uint32)SPIM_RXDATA_PTR), LO16((uint32)&rx_data[0]));
CyDmaTdSetAddress(DMA_Tx_TD[0], LO16((uint32)&tx_data[0]), LO16((uint32)SPIM_TXDATA_PTR));
CyDmaChSetInitialTd(DMA_Rx_Chan, DMA_Rx_TD[0]);
CyDmaChSetInitialTd(DMA_Tx_Chan, DMA_Tx_TD[0]);
// enable the DMAs
CyDmaChEnable(DMA_Rx_Chan, 1);
CyDmaChEnable(DMA_Tx_Chan, 1);
while(0 == (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)) {}
/* Freeing the DMA Channel and TDs */
CyDmaChDisable(DMA_Rx_Chan);
CyDmaChDisable(DMA_Tx_Chan);
CyDmaTdFree(DMA_Rx_TD[0]);
CyDmaTdFree(DMA_Tx_TD[0]);
memcpy(readBuffer,rx_data+headerLength,size - headerLength);
return 0;
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello David,
Can you please attach the complete Creator project, so that we can review the project. Also can you please let us know which device exactly is acting as the slave?
Thanks,
Hima
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hima,
Project attached.
Device is Decawave DWM1000 ultra wide band rf module.
The spi functions are in deca_spi.
The problem is the time it takes to execute from line 75 in main.c -> if (status_reg & SYS_STATUS_RXFCG) until transmit is too long and causes timeout that prevents transmission.
This code was ported from an STM32 based project. They also have an arduino version that runs on a relatively slow processor but they manage to get spi up around 20 MHz.
The company has an app note regarding the spi that is also attached.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi user_343349849,
In your code, in the following line,
LINE 80: if (frame_len <= RX_BUFFER_LEN) //if correct number of bytes received then process data
{
dwt_readrxdata(rx_buffer, frame_len, 0);
}
You have defined RX_BUFFER_LEN to be 1024. So I assume you can receive up to 1024 bytes of data (or maybe less). But you have defined static uint8 rx_buffer[12]; as 12 bytes. Also inside the readfromspi() you have defined volatile uint8 rxbuf[4]; as 4 bytes. When I modified these two buffers to 1024 bytes, this error did not occur.
Since we don't have an actual slave that can respond as per your slave, this may or may not be the problem. Please check it from your actual setup and let us know.
Also I noticed the following in your code. In deca_spi.c, you have set the clock divider value as
void spi_set_rate_low (void)
{
SPI_Clock_SetDividerValue(9); //48 MHz Master / 9 = 5.33 MHz Clock = 2.66MHz bit rate
}
void spi_set_rate_high (void)
{
SPI_Clock_SetDividerValue(2); //48 MHz Master / 2 = 24 MHz Clock = 12MHz bit rate
}
But please note that the value given in the function is not the actual clkDivider. It is ClkDivider + 1 . Say you need to divide the clock by 2 (48Mhz/2 = 24 Mhz), you need to set the SetDividerValue as 1 and not 2. Please take this into account.
Regards,
Bragadeesh
Bragadeesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Bragadeesh,
I really appreciate you have taken the time to dig into the code and find this.
The code was written by third party and I am porting it to PSOC.
Line 80 does not make sense, it should be if number of bytes >= RX_BUF_LEN (which is 12 bytes) because that line will always only process rx_buffer and should never have 1024 bytes.
I have changed the spi routine to use the DMA (adopted from another forum post) now and managed to get rid of the inter-digit gaps. (snippet below), Will also take a look at clock divider, I did not realize the actual divider value was supplied value + 1.
The code below looks good on logic analyzer but in the main look it sometimes gets wrong values from spi when running at 16MHz. I thing the hardware is causing this because I have quite long wires dangling around between the PSOC 5 kit and the device. I will lay up a PCB with short tracks and test again.I am able to supply the slave device if anyone is willing to help run through and check the code with device connected.
int readfromspi(uint16 headerLength, const uint8 *headerBuffer, uint32 readLength, uint8 *readBuffer)
{
const uint8_t DMA_REQUEST_PER_BURST = 1;
const uint8_t DMA_BYTES_PER_BURST = 1;
uint8_t DMA_Rx_Chan = 0;
uint8_t DMA_Tx_Chan = 0;
uint8_t DMA_Rx_TD[1] = {0};
uint8_t DMA_Tx_TD[1] = {0};
uint8 size;
uint8 tx_data[50];
uint8 rx_data[50];
size = headerLength + readLength;
memcpy(tx_data,headerBuffer, headerLength);
memcpy(tx_data + headerLength, readBuffer, readLength);
// Allocate DMA Channels
DMA_Rx_Chan = DMA_Rx_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST,
HI16(CYDEV_PERIPH_BASE), HI16(CYDEV_SRAM_BASE));
DMA_Tx_Chan = DMA_Tx_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST,
HI16(CYDEV_SRAM_BASE), HI16(CYDEV_PERIPH_BASE));
// Allocate TDs
DMA_Rx_TD[0] = CyDmaTdAllocate();
DMA_Tx_TD[0] = CyDmaTdAllocate();
CyDmaTdSetConfiguration(DMA_Rx_TD[0], size, CY_DMA_DISABLE_TD, CY_DMA_TD_INC_DST_ADR);
CyDmaTdSetConfiguration(DMA_Tx_TD[0], size, CY_DMA_DISABLE_TD, CY_DMA_TD_INC_SRC_ADR);
CyDmaTdSetAddress(DMA_Rx_TD[0], LO16((uint32)SPIM_RXDATA_PTR), LO16((uint32)&rx_data[0]));
CyDmaTdSetAddress(DMA_Tx_TD[0], LO16((uint32)&tx_data[0]), LO16((uint32)SPIM_TXDATA_PTR));
CyDmaChSetInitialTd(DMA_Rx_Chan, DMA_Rx_TD[0]);
CyDmaChSetInitialTd(DMA_Tx_Chan, DMA_Tx_TD[0]);
// enable the DMAs
CyDmaChEnable(DMA_Rx_Chan, 1);
CyDmaChEnable(DMA_Tx_Chan, 1);
while(0 == (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)) {}
/* Freeing the DMA Channel and TDs */
CyDmaChDisable(DMA_Rx_Chan);
CyDmaChDisable(DMA_Tx_Chan);
CyDmaTdFree(DMA_Rx_TD[0]);
CyDmaTdFree(DMA_Tx_TD[0]);
memcpy(readBuffer,rx_data+headerLength,size - headerLength);
return 0;
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
PS. Not sure why they use 16 bit for header length and 32 bit for body. I think the max number of bytes in any transfer would be less than 100. Te code seems to be all over the place.