USART (Universal Synchronous/Asynchronous Receiver/Transmitter) is the serial communication backbone of most embedded projects. On the PY32F0xx, USART is used for debug output, communicating with a host PC, connecting GPS modules, and interfacing with other microcontrollers.
The PY32F0xx USART implementation is functionally identical to STM32 USART, making any existing STM32 USART knowledge directly applicable.
USART vs UART
The PY32F0xx implements USART — a superset of UART that adds synchronous mode (a shared clock signal between transmitter and receiver). In practice, asynchronous UART mode is used for virtually all applications, which requires no clock line.
UART (Asynchronous): TX and RX wires only, both sides pre-agree on baud rate
USART (Synchronous): TX, RX, and CLK wires — master drives the clock
Most applications use UART mode (no CLK signal).
USART1 Pin Mapping on PY32F003
| Signal | Default GPIO Pin |
|---|---|
| USART1_TX | PA9 (or PA1 on remapped) |
| USART1_RX | PA10 (or PA0 on remapped) |
On the PY32F003 in TSSOP20 package, PA1 (TX) and PA0 (RX) are the accessible USART pins.
Complete USART1 Configuration
Step 1: Enable Clocks
// Enable clock for GPIOA (for TX and RX pins)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// Enable clock for USART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
Both GPIOA and USART1 are on the APB2 bus on the PY32F003.
Step 2: Configure GPIO Pins for USART
GPIO_InitTypeDef GPIO_InitStructure;
// Configure PA9 (or PA1) as USART1 TX
// Alternate function push-pull output
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA9 = TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // Alternate function
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure PA10 (or PA0) as USART1 RX
// Floating input — let the transmitting device drive the signal
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PA10 = RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
Step 3: Configure USART1 Settings
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 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 | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
Configuration Options
| Parameter | Common Values | Notes |
|---|---|---|
USART_BaudRate | 9600, 19200, 115200 | Must match the connected device |
USART_WordLength | USART_WordLength_8b, USART_WordLength_9b | 8-bit is standard |
USART_StopBits | USART_StopBits_1, USART_StopBits_2 | 1 stop bit is standard |
USART_Parity | USART_Parity_No, USART_Parity_Even, USART_Parity_Odd | No parity is most common |
USART_Mode | USART_Mode_Tx, USART_Mode_Rx, or both | Enable TX, RX, or full-duplex |
Step 4: Enable USART1
USART_Cmd(USART1, ENABLE);
Sending Data Over USART
To transmit a single byte, write to the USART data register and wait for the transmit buffer to be empty:
void USART_SendByte(USART_TypeDef *USARTx, uint8_t data) {
// Wait until transmit data register is empty
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
USART_SendData(USARTx, data);
}
To transmit a string:
void USART_SendString(USART_TypeDef *USARTx, const char *str) {
while (*str) {
USART_SendByte(USARTx, (uint8_t)*str);
str++;
}
}
Usage:
USART_SendString(USART1, "Hello from PY32!\r\n");
Receiving Data Over USART
To receive a single byte (polling mode):
uint8_t USART_ReceiveByte(USART_TypeDef *USARTx) {
// Wait until data is received
while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET);
return (uint8_t)USART_ReceiveData(USARTx);
}
For non-blocking reception, use interrupt-driven mode:
// Enable RXNE interrupt in USART
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// Configure NVIC for USART1
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// ISR: called when a byte is received
void USART1_IRQHandler(void) {
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
uint8_t received = USART_ReceiveData(USART1);
// Process received byte here
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
Complete USART Echo Example
This example initializes USART1 and echoes back every received character:
#include "py32f0xx.h"
#include "py32f0xx_gpio.h"
#include "py32f0xx_rcc.h"
#include "py32f0xx_usart.h"
void USART1_Init(void) {
// Enable clocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// Configure GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure USART
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 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 | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
int main(void) {
USART1_Init();
USART_SendString(USART1, "PY32 USART Echo Ready\r\n");
while (1) {
// Wait for and echo received byte
uint8_t byte = USART_ReceiveByte(USART1);
USART_SendByte(USART1, byte);
}
}
USART Wiring
PY32F003 USB-TTL Adapter / Other Device
-------- --------------------------------
PA9 (TX) -----> RX
PA0 (RX) <----- TX
GND ------ GND
Always cross-connect TX to RX and share a common GND reference.
Final Thoughts
USART on the PY32F0xx is straightforward to configure and is the first peripheral most developers bring up in a new project — typically to enable printf-style debug output. The configuration flow matches STM32 exactly, making any existing STM32 USART code directly portable.
Interrupt-driven reception is preferred for any non-trivial application because it keeps the CPU free during idle periods rather than polling the receive buffer in a tight loop.
USART is the voice of the PY32 — it is how the microcontroller communicates with the world.