PWM generation using DMA

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

cross mob
Not applicable
Hello,

I want to generate a pwm using the direct memory access. For that I´ve also read the following threads, but they didn´t help on my problem:

https://www.infineonforums.com/archive/index.php/t-927.html?
and
https://www.infineonforums.com/archive/index.php/t-940.html?

My problem is the following:
I want to store a defined number of pwm duty cycles for example for 50 pwm periods in an array and then I want to start the pwm and the controller cares for the 50 periods without any interaction with my motor
control task (feedback loops and so on). During this task I´m calculating the duty cycles for the next 50 periods to be ready to be transfered at the end if the first 50 elements.
Do I have to use the timer compare event to trigger the dma to transfer the new duty cycle value and to write some value into the shadow register? How can I transfer these values from an array in memory to different memory
lcations(pwm/timer register). For example for only one pwm there is the high threshold(HT), the low threshold(LT) and the shadow register(SR). All these 3 registers can be found in different memory locations. Now I want to transfer them with
each trigger. My first trial was a linked list. So I have an array(list) for the HT values, an array for the LT values and an array for the SR values. I was not able to organize the dma transfer in a way that at the first trigger only the first elements
of each array were transferred and on the second trigger the second entries and so on.
Or is there another comfortable way to generate a pwm sequence using the dma?
I have already implemented a solution on STM32F407 for a while and now I have to do it the same way for a very important customer on the xmc4500.

Can you provide a running example or something like? Because I was not able to find a suitable solution for my high priority problem.

Kind regards
Sandro
0 Likes
4 Replies
lock attach
Attachments are accessible only for community members.
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hello Sandro,

Find attached an example.
Let us know if you need further help.

Regards,
Jesus
0 Likes
Not applicable
Hello Jesus,

thank you very much for the provided code. I will check this out. What would be your advice to generate 6 different pwms using linked lists? I wanted to do it the following way:

1. defining an array for the duty cycles for pwm1 as source_buffer0
2. defining an array for the shadow register values1 as source_buffer1
.....
11. defining an array for the duty cycles for pwm6 as source_buffer6
12. defining an array for the shadow register values6 as source_buffer6

each dma transfer should only the n-th value f each array above. Here is some example code I wr


/***************************************************************************************
* Includes (scope: module-local)
***************************************************************************************/
/* include header corresponding to this c-file */
#include "xmc4500_dma.h"
#include "xmc4500_timer.h"
/***************************************************************************************
* Constants and macros (scope: module-local)
***************************************************************************************/
static XMC_DMA_CH_CONFIG_t DMA_CH_InitStructure; /* defines the structure for initializing the SPI channel for SPI Toolkit Recorder */

/***************************************************************************************
* Declaration of variables (scope: module-local)
***************************************************************************************/

static uint32_t source_buffer_0[4]={1,4,7,10};
static uint32_t source_buffer_1[4]={2,5,8,11};
static uint32_t source_buffer_2[4]={3,6,9,12};

static uint32_t dest_buffer_0=0;
static uint32_t dest_buffer_1=0;
static uint32_t dest_buffer_2=0;

static XMC_DMA_LLI_t LLI0,LLI1,LLI2;
/***************************************************************************************
* Implementation exported functions (scope: global)
***************************************************************************************/
void dma_Init(void){

XMC_DMA_Enable(DMA_MODULE);

// DMA_CH_InitStructure.enable_interrupt = false;
// DMA_CH_InitStructure.dst_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_32;
// DMA_CH_InitStructure.src_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_32;
// DMA_CH_InitStructure.dst_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE;
// DMA_CH_InitStructure.src_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE;
// DMA_CH_InitStructure.dst_burst_length = XMC_DMA_CH_BURST_LENGTH_4;
// DMA_CH_InitStructure.src_burst_length = XMC_DMA_CH_BURST_LENGTH_4;
// DMA_CH_InitStructure.enable_src_gather = false;
// DMA_CH_InitStructure.enable_dst_scatter = false;
// DMA_CH_InitStructure.transfer_flow = XMC_DMA_CH_TRANSFER_FLOW_M2M_DMA;
// DMA_CH_InitStructure.src_addr = (uint32_t) (&source_buffer_0[0]);
// DMA_CH_InitStructure.dst_addr = (uint32_t) (&dest_buffer_0);
// DMA_CH_InitStructure.src_gather_interval = 0;
// DMA_CH_InitStructure.src_gather_count = 0;
// DMA_CH_InitStructure.dst_scatter_interval = 0;
// DMA_CH_InitStructure.dst_scatter_count = 0;
// DMA_CH_InitStructure.block_size = 3; //Anzahl der Einträge im Array
DMA_CH_InitStructure.transfer_type = XMC_DMA_CH_TRANSFER_TYPE_MULTI_BLOCK_SRCADR_LINKED_DSTADR_LINKED;
DMA_CH_InitStructure.priority = XMC_DMA_CH_PRIORITY_0;
DMA_CH_InitStructure.src_handshaking = XMC_DMA_CH_SRC_HANDSHAKING_HARDWARE;
DMA_CH_InitStructure.src_handshaking = XMC_DMA_CH_SRC_HANDSHAKING_HARDWARE;
DMA_CH_InitStructure.linked_list_pointer=(XMC_DMA_LLI_t*)(&LLI0);


LLI0.src_addr=(uint32_t*)(&source_buffer_0[0]);
LLI0.dst_addr=(uint32_t*)&dest_buffer_0;
LLI0.llp=(XMC_DMA_LLI_t*)(&LLI1);
LLI0.enable_dst_linked_list = true;
LLI0.enable_src_linked_list = true;
LLI0.enable_interrupt=false;
LLI0.dst_transfer_width=XMC_DMA_CH_TRANSFER_WIDTH_32;
LLI0.src_transfer_width=XMC_DMA_CH_TRANSFER_WIDTH_32;
LLI0.dst_address_count_mode=XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE;
LLI0.src_address_count_mode=XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT;
LLI0.dst_burst_length=XMC_DMA_CH_BURST_LENGTH_1;
LLI0.src_burst_length=XMC_DMA_CH_BURST_LENGTH_1;
LLI0.enable_src_gather=0;
LLI0.enable_dst_scatter=0;
LLI0.transfer_flow=XMC_DMA_CH_TRANSFER_FLOW_M2M_DMA;
LLI0.block_size=1;

LLI1.src_addr=(uint32_t*)(&source_buffer_1[0]);
LLI1.dst_addr=(uint32_t*)&dest_buffer_1;
LLI1.llp=(XMC_DMA_LLI_t*)(&LLI2);
LLI1.enable_dst_linked_list = true;
LLI1.enable_src_linked_list = true;
LLI1.enable_interrupt=false;
LLI1.dst_transfer_width=XMC_DMA_CH_TRANSFER_WIDTH_32;
LLI1.src_transfer_width=XMC_DMA_CH_TRANSFER_WIDTH_32;
LLI1.dst_address_count_mode=XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE;
LLI1.src_address_count_mode=XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT;
LLI1.dst_burst_length=XMC_DMA_CH_BURST_LENGTH_1;
LLI1.src_burst_length=XMC_DMA_CH_BURST_LENGTH_1;
LLI1.enable_src_gather=0;
LLI1.enable_dst_scatter=0;
LLI1.transfer_flow=XMC_DMA_CH_TRANSFER_FLOW_M2M_DMA;
LLI1.block_size=1;

LLI2.src_addr=(uint32_t*)(&source_buffer_2[0]);
LLI2.dst_addr=(uint32_t*)&dest_buffer_2;
LLI2.llp=0x0000;
LLI2.enable_dst_linked_list = true;
LLI2.enable_src_linked_list = true;
LLI2.enable_interrupt=false;
LLI2.dst_transfer_width=XMC_DMA_CH_TRANSFER_WIDTH_32;
LLI2.src_transfer_width=XMC_DMA_CH_TRANSFER_WIDTH_32;
LLI2.dst_address_count_mode=XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE;
LLI2.src_address_count_mode=XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT;
LLI2.dst_burst_length=XMC_DMA_CH_BURST_LENGTH_1;
LLI2.src_burst_length=XMC_DMA_CH_BURST_LENGTH_1;
LLI2.enable_src_gather=0;
LLI2.enable_dst_scatter=0;
LLI2.transfer_flow=XMC_DMA_CH_TRANSFER_FLOW_M2M_DMA;
LLI2.block_size=1;

XMC_DMA_CH_Init(DMA_MODULE, DMA_CH, &DMA_CH_InitStructure);
}



uint32_t dma_Get(void){
XMC_DMA_CH_Enable(DMA_MODULE, DMA_CH);
uint16_t test=0;
test++;
return 0;
}


/* EOF */



My problem is that only the first dma transfer (triggered in software in this example) transfers the data correctly.

dest_buffer_0=source_buffer_0[0]=1 -> ok
dest_buffer_1=source_buffer_1[0]=2 -> ok
dest_buffer_2=source_buffer_2[0]=3 -> ok

but the second trigger only transfers the value for the last linked list.

dest_buffer_0=source_buffer_0[0]=1 -> not ok
dest_buffer_1=source_buffer_1[0]=2 -> not ok
dest_buffer_2=source_buffer_2[0]=6 -> ok

What is the problem?

Kind regards
Sandro
0 Likes
Not applicable
Hi again,

it seems that the actual list pointer stops after the first transfer at the last linked list. How to get it back to the first linked list for the next transfer? Which setting is correct to achieve this beahavior? I don´t want to use any interrupt to set any register
during runt time.

This should be the memory content after the second successful dma transfer:

dest_buffer_0=source_buffer_0[0]=4 -> ok
dest_buffer_1=source_buffer_1[0]=5 -> ok
dest_buffer_2=source_buffer_2[0]=6 -> ok
0 Likes
Not applicable
Hello again,

sorry for an error in my last post: copy and paste of array indices... here is the corrected post:

My problem is that only the first dma transfer (triggered in software in this example) transfers the data correctly.

dest_buffer_0=source_buffer_0[0]=1 -> ok
dest_buffer_1=source_buffer_1[0]=2 -> ok
dest_buffer_2=source_buffer_2[0]=3 -> ok

but the second trigger only transfers the value for the last linked list.

dest_buffer_0=source_buffer_0[1]=1 -> not ok
dest_buffer_1=source_buffer_1[1]=2 -> not ok
dest_buffer_2=source_buffer_2[1]=6 -> ok

the third trigger only transfers the value for the last linked list,too.

dest_buffer_0=source_buffer_0[2]=1 -> not ok
dest_buffer_1=source_buffer_1[2]=2 -> not ok
dest_buffer_2=source_buffer_2[2]=9 -> ok

it seems that the actual list pointer stops after the first transfer at the last linked list. How to get it back to the first linked list for the next transfer? Which setting is correct to achieve this beahavior? I don´t want to use any interrupt to set any register
during runt time.

This should be the memory content after the each one of the first three successful dma transfers:
dest_buffer_0=source_buffer_0[0]=1 -> ok
dest_buffer_1=source_buffer_1[0]=2 -> ok
dest_buffer_2=source_buffer_2[0]=3 -> ok

dest_buffer_0=source_buffer_0[1]=4 -> ok
dest_buffer_1=source_buffer_1[1]=5 -> ok
dest_buffer_2=source_buffer_2[1]=6 -> ok

dest_buffer_0=source_buffer_0[2]=7 -> ok
dest_buffer_1=source_buffer_1[2]=8 -> ok
dest_buffer_2=source_buffer_2[2]=9 -> ok

I want to generate 6 pwms and I think that there is only one way using the linked list method and linked list method is only available for channel 0 and 1.
0 Likes