cancel
Showing results for 
Search instead for 
Did you mean: 

Getting DMA USART to work on STM32L053R8T6

Konstantin Xen
Associate
Posted on April 01, 2018 at 16:23

Hi there STM community. I am having an issue in getting my computer (virtual COM port, to be exact) to communicate with my STM32L053R8T6 board by DMA and USART. Here is my code for the DMA and USART part:

&sharpinclude 'Device/Include/stm32l0xx.h' // Device header

&sharpinclude 'JB.h'

&sharpinclude <string.h>

&sharpdefine PCLK 32000000

&sharpdefine BAUD 19200

uint8_t stringtosend[] = 'test\n';

uint8_t stringtoreceive[] = ' ';

void ENABLE_UART_DMA(void){

RCC->AHBENR |= RCC_AHBENR_DMA1EN; //enable periph.clk for DMA1

/**Enabling DMA for transmission

* DMA1, Channel 4 mapped for USART2TX

* USART2 TDR for peripheral address

* stringtosend for data address

* Memory increment, memory to peripheral | 8-bit transfer | transfer complete interrupt**/

DMA1_CSELR->CSELR = (DMA1_CSELR->CSELR & ~DMA_CSELR_C4S) | (4 << (3 * 4));

DMA1_Channel4->CPAR = (uint32_t)&(USART2->TDR);

DMA1_Channel4->CMAR = (uint32_t)stringtosend;

DMA1_Channel4->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE;

/**Enabling DMA for reception

* DMA1, Channel 5 mapped for USART2RX

* USART2 RDR for peripheral address

* stringtoreceive for data address

* Data size given

* Memory increment, peripheral to memory | 8-bit transfer | transfer complete interrupt**/

DMA1_CSELR->CSELR = (DMA1_CSELR->CSELR & ~DMA_CSELR_C5S) | (4 << (4 * 4));

DMA1_Channel5->CPAR = (uint32_t)&(USART2->RDR);

DMA1_Channel5->CMAR = (uint32_t)stringtoreceive;

DMA1_Channel5->CNDTR = sizeof(stringtoreceive);

DMA1_Channel5->CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN;

NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 0); //NVIC enabled, max priority, channels 4-7

NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);

}

void CONFIGURE_UART_PARAM(void){

RCC->IOPENR |= ( 1ul << 0); //Enable GPIOA clock

RCC->APB1ENR |= ( 1ul << 17); //Enable USART&sharp2 clock

GPIOA->AFR[0] &= ~((15ul << 4* 3) | (15ul << 4* 2) ); //Clear PA2,PA3

GPIOA->AFR[0] |= (( 4ul << 4* 3) | ( 4ul << 4* 2) ); //Set PA2,PA3

GPIOA->MODER &= ~(( 3ul << 2* 3) | ( 3ul << 2* 2) ); //Same as above

GPIOA->MODER |= (( 2ul << 2* 3) | ( 2ul << 2* 2) );

USART2->BRR = PCLK/BAUD;

USART2->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; //Enable DMA mode in transmit and receive

/*UART enabled for transmission and reception*/

USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;

while((USART2->ISR & USART_ISR_TC) != USART_ISR_TC)

{

/* add time out here for a robust application */

}

USART2->ICR = USART_ICR_TCCF;

}

void CONFIGURE_EXTI(void){

SYSCFG->EXTICR[0] = ((SYSCFG->EXTICR[0] & 0x0000) | SYSCFG_EXTICR4_EXTI13_PC); //clear EXTICR and set to PC13(B1)

EXTI->FTSR |= EXTI_FTSR_TR13; //falling edge trigger

EXTI->IMR |= EXTI_IMR_IM13; //unmask

NVIC_SetPriority(EXTI4_15_IRQn, 0); //def interrupt

NVIC_EnableIRQ(EXTI4_15_IRQn);

}

/*************************************************************************************************************************************************************************************************************************/

/*************************************************************************************************************************************************************************************************************************/

/*Interrupt Handlers*/

void DMA1_Channel4_5_6_7IRQHandler(void){

if((DMA1->ISR & DMA_ISR_TCIF4) == DMA_ISR_TCIF4){

DMA1->IFCR = DMA_IFCR_CTCIF4;/* Clear TC flag */

}

else if((DMA1->ISR & DMA_ISR_TCIF5) == DMA_ISR_TCIF5){

DMA1->IFCR = DMA_IFCR_CTCIF5;/* Clear TC flag */

DMA1_Channel5->CCR &= ~DMA_CCR_EN;

DMA1_Channel5->CNDTR = sizeof(stringtoreceive);/* Data size */

DMA1_Channel5->CCR |= DMA_CCR_EN;

}

}

void EXTI4_15_IRQHandler(void){

if(!(GPIOC->IDR & (1 << 13))){

/* Clear EXTI 13 flag */

EXTI->PR = EXTI_PR_PIF13;

/* start 8-bit transmission with DMA */

DMA1_Channel4->CCR &= ~DMA_CCR_EN; //channel disable

DMA1_Channel4->CNDTR = sizeof(stringtosend);/* Data size */

DMA1_Channel4->CCR |= DMA_CCR_EN; //channel enable

}

}

Now then, this specific code is based on an example from the STM32L0 snippets package, USART/Communcation Using DMA. USART 1 was simply redefined to USART 2 (as that is the one used by the virtual COM port), and the DMA channels were redefined according to that as well.  However, the way this works is very simple: it will only print stringtosend once, and will not receive data by RX either - as if it completely ignores the DMA interrupt handler - which I am not sure how to test. What I have seems to reflect the reference manual well enough, and all the main does is:

int main(){

SystemCoreClockInit();

CONFIGURE_UART_PARAM();

ENABLE_UART_DMA();

pushbutton_def();

CONFIGURE_EXTI();

while(1){

}

...which should just react to the defined interrupts, however it does not, and for the life of me, I cannot see why.

Attached are my project+the relevant code example from STM. Would love if you could help me - also, this project is supposed to be based entirely on the ref.manual - so, if you are kind enough to help with your code, I cannot use HAL/LL APIs.

Thank you.

#stm32l0-uart #stm32l0 #dma-usart #virtual-com
0 REPLIES 0