cancel
Showing results for 
Search instead for 
Did you mean: 

stm32 uart Tx dma transmission doesn't work

ASeyo
Associate II

I'm using the stm32f103 and I'm trying to send a text stored in SRAM via DMA to the USART 2 peripheral. My assumption is I'll turn on the usart2 TX dma ( DMAT )request whenever I need it and turn it off after the current transmission completes, (i.e In the DMA1_Channel7_IRQHandler). That is to say when I call the serialPrint function(DEFINED IN MY CODE) USART2 DMAT is turned ON and the DMA1 will serve it. But nothing seems working. The DMA1_Channel7_IRQHandler is not serviced after all.

I spent a lot of time in this problem but I couldn't get it working. Somebody help, thanks. Below is my code....

/*

 I'll use DMA to move data from memory to the usart2 peripheral.

*/

#include "stm32f10x.h"         // Device header

#include <string.h>

void clockConfig(void);

void usart2Init(void);

void DMA1channel7Init(void);

void serialPrint(char* data, uint16_t bufLen);

uint8_t sendBuf[64];

int main(void)

{

clockConfig();

usart2Init();

DMA1channel7Init();

serialPrint("Hello Serial1\n\r", 15);

while(1)

{

}

}

void serialPrint(char* data, uint16_t bufLen)

{

memcpy(sendBuf, data, bufLen);

// DMA1_Channel 7 number of transfer bytes

DMA1_Channel7->CNDTR = bufLen;

// Enable USART2_Tx DMA Request

USART2->CR3 |= USART_CR3_DMAT;

}

void DMA1_Channel7_IRQHandler(void)

{

if( DMA1->ISR & DMA_ISR_TCIF7 )

{

// Disable transfer complete flag

DMA1->IFCR |= DMA_IFCR_CTCIF7;

// Disable DMA request

  USART2->CR3 &= ~USART_CR3_DMAT;

}

}

void usart2Init(void)

{

// USART2_Tx: PA2

// Enable clock access for port A

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

// Configure PA2 as AF push pull

GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2;

GPIOA->CRL &= ~GPIO_CRL_CNF2_0;

// Enable clock access for USART2

RCC->APB1ENR |= RCC_APB1ENR_USART2EN;

// @36MHz 9600bps

USART2->BRR = 0xEA6;

// Enable USART2_Tx

USART2->CR1 |= USART_CR1_TE;

// Enable USART2

USART2->CR1 |= USART_CR1_UE;

}

void DMA1channel7Init(void)

{

// Enable clock access for DMA1

RCC->AHBENR |= RCC_AHBENR_DMA1EN;

// Configure DMA1_Channel7

// peripheral address

DMA1_Channel7->CPAR = (uint32_t)&USART2->DR;

// Memory address

DMA1_Channel7->CMAR = (uint32_t)sendBuf;

// Direction is from memory to peripheral

DMA1_Channel7->CCR |= DMA_CCR7_DIR;

// Memory increment 

DMA1_Channel7->CCR |= DMA_CCR7_MINC;

// 1Byte memory and peripheral size

DMA1_Channel7->CCR &= ~( DMA_CCR7_MSIZE | DMA_CCR7_PSIZE ); 

// Enable transmission complete interrupt

DMA1_Channel7->CCR |= DMA_CCR7_TCIE;

NVIC_EnableIRQ(DMA1_Channel7_IRQn);

// Enable DMA

DMA1_Channel7->CCR |= DMA_CCR7_EN;

}

void clockConfig(void)

{

// HSE ON

RCC->CR |= 0x1<<16;

// wait unit HSE is ready

while(!(RCC->CR & (0x1<<17))){}

// PLL OFF

RCC->CR &= ~(0x1<<24);

//HSE clock not divided

RCC->CFGR &= ~(0x1<<17);

// PLL SRC = HSE 

RCC->CFGR |= 0x1<<16;

// PLL MUL, x9

RCC->CFGR &= ~(0xF<<18);

RCC->CFGR |= 0x7<<18;

// PLL ON

RCC->CR |= 0x1<<24;

// wait until PLL is ready

while(!(RCC->CR & (0x1 << 25))){}

// choose PLL as Sys clock 

RCC->CFGR &= ~(0x3);

RCC->CFGR |= 0x2;

// AHB prescaler x1

RCC->CFGR &= ~(0xF<<4);

 // APB1 (36MHz max ) prescaler /2

RCC->CFGR &= ~(0x7<<8);

RCC->CFGR |= (0x4<<8);

 // APB2(72MHz) prescaler x1

RCC->CFGR &= ~(0x7<<11);

}

1 ACCEPTED SOLUTION

Accepted Solutions
ASeyo
Associate II

I got it working. The reason is DMA CNDTR can only be written when the

channel is disabled. If you try writing when enabled it basically treats it as a zero, So no transfer occurs.

View solution in original post

6 REPLIES 6

Polled Tx (i.e. without DMA) works?

JW

Yes, not exactly the same code though.

I don't see any problem in your code. I don't use 'F1 though.

Make sure the respective TCIFx DMA status flag is clear before you enable the DMA channel.

Read out and check the content of respective DMA, GPIO and USART registers.

JW

Thanks buddy. I appreciate your help. I think everything is setup correctly. But I don't know what the problem is:sad_but_relieved_face:

Jefferson Cunalata
Associate II

I had the same problem. It is not documented, but problem is because DMA TC interrupt flag triggers when the las 16 bits data have been transfered.

For example here I am passing 16 bytes from memory sram to uart, when TC is triggered I have toggle a pin, and it is clear that transfer is not totally complete in uart, but for dma is complete. Just the las two bytes are not complete transfered in UART peripheral.

0690X0000098JpLQAU.png

ASeyo
Associate II

I got it working. The reason is DMA CNDTR can only be written when the

channel is disabled. If you try writing when enabled it basically treats it as a zero, So no transfer occurs.