cancel
Showing results for 
Search instead for 
Did you mean: 

How to use PWM with DMA (STL Libraries)

ATZ99
Associate II

Goodmorning to everyone,

I read a lot about this argument, and I know that with HAL libraries this topic is really easy to do. Unfortunately due to project request i need to use STL libraries. I create a pwm signal with TIM1. This signal is about 1MHz and i need to change every period the DC of the signal due to transmision protocol needs.

I drop here my program in order to let you understand better what I am doing.

I never used DMA using this libraries and I have totally no ideas where to start, could someone help me?

thank you!

If you need more details this program doesn't works only because every 13 period sent, it stops for about 2 period. This probably because some main interrupts have the priority on the exti one. I thought that this problem could be solved using DMA.

static __IO uint32_t TimingDelay;
volatile int LedOff = 0;
volatile int DataSend = 0; //variable used to avoid strange Tim3 ISR executions
volatile uint8_t LED_Data[MAX_LED][4];
volatile uint8_t LED_Mod[MAX_LED][4];  //used to programme leds brightness
volatile uint16_t pwmData[MAX_BITLED+STOP_BITS];
volatile uint32_t DataIndx = 0;
volatile uint32_t TimIndx = 0;
/* Private function prototypes -----------------------------------------------*/
static void Delay(uint32_t nCount);
 
#define WAIT_1s 1000 //ticks to get about a second of pause
#define WAIT_50ms 50 //ticks to get about 50ms of pause
#define NEW_FREQUENCY 4200U
/* Led Control constants -----------------------------------------------------*/
#define MAX_LED 8
#define PI 3.14159265
#define USE_BRIGHTNESS 0
#define STOP_BITS 50
#define HIGH_VALUE 8
#define LOW_VALUE 4
#define MAX_BITLED 24*MAX_LED
/* PWM_TIM and PWM values ----------------------------------------------------*/
#define PWM_PSC 1
#define PWM_GPIO GPIOA
#define PWM_PIN_SOURCE GPIO_PinSource8
#define PWM_PIN GPIO_Pin_8
#define PWM_AF_TIMER GPIO_AF_TIM1
#define PWM_TIMER TIM1
#define PULSE_VALUE 12
 
void TIM_PWMConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef TIM_OCInitStruct;
 
	/* Connect the involved PWM pins to AF -------------------------------------*/
	GPIO_PinAFConfig(PWM_GPIO, PWM_PIN_SOURCE, PWM_AF_TIMER);
 
	/* Configure these PWM pins in alternate function mode ---------------------*/
	GPIO_StructInit(&GPIO_InitStruct);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_Pin = PWM_PIN;
	GPIO_Init(PWM_GPIO, &GPIO_InitStruct);
 
	/* Configure timer ---------------------------------------------------------*/
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
	TIM_TimeBaseInitStruct.TIM_Prescaler = PWM_PSC;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_Period = PULSE_VALUE;
	TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseInitStruct);
	TIM_ARRPreloadConfig(TIM1, ENABLE);
 
	/* Configure the channels for PWM MODE -------------------------------------*/
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse = 0;
	TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
	TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Set;
	TIM_OC1Init(PWM_TIMER, &TIM_OCInitStruct);	
	
	/* Turning on the TIM counter ----------------------------------------------*/
	TIM_CtrlPWMOutputs(TIM1, ENABLE);
	TIM_Cmd(PWM_TIMER, ENABLE);
 
	/* Enable ARR Prereload ----------------------------------------------------*/
	TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);
}
 
void SetPWM(double Duty)
{
	TIM_OCInitTypeDef TIM_OCInitStruct;
 
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
	TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Set;
 
	TIM_OCInitStruct.TIM_Pulse = Duty;
	TIM_OC1Init(PWM_TIMER, &TIM_OCInitStruct);
	TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);
}
 
void PWM_ControlConfig(void)
{
		/* EXTI Configuration ------------------------------------------------------*/
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource9);
	EXTI_InitTypeDef EXTI_PWM_Struct;
	EXTI_StructInit(&EXTI_PWM_Struct);
	
	EXTI_PWM_Struct.EXTI_Line = EXTI_Line9; 
	EXTI_PWM_Struct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_PWM_Struct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_PWM_Struct.EXTI_LineCmd = ENABLE;
 
	EXTI_Init(&EXTI_PWM_Struct);
 
	/* NVIC Configuration ------------------------------------------------------*/
	NVIC_InitTypeDef NVIC_PWM_Struct;
	NVIC_PWM_Struct.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_PWM_Struct.NVIC_IRQChannelPreemptionPriority = 0x00;
	NVIC_PWM_Struct.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_PWM_Struct.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&NVIC_PWM_Struct);
}
 
void EXTI9_5_IRQHandler()
{
	if (EXTI_GetITStatus(EXTI_Line9) != RESET) 
	{
		if (TimIndx < DataIndx && DataSend) //If data signal has not finished yet
		{
			if(TimIndx == 0)
			{
				TimIndx++; //The first data as already been sent when the trasmission started
			}
			else if (TimIndx < MAX_BITLED)//after the first data sent, the cycle start the normal behavior
			{
				SetPWM(pwmData[TimIndx]);
				TimIndx++;
			}
			else //all the data as been sent, now silence as to be delivered in order to let leds know that the signal has ended
			{
				SetPWM(0);
				for(int i = 0; i<350; i++); //set silence for about 50us
 
				
				//Setting all the values in order to be ready to start another data transmission
				DataIndx = 0;
				TimIndx = 0;
				DataSend = 0;
			}
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line9);
}
 
void Set_LED (int LEDnum, int Red, int Green, int Blue)
{
	LED_Data[LEDnum][0] = LEDnum;
	LED_Data[LEDnum][1] = Green;
	LED_Data[LEDnum][2] = Red;
	LED_Data[LEDnum][3] = Blue;
}
 
void DataLed_Send (void)
{
	volatile uint32_t color;
 
	for (int i= 0; i<MAX_LED; i++)
	{
		color = ((LED_Data[i][1]<<16) | (LED_Data[i][2]<<8) | (LED_Data[i][3]));
 
		for (int i=23; i>=0; i--)
		{
			if (color&(1<<i))	pwmData[DataIndx] = HIGH_VALUE;  // 2/3 of PWM Period
			else 	pwmData[DataIndx] = LOW_VALUE;  // 1/3 of PWM Period
			DataIndx++;
		}
	}
	for (int i=0; i<STOP_BITS; i++)
	{
		pwmData[DataIndx] = 0;
		DataIndx++;
	}
	
	DataSend = 1;
	TimIndx = 0;
	SetPWM(pwmData[0]);
	while(DataIndx);
}
 
int main(void)
{     
	/* Setting up the SysTick routine ------------------------------------------*/
	SysTick_Config(SystemCoreClock / NEW_FREQUENCY);
	
	/* Peripheral clock enables ------------------------------------------------*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
	/* Setting up peripherals --------------------------------------------------*/
	TIM_PWMConfig();
	PWM_ControlConfig();
	
	/* Leds initialization -----------------------------------------------------*/
        while(1)	
        {
               for(int k = 0; k < MAX_LED; k++) {Set_LED(k, 0, 255, 0);}
	       DataLed_Send();
	       Delay(WAIT_1s);
         }
}

7 REPLIES 7

I can't see DMA being mentioned in this code.

OTOH I see EXTI you don't mention in the narrative.

JW

ATZ99
Associate II

.

You are right, in this code I change the PWM DC using EXTI interrupt, in fact the output pin of the PWM signal of the TIM1 is physically connected with the EXTI_line_9 pin. I need to change this model into another one with DMA. I cannot find any material that could help me to configure and use DMA, neither an example.

TDK
Guru

> How to use PWM with DMA (STL Libraries)

It seems like you mean the Standard Peripheral Library (SPL), yes?

https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-standard-peripheral-libraries/stsw-stm32065.html#get-software

If you download the SPL, there are examples within the zip file. For example, here is a list of examples for the F4 version:

In addition to this example (DMA\FLASH_RAM), other examples use the DMA:
 
  * <ul>
  * <li><B>  Complete List of DMA Examples </B>
  * - @subpage ADC_DMA
  * - @subpage ADC_DualModeInterleaved
  * - @subpage ADC_DualModeRegulSimu
  * - @subpage ADC_TripleModeInterleaved
  * - @subpage ADC_VBATMeasurement
  * - @subpage CRYP_AES_DMA
  * - @subpage CRYP_TDES_DMA
  * - @subpage DAC_SignalsGeneration
  * - @subpage DCMI_CameraExample  
  * - @subpage HASH_SHA1MD5_DMA
  * - @subpage I2C_DataExchangeDMA
  * - @subpage NVIC_DMAWFIMode
  * - @subpage SPI_DataExchangeDMA  
  * - @subpage TIM_DMA
  * - @subpage TIM_DMABurst
  * - @subpage USART_DataExchangeDMA
  * </ul>

If you feel a post has answered your question, please click "Accept as Solution".
ATZ99
Associate II

Honestly I always heard it call STL (its only few weeks that i'm working with this libraries), but looking for this SPL seems the same, so probably i was just using the wrong name! I'll download this examples and give them a try, in case i will not succeed i'll came back asking for more advice!

TIll now, thank you so much!

ATZ99
Associate II

Here i am again!

Goodevening to everyone, after some experimental days i come back to you for more help.

I tried lots of examples but for some reason noone seems doing the desidered purpose.

Basically when i start the comunication seems that it isn't working, it got stucked waiting the end of the transmission that never come.

I put here my modified code

/* Private typedef -----------------------------------------------------------*/
TIM_OCInitTypeDef TIM_OCInitStruct;
 
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static __IO uint32_t TimingDelay;
volatile int LedOff = 0;
volatile int DataSentFlag = 0;
volatile uint8_t LED_Data[MAX_LED][4];
volatile uint8_t LED_Mod[MAX_LED][4];  //used to programme leds brightness
volatile uint16_t pwmData[MAX_BITLED + STOP_BITS];
volatile uint16_t DataIndx = 0; 
 
/* Delay constants -----------------------------------------------------------*/
#define SYSTICK_FREQUENCY 				1000U
#define WAIT_1s 							1000 			//ticks to get about a second of pause
#define WAIT_50ms 						50 				//ticks to get about 50ms of pause
#define NEW_FREQUENCY 					4200U
 
/* Led Control constants -----------------------------------------------------*/
#define MAX_LED 								8
#define PI 								        3.14159265
#define USE_BRIGHTNESS 						0
#define STOP_BITS 							50
#define MAX_BITLED 							24*MAX_LED
 
/* PWM_TIM and PWM values ----------------------------------------------------*/
#define PWM_PSC 								0
#define PWM_GPIO 								GPIOA
#define PWM_PIN_SOURCE 						GPIO_PinSource8
#define PWM_PIN 									GPIO_Pin_8
#define PWM_AF_TIMER 							GPIO_AF_TIM1
#define PWM_TIMER 								TIM1
#define PWM_FREQUENCY							850000
 
/* DMA Values ----------------------------------------------------------------*/
#define TIMEOUT_MAX       		10000 		//Maximum timeout value 
#define DMA_STREAM			DMA2_Stream6
#define DMA_CHANNEL              	DMA_Channel_6
#define BUFFER_SIZE              	MAX_BITLED + STOP_BITS
 
static void TIM_PWMConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	/* Enable TIM Clock --------------------------------------------------------*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
 
	/* Connect the involved PWM pins to AF -------------------------------------*/
	GPIO_PinAFConfig(PWM_GPIO, PWM_PIN_SOURCE, PWM_AF_TIMER);
 
	/* Configure these PWM pins in alternate function mode ---------------------*/
	GPIO_StructInit(&GPIO_InitStruct);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_Pin = PWM_PIN;
	
	GPIO_Init(PWM_GPIO, &GPIO_InitStruct);
 
	/* Configure timer ---------------------------------------------------------*/
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
	TIM_TimeBaseInitStruct.TIM_Prescaler = PWM_PSC;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
	TIM_TimeBaseInitStruct.TIM_Period = (SystemCoreClock / PWM_FREQUENCY) - 1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 1;
	
	TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseInitStruct);
 
	/* Configure the channels for PWM MODE -------------------------------------*/
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_Pulse = 0;
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
	TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
	TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Set;
	
	TIM_OC1Init(PWM_TIMER, &TIM_OCInitStruct);	
	
	/* Turning on the TIM counter ----------------------------------------------*/
	TIM_Cmd(PWM_TIMER, ENABLE);
 
	/* TIM1 Update DMA Request enable ------------------------------------------*/
  TIM_DMACmd(PWM_TIMER, TIM_DMA_CC1, DISABLE);
 
	/* Enable ARR Prereload ----------------------------------------------------*/
	TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);
	
	/* Main Output Enable ------------------------------------------------------*/
  TIM_CtrlPWMOutputs(PWM_TIMER, ENABLE);
}
 
static void DMA_Config(void)
{
  DMA_InitTypeDef  DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	__IO uint32_t    Timeout = TIMEOUT_MAX;
  
  /* DMA clock Enable --------------------------------------------------------*/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
 
  DMA_DeInit(DMA_STREAM);
	 /* Check if the DMA Stream is disabled before enabling it.
     Note that this step is useful when the same Stream is used multiple times:
     enabled, then disabled then re-enabled... In this case, the DMA Stream disable
     will be effective only at the end of the ongoing data transfer and it will 
     not be possible to re-configure it before making sure that the Enable bit 
     has been cleared by hardware. If the Stream is used only once, this step might 
     be bypassed. */
  while (DMA_GetCmdStatus(DMA_STREAM) != DISABLE)
  {
  }
	
  DMA_InitStructure.DMA_Channel = DMA_CHANNEL;  
  DMA_InitStructure.DMA_PeripheralBaseAddr = TIM_DMABase_CCR1;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pwmData;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
 
  DMA_Init(DMA_STREAM, &DMA_InitStructure);
	
	/* DMA enable --------------------------------------------------------------*/
  DMA_Cmd(DMA_STREAM, ENABLE);
	
	/* Check if the DMA Stream has been effectively enabled.
     The DMA Stream Enable bit is cleared immediately by hardware if there is an 
     error in the configuration parameters and the transfer is no started (ie. when
     wrong FIFO threshold is configured ...) */
  Timeout = TIMEOUT_MAX;
  while ((DMA_GetCmdStatus(DMA_STREAM) != ENABLE) && (Timeout-- > 0))
  {
  }
   
  // Check if a timeout condition occurred
  if (Timeout == 0)
  {
    // Manage the error: to simplify the code enter an infinite loop
    while (1)
    {
			GPIO_Toggle(GPIOA, GPIO_Pin_5); //toggle pin PA5
			Delay(WAIT_1s /5);
    }
  }
	
	// Enable DMA Stream Transfer Complete interrupt
  DMA_ITConfig(DMA_STREAM, DMA_IT_TC, ENABLE);
	
	// Enable the DMA Stream IRQ Channel
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure); 
}
 
void DMA2_Stream6_IRQHandler()
{
	if (DMA_GetITStatus(DMA_STREAM, DMA_IT_TC) != RESET) 
	{
		/* Clear DMA Stream Transfer Complete interrupt pending bit */
    DMA_ClearITPendingBit(DMA_STREAM, DMA_IT_TC); 
		
		/* TIM1 Update DMA Request enable ------------------------------------------*/
		TIM_DMACmd(PWM_TIMER, TIM_DMA_CC1, DISABLE);
		DataSentFlag = 1;
	} 
}
 
void SetPWM(double Duty)
{
	TIM_OCInitStruct.TIM_Pulse = (Duty / 10) * ((SystemCoreClock / PWM_FREQUENCY) - 1);
	TIM_OC1Init(PWM_TIMER, &TIM_OCInitStruct);
	TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);
}
 
void DataLed_Send (void)
{
	volatile uint32_t color;
 
	for (int i= 0; i<MAX_LED; i++)
	{
		#if USE_BRIGHTNESS
			color = ((LED_Mod[i][1]<<16) | (LED_Mod[i][2]<<8) | (LED_Mod[i][3]));
		#else
			color = ((LED_Data[i][1]<<16) | (LED_Data[i][2]<<8) | (LED_Data[i][3]));
		#endif
 
		for (int i=23; i>=0; i--)
		{
			if (color&(1<<i))	{pwmData[DataIndx] = (uint16_t)(2/3 * ((SystemCoreClock / PWM_FREQUENCY) - 1));}  // 2/3 of PWM Period
			else {pwmData[DataIndx] = (uint16_t)(1/3 * ((SystemCoreClock / PWM_FREQUENCY) - 1));}  							// 1/3 of PWM Period
			DataIndx++;
		}
	}
	for (int i=0; i<STOP_BITS; i++)
	{
		pwmData[DataIndx] = 0;
		DataIndx++;
	}
	
	/* TIM1 Update DMA Request enable ------------------------------------------*/
	TIM_DMACmd(PWM_TIMER, TIM_DMA_CC1, ENABLE);
	SetPWM(1); //small value in order to let the interrupt turn on (should not be read as a bit)
	while(!DataSentFlag);
	GPIO_Toggle(GPIOA, GPIO_Pin_5); //toggle pin PA5
	DataSentFlag = 0; //ready for a new transmission
}
 
int main(void)
{     
	/* Setting up the SysTick routine ------------------------------------------*/
	SysTick_Config(SystemCoreClock / NEW_FREQUENCY);
	
	/* Peripheral clock enables ------------------------------------------------*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
	/* Setting up peripherals --------------------------------------------------*/
	TIM_PWMConfig();
	PWM_ControlConfig();
	
	/* Leds initialization -----------------------------------------------------*/
        while(1)	
        {
               for(int k = 0; k < MAX_LED; k++) {Set_LED(k, 0, 255, 0);}
	       DataLed_Send();
	       Delay(WAIT_1s);
         }

What are your thoughts? basically it sticks in the while at line 218, this because it doesn't never goes inside the handler of the DMA and so doesn't put DatSentFlag = 1.

Could be because it doesn't end the transmsion due to some DMA configuration errors?