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.