STM32F103 series practical universal synchronous asynchronous receiver and transmitter (USART)

Publisher:boyhxzLatest update time:2018-12-17 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Universal Synchronous/Asynchronous Receiver/Transmitter (USART)


The STM32F103xC, STM32F103xD and STM32F103xE enhanced series products have three built-in universal synchronous/asynchronous receivers (USART1, USART2 and USART3), and two universal asynchronous receivers (UART4 and UART5). These five interfaces provide asynchronous communication, support IrDA SIR ENDEC transmission codec, multi-processor communication mode, single-line half-duplex communication mode and LIN master/slave function. The communication rate of the USART1 interface can reach 4.5 Mbit/s, and the communication rate of other interfaces can reach 2.25 Mbit/s. The USART1, USART2 and USART3 interfaces have hardware CTS and RTS signal management, ISO7816 compatible smart card mode and SPI-like communication mode. All other interfaces except UART5 can use DMA operation.


1. Main features of USART


1.1. Full-duplex, asynchronous communication

1.2.NRZ standard format

1.3. Fractional Baud Rate Generator System

    1.3.1Programmable baud rate for both sending and receiving, up to 4.5Mbits/s

1.4. Programmable data word length (8 or 9 bits)

1.5. Configurable stop bits - supports 1 or 2 stop bits

1.6. LIN master's ability to send a synchronous break character and LIN slave's ability to detect a break character

    1.6.1 When USART hardware is configured as LIN, a 13-bit break character is generated; a 10/11-bit break character is detected

1.7. The sender provides the clock for synchronous transmission

1.8.IRDA SIR Encoder and Decoder

    1.8.1. Support 3/16 bit duration in normal mode

1.9. Smart card emulation function

    1.9.1. Smart card interface supports asynchronous smart card protocol defined in ISO7816-3 standard

    1.9.2. 0.5 and 1.5 stop bits used by smart cards

1.10. Single-line half-duplex communication

1.11. Configurable multi-buffer communication using DMA

    1.11.1. Buffering receive/transmit bytes in SRAM using centralized DMA

1.12. Separate Transmitter and Receiver Enable Bits

1.13. Detection flag

    1.13.1. Receive buffer full

    1.13.2. Transmit Buffer Empty

    1.13.3. Transmission end mark

1.14. Verification Control

    1.14.1. Sending a check digit

    1.14.2. Verify received data

1.15. Four error detection flags


1.15.1. Overflow Error

1.15.2. Noise Error

1.15.3. Frame Error

1.15.4. Verification Error


1.16.10 interrupt sources with flags

    1.16.1.CTS Changes

    1.16.2.LIN Break Character Detection

    1.16.3. Send data register empty

    1.16.4. Sending completed

    1.16.5. Receive data register full

    1.16.6. Bus is detected to be idle

    1.16.7. Overflow Error

    1.16.8. Frame Error

    1.16.9. Noise Error


    1.16.10. Verification Error

1.17. Multiprocessor communication -- if address does not match, enter silent mode

1.18. Wake up from silent mode (by idle bus detection or address mark detection)

1.19. Two ways to wake up the receiver: address bit (MSB, bit 9), bus idle


2. USART Function Overview


The interface is connected to other devices through three pins (see the figure below). Any USART bidirectional communication requires at least two pins: receive data input (RX) and transmit data output (TX).


RX: Receive data input. Use oversampling technology to distinguish data from noise and recover data.


TX: Transmit data output. When the transmitter is disabled, the output pin reverts to its I/O port configuration. When the transmitter is enabled and not transmitting data, the TX pin is at a high level. In single-wire and smart card modes, this I/O port is used for both data transmission and reception.


2.1. The bus should be in idle state before sending or receiving

2.2. A start bit

2.3. A data word (8 or 9 bits), least significant bit first

2.4.0.5, 1, 1.5, 2 stop bits, indicating the end of the data frame

2.5. Using the fractional baud rate generator - 12-bit integer and 4-bit decimal representation.

2.6. A status register (USART_SR)

2.7. Data Register (USART_DR)

2.8. A baud rate register (USART_BRR), 12-bit integer and 4 decimal places

2.9. A smart card mode protection time register (USART_GTPR) 


The following pins are required in synchronous mode:


CK: Transmitter Clock Output. This pin outputs the clock used to synchronize transmissions (there is no clock pulse on the Start and Stop bits, and software can optionally send a clock pulse on the last data bit). Data can be received synchronously on RX. This can be used to control external devices with shift registers (such as LCD drivers). The clock phase and polarity are software programmable. In smart card mode, CK can provide the clock for the smart card.


The following pins are required in IrDA mode:


IrDA_RDI: data input in IrDA mode;


IrDA_TDO: Data output in IrDA mode.


The following pins are required in hardware flow control mode:


nCTS: Clear to send, if it is high level, it blocks the next data transmission when the current data transmission ends;


nRTS: Send request. If it is low, it indicates that USART is ready to receive data.



Taking STM32F103ZET6 as an example, the following introduces the use of the asynchronous receiver of the universal synchronous asynchronous receiver through library functions combined with register configuration (the project verifies that the operation is stable).


The general (conventional) steps for serial port settings can be summarized as follows:


1) Serial port clock enable, GPIO clock enable;


2) Serial port reset (can be omitted);


3) GPIO port mode setting;


4) Initialize serial port parameters;


5) Enable interrupts and initialize NVIC (this step is required only if interrupts need to be enabled);


6) Enable the serial port;


7) Write an interrupt handling function.


In addition to the conventional configuration method mentioned above, USART can also use DMA for continuous communication. The DMA requests for the Rx buffer and Tx buffer are generated separately.


Send using DMA


Using DMA for transmission can be activated by setting the DMAT bit on the USART_CR3 register. When the TXE bit is set to '1', DMA transfers data from the specified SRAM area to the USART_DR register. The steps to assign a DMA channel for USART transmission are as follows (x represents the channel number):


1. Configure the USART_DR register address as the destination address of DMA transfer in the DMA control register. After each TXE event, the data will be transferred to this address.


2. Configure the memory address as the source address of the DMA transfer in the DMA control register. After each TXE event, the data will be read from this memory area and transferred to the USART_DR register.


3. Configure the total number of bytes to be transferred in the DMA control register.


4. Configure channel priority on DMA registers.


5. Configure the DMA interrupt to be generated when the transfer is halfway or fully completed, as required by the application.


6. Activate the channel on the DMA register.


When the transfer completes the amount of data specified by the DMA controller, the DMA controller generates an interrupt on the interrupt vector of the DMA channel.


In transmit mode, when DMA has transmitted all the data to be transmitted, the DMA controller sets the TCIF flag of the DMA_ISR register; monitoring the TC flag of the USART_SR register can confirm whether the USART communication is over, so as to avoid destroying the last transmitted data before shutting down the USART or entering the stop mode; the software needs to wait for TXE=1 first, and then wait for TC=1.


Receiving using DMA


You can activate DMA reception by setting the DMAR bit in the USART_CR3 register. Each time a byte is received, the DMA controller transfers the data from the USART_DR register to the specified SRAM area (refer to the DMA related instructions). The steps to assign a DMA channel for USART reception are as follows (x represents the channel number):


1. Configure the USART_DR register address as the source address of the transfer through the DMA control register. After each RXNE event, data will be read from this address and transferred to the memory.


2. Configure the memory address as the destination address of the transfer through the DMA control register. After each RXNE event, the data will be transferred from USART_DR to this memory area.


3. Configure the total number of bytes to be transferred in the DMA control register.


4. Configure channel priority on DMA registers.


5. Configure the DMA interrupt to be generated when the transfer is halfway or fully completed, as required by the application.


6. Activate the channel on the DMA control register.


When the reception completes the transfer amount specified by the DMA controller, the DMA controller generates an interrupt on the interrupt vector of the DMA channel.


Error flags and interrupt generation in multi-buffer communications


In case of multi-buffer communication, if any error occurs during communication, the error flag will be set after the current byte is transferred. If the interrupt enable bit is set, an interrupt will be generated. In case of single byte reception, the frame error, overflow error and noise flags that are set together with RXNE have separate error flag interrupt enable bits; if set, an interrupt will be generated after the current byte transfer is completed.


code show as below:


1. Define receive and send data cache variables


#define COMx_RXBUFFER_SIZE 255 //Serial port receive buffer length

typedef struct COMx_RXBUFFER

{

  u8 buffer[COMx_RXBUFFER_SIZE]; //Receive buffer

  u8 RxFlag; //Receive data flag 1: New data received 0: No new data received

  u16 RxLen; //Received data length

}COMx_RXBUFFER;

#define UART1_RX_LEN COMx_RXBUFFER_SIZE //USART1 DMA receive buffer length

uint8_t Uart1_Tx[UART1_TX_LEN] = {0}; //Serial port 1 sends DMA buffer     

uint8_t Uart1_Rx[UART1_RX_LEN] = {0}; //Serial port 1 receives DMA buffer 

//Serial port 1 receives DMA buffer

COMx_RXBUFFER Uart1_RxBuffer;


2. Configure the serial port


static void BSP_USART1_Init(u32 baud)

{

    USART_InitTypeDef bsp_usart_init;

    GPIO_InitTypeDef    bsp_usartpin_init;    

    // Enable USART1 clock, enable USART1 pin clock

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);   

    //Initialize USART1 pin PA9 TX

    bsp_usartpin_init.GPIO_Pin = GPIO_Pin_9;

    bsp_usartpin_init.GPIO_Speed =  GPIO_Speed_50MHz;

    bsp_usartpin_init.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOA, &bsp_usartpin_init);    

    //Initialize USART1 pin PA10 RX

    bsp_usartpin_init.GPIO_Pin = GPIO_Pin_10;

    bsp_usartpin_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &bsp_usartpin_init);    

    // Initialize USART1 parameters

    bsp_usart_init.USART_BaudRate = baud;

    bsp_usart_init.USART_WordLength = USART_WordLength_8b;

    bsp_usart_init.USART_StopBits = USART_StopBits_1;

    bsp_usart_init.USART_Parity = USART_Parity_No;

    bsp_usart_init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    bsp_usart_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  

    USART_Init(USART1, &bsp_usart_init);    

    // Initialize interrupt

    BSP_NVIC_Init(USART1_IRQn, 1, 1);    

    // Enable USART1 bus idle interrupt

    USART_ITConfig(USART1,USART_IT_TC,DISABLE);  

    USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);  

    USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); 

    //Serial port receive DMA configuration

    BSP_DMAUsar1Rx_Init();

    //Serial port sends DMA configuration

    BSP_DMAUsar1Tx_Init();

    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //Receive using DMA

    //Open USART1

    USART_Cmd(USART1, ENABLE);

}


Analyze the above code:


1. Enable the serial port clock. The serial port is a peripheral mounted under APB2, so the enable function is:


RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);


2. Serial port reset. When a peripheral device fails, you can reset it through the reset setting, and then reconfigure the peripheral device to make it work again. Generally, when the system starts to configure the peripheral device, it will first perform the operation of resetting the peripheral device (omitted here);


3.GPIO port mode setting. Configure the pins according to the figure below. USART1 used here corresponds to pins PA9 (TX) and PA10 (RX);



4. Serial port parameter configuration. Custom baud rate, 1 start bit, 1 stop bit, 8 data bits, no parity, no flow control. Enable receiving and sending data functions.


5. Enable the bus idle interrupt and initialize the interrupt. For more information about interrupts, refer to the relevant content


The initialization interrupt code is as follows:


/*

*********************************************************************************************************

*                                            BSP_NVIC_Init()

*

* Description: Interrupt priority initialization function, used to set the priority of the interrupt

*

* Argument(s) : IRQChannel interrupt channel.

* PreemptionPrio interrupt preemption priority

* SubPrio interrupt subpriority       

*

* Return(s)   : none.

*

* Caller(s)   : Application.

*

* Note(s)     : none.

*********************************************************************************************************

*/

void BSP_NVIC_Init(u8 IRQChannel, u8 PreemptionPrio, u8 SubPrio)

{

    NVIC_InitTypeDef    bsp_nvic_init;

    

    bsp_nvic_init.NVIC_IRQChannel = IRQChannel;

    bsp_nvic_init.NVIC_IRQChannelPreemptionPriority = PreemptionPrio;

    bsp_nvic_init.NVIC_IRQChannelSubPriority = SubPrio;

    bsp_nvic_init.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&bsp_nvic_init);  

}


6. Configure DMA mode to receive serial port data. For more information about DMA, see the DMA controller introduction.


code show as below:


//USART1 receive DMA configuration

static void BSP_DMAUsar1Rx_Init(void)

{

    DMA_InitTypeDef   DMA_InitStructure;

      

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //Start DMA clock  

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); //Peripheral address      

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Rx; //Memory address      

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //dma transmission direction is unidirectional      

    DMA_InitStructure.DMA_BufferSize = UART1_RX_LEN; //Set the length of the DMA buffer during transmission     

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Disable DMA peripheral increment mode, a peripheral        

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Set DMA memory increment mode      

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //Peripheral data word length         

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //Memory data word length      

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //Set DMA transfer mode      

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //Set the DMA priority level      

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //Disable the variables in the two DMA memories from accessing each other

    DMA_Init(DMA1_Channel5,&DMA_InitStructure);   

    DMA_Cmd(DMA1_Channel5,ENABLE); //Enable channel 5  

}


7. Configure DMA mode to send serial port data. The code is as follows:


//USART1 sends DMA configuration

static void BSP_DMAUsar1Tx_Init(void)

{

    DMA_InitTypeDef   DMA_InitStructure;

    

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //Start DMA clock  

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); //DMA peripheral base address

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Tx; //DMA memory base address

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //Data transmission direction, read from memory and send to peripherals

    DMA_InitStructure.DMA_BufferSize = UART1_TX_LEN; //DMA channel DMA buffer size

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Peripheral address register remains unchanged

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Memory address register increment

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //Data width is 8 bits

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //Data width is 8 bits

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //Work in normal mode

    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA channel x has medium priority 

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA channel x is not set for memory to memory transfer

    DMA_Init(DMA1_Channel4, &DMA_InitStructure); //Initialize the registers identified by the DMA channel USART1_Tx_DMA_Channel according to the parameters specified in DMA_InitStruct                

}


8. Enable DMA mode to receive data and turn on the serial port function.


9. The interrupt processing function is as follows:


//USART1 interrupt function.

void USART1_IRQHandler(void)

{    

    uint16_t i = 0; 

    OSIntEnter(); 

    

    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  

    {

      //1. Clear USART1 receive completion interrupt

        //USART_ClearFlag(USART1,USART_IT_IDLE);  

        USART1->SR;  

        USART1->DR; //Clear USART_IT_IDLE flag  

      //2. Store the received data content, length, and flag bit

        DMA_Cmd(DMA1_Channel5,DISABLE); //Disable DMA

        if(!Uart1_RxBuffer.RxFlag) //Determine whether there is a data packet being processed

        {

            Uart1_RxBuffer.RxLen = UART1_RX_LEN - 

                                   DMA_GetCurrDataCounter(DMA1_Channel5); //Calculate the length of the received data packet      

            for (i = 0;i < Uart1_RxBuffer.RxLen;i++) // Cache the received data packet

            {  

                Uart1_RxBuffer.buffer[i] = Uart1_Rx[i];

            }

            Uart1_RxBuffer.RxFlag = 1; //Set the receiving status flag

        }

        DMA_SetCurrDataCounter(DMA1_Channel5,UART1_RX_LEN); //Set the transmission data length

        DMA_Cmd(DMA1_Channel5,ENABLE); //Open DMA 

    }     

    // 3. Send message to task_command_process

    OSMboxPost(MboxCmdSet, &Uart1_RxBuffer.buffer[0]); // Inform App_TaskCommandProcess() that one command has arrived.

    OSIntExit(); 

}


Because the project is developed based on the ucos-ii system, the interrupt function contains ucos-ii system related functions. The interrupt processing steps are as follows:


    9.1. Determine whether the interrupt type is a bus idle interrupt. If not, exit the interrupt without any processing; if yes, continue processing;


    9.2. Clear the interrupt flag;


    9.3. Turn off the DMA receiving function and obtain the length of the received data;


    9.4. Extract the received data from the DMA receive buffer according to the received data length;


    9.5. Reset DMA transfer data length and enable DMA receiving function;


    9.6. Exit the interrupt handling function.


Since the time when the serial port receives data is unknown, interrupts are used to process the received data. However, it is obviously not enough to only receive data without interruption. The following is an introduction to the data sending function. The code is as follows:


//USART1 DMA sends data of specified length

//str: the first address of the data to be sent

//cndtr: data transmission volume 

void BSP_DMAUsart1Puts(unsigned char *str,u8 cndtr)

{   

    memcpy(Uart1_Tx, str, cndtr);

    USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //Enable DMA transmission of serial port 1

    DMA_Cmd(DMA1_Channel4, DISABLE ); //Disable the channel indicated by USART1 TX DMA1      

    DMA_SetCurrDataCounter(DMA1_Channel4,cndtr); //DMA channel DMA buffer size

    DMA_Cmd(DMA1_Channel4, ENABLE); //Enable the channel indicated by USART1 TX DMA1     

}


The time to send data through the serial port is predictable, so the normal way to send serial port data can be used. The steps are as follows:


1. Transfer the data to be sent to the DMA send buffer;


2. Turn off the DMA serial port data sending function;


3. Set the size of the data to be sent;


4. Enable the DMA serial port sending function to send the data out.


This concludes the introduction to serial communication. To get the received data, just check the data in the variable Uart1_RxBuffer.buffer[]. To send data, call the following function.


void BSP_DMAUsart1Puts(unsigned char *str,u8 cndtr);

Reference address:STM32F103 series practical universal synchronous asynchronous receiver and transmitter (USART)

Previous article:STM32F103 USART serial port simple implementation
Next article:STM32 serial communication USART program example

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号