About the configuration of serial port opening DMA for sending and receiving

When I was developing with STM32 before, I used 485 to collect data. Because the amount of data is relatively large, the DMA channel is turned on. Here is a summary of the 485 serial port configuration and DMA configuration and subsequent related transceiver operations. First of all, my 485 is connected to the serial port one on the board. According to the manual, it can be seen that the channel 4 and channel 5 of DMA1 are used here, and the next step is the related configuration. PS: Development with library functions

// some definitions

#define RX_LEN 1024

u8 real_recv_len ; //The length of the data actually received by the serial port

OS_SEM tx_sem; //Semaphore sent


Serial port configuration:

/*Open serial port 1 GPIO to deduct DMA related clock*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//Open the remapping function of GPIOA
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/*Configure the IO port function of RX TX*/

//PA10  RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//PA9  TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//UART1
  USART_InitStructure.USART_BaudRate = 9600;//9600;
  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_Tx; //Do not enable receiving the corresponding task to enable
  USART_Init(USART1, &USART_InitStructure);
  USART_ClearFlag(USART1, USART_FLAG_TC);
  USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
  USART_DMACmd(USART1, USART1, ENABLE);
  USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
  //DMA1_CH4 USART1 TX
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //Destination address
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //Direction
  DMA_InitStructure.DMA_PeripheralInc = DMA_DisableInc The peripheral address register is not incremented
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //The memory address is incremented
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //Peripheral byte is the unit
  DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //The unit of memory
  _ InitStructure.DMA_Mode = DMA_Mode_Normal; //
  DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M
  = DMA_M2M_Disable ; DMA_IT_TC, ENABLE); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //Direction DMA_Init(DMA1_Channel5, &DMA_InitStructure); USART_Cmd(USART1, ENABLE);
 
 
 
 
 


Next is the configuration of the interrupt function and the sending and receiving of data.

First define the macro definition of DMA enable

#define DMA1_CH4_EN()  DMA1_Channel4->CCR |= DMA_CCR1_EN  //开DMA
#define DMA1_CH5_EN()  DMA1_Channel5->CCR |= DMA_CCR1_EN;//开DMA
#define DMA1_CH4_DIS() DMA1_Channel4->CCR &= (u16)(~DMA_CCR1_EN)  //关DMA
#define DMA1_CH5_DIS() DMA1_Channel5->CCR &= (u16)(~DMA_CCR1_EN);  //关DMA

Next is the completion of the interrupt function

void USART1_IRQHandler()
{
u32 temp;
int len;
u16 crc , crc_sum; 

usart1_rx_dis();  //First close the serial port reception

//Clear the interrupt flag
temp = USART1->SR;
temp = USART1->DR;

real_recv_len = MODBUS_RX_LEN - DMA1_Channel5->CNDTR; //The length of the data received this time

//You can do what you want, but don't do too complicated operations in the interrupt function and don't do some data-heavy operations and floating-point operations

...

...

...

//Enable the reception of serial port 1 after the operation

usart1_rx_en ();
}

//The following is the interrupt function of DMA

void DMA1_Channel4_IRQHandler()
{
DMA1->IFCR = DMA1_IT_TC4; //Clear the flag
DMA1_CH4_DIS(); //Close send DMA
isr_sem_send(&tx_sem); //Set the semaphore
}


// send function below

static int usart1_send(u8* buf, u8 lenth)
{
//Use the semaphore to determine whether DMA1 is interrupted
if(os_sem_wait(&tx_sem, 50) == OS_R_TMO)
{
DMA1_CH4_DIS();
}


  DMA1_Channel4->CMAR = (u32)buf;
  DMA1_Channel4->CNDTR = lenth;
usart1_rx_en (); 
  DMA1_CH4_EN (); // Publish
return 0;
}


//The following is the encapsulation of the receive initialization and enable failure function of channel one


//Enable receiving
static void usart1_rx_en()
{
DMA1_Channel5->CNDTR = RX_LEN;
DMA1_CH5_EN ();
USART1->CR1 |= USART_Mode_Rx; //Enable reception
}

//Close reception
static void usart1_rx_dis()
{
USART1->CR1 &= ~USART_Mode_Rx; //Close reception
DMA1_CH5_DIS(); //Turn off receive DMA
}

//Receive initialization
void lcd_rx1_init()
{
DMA1_Channel5->CNDTR = RX_LEN;
DMA1_Channel5->CMAR = (u32)modebus_rx_buff;
}


After testing, it can be used normally. Most of them refer to the book "Playing with STM32 with Zero Dead Angle". It is well written and many examples are very useful.


    






Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325589852&siteId=291194637