The STM32G030

The STM32G030 is similar in many ways to the STM32F030. It has approximately the same peripherals and is available for a similar price (in western countries). There are some significant differences however:
The ‘G030 however uses a Cortex M0+ (instead of the M0 in the F030),
The ‘G030 has a maximum clock speed of 64MHz (48MHz for the F030),
The model I chose STM32G030K8T6 has twice the Flash (64KB) and twice the RAM (8KB) that the ‘F030 has.
stm32g030_display
Full size image
I’ve put together a number of examples over on github that might help someone get started. These include a simple blinky, serial comms, serial comms with an ADC, systick interrupts and finally driving an ST7789 LCD display.

Performance improvement for STM32F030/ST7789 graphics library

stm32f030_st7789_nrf24l01

I’ve been working on a new project involving an STM32F030, an ST7789 display and an NRF24L01 radio link. As part of this project I took a good look at the graphics library that I used in the Dublin Maker badge in 2019. It turns out that there was plenty of scope to improve it’s performance. Tweaks included flattening function calls and using the set/reset registers in the STM32F030. Here’s an excerpt from the old library:

void display::fillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t Colour)
{
    openAperture(x, y, x + width - 1, y + height - 1);
    for (y = 0; y < height; y++)
    {
        for (x = 0; x < width; x++)
        {
            writeData16(Colour);
        }
    }
}
void display::RSLow()
{
    GPIOB->ODR &= ~(1 << 1); // drive D/C pin low
}
void display::RSHigh()
{ 
    GPIOB->ODR |= (1 << 1); // drive D/C pin high
}

The new version of these functions looks like this:

void display::fillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t Colour)
{
    
    register uint32_t pixelcount = height * width;
    uint16_t LowerY = height+y;
    if ((LowerY) <= VIRTUAL_SCREEN_HEIGHT) 
    {
        openAperture(x, y, x + width - 1, y + height - 1);
        RSHigh();
        while(pixelcount--)
            transferSPI16(Colour);
    }
    else
    {
        // Drawing a box beyond the extents of the virtual screen.  
        // Need to wrap this around to the start of the screen.
        uint16_t LowerHeight = (VIRTUAL_SCREEN_HEIGHT-y);
        uint16_t UpperHeight = height - LowerHeight;
        openAperture(x, y, x + width - 1, VIRTUAL_SCREEN_HEIGHT-1);
        RSHigh();
        pixelcount = LowerHeight * width;
        while(pixelcount--)
            transferSPI16(Colour);
      
        openAperture(x, 0,x + width - 1, UpperHeight);
        RSHigh();
        pixelcount = UpperHeight * width;
        while(pixelcount--)
                transferSPI16(Colour);
        
    }
}
void display::RSLow()
{ 
// Using Set/Reset register here as this needs to be as fast as possible   
    GPIOB->BSRR = ((1 << 1) << 16); // drive D/C pin low
}
void display::RSHigh()
{ 
// Using Set/Reset register here as this needs to be as fast as possible     
    GPIOB->BSRR = ((1 << 1)); // drive D/C pin high
}

The new version is a good deal bigger for a couple of reasons:
First of all, the fill rectangle function has been extended so that it is usable with display scrolling (a new feature)
Secondly, the call to writeData16 has been eliminated (removing the function call overhead). This means that lower level SPI function calls have to be used. Also, the nested loop for x and y co-ordinates has been changed to a single loop that fires out the pixels as a continuous stream – the display hardware itself looks after the x and y coordinates.

So how much faster is it? To test this I wrote a simple program to fire a full filled rectangle at the display 50 times and measured how long it took.
The results:
The old driver :
50 rectangles (240*240) took 8.6 seconds. This corresponds to a pixel write speed of 334883 pixels per second.
The new driver:
50 rectangles (240*240) took 4.6 seconds or 626086 pixels per second. Nearly twice as fast as the older library. At this speed it takes 92 milliseconds to fill the display. Not stellar by PC standards but good enough for my needs.
Code is available over on github.

Environmental sensing using the STM32G071

stm32g071_environment_assembled_board
Full size image
This project displays information about the environment on an ST7789 display. There’s a text version of the data and a simple trend graph of the dust/pollen data. The sensors used are as follows:
Pressure/Temperature: BMP280
Light : TLS2561
Dust : DM501A

The BMP280 and TLS2561 connect back to the STM32G071 over the I2C1 bus. The DM501A light sensor connects back to a GPIO pin. This pin is sampled at 1kHz. When a dust particle is detected in the sensor this pin is driven low. The program simply counts the number of milliseconds (samples) that this pin is low over a 1 minute interval and displays this figure.

Environmental information is sent back to a host PC using a UART. It is also written to the ST7789 display.

Code is available over here on github.

The STM32F030 driving an ST7789 display

The ST7789 display used in this example is a 1.3 inch 240×240 colour LCD display. It interfaces to the STM32F030 at the pretty fast speed of 24MHz. The display is connected as follows:
stm32f030_st7789_schematic
My intention with this circuit is to create a low cost conference badge (actually for Dublin Maker 2019). The target bill-of-materials cost is €5 – most of which is attributed to the display.
stm32f030_st7789
Full size image
Connecting the hardware is only part of the story however and a software library is also required. This was based on the Breadboard Games code from last August in Wexford. The main changes that had to be addressed were the new initialization code and the openAperture code. These were based on the Adafruit library code and the manufacturer’s datasheet. This library includes some graphic drawing primitives as well as other functions to support game play (e.g. timing and random number generation). Additional functions will be added as the badge develops.
Code is available on github
A video of the library in operation is available on YouTube.