打印

DMA用于通信,如何判断前次操作完成

[复制链接]
5740|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zb214|  楼主 | 2008-7-16 16:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我想用DAM做USRAT1 发送,在发送下一个数据包之前,首先应该判断上一个数据包是否发送完毕。或者一个DMA通道分时复用IIC和USART通信,需要对上次的传输是否完成进行判断。

使用了下面的判断语句:
while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);  //等待上一个数据帧发送完毕
但是仿真的时候老是停留在这个地方,去掉这个语句就能使用,请问如何实现上述功能,完全的程序如下:
********************************************************************************
 *函数原型:  void RS232_SendData(uint8 comm,uint8 Len)                                               
 *参数说明:  comm : 命令字
 *             Len  : 帧数据长度 
 *返回值:      无  
 *说明:      将待发送的数据发送出去                                          
 ********************************************************************************/
void RS232_SendData(u8 comm,u8 Len)     //将待发送的数据发送出去
{
    DMA_InitTypeDef DMA_InitStructure;
    u8     i = 0;

    struct DATA_BUF *send_pk = &TXD_BUF[0];        //初始化定义

    //while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);  //等待上一个数据帧发送完毕
    send_pk->IP_addr = IP_ADDR;            //设置发送从机的IP地址
    send_pk->command = comm;            //设置反回发送命令,
    send_pk->length = Len & GET_LEN;    //设置帧数据长度
        
    send_pk->state &= ~GET_ERROR;        //设置错误标志位,无 

    RS232_TxBuffer[0] = UART_START0;
    RS232_TxBuffer[1] = UART_START1;
    RS232_TxBuffer[2] = IP_ADDR;        //设置发送从机的IP地址
    RS232_TxBuffer[3] = comm;            //设置反回发送命令,
    RS232_TxBuffer[4] = Len & GET_LEN;    //设置帧数据长度
    for(i=0;i<Len;i++)
    {
        RS232_TxBuffer[i+5] = send_pk->byte;    
    }    

    RS232_TxBuffer[Len+5] = RS232_SetSum(send_pk);        //计算校验和

    DMA_DeInit(DMA1_Channel4);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RS232_TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = Len+6;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
 
      //DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
         
    DMA_Cmd(DMA1_Channel4, ENABLE);
    
}
沙发
ST_ARM| | 2008-7-16 17:20 | 只看该作者

你的使用方法不对

用DAM做USRAT1发送,使用DMA发送的一个数据包发送完毕后,才能去使用DMA做其他操作。所以你的程序进行UART发送时,必须等待DMA发送结束,代码如下:

void RS232_SendData(u8 comm,u8 Len)     //将待发送的数据发送出去
{
    DMA_InitTypeDef DMA_InitStructure;
    u8     i = 0;

    struct DATA_BUF *send_pk = &TXD_BUF[0];        //初始化定义
    ...

    ...
    DMA_DeInit(DMA1_Channel4);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RS232_TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = Len+6;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

    DMA_Cmd(DMA1_Channel4, ENABLE);

}
你在主循环中使用轮询的方式:
    while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);  //等待上一个数据帧发送完毕

使用特权

评论回复
板凳
zb214|  楼主 | 2008-7-16 18:04 | 只看该作者

那这样主程序就干不了其他事情了

那这样主程序就干不了其他事情了,一直在等待发送完毕,还不如不用DMA了。
用DMA的意图是,我把数据放缓冲区就不用管它了,然后主程序在去干其他事情,但是不排除发新的数据包的时候前面一个包还没有发出去,只有这个时候才需要等待前一个包发送完成。
否则如果是把数据放缓冲区然后主程序在那里死等,没有效率。

使用特权

评论回复
地板
香水城| | 2008-7-16 18:25 | 只看该作者

可以使用DMA结束中断,或在启动DMA后作其他事情

在所有事情处理完要发送下一个数据包时查询等待。

当然在中断中初始化下一次DMA操作是最省时间的做法。

使用特权

评论回复
5
zb214|  楼主 | 2008-7-17 02:14 | 只看该作者

原因是程序初始的时候DMA1_FLAG_TC4标志是清零的

原因是程序初始的时候DMA1_FLAG_TC4标志是清零的,得DMA发送数据完成后才会有置1,我在发送数据的时候开始就判断是否是置1从而判断上次发送完毕,结果刚开机DMA1_FLAG_TC4是 0,一直死循环。现在在串口初始化的时候配置DMA做一次传输,就将DMA1_FLAG_TC4 位置1了,以后的发送即可在先前去判断这个位。但是这样做开机会发送一个字节的数据,属于笨办法,有没有更好的方式?
/********************************************************************************
 *函数原型:  void    RS232_Init(u32 baud)                                                
 *参数说明:  baud: 波特率                                     
 *返回值:    无                                                               
 *说明:      USART 通讯口初始化程序 设置帧格式: 8 个数据位,无奇偶效验位,1个停止位 8N1                                            
 ********************************************************************************/
void    RS232_Init(u32 baud)    //USART 通讯口初始化程序
{
    USART_InitTypeDef USART_InitStructure;    
    DMA_InitTypeDef DMA_InitStructure;

    USART_InitStructure.USART_BaudRate = baud;            //波特率设置
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;     //通讯格式 8N1,无硬件流控
      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(USART1, &USART_InitStructure);
 
      /* Enable the USART Transmoit interrupt: this interrupt is generated when the 
         USART1 transmit data register is empty */  
          

      /* Enable the USART Receive interrupt: this interrupt is generated when the 
        USART1 receive data register is not empty */
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    RS232_BufInit();    //初始化发送与接收缓冲区,并构缓冲区环型链表
 ///////////////////////////////////首先开启一次DMA传送使DMA1_FLAG_TC4 置位/////////////////////     
    DMA_DeInit(DMA1_Channel4);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RS232_TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 1;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
 
    
    DMA_Cmd(DMA1_Channel4, ENABLE);


    USART_Cmd(USART1, ENABLE); 
}


/********************************************************************************
 *函数原型:  u8 RS232_SetSum (struct DATA_BUF *set_pk)                                               
 *参数说明:  *set_pk : 指向待计算的数据帧
 *返回值:    num_sum : 8位效验和   
 *说明:      计算数据帧效验和                                             
 ********************************************************************************/
u8 RS232_SetSum (struct DATA_BUF *set_pk)    //计算数据帧效验和
{
    u8 num_sum = 0;
    u8 i = 0;
    
    num_sum =  UART_START0 +UART_START1;
    num_sum += set_pk->IP_addr;
    num_sum += set_pk->length & GET_LEN;
    num_sum += set_pk->command;
    
    for(i=0; i<set_pk->length; i++)
        num_sum += set_pk->byte;

    return    num_sum; 
}
/********************************************************************************
 *函数原型:  void RS232_SendData(uint8 comm,uint8 Len)                                               
 *参数说明:  comm : 命令字
 *             Len  : 帧数据长度 
 *返回值:      无  
 *说明:      将待发送的数据发送出去                                          
 ********************************************************************************/
void RS232_SendData(u8 comm,u8 Len)     //将待发送的数据发送出去
{
    DMA_InitTypeDef DMA_InitStructure;
    u8     i = 0;

    struct DATA_BUF *send_pk = &TXD_BUF[0];        //初始化定义

    while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);  //等待上一个数据帧发送完毕

    send_pk->IP_addr = IP_ADDR;            //设置发送从机的IP地址
    send_pk->command = comm;            //设置反回发送命令,
    send_pk->length = Len & GET_LEN;    //设置帧数据长度
        
    send_pk->state &= ~GET_ERROR;        //设置错误标志位,无 

    RS232_TxBuffer[0] = UART_START0;
    RS232_TxBuffer[1] = UART_START1;
    RS232_TxBuffer[2] = IP_ADDR;        //设置发送从机的IP地址
    RS232_TxBuffer[3] = comm;            //设置反回发送命令,
    RS232_TxBuffer[4] = Len & GET_LEN;    //设置帧数据长度
    for(i=0;i<Len;i++)
    {
        RS232_TxBuffer[i+5] = send_pk->byte;    
    }    

    RS232_TxBuffer[Len+5] = RS232_SetSum(send_pk);        //计算校验和

    DMA_DeInit(DMA1_Channel4);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RS232_TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = Len+6;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
 
     DMA_ClearFlag(DMA1_FLAG_TC4);
        
    DMA_Cmd(DMA1_Channel4, ENABLE);

}

使用特权

评论回复
6
香水城| | 2008-7-17 07:26 | 只看该作者

没有什么好办法,本质上第一次与随后的传输不一样

因为你的判断条件是“前次操作是否完成”,而第一次传输之前没有任何操作,当然这样的判断条件不成立了。

唯一的办法是改变这个判断条件,但这意味着改变你的程序架构,需要你自己决定是否值得做这样的改变。


也许一个简单的办法是:设置一个“前次操作完成”的软件标志,在初始化程序时把它设置为"真",随后在每次传输之前判断并清除它,在监测到传输完成的硬件标记时设置这个软件标志。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

23

帖子

0

粉丝