Skip to content

Lidar Mapping (PoC) »

GNSS Emulator using STM32 MCU

Last update: 2022-05-07


The emulator should output:

  1. PPS signal at 1Hz, 25% duty cycle

  2. GPRMC at 1Hz, about 83 bytes per message

  3. GNGGA at 1Hz, about 86 bytes per message

  4. OBSVMA at 1Hz, about 2700 bytes per message

  5. All messages are aligned to the rising edge of PPS signal.
    Outputs are concurrent.


The main MCU is STM32F103C8Tx, mounted on a Blue Pill dev board.

PPS Signal#

PPS signal will be output by PWM function of the Timer 1 module:

  • Clock source: Internal Clock, at 72 MHz
  • Channel 1: PWM Generation CH1
  • Pre-scaler PSC: 36000-1
  • Counter Period AAR: 2000-1
  • PWM Generation Channel 1:
    • Mode: 1 (Positive at start)
    • Pulse: 500 (25% of AAR)
  • Interrupt: on Update

UART Protocol#

Using a setting of 8-N-1 (8 bit, No parity, 1 stop bit), each byte requires 10 bits. Baud rate at 115200 bit-per-second means the speed is 11520 byte-per-second. At this speed, 4 OBSVMA messages can be transfer completely in a second.

All messages on UART ports will be sent in DMA mode which allows sending data concurrently. Interrupt must be enabled to make DMA function work properly.

The UART1, UART2, UART3 are configured as:

  • Mode: Asynchronous
  • Hardware Flow Control: Disabled
  • Baud Rate: 115200 bps, 8-N-1
  • Interrupt: Enabled
  • DMA:
    • Channel: TX
    • Direction: Memory to Peripheral,
    • Mode: Normal
    • Data width: Byte
    • Increment Address: Memory only


All messages are pre-filled, only some necessary parts will be modified to reduce processing time.

  • UTC Time must be updated every second in GPRMC and GNGGA
  • GPRMC message must have correct CRC value







OBSVMA is a long message, at least 2600 bytes

Pin map on STM32F103C8Tx



  • Messages are predefined. Only timestamp bytes and CRC need to be updated. Pre-calculate an CRC byte except timestamp bytes at startup.
  • When timestamp is update, new CRC is calculated using pre-calculated CRC and timestamp bytes. This reduces time of updating message.
  • All messages will be sent using DMA mode to not block each other.

Example for GPRMC messages:

uint8_t GPRMC_Buffer[]="$GPRMC,000000.00,A,2057.59811106,N,10546.17288672,E,0.109,193.8,200821,1.5,W,A*21\r\n";
uint32_t GPRMC_Length  = 0;
uint8_t GPRMC_CRC_Old  = 0; // CRC except time, calculated once at startup
uint8_t GPRMC_CRC_New  = 0; // CRC New = CRC Old + Timestamps[]

Main loop will send 3 messages using DMA:

int main(void)
    GPRMC_Length  = strlen((char*)GPRMC_Buffer);
    GPRMC_CRC_Old = CalculateCRC(GPRMC_Buffer, GPRMC_Length);

    while (1)
        if (PPS_flag == 1) {
            UpdateTime(GPRMC_Buffer+7, &Clock);
            GPRMC_CRC_New = RecalculatedCRC(GPRMC_Buffer+7, 6, &GPRMC_CRC_Old);
            UpdateCRC(GPRMC_Buffer+79, &GPRMC_CRC_New);
            HAL_UART_Transmit_DMA(&huart1, GPRMC_Buffer, GPRMC_Length);

            ... other code ...
            HAL_UART_Transmit_DMA(&huart2, GNGGA_Buffer, GNGGA_Length);

            ... other code ...
            HAL_UART_Transmit_DMA(&huart3, OBSVMA_Buffer, OBSVMA_Length);


Output of GNSS emulator

Concurrent outputs