cancel
Showing results for 
Search instead for 
Did you mean: 

DMA with eTimer and GPIO

raghu tumati
Associate II
Posted on October 03, 2017 at 19:25

Hi 

I'm using the SPC560P40L1

Im trying to switch a GPIO using pre-defined data stored in memory. I would like the GPIO to switch after a rising edge on a PWM pin which is being monitored by ETC/eTimer. I also need the DMA to control all of this. The CPU is pretty loaded already. 

Is there an example code I could use? Im using the SPC5studio and they only have examples of DMA use with SPI and ADC. 

I looked at the reference manual and that is not easy to start of with as a beginner to DMA  

Can anyone point me in the right direction to get started?

-Thanks

8 REPLIES 8
Erwan YVIN
ST Employee
Posted on October 04, 2017 at 11:12

Hello Raghu,

Sorry , There is no DMA drivers with ETC/eTIMER

and we have no example with

SPC560P40L1

0690X00000608T0QAI.png

You can create your own configuration by API

You can use DMA_MUX Channel 16,17,18,19 for eTimer

SPC5_ADC0_DMA_DEV_ID ==> Channel 16

Do not hesitate to update the file icu_lld.c to follow the ADC Example below (by the patch mode)

  • Driver Structure Modification
  • to integrate the Allocation
  • to integratethe starting

/**
 * @brief DMA configuration for ADC0.
 */
#if SPC5_ADC_USE_ADC0 || defined(__DOXYGEN__)
#if (SPC5_ADC_DMA_MODE == SPC5_ADC_DMA_ON) || defined(__DOXYGEN__)
static const edma_channel_config_t adc_adc0_dma_config = {
 SPC5_ADC_ADC0_DMA_CH_ID,
 SPC5_ADC0_DMA_DEV_ID,
 SPC5_ADC_ADC0_DMA_IRQ_PRIO,
 adc_serve_adc_irq, adc_serve_dma_error_irq, &ADCD1
};
#endif /* SPC5_ADC_DMA_MODE */
#endif /* SPC5_ADC_USE_ADC0 */�?�?�?�?�?�?�?�?�?�?�?�?�?

For init,

adcp->adc_dma_channel = edmaChannelAllocate(&adc_adc0_dma_config);�?

For Start,

#if SPC5_ADC_DMA_MODE == SPC5_ADC_DMA_ON
 /* Starting DMA channels.*/
 edmaChannelStart(adcp->adc_dma_channel);
#endif /* SPC5_ADC_DMA_MODE */�?�?�?�?

Best regards

Erwan

Posted on October 04, 2017 at 23:27

Hi Erwan 

Thanks for the reply. But what about switching the GPIO using the DMA (DMA transfers data between memory and GPIO). Is that possible? 

I do not think it is from the following line in the manual,

  • DMA transfers possible between system memories, DSPIs, ADC, FlexPWM, eTimer and CTU

but just wanted to confirm with you. 

In which case maybe I can use one of the DSPI pins to switch following a memory map? So using the DSPI pins to output a certain data from memory and make it function like a GPIO. 

I still need the DMA transfer to start after an interrupt from eTimer ICU. 

Do you have any suggestions that could make this easier or am I on the right path? 

Erwan YVIN
ST Employee
Posted on October 05, 2017 at 11:27

Hello Raghu ,

for GPIO Ports, you have to use the Onchip Memory

'Using the GPIO Ports to drive or sample waveforms. By configuring the DMA to transfer

data to one or more GPIO ports, it is possible to create complex waveforms using

tabular data stored in on-chip memory. Conversely, using the DMA to periodically

transfer data from one or more GPIO ports, it is possible to sample complex waveforms

and store the results in tabular form in on-chip memory.'

Use eTimer /CTU/DSPI (Cf Table 246).

if you enable DMA Transfer for eTimer ICU, the DMA Interrupt will be handled not the ICU Interrupt.

Check DMA MUX (Chapter 20)

For RLA & HAL Drivers , there are a nice example how to configure the DMA Channel.

      Best regards

                                  Erwan

Posted on October 06, 2017 at 01:41

Hi Erwan

I looked at the section you referenced and it mentions to use a PIT to configure a periodic SPI or GPIO transfer. 

But in the PIT section, there is no information on how to setup trigger for DMA? Is it automatic i.e as soon as I enable the PIT, will it generate a continuous trigger depending on its period? Do I need to enable the PIT interrupt? 

'Besides the normal routing functionality, the first four channels of the DMA Mux provide a special periodic triggering capability that can be used to provide an automatic mechanism to transmit bytes, frames or packets at fixed intervals without the need for processor intervention. The trigger is generated by the Periodic Interrupt Timer (PIT); as such, the configuration of the periodic triggering interval is done via configuration registers in the PIT. Please refer to Chapter 31: Periodic Interrupt Timer (PIT) for more information on this topic'

Erwan YVIN
ST Employee
Posted on October 06, 2017 at 10:56

Hello Raghu ,

the PIT is used only for the DMA triggering.

First , configure 1 PIT channel (#1 , #2, #3 or #4) with your timer settings

Second, you have to use the corresponding DMA Channel #0 to DMA Channel #3 in settings the good source..

0690X00000608VbQAI.png

  

   Best regards

              Erwan

Posted on October 10, 2017 at 23:48

Hi Erwan

I have the following configuration set for using DSPI_1 TX which is source 3 for my device for using DMA with PIT

1. Configure DSPI1 TX1 for Ch 2

2. Configure PIT CH 3. PIT timer is set for ~15KHz

3. Write 0xC3 to CH2CONFIG register. 

But I am confused about how to implement the spi_lld_send(&SPID2, 256, buff) command for periodic data to be sent. Do I have to implement this in a for loop. Right now I do not see any data being sent on the TX pin. I have tried both in an infinite for loop and outside of it with the same result. 

I have confirmed the PIT working with a GPIO pin toggle in a callaback.

I have also confirmed the DMA SPI transfer just by itself. If I set CH2CONFIG to 0x83, and implement spi_lld_send(&SPID2, 256, buff)  in a infinite for loop, I can see output on TX pin continuously. 

but PIT with DSPI using DMA is not working. My final goal is to send SPI data at 15KHz timing and change the SPI data every now and then. Would appreciate any feedback...  

Posted on October 19, 2017 at 01:19

Hi Erwan 

Any chance you have an update on my question?

-Thanks

Posted on October 19, 2017 at 11:15

Hello Raghu ,

No loop is required.you should configure your edma descriptors in order to map with DSPI.PUSHR in your case

(Cf below as example)

// Transfer Control Descriptor for DSPI C TFFF
 EDMA.TCD[2].SADDR = (vuint32_t) &DSPI_TXQUEUE[0]; // Start Address
 EDMA.TCD[2].DADDR = DSPIPUSHR; // Destination address
 EDMA.TCD[2].SMOD = 0x00; // Source address modulo
 EDMA.TCD[2].DMOD = 0x00; // Destination address modulo
 EDMA.TCD[2].DSIZE = 0x02; // Destination transfer size : 32 Bits
 EDMA.TCD[2].SSIZE = 0x02; // Source transfer size : 32 Bits
 EDMA.TCD[2].SOFF = 0x4; // Signed source address offset
 EDMA.TCD[2].NBYTES = 0x4; // Inner 'minor' byte count
 EDMA.TCD[2].SLAST = 0; // last Signed source address adjust
 EDMA.TCD[2].DOFF = 0x0; // Signed destination address offset
 EDMA.TCD[2].DLAST_SGA = 0x0; // Signed destination address adjust
 EDMA.TCD[2].BITERE_LINK = 0x0; // //Channel-to-channel Linking on Minor Loop Complete
 EDMA.TCD[2].BITER = 0x1; // begining 'major' iteration count
 EDMA.TCD[2].CITERE_LINK = 0x0; // Channel-to-channel Linking on Minor Loop Complete
 EDMA.TCD[2].CITER=0x1; // Current “major�? iteration count Disabled
 EDMA.TCD[2].BWC = 0x00; // Bandwidth control : No DMA Stalls
 EDMA.TCD[2].MAJORLINKCH = 0x00; // Major Channel number
 EDMA.TCD[2].MAJORE_LINK = 0x0; // Major Channel Link : Disabled
 EDMA.TCD[2].DONE = 0x00; // Channel Done
 EDMA.TCD[2].ACTIVE = 0x00; // Channel ACtive
 EDMA.TCD[2].E_SG = 0x0; // Enable Scatter/Gather : Disabled
 EDMA.TCD[2].D_REQ = 0x0; // Do NOT disable TCD When done
 EDMA.TCD[2].INT_HALF = 0x0; // Interrupt on minor loop count
 EDMA.TCD[2].INT_MAJ = 0x0; // Interrupt on major loop completion : Disabled
 EDMA.TCD[2].START = 0x00; // Explicit Channel Start bit�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

in IRQ #13 for Channel 2 , you can prepare in dma done in order to prepare the next frames to send.

Best regards

Erwan