SPI DMA operation

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

Hi,

I have not used the DMA yet and now looking at using it for Buffer to SPI and SPI to Buffer data transfer.

For beginning, I thought of using the example code in Creator for 5LP. It appears straight forward but how is the transmission initiated in a real world example?

Can I simply load data into txBuffer, wait till transfer complete and read results each time I want to transfer, like below?

sprintf(txBuffer,"some data"); //put new data in tx Buffer

while (0u == (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE))  { }  //.wait till transferred

for(i=0u; i<BUFFER_SIZE; i++)

  {

      LCD_PrintHexUint8(rxBuffer);  //read received data

   }

Thanks

0 Likes
4 Replies
DaHu_285096
Level 5
Level 5
10 likes received 250 replies posted 100 replies posted

Further to my Post, How do you specify how many bytes to send for any particular transaction?

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

Attached is my project connecting F-RAM to PSoC 3 with DMA.  This project is created by PSoC Creator 3.0 SP1.  So, I don't know if a recent PSoC Creator can be used.

You can find the same project on my GitHub repository at "GitHub - noritan/Design116_3p0_3: F-RAM test project using SPI "

It seems that the data length is specified by the CyDmaTdSetConfiguration() API function.

    // Initialize DMA RX descriptors

    DMA_RX_Chan = DMA_RX_DmaInitialize(

        DMA_RX_BYTES_PER_BURST, DMA_RX_REQUEST_PER_BURST,

        HI16(DMA_RX_SRC_BASE), HI16(DMA_RX_DST_BASE)

    );

    DMA_RX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_RX_TD[0],

        sizeof misoBuffer,

        CY_DMA_DISABLE_TD,

        TD_INC_DST_ADR | DMA_RX__TD_TERMOUT_EN

    );

    CyDmaTdSetAddress(DMA_RX_TD[0],

        LO16((uint32)SPIM_RXDATA_PTR), LO16((uint32)misoBuffer.stream)

    );

    CyDmaChSetInitialTd(DMA_RX_Chan, DMA_RX_TD[0]);

Regards,

Noriaki

0 Likes

Thanks,

Would something like below work? Where I re-init the dma each call with new numBytes to send/receive. Would I still need the "CyDmaChSetRequest(..." function if I am reinitializing the dma each call?

CY_ISR(DMA_RX_INT_ISR) {

    DMA_RX_completed = 1;

}

void spiWrite(uint8 numBytes) {

   

    txBuffer[0] = dat0;

    txBuffer[1] = dat1;

    txBuffer[2] = dat2;

dmaInit(numBytes);

       

    CyDmaChSetRequest(DMA_TX_Chan, CY_DMA_CPU_REQ); ???

       

    // Wait for transfer completed

    while (!DMA_RX_completed) ;

}

void dmaInit(uint8 numBytes) {

    // Initialize DMA TX descriptors

    DMA_TX_Chan = DMA_TX_DmaInitialize(

        DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST,

        HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE)

    );

    DMA_TX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_TX_TD[0],

        numBytes,

        CY_DMA_DISABLE_TD,

        TD_INC_SRC_ADR

    );

    CyDmaTdSetAddress(DMA_TX_TD[0],

        LO16((uint32)mosiBuffer.stream), LO16((uint32)SPIM_TXDATA_PTR)

    );

    CyDmaChSetInitialTd(DMA_TX_Chan, DMA_TX_TD[0]);

   

    // Initialize DMA RX descriptors

    DMA_RX_Chan = DMA_RX_DmaInitialize(

        DMA_RX_BYTES_PER_BURST, DMA_RX_REQUEST_PER_BURST,

        HI16(DMA_RX_SRC_BASE), HI16(DMA_RX_DST_BASE)

    );

    DMA_RX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_RX_TD[0],

        numBytes,

        CY_DMA_DISABLE_TD,

        TD_INC_DST_ADR | DMA_RX__TD_TERMOUT_EN

    );

    CyDmaTdSetAddress(DMA_RX_TD[0],

        LO16((uint32)SPIM_RXDATA_PTR), LO16((uint32)misoBuffer.stream)

    );

    CyDmaChSetInitialTd(DMA_RX_Chan, DMA_RX_TD[0]);

}

Main Loop

...

spiWrite(3);

for(int i = 0; i < numBytes ; i++)

{

  //do something with rxBuffer

}

...

0 Likes

It is required to call CyDmaChSetRequest(DMA_TX_Chan, CY_DMA_CPU_REQ); to start a DMA transfer with or without initialization.  By calling this API, the DMA writes a byte to the SPI data register and the SPI starts a transfer sequence.

In addition, don't forget to enable the DMA channel when starting a DMA sequence.

Regards,

Noriaki

0 Likes