STM32F767单片机UART DMA程序源码

#include <string.h>
#include "stm32f7_uart_dma.h"
#include "../MyModules/RingQueue.h"
#include "../MyModules/Protocol.h"


/** @addtogroup STM32F7xx_LL_Examples
  * @{
  */


/** @addtogroup USART_Communication_TxRx_DMA
  * @{
  */


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DMA_RECEPT_DATA_SIZE 1 //73×Ö½Ú´¥·¢DMAÖжÏ
#define DMA_DATA_BUF_SIZE 128 //DMA·¢ËÍ»º´æ´óС
/* Private macro -------------------------------------------------------------*/
#define USE_USART2//USE_USART3//USE_USART2


#ifdef USE_USART3
#define UART_GPIOx GPIOD
#define UART_TX_PIN LL_GPIO_PIN_8
#define UART_RX_PIN LL_GPIO_PIN_9
#define UART_NUM USART3
#define LL_APB1_GRP1_PERIPH_USARTx LL_APB1_GRP1_PERIPH_USART3
#define LL_RCC_USARTx_CLKSOURCE_PCLK1 LL_RCC_USART3_CLKSOURCE_PCLK1
#define UART_SEND_STREAM LL_DMA_STREAM_3
#define UART_RECV_STREAM LL_DMA_STREAM_1
#define UART_DMA_CHANNEL LL_DMA_CHANNEL_4
#define UART_DMA_NUM DMA1
#else
#define UART_GPIOx GPIOD
#define UART_TX_PIN LL_GPIO_PIN_5
#define UART_RX_PIN LL_GPIO_PIN_6
#define UART_NUM USART2
#define LL_APB1_GRP1_PERIPH_USARTx LL_APB1_GRP1_PERIPH_USART2
#define LL_RCC_USARTx_CLKSOURCE_PCLK1 LL_RCC_USART2_CLKSOURCE_PCLK1
#define UART_SEND_STREAM LL_DMA_STREAM_6
#define UART_RECV_STREAM LL_DMA_STREAM_5
#define UART_DMA_CHANNEL LL_DMA_CHANNEL_4
#define UART_DMA_NUM DMA1
#endif
/* Private variables ---------------------------------------------------------*/
/* Buffer used for transmission */
uint8_t cTxDMABuffer[DMA_DATA_BUF_SIZE];
/* Buffer used for reception */
uint8_t cRxDMABuffer[DMA_DATA_BUF_SIZE];


#define RX_BUF_MAX_SIZE     (MAX_CMD_SIZE*10)        
static unsigned char RingBuffer[RX_BUF_MAX_SIZE];   
static RING_QUEUE RingQueue;             
/* Private functions ---------------------------------------------------------*/


/**
  * @brief  This function configures the DMA Channels for TX and RX transfers
  * @note   This function is used to :
  *         -1- Enable DMA1 clock
  *         -2- Configure NVIC for DMA transfer complete/error interrupts 
  *         -3- Configure DMA TX channel functional parameters
  *         -4- Configure DMA RX channel functional parameters
  *         -5- Enable transfer complete/error interrupts
  * @param  None
  * @retval None
  */
void Configure_USART2_DMA(void)
{


  /* DMA1 used for USART3 Transmission and Reception
   */
  /* (1) Enable the clock of DMA1 */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);


  /* (2) Configure NVIC for DMA transfer complete/error interrupts */
#ifdef USE_USART3
  NVIC_SetPriority(DMA1_Stream3_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Stream3_IRQn);
  NVIC_SetPriority(DMA1_Stream1_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Stream1_IRQn);
#else
  NVIC_SetPriority(DMA1_Stream5_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Stream5_IRQn);
  NVIC_SetPriority(DMA1_Stream6_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Stream6_IRQn);
#endif
  /* (3) Configure the DMA functional parameters for transmission */
  LL_DMA_SetChannelSelection(UART_DMA_NUM, UART_SEND_STREAM, UART_DMA_CHANNEL);
  LL_DMA_ConfigTransfer(UART_DMA_NUM, UART_SEND_STREAM, 
                        LL_DMA_DIRECTION_MEMORY_TO_PERIPH | 
                        LL_DMA_PRIORITY_HIGH              | 
                        LL_DMA_MODE_NORMAL                | 
                        LL_DMA_PERIPH_NOINCREMENT         | 
                        LL_DMA_MEMORY_INCREMENT           | 
                        LL_DMA_PDATAALIGN_BYTE            | 
                        LL_DMA_MDATAALIGN_BYTE);
  LL_DMA_ConfigAddresses(UART_DMA_NUM, UART_SEND_STREAM,
                         (uint32_t)cTxDMABuffer,
                         LL_USART_DMA_GetRegAddr(UART_NUM, LL_USART_DMA_REG_DATA_TRANSMIT),
                         LL_DMA_GetDataTransferDirection(UART_DMA_NUM, UART_SEND_STREAM));
  LL_DMA_SetDataLength(UART_DMA_NUM, UART_SEND_STREAM, DMA_DATA_BUF_SIZE);


  /* (4) Configure the DMA functional parameters for reception */
  LL_DMA_SetChannelSelection(UART_DMA_NUM, UART_RECV_STREAM, UART_DMA_CHANNEL);
  LL_DMA_ConfigTransfer(UART_DMA_NUM, UART_RECV_STREAM, 
                        LL_DMA_DIRECTION_PERIPH_TO_MEMORY | 
                        LL_DMA_PRIORITY_HIGH              | 
                        LL_DMA_MODE_NORMAL | //LL_DMA_MODE_NORMAL                | //LL_DMA_MODE_CIRCULAR ÖжÏÑ­»·
                        LL_DMA_PERIPH_NOINCREMENT         | 
                        LL_DMA_MEMORY_INCREMENT           | 
                        LL_DMA_PDATAALIGN_BYTE            | 
                        LL_DMA_MDATAALIGN_BYTE);
  LL_DMA_ConfigAddresses(UART_DMA_NUM, UART_RECV_STREAM,
                         LL_USART_DMA_GetRegAddr(UART_NUM, LL_USART_DMA_REG_DATA_RECEIVE),
                         (uint32_t)cRxDMABuffer,
                         LL_DMA_GetDataTransferDirection(UART_DMA_NUM, UART_RECV_STREAM));
  LL_DMA_SetDataLength(UART_DMA_NUM, UART_RECV_STREAM, DMA_RECEPT_DATA_SIZE);


  /* (5) Enable DMA transfer complete/error interrupts  */
  LL_DMA_EnableIT_TC(UART_DMA_NUM, UART_SEND_STREAM);
  LL_DMA_EnableIT_TE(UART_DMA_NUM, UART_SEND_STREAM);
  LL_DMA_EnableIT_TC(UART_DMA_NUM, UART_RECV_STREAM);
  LL_DMA_EnableIT_TE(UART_DMA_NUM, UART_RECV_STREAM);
}


/**
  * @brief  This function configures USARTx Instance.
  * @note   This function is used to :
  *         -1- Enable GPIO clock and configures the USART3 pins.
  *         -2- Enable the USART3 peripheral clock and clock source.
  *         -3- Configure USART3 functional parameters.
  *         -4- Enable USART3.
  * @note   Peripheral configuration is minimal configuration from reset values.
  *         Thus, some useless LL unitary functions calls below are provided as
  *         commented examples - setting is default configuration from reset.
  * @param  None
  * @retval None
  */
void Configure_USART2(void)
{


  /* (1) Enable GPIO clock and configures the USART pins **********************/


  /* Enable the peripheral clock of GPIO Port */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD);


  /* Configure Tx Pin as : Alternate function, High Speed, Push pull, Pull up */
  LL_GPIO_SetPinMode(UART_GPIOx, UART_TX_PIN, LL_GPIO_MODE_ALTERNATE);
#ifdef USE_USART3
  LL_GPIO_SetAFPin_8_15(UART_GPIOx, UART_TX_PIN, LL_GPIO_AF_7);
#else
LL_GPIO_SetAFPin_0_7(UART_GPIOx, UART_TX_PIN, LL_GPIO_AF_7);
#endif
  LL_GPIO_SetPinSpeed(UART_GPIOx, UART_TX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinOutputType(UART_GPIOx, UART_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
  LL_GPIO_SetPinPull(UART_GPIOx, UART_TX_PIN, LL_GPIO_PULL_UP);


  /* Configure Rx Pin as : Alternate function, High Speed, Push pull, Pull up */
  LL_GPIO_SetPinMode(UART_GPIOx, UART_RX_PIN, LL_GPIO_MODE_ALTERNATE);
#ifdef USE_USART3
  LL_GPIO_SetAFPin_8_15(UART_GPIOx, UART_RX_PIN, LL_GPIO_AF_7);
#else
LL_GPIO_SetAFPin_0_7(UART_GPIOx, UART_RX_PIN, LL_GPIO_AF_7);
#endif
  LL_GPIO_SetPinSpeed(UART_GPIOx, UART_RX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinOutputType(UART_GPIOx, UART_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
  LL_GPIO_SetPinPull(UART_GPIOx, UART_RX_PIN, LL_GPIO_PULL_UP);


  /* (2) Enable USART3 peripheral clock and clock source ****************/
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USARTx);


  /* Set clock source */
  LL_RCC_SetUSARTClockSource(LL_RCC_USARTx_CLKSOURCE_PCLK1);


  /* (3) Configure USART3 functional parameters ********************************/
  
  /* Disable USART prior modifying configuration registers */
  /* Note: Commented as corresponding to Reset value */
  // LL_USART_Disable(UART_NUM);


  /* TX/RX direction */
  LL_USART_SetTransferDirection(UART_NUM, LL_USART_DIRECTION_TX_RX);


  /* 8 data bit, 1 start bit, 1 stop bit, no parity */
  LL_USART_ConfigCharacter(UART_NUM, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);


  /* No Hardware Flow control */
  /* Reset value is LL_USART_HWCONTROL_NONE */
  // LL_USART_SetHWFlowCtrl(UART_NUM, LL_USART_HWCONTROL_NONE);


  /* Oversampling by 16 */
  /* Reset value is LL_USART_OVERSAMPLING_16 */
  // LL_USART_SetOverSampling(UART_NUM, LL_USART_OVERSAMPLING_16);


  /* Set Baudrate to 115200 using APB frequency set to 54000000 Hz */
  /* Frequency available for USART peripheral can also be calculated through LL RCC macro */
  /* Ex :
      Periphclk = LL_RCC_GetUSARTClockFreq(Instance); or LL_RCC_GetUARTClockFreq(Instance); depending on USART/UART instance
  
      In this example, Peripheral Clock is expected to be equal to 54000000 Hz => equal to SystemCoreClock/4
  */
  LL_USART_SetBaudRate(UART_NUM, SystemCoreClock/4, LL_USART_OVERSAMPLING_16, 115200); 


  /* (4) Enable UART_NUM **********************************************************/
  LL_USART_Enable(UART_NUM);
}


/**
  * @brief  This function initiates TX and RX DMA transfers by enabling DMA channels
  * @param  None
  * @retval None
  */
void USART2_StartTransfers(void)
{
unsigned char errm;
// ³õʼ»¯»º´æÇø
RingQueueInit(&RingQueue, RingBuffer, RX_BUF_MAX_SIZE, &errm);
  /* Enable DMA RX Interrupt */
  LL_USART_EnableDMAReq_RX(UART_NUM);


  /* Enable DMA TX Interrupt */
  LL_USART_EnableDMAReq_TX(UART_NUM);


  /* Enable DMA Channel Rx */
  LL_DMA_EnableStream(UART_DMA_NUM, UART_RECV_STREAM);


  /* Enable DMA Channel Tx */
  //LL_DMA_EnableStream(UART_DMA_NUM, UART_SEND_STREAM);
}


int SerialDMASend(unsigned char *p_data,unsigned int size)
{
if(size > 0)
{
memcpy(cTxDMABuffer,p_data,size);
LL_DMA_SetDataLength(UART_DMA_NUM, UART_SEND_STREAM, size);
/* Enable DMA Channel Tx */
LL_DMA_EnableStream(UART_DMA_NUM, UART_SEND_STREAM);
}
return 0;
}


int SerialDMARecv(unsigned char *p_data,unsigned int max_size)
{
unsigned char err;
unsigned int size = 0;
if (0 == RingQueueGetLength(&RingQueue))
return 0;
size = RingQueueOut(&RingQueue, p_data, max_size, &err);
if (err == RQ_ERR_NONE)
{
return size;
}
return 0;
}


#ifdef USE_MTI
//УÑéºÍ£ºBID....CheckSUM,ÀÛ¼ÓΪ0
char CalChecksum(char *p_data,unsigned int size)
{
unsigned int i = 0;
char result = 0;
for(i = 1;i < size;i++)
result += p_data[i];
return result;
}
int GetCommandFromRingQueue(unsigned char *p_data,unsigned int max_size)
{
unsigned char ring_err = 0;
unsigned int ring_size = 0;
volatile unsigned int cmd_length = 0;
if (RingQueueGetLength(&RingQueue) < 5) //Ö¸Á¶È×îСΪ5×Ö½Ú
return -1;
ring_size = RingQueueLook(&RingQueue, p_data, 5, &ring_err);//ÏÈÈ¡³ö5×Ö½ÚÍ·Êý¾Ý
if(ring_size != 5)
return -2;

if((p_data[0] != PACKAGE_HEAD_PREAMBLE)||(p_data[1] != PACKAGE_HEAD_BID))//Æ¥ÅäÍ·Á½¸ö×Ö½Ú
{
RingQueueOut(&RingQueue, p_data, 2, &ring_err);//Å×Æú´íÎóµÄÁ½¸öÊý¾ÝÍ·
return -3;
}
cmd_length = CMD_FREAMBLE_SIZE + CMD_BID_SIZE + CMD_MID_SIZE + CMD_LEN_SIZE;

if(p_data[3] <= PACKAGE_LEN_STANDARD)//±ê×¼Êý¾Ý
{
cmd_length += p_data[3];
}
else if(p_data[3] == PACKAGE_LEN_EXTENDED)//À©Õ¹Êý¾Ý
{
cmd_length += CMD_EXTLEN_SIZE;
cmd_length += p_data[4]*256+p_data[5];
RingQueueOut(&RingQueue, p_data, cmd_length, &ring_err);//£¿ÏÈÅ×Æú0xFFÀ©Õ¹Êý¾Ý´¦Àí
return -8;
}
else
{
RingQueueOut(&RingQueue, p_data, 2, &ring_err);//Å×Æú´íÎóµÄÁ½¸öÊý¾ÝÍ·
return -4;//´íÎóµÄ³¤¶ÈÊý¾Ý
}
//cmd_length += CMD_IND_ID_SIZE;//IND ID Size
cmd_length += CMD_CHECKSUM_SIZE;//CheckSum Size
ring_size = RingQueueLook(&RingQueue, p_data, cmd_length, &ring_err);
if(ring_size < cmd_length)
return -5;//¶ÁÈ¡µ½µÄÊý¾ÝÁ¿²»×ãÒ»Ö¡
if(0 != (unsigned char)CalChecksum((char*)p_data,cmd_length))
{
RingQueueOut(&RingQueue, p_data, 2, &ring_err);//Å×Æú´íÎóµÄÁ½¸öÊý¾ÝÍ·
return -6;//УÑé´íÎó
}
ring_size = RingQueueOut(&RingQueue, p_data, cmd_length, &ring_err);
if (ring_err != RQ_ERR_NONE)
{
return -7; //Êý¾Ý¶ÁÈ¡´íÎó
}
return cmd_length;//ring_size;
}
#else
/*!
* Compute a CRC for a specified buffer.
* \param[in] pBuffer Read only buffer to compute the CRC on.
* \param[in] bufferSize Buffer size in bytes.
* \return The computed 16 bit CRC.
*/
unsigned short calcCRC(const void *pBuffer, unsigned short bufferSize)
{
const unsigned char *pBytesArray = (const unsigned char*)pBuffer;
unsigned short poly = 0x8408;
unsigned short crc = 0;
unsigned char carry;
unsigned char i_bits;
unsigned short j;
for (j =0; j < bufferSize; j++)
{
crc = crc ^ pBytesArray[j];
for (i_bits = 0; i_bits < 8; i_bits++)
{
carry = crc & 1;
crc = crc / 2;
if (carry)
{
crc = crc^poly;
}
}
}
return crc;
}
int GetCommandFromRingQueue(unsigned char *p_data,unsigned int max_size)
{
unsigned char ring_err = 0;
unsigned int ring_size = 0;
volatile unsigned int cmd_length = 0;
unsigned short check_sum = 0;
if (RingQueueGetLength(&RingQueue) < MIN_CMD_SIZE) //Ö¸Á¶È×îСΪMIN_CMD_SIZE×Ö½Ú
return -1;
ring_size = RingQueueLook(&RingQueue, p_data, MIN_CMD_SIZE, &ring_err);//ÏÈÈ¡³öMIN_CMD_SIZE×Ö½ÚÍ·Êý¾Ý
if(ring_size != MIN_CMD_SIZE)
return -2;

if((p_data[0] != PACKAGE_HEAD_SYNC_1)||(p_data[1] != PACKAGE_HEAD_SYNC_2))//Æ¥ÅäÍ·Á½¸ö×Ö½Ú
{
RingQueueOut(&RingQueue, p_data, 2, &ring_err);//Å×Æú´íÎóµÄÁ½¸öÊý¾ÝÍ·
return -3;
}
cmd_length = MIN_CMD_SIZE + p_data[4] + p_data[5]*256;
if(cmd_length > CMD_MAX_DATA_SIZE)
{
RingQueueOut(&RingQueue, p_data, 2, &ring_err);//³¤¶È²»¶ÔÅ×Æú´íÎóµÄÁ½¸öÊý¾ÝÍ·
return -4;//´íÎóµÄ³¤¶ÈÊý¾Ý
}
ring_size = RingQueueLook(&RingQueue, p_data, cmd_length, &ring_err);
if(ring_size < cmd_length)
return -5;//¶ÁÈ¡µ½µÄÊý¾ÝÁ¿²»×ãÒ»Ö¡
check_sum = p_data[cmd_length - 3] + p_data[cmd_length - 2]*256;
if(check_sum != (unsigned short)calcCRC((char*)(p_data + 2),cmd_length - 5))//´ÓµÚ2×Ö½Ú¿ªÊ¼¼ÆËã,²»¼ÆËãͷβºÍ×ÔÉí5×Ö½Ú
{
RingQueueOut(&RingQueue, p_data, 2, &ring_err);//Å×Æú´íÎóµÄÁ½¸öÊý¾ÝÍ·
return -6;//УÑé´íÎó
}
ring_size = RingQueueOut(&RingQueue, p_data, cmd_length, &ring_err);
if (ring_err != RQ_ERR_NONE)
{
return -7; //Êý¾Ý¶ÁÈ¡´íÎó
}
return ring_size;
}
#endif
/**
  * @brief  Function called from DMA1 IRQ Handler when Tx transfer is completed 
  * @param  None
  * @retval None
  */
void DMA1_TransmitComplete_Callback(void)
{
  /* DMA Tx transfer completed */
/* Disable UART_DMA_NUM Tx Channel */
  LL_DMA_DisableStream(UART_DMA_NUM, UART_SEND_STREAM);
}


/**
  * @brief  Function called from DMA1 IRQ Handler when Rx transfer is completed 
  * @param  None
  * @retval None
  */
void DMA1_ReceiveComplete_Callback(void)
{
unsigned char err;
  /* DMA Rx transfer completed */
//NVIC_DisableIRQ(DMA1_Stream5_IRQn);
//LL_USART_DisableDMAReq_RX(UART_NUM);
  /* Disable UART_DMA_NUM Rx Channel */
  LL_DMA_DisableStream(UART_DMA_NUM, UART_RECV_STREAM);
RingQueueIn(&RingQueue, (pRQTYPE)cRxDMABuffer,DMA_RECEPT_DATA_SIZE, RQ_OPTION_WHEN_FULL_DISCARD_FIRST, &err);
//SerialDMASend(cRxDMABuffer,DMA_RECEPT_DATA_SIZE);
//uart3_send(cRxDMABuffer, DMA_RECEPT_DATA_SIZE);
 /* Enable DMA Channel Rx */
  LL_DMA_EnableStream(UART_DMA_NUM, UART_RECV_STREAM);
//LL_USART_EnableDMAReq_RX(UART_NUM);
//NVIC_EnableIRQ(DMA1_Stream5_IRQn);
}


/**
  * @brief  Function called in case of error detected in USART IT Handler
  * @param  None
  * @retval None
  */
void USART_TransferError_Callback(void)
{
  /* Disable UART_DMA_NUM Tx Channel */
  LL_DMA_DisableStream(UART_DMA_NUM, UART_SEND_STREAM);


  /* Disable UART_DMA_NUM Rx Channel */
  LL_DMA_DisableStream(UART_DMA_NUM, UART_RECV_STREAM);


  /* Set LED1 to Blinking mode to indicate error occurs */
  //LED_Blinking(LED_BLINK_ERROR);
}

猜你喜欢

转载自blog.csdn.net/wuyusheng314/article/details/79428056