一 环形队列的建立
volatile typedef struct //队列结构体定义
{
uint8_t Rx_Buffer[UART_BUF_LEN ];
uint32_t rx_in_ptr;
uint32_t rx_out_ptr;
uint32_t rx_len;
}uart_buffer;
uint16_t Init_Uart_Buf(uart_buffer* Buf) //队列初始化
{
Buf->rx_in_ptr=Buf->rx_out_ptr=0;
return SUCCESS;
}
uint32_t Uart_Buf_Len(uart_buffer* Buf) //计算buf长度
{
uint32_t len;
len= (Buf->rx_in_ptr - Buf->rx_out_ptr + UART_BUF_LEN)%UART_BUF_LEN;
return len;
}
uint16_t In_Uart_Buf(uart_buffer* Buf , uint8_t c) //往buf写入一字节数据
{
if((Buf->rx_in_ptr+1) % UART_BUF_LEN==Buf->rx_out_ptr)
{
ECHO_STR_N("buffer in ptr touch the out ptr");
return ERROR;
}
Buf->Rx_Buffer[Buf->rx_in_ptr]=c;
Buf->rx_in_ptr= (( Buf->rx_in_ptr+1)%UART_BUF_LEN);
return SUCCESS;
}
uint8_t Out_Uart_Buf(uart_buffer* Buf ) //buf读取一字节数据
{
uint8_t ch;
if((Buf->rx_out_ptr % UART_BUF_LEN)==Buf->rx_in_ptr) return ERROR;
ch = Buf->Rx_Buffer[Buf->rx_out_ptr];
Buf->rx_out_ptr= ( Buf->rx_out_ptr+1)%UART_BUF_LEN;
return ch;
}
二, DMA初始化
void UART_DMA_TxConfig(void) //DMA的初始化,省略串口初始化
{
NVIC_InitTypeDef NVIC_InitStructure;
//DMA_InitTypeDef UARTDMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
DMA_ClearFlag(UART_TX_DMA_STREAM, UART_TX_DMA_FLAG_FEIF | UART_TX_DMA_FLAG_DMEIF | UART_TX_DMA_FLAG_TEIF | UART_TX_DMA_FLAG_HTIF | UART_RX_DMA_FLAG_TCIF);
/* DMA2 Stream3 or Stream6 disable */
DMA_Cmd(UART_TX_DMA_STREAM, DISABLE);
/* DMA2 Stream3 or Stream6 Config */
DMA_DeInit(UART_TX_DMA_STREAM);
UARTDMA_InitStructure.DMA_Channel = UART_TX_DMA_CHANNEL;
UARTDMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t)(&(USART2->DR)) ;
UARTDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Uart_Tx_Arr.Rx_Buffer[Uart_Tx_Arr.rx_out_ptr]; // &Test_Buffer;
UARTDMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
UARTDMA_InitStructure.DMA_BufferSize = 1; // Uart_Buf_Len(&Uart_Tx_Arr);
UARTDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
UARTDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
UARTDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte ;
UARTDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte ;
UARTDMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
UARTDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
UARTDMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
UARTDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
UARTDMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
UARTDMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(UART_TX_DMA_STREAM, &UARTDMA_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = UART_TX_DMA_IRQn ; //中断分组
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(UART_TX_DMA_STREAM, DMA_IT_TC, ENABLE); //DMA中断时能
/* DMA2 Stream3 or Stream6 enable */
USART_DMACmd(USART2, USART_DMAReq_Tx , ENABLE); //串口DMA开启
DMA_Cmd(UART_TX_DMA_STREAM, ENABLE); //DMA开启
}
三 buf.c里的数据发送函数,将Buf里的count个字节发往队列缓冲,用DMA方式
uint16_t UART_Tx_Str (char* Buf,uint32_t count)
{
uint32_t len=0,i=0;
uint16_t DMA_State=0; //设置一个局部DMA传输标志,0表示上次DMA传输完成,1表示上次DMA正在工作,既DMA传输结束中断未发生
if (Uart_Buf_Len(&Uart_Tx_Arr)!=0) //通过读取队列buf长度判断是否DMA传输完成,如果buf不为空,表明DMA未结束传输,不需要主动开启DMA,中断中会自动 // 开启
{DMA_State=1;}
__disable_irq(); //为了避免写buf数据时被DMA中断打断,关闭全局中断
for (i=0;i<count;i++)
{
In_Uart_Buf(&Uart_Tx_Arr,*(Buf+i)); //往缓冲区写数据,可以写过队列0地址 ,
}
if (DMA_State==0) //如果上次DMA传输已经结束,本次需要开启DMA,
{
if(Uart_Tx_Arr.rx_out_ptr>Uart_Tx_Arr.rx_in_ptr) // !!!!重点 如果out指针大于in指针,队列0地址被截断,DMA需要分段传输,由于DMA地址只会自加
{ //
DMA_Cmd(UART_TX_DMA_STREAM,DISABLE); //
DMA_LENGTH=UART_BUF_LEN-Uart_Tx_Arr.rx_out_ptr; //第一段传输,ut指针到队列0地址,第二段传输在DMA中断函数中自动更新
UARTDMA_InitStructure.DMA_BufferSize = DMA_LENGTH; //
UARTDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&Uart_Tx_Arr.Rx_Buffer[Uart_Tx_Arr.rx_out_ptr]);
DMA_Init(UART_TX_DMA_STREAM, &UARTDMA_InitStructure);
DMA_Cmd(UART_TX_DMA_STREAM,ENABLE);
}else{
DMA_Cmd(UART_TX_DMA_STREAM,DISABLE); //¹Ø±ÕDMA ¡£ÖØÐÂÅäÖõØÖ·Êý¾Ý
DMA_LENGTH=Uart_Buf_Len(&Uart_Tx_Arr);
UARTDMA_InitStructure.DMA_BufferSize = DMA_LENGTH; //ÖØÔØsize
UARTDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&Uart_Tx_Arr.Rx_Buffer[Uart_Tx_Arr.rx_out_ptr]);
DMA_Init(UART_TX_DMA_STREAM, &UARTDMA_InitStructure);
DMA_Cmd(UART_TX_DMA_STREAM,ENABLE);
}
}
//DMA_ITConfig(UART_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
__enable_irq(); // 开全局中断
return UART_OK;
}
四 DMA发送结束中断
void DMA1_Stream6_IRQHandler ()
{
if(DMA_GetITStatus(UART_TX_DMA_STREAM , DMA_IT_TCIF6))
{
DMA_ClearITPendingBit(UART_TX_DMA_STREAM , DMA_IT_TCIF6); //清中断标志
Uart_Tx_Arr.rx_out_ptr=(Uart_Tx_Arr.rx_out_ptr+DMA_LENGTH)%UART_BUF_LEN; 更新out指针,
DMA_LENGTH=0;
if (Uart_Buf_Len(&Uart_Tx_Arr)!=0) // 更新out指针后如果buf还有数据,则开启DMA,继续下次传输,如果为空,说明已无数据
{
if(Uart_Tx_Arr.rx_out_ptr>Uart_Tx_Arr.rx_in_ptr) //参考buf.c
{
DMA_Cmd(UART_TX_DMA_STREAM,DISABLE); //
DMA_LENGTH=UART_BUF_LEN-Uart_Tx_Arr.rx_out_ptr;
UARTDMA_InitStructure.DMA_BufferSize = DMA_LENGTH;
UARTDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&Uart_Tx_Arr.Rx_Buffer[Uart_Tx_Arr.rx_out_ptr]);
DMA_Init(UART_TX_DMA_STREAM, &UARTDMA_InitStructure);
DMA_Cmd(UART_TX_DMA_STREAM,ENABLE);
}else{
DMA_Cmd(UART_TX_DMA_STREAM,DISABLE); //
DMA_LENGTH=Uart_Buf_Len(&Uart_Tx_Arr);
UARTDMA_InitStructure.DMA_BufferSize = DMA_LENGTH; //ÖØÔØsize
UARTDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&Uart_Tx_Arr.Rx_Buffer[Uart_Tx_Arr.rx_out_ptr]);
DMA_Init(UART_TX_DMA_STREAM, &UARTDMA_InitStructure);
DMA_Cmd(UART_TX_DMA_STREAM,ENABLE);
}
}
}
}