Post Go back to editing

I would like to look at a register level SPI example for the ADSP-SC573

Category: Choose a category

I would like to look at a register level SPI example for the ADSP-SC573. I managed to get my code to work but I don't know if I do things the optimal way.

I'm trying to figure out how code the following sequence (not using DMA or interrupts for now):

  1. Setup SPI0
  2. Set chip select low
  3. Send a few 16-bit words
  4. Set chip select high
  5. Turn off SPI0.

This is my code for now:

  // Setup SPI0 register settings
  *pREG_SPI0_CTL = 0x0; // Keep SPI module off while setting up registers
  *pREG_SPI0_SLVSEL = 0xFE20; // Set CS high
  *pREG_SPI0_CLK = 0xA;
  *pREG_SPI0_DLY = 0x301;
  *pREG_SPI0_RWC = 0;
  *pREG_SPI0_RWCR = 0;
  *pREG_SPI0_RXCTL = 0;
  *pREG_SPI0_TWC = 0;
  *pREG_SPI0_TWCR = 0;
  *pREG_SPI0_TXCTL = 0x5;
  *pREG_SPI0_RXCTL = 0x5;
  *pREG_SPI0_CTL = 0x203;

  *pREG_SPI0_SLVSEL = 0xDE20; // Set CS low
  *pREG_SPI0_TFIFO = 0xABDE; // Send data

  // Wait until one word has been received
  while ((*pREG_SPI0_STAT & BITM_SPI_STAT_RFS) == ENUM_SPI_STAT_RFIFO_EMPTY)
  {
    ; // Wait
  }

  uint32_t rxData1 = *pREG_SPI0_RFIFO;

  *pREG_SPI0_TFIFO = 0x123; // Send more data
  // Wait until one word has been received
  while ((*pREG_SPI0_STAT & BITM_SPI_STAT_RFS) == ENUM_SPI_STAT_RFIFO_EMPTY)
  {
    ; // Wait
  }

  uint32_t rxData2 = *pREG_SPI0_RFIFO;

  *pREG_SPI0_TFIFO = 0x4567; // Send more data
  // Wait until one word has been received
  while ((*pREG_SPI0_STAT & BITM_SPI_STAT_RFS) == ENUM_SPI_STAT_RFIFO_EMPTY)
  {
    ; // Wait
  }

  uint32_t rxData3 = *pREG_SPI0_RFIFO;

  *pREG_SPI0_SLVSEL = 0xFE20; // Set CS high
  *pREG_SPI0_CTL = 0x0; // Disable SPI



Pasted my new code (that works now).
[edited by: masip at 2:24 PM (GMT -4) on 30 Aug 2022]
  • I have managed to convert a lot of my code to use bare metal SPI registers. The time spent on SPI is much lower now. But now I have left my DMA based SPI routines that I would like to convert to register level. Anyone having any examples that I can look at? Examples for the blackfin would also work I think.

  • Hi,

    Please refer the below FAQ for ADSP-SC589. The code is used for data transfer using SPI peripheral. It can be used for core mode or DMA mode data transfer. Please take this as reference and modify it as per your requirement.

    ez.analog.com/.../adsp-sc58x-2158x-spi---example-code

    Regards,
    Anand Selvaraj

  • I have tried the example, thank you.

    But I had a problem when running the example. The DMA didn't see changes I made in the data before sending it (it clocked out the same data all the time). And the CPU didn't see the received data after receiving it (it saw the same data every time).

    I examined the ADI SPI drivers and found that it (at least before sending) flushes the cache. So I begun to test that.

    What is the proper way to flush the memory cache when using SPI DMA (in ARM core)?

    I have a txBuffer[] array that contains the data I want to send on the SPI. And I have an rxBuffer[] array that will collect all received data from SPI.

    I have setup the SPI and DMA using register level coding.

    I got Rx and Tx to work today by doing this:

    1. Update txBuffer[] with new data to be sent on SPI
    2. Call flush_data_buffer((void *)pFlushStartaddr, (void *)pFlushEndaddr, ADI_FLUSH_DATA_NOINV) så DMA will read the new data from txBuffer[]
    3. Setup SPI as master transmitter/receiver and DMA to send txBuffer[] and receive data to rxBuffer[]
    4. Call flush_data_buffer((void *)pFlushStartaddr, (void *)pFlushEndaddr, ADI_FLUSH_DATA_INV);  so CPU can see the new data in rxBuffer.

    So before sending data i called flush_data_buffer() with ADI_FLUSH_DATA_NOINV. And after receiving the SPI data I called flush_data_buffer() with ADI_FLUSH_DATA_INV.

    What is the technical difference between ADI_FLUSH_DATA_NOINV and ADI_FLUSH_DATA_INV?

    And is this the correct way to do this?

  • Hi,

    Apologies for the delay.

    Yes you are doing correctly if you are using external memory in your application.

    If your input data buffer resides in cacheable memory, then after modifying the buffer it should be flushed from memory using the flush_data_buffer API in the ADI_FLUSH_DATA_NOINV mode. This prevents the DMA transfer from accessing stale data. If your results buffer resides in cacheable memory, then before triggering the RX DMA channel to permit transferring new results, the buffer should be  flushed using the flush_data_buffer API in the ADI_FLUSH_DATA_NOINV mode. The data should then not be accessed until the RX DMA channel says the next set of results are ready. When the results are ready, the buffer should be invalidated by calling the flush_data_buffer API in the ADI_FLUSH_DATA_INV mode.

    The invalidate parameter indicates whether invalidation is also required, while flushing.
    ADI_FLUSH_DATA_NOINV Clean cache only and ADI_FLUSH_DATA_INV Clean and invalidate cache.

    To know more about flush_data_buffer please refer the below CCES help path.
    CrossCore® Embedded Studio <version> > System Run-Time Documentation > Cache and CPLBs > SHARC+ Caching Configuration and Support Functions > flush_data_buffer

    Regards,
    Anand Selvaraj.