让DMA USART在STM32L053R8T6上工作

时间:2018-04-01 20:51:49

标签: c stm32 dma usart

我的问题是让我的计算机(确切地说是虚拟COM端口)通过DMA和USART与我的STM32L053R8T6(Nucleo)板通信。这是我的DMA和USART部分的代码:

#include "Device/Include/stm32l0xx.h"   // Device header
#include "JB.h"
#include <string.h>

#define PCLK    32000000
#define 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#2 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 Channel 4 Transfer Complete flag
  }
  else if((DMA1->ISR & DMA_ISR_TCIF5) == DMA_ISR_TCIF5){
    DMA1->IFCR = DMA_IFCR_CTCIF5; //Clear Channel 5 Transfer Complete 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
  }
}

//void EXTI4_15_IRQHandler(void){
//  if((EXTI->PR & EXTI_PR_PIF13) == EXTI_PR_PIF13){
//    /* 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
//  }
//}

现在,此特定代码基于STM32L0片段包1.20,USART / Communcation Using DMA中的示例。 USART 1被简单地重新定义为USART 2(因为它是虚拟COM端口使用的那个),并且DMA通道也根据它重新定义。但是,这里的问题非常简单:它只会打印一次stringtosend(每次按下按钮B1都会这样做),也不会通过RX接收数据 - 好像它完全忽略了DMA中断处理程序 - 我我不确定如何测试(此板上没有可用的跟踪功能)。我所拥有的似乎足够好地反映了参考手册,所有主要内容都是:

int main(){

SystemCoreClockInit();
CONFIGURE_UART_PARAM();
ENABLE_UART_DMA();
pushbutton_def();
CONFIGURE_EXTI();

while(1){
}

......应该只对已定义的中断作出反应,但事实并非如此,对于我的生活,我看不出原因。我很乐意,如果你可以帮助我 - 我也想避免使用HAL或LL API - 这不是一个足够复杂的项目来保证它们的使用(USART / DMA两个板之间有几个输入,输出,通信),而且我会我更愿意学习更接近注册级别的工作。

谢谢!

编辑(响应Berendi的建议): 1. GPIOC在另一个文件中定义,使用pushbutton_def()调用:

RCC->IOPENR |= (1UL << 2); //enable GPIOC
  1. 我完全理解你的解释是什么意思(事实上,这两个寄存器的寄存器是“相同的”,0x00000020U),但我不确定如何重新定义它:这是我的尝试之后查看参考手册(SYSCFG部分)和来源(仍然,它不起作用):

    SYSCFG-&gt; EXTICR [3] =((SYSCFG-&gt; EXTICR [3]&amp; 0x0000)| SYSCFG_EXTICR4_EXTI13_PC);

  2. 正如所建议的那样,我在DMA通道之后立即向EXTIhandler添加了USART2->ICR = USART_ICR_TCCF;。我把它保存在USART定义中。但是,该消息仍然只被发送一次。

1 个答案:

答案 0 :(得分:1)

GPIOC未启用

下面,

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

您也应该启用GPIOC

EXTI13已映射到PA13

下面,

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

您正在为EXTI0 - EXTI3设置配置注册,实际上将 EXTI1映射到PC1 EXTI13仍然映射到PA13,实际上是SWDIO,连接到板载调试器。我猜SWDIO上的流量会触发EXTI中断,处理程序会检查PC13,它始终读为0,因为端口被禁用,并启用DMA。 DMA传输仅工作一次,因为

USART_ISR_TC未在中断中清除

但在启动时只有一次。你应该移动这一行

USART2->ICR = USART_ICR_TCCF;

到EXTI中断处理程序。

我不确定为什么接收不起作用,也许DMA处理程序没有机会运行,因为EXTI经常被SWD流量重新触发。两个中断都具有相同的优先级,具有较低中断号的中断获胜,这是EXTI处理程序。如果它在完成之前总是被重新触发,那么它将再次被调用,而不是让其他处理程序运行。