硬汉嵌入式论坛

 找回密码
 立即注册
查看: 8293|回复: 5
收起左侧

[有问必答] 串口DMA请教

[复制链接]

116

主题

800

回帖

1148

积分

至尊会员

积分
1148
QQ
发表于 2015-3-17 09:44:37 | 显示全部楼层 |阅读模式
配置是抄串口1DMA中断例程的,只是把串口1配置成串口4,目前串口能够正常收发,但是用DMA就一点反应都没,每次收发时while ((DMA_GetCmdStatus(USARTx_TX_DMA_STREAM) != ENABLE) && ( Timeout > 0))这句话都是超时的,请版主帮忙看下会是啥原因引起的

GPIO_InitTypeDef  GPIO_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;
    USART_InitTypeDef USART_InitStructure;
   
    /* 串口4 TX = PA0   RX = PA1 */

    /* 第1步: 配置GPIO */

   
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);     /* 打开 GPIO 时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);     /* 打开 UART 时钟 */
    RCC_APB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);      /* 打开 DMA1 时钟 */
   

    //此为打开AF复用时钟,与m3有区别,只配置复用的引脚,且只能一个引脚一个引脚配置
   
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_UART4); /* 将 PA0 映射为 USART4_TX */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_UART4); /* 将 PA1 映射为 USART4_RX */
   

    /* 配置 USART Tx 为复用功能 */
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    /* 输出类型为推挽 */
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;    /* 内部上拉电阻使能 */
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;    /* 复用模式 */

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 配置 USART Rx 为复用功能 */

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 第2步: 配置串口硬件参数 */
    USART_InitStructure.USART_BaudRate   = 115200;//460800;    /* 波特率 */
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits   = USART_StopBits_1;
    USART_InitStructure.USART_Parity     = USART_Parity_No ;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(UART4, &USART_InitStructure);
   
     /* Enable the USARTx Interrupt */
    USART_Cmd(UART4, ENABLE);        /* 使能串口 */
   
        /* 使能 USART DMA RX 请求 */
    USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);
   
    /* 使能 USART DMA TX 请求 */
    USART_DMACmd(UART4, USART_DMAReq_Tx, ENABLE);
   
    /* 使能发送传输完成中断 */
    DMA_ITConfig(USARTx_TX_DMA_STREAM, DMA_IT_TC, ENABLE);  
   
    /* 使能接收传输完成中断 */
    DMA_ITConfig(USARTx_RX_DMA_STREAM, DMA_IT_TC, ENABLE);     
   
    /* 使能 DMA Stream 中断通道 */
    NVIC_InitStructure.NVIC_IRQChannel = USARTx_DMA_TX_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* 使能 DMA Stream 中断通道 */
    NVIC_InitStructure.NVIC_IRQChannel = USARTx_DMA_RX_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


void USART_DMA_RxConfig(unsigned int *BufferDST, unsigned int BufferSize)
{
    DMA_InitTypeDef  DMA_InitStructure;
    __IO uint32_t    Timeout = TIMEOUT_MAX;
    /*
      使能前检测DMA是否被禁止。
      请注意,在使用相同数据流的多次传输时,这一步很有用:使能,然后禁止,然后使能
      ..... 在这种情况下,只有在数据传输结束的时候,DMA的禁止才有效,在确保使能位被
      硬件清除之前做确认是不可能的,如果DMA传输只做一次,这一步可以忽略。
    */
    DMA_Cmd(USARTx_RX_DMA_STREAM, DISABLE);
    while (DMA_GetCmdStatus(USARTx_RX_DMA_STREAM) != DISABLE)
    {
    }
   
    DMA_InitStructure.DMA_BufferSize = BufferSize;                 /* 配置DMA大小 */
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;          /* 在这个程序里面使能或者禁止都可以的 */
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;  /* 设置阀值 */
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;   /* 设置内存为单字节突发模式 */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;/* 设置内存数据的位宽是字节 */
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;        /* 使能地址自增 */
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                  /* 设置DMA是正常模式 */
    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(UART4->DR)) ;   /* 设置外设地址 */
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     /* 设置外设为单字节突发模式 */
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; /* 设置外设数据的位宽是字节 */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        /* 禁止外设地址自增 */
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                     /* 设置优先级 */
   
    /* 配置 RX DMA */
    DMA_InitStructure.DMA_Channel = USARTx_RX_DMA_CHANNEL ;      /* 配置接收通道 */
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;     /* 设置从外设到内存 */
    DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)BufferDST ; /* 设置内存地址 */
    DMA_Init(USARTx_RX_DMA_STREAM,&DMA_InitStructure);
   
    /* 使能 DMA USART TX Stream */
    DMA_Cmd(USARTx_RX_DMA_STREAM, ENABLE);
   
    /*
       检测DMA Stream 是否被正确的使能.如果DMA的参数配置错误了,那么DMA Stream
       的使能位会被硬件清除掉,从而使得传输停止比如FIFO的阀值配置错误
    */
    Timeout = TIMEOUT_MAX;
    while ((DMA_GetCmdStatus(USARTx_RX_DMA_STREAM) != ENABLE) && (Timeout > 0))
    {
        Timeout--;
    }
   
    /* 检测是否超时 */
    if (Timeout == 0)
    {
        /* 处理错误 */
        //TimeOut_UserCallback();
    }
}

void USART_DMA_TxConfig(unsigned int *BufferSRC, unsigned int BufferSize)
{
    DMA_InitTypeDef  DMA_InitStructure;
    __IO uint32_t    Timeout = TIMEOUT_MAX;
   
    /* 复位 DMA Stream 寄存器 (用于调试目的) */
     /* DMA_DeInit(USARTx_TX_DMA_STREAM); */

    /*
      使能前检测DMA是否被禁止。
      请注意,在使用相同数据流的多次传输时,这一步很有用:使能,然后禁止,然后使能
      ..... 在这种情况下,只有在数据传输结束的时候,DMA的禁止才有效,在确保使能位被
      硬件清除之前做确认是不可能的,如果DMA传输只做一次,这一步可以忽略。
    */
    DMA_Cmd(USARTx_TX_DMA_STREAM, DISABLE);
    while (DMA_GetCmdStatus(USARTx_TX_DMA_STREAM) != DISABLE)
    {
    }
   
    DMA_InitStructure.DMA_BufferSize = BufferSize;/* 配置DMA大小 */
     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;                  /* 在这个程序里面使能或者禁止都可以的 */
     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;          /* 设置阀值 */
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;           /* 设置内存为单字节突发模式 */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;        /* 设置内存数据的位宽是字节 */
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                /* 使能地址自增 */
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                          /* 设置DMA是正常模式 */
    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(UART4->DR)) ;  /* 设置外设地址 */
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;    /* 设置外设为单字节突发模式 */
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;; /* 设置外设数据的位宽是字节 */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;/* 禁止外设地址自增 */
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;             /* 设置优先级 */
   
    /* 配置 TX DMA */
    DMA_InitStructure.DMA_Channel = USARTx_TX_DMA_CHANNEL ;      /* 配置发送通道 */
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral ;     /* 设置从内存到外设 */
    DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)BufferSRC ; /* 设置内存地址 */
    DMA_Init(USARTx_TX_DMA_STREAM,&DMA_InitStructure);
   
    /* 使能 DMA USART TX Stream */
    DMA_Cmd(USARTx_TX_DMA_STREAM, ENABLE);
   
    /*
       检测DMA Stream 是否被正确的使能.如果DMA的参数配置错误了,那么DMA Stream
       的使能位会被硬件清除掉,从而使得传输停止比如FIFO的阀值配置错误
    */
    Timeout = TIMEOUT_MAX;
    while ((DMA_GetCmdStatus(USARTx_TX_DMA_STREAM) != ENABLE) && ( Timeout > 0))
    {
        Timeout--;
    }
   
    /* 检测是否超时 */
    if (Timeout == 0)
    {
        /* 处理错误 */
        //TimeOut_UserCallback();
    }
   
}

通道宏定义

#define USARTx_DMA                       DMA1
#define USARTx_DMAx_CLK                  RCC_AHB1Periph_DMA1

#define USARTx_TX_DMA_CHANNEL            DMA_Channel_4
#define USARTx_TX_DMA_STREAM             DMA1_Stream4
#define USARTx_TX_DMA_FLAG_FEIF          DMA_FLAG_FEIF4
#define USARTx_TX_DMA_FLAG_DMEIF         DMA_FLAG_DMEIF4
#define USARTx_TX_DMA_FLAG_TEIF          DMA_FLAG_TEIF4
#define USARTx_TX_DMA_FLAG_HTIF          DMA_FLAG_HTIF4
#define USARTx_TX_DMA_FLAG_TCIF          DMA_FLAG_TCIF4
         
#define USARTx_RX_DMA_CHANNEL            DMA_Channel_4
#define USARTx_RX_DMA_STREAM             DMA1_Stream2
#define USARTx_RX_DMA_FLAG_FEIF          DMA_FLAG_FEIF2
#define USARTx_RX_DMA_FLAG_DMEIF         DMA_FLAG_DMEIF2
#define USARTx_RX_DMA_FLAG_TEIF          DMA_FLAG_TEIF2
#define USARTx_RX_DMA_FLAG_HTIF          DMA_FLAG_HTIF2
#define USARTx_RX_DMA_FLAG_TCIF          DMA_FLAG_TCIF2

#define USARTx_DMA_TX_IRQn               DMA1_Stream4_IRQn
#define USARTx_DMA_RX_IRQn               DMA1_Stream2_IRQn
#define USARTx_DMA_TX_IRQHandler         DMA1_Stream4_IRQHandler
#define USARTx_DMA_RX_IRQHandler         DMA1_Stream2_IRQHandler


操作方式

USART_DMA_RxConfig((u32*)uc_ReadBuf, 1);
USART_DMA_TxConfig((u32*)uc_ReadBuf, 1);
回复

使用道具 举报

116

主题

800

回帖

1148

积分

至尊会员

积分
1148
QQ
 楼主| 发表于 2015-3-17 09:45:58 | 显示全部楼层
想用安富莱提供的例程在线仿真,结果每次都是下载完后keil就死机,无法操作
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117530
QQ
发表于 2015-3-17 09:57:18 | 显示全部楼层
你的DMA中断做处理了吗。
回复

使用道具 举报

356

主题

2180

回帖

3253

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3253
发表于 2015-3-17 10:25:22 | 显示全部楼层
不同的串口,需要配置不一样的DMA通道的,注意检查一下子。
回复

使用道具 举报

116

主题

800

回帖

1148

积分

至尊会员

积分
1148
QQ
 楼主| 发表于 2015-3-17 11:04:37 | 显示全部楼层
中断加了的,DMA通道没问题,后来我直接全部采用你们的例程,就把宏定义改为串口4,通道没变,结果就能发出去,但是如果移植到ucos中,结果系统就起不来,如果DMA不作任何处理系统正常(已经调用初始化), 但是只要调用dma操作系统就挂掉u切换,只有中断能响应,还没找到原因
回复

使用道具 举报

116

主题

800

回帖

1148

积分

至尊会员

积分
1148
QQ
 楼主| 发表于 2015-3-17 11:40:13 | 显示全部楼层
哎,都是ctrl v惹得祸,找了我好久
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-13 02:02 , Processed in 0.041536 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表