Code branching to CyPmHviRestore

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

cross mob
DaHu_285096
Level 5
Level 5
10 likes received 250 replies posted 100 replies posted

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

0 Likes
1 Solution

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;

}

View solution in original post

0 Likes
5 Replies
himam_31
Employee
Employee
50 likes received 25 likes received 10 likes received

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

0 Likes
lock attach
Attachments are accessible only for community members.

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.

0 Likes

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

Regards,
Bragadeesh
0 Likes

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;

}

0 Likes

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.

0 Likes