_       _       
  (_) ___ | |_ ____
  | |/ _ \| __|_  /
  | | (_) | |_ / / 
 _/ |\___/ \__/___|
|__/               

Frank's barebones program and build script for STM32F031x6

Frank Duignan's barebones program and build script for ARM STM32F031K6

To install GCC for ARM Cortex-R/M processors on Debian:

sudo apt install gcc-arm-none-eabi

build.sh

# STM32F031K6 build script by Frank Duignan

arm-none-eabi-gcc -static -mthumb -g -mcpu=cortex-m0 *.c -T linker_script.ld -o main.elf -nostartfiles
arm-none-eabi-objcopy -g -O binary main.elf main.bin

linker_script.ld

/* Code by Frank Duignan */

/* Linker script for stm32f031*/
MEMORY
{
    flash : org = 0x08000000, len = 32k
    ram : org = 0x20000000, len = 4k
}

SECTIONS
{

    . = ORIGIN(flash);
        .text : {
          *(.vectors); /* The interrupt vectors */
          *(.text);
        } >flash
    . = ORIGIN(ram);
        .data : {
      INIT_DATA_VALUES = LOADADDR(.data);
      INIT_DATA_START = .;
        *(.data);
      INIT_DATA_END = .;
        } >ram AT>flash
    BSS_START = .;
    .bss : {

        *(.bss);

    } > ram
    BSS_END = .;
}

init.c

//
// Code by Frank Duignan
//

#include <stdint.h>
#include "../include/stm32f031x6.h"

void init(void);
void Default_Handler(void);
int main(void);

// The following are 'declared' in the linker script
extern unsigned char  INIT_DATA_VALUES;
extern unsigned char  INIT_DATA_START;
extern unsigned char  INIT_DATA_END;
extern unsigned char  BSS_START;
extern unsigned char  BSS_END;

// the section "vectors" is placed at the beginning of flash 
// by the linker script
const void * Vectors[] __attribute__((section(".vectors"))) ={
    (void *)0x20001000,     /* Top of stack (4k) */ 
    init,           /* Reset Handler */
    Default_Handler,    /* NMI */
    Default_Handler,    /* Hard Fault */
    Default_Handler,    /* MemManage */
    Default_Handler,    /* Reserved  */
    Default_Handler,    /* Reserved */
    Default_Handler,    /* Reserved */ 
    Default_Handler,    /* Reserved */
    Default_Handler,    /* Reserved */
    Default_Handler,    /* Reserved */
    Default_Handler,    /* SVCall */
    Default_Handler,    /* Reserved */
    Default_Handler,    /* Reserved */
    Default_Handler,    /* PendSV */
    Default_Handler,    /* SysTick */   
/* External interrupt handlers follow */
    Default_Handler,    /* 0: WWDG */
    Default_Handler,    /* 1: Reserved */
    Default_Handler,    /* 2: RTC */
    Default_Handler,    /* 3: FLASH */
    Default_Handler,    /* 4: RCC */
    Default_Handler,    /* 5: EXTI0_1 */
    Default_Handler,    /* 6: EXTI2_3 */
    Default_Handler,    /* 7: EXTI4_5 */
    Default_Handler,    /* 8: Reserved */
    Default_Handler,    /* 9: DMA_CH1 */
    Default_Handler,    /* 10: DMA_CH2_3 */
    Default_Handler,    /* 11: DMA_CH4_5 */
    Default_Handler,    /* 12: ADC */
    Default_Handler,    /* 13: TIM1_BRK_UP_TRG_COM */
    Default_Handler,    /* 14: TIM1_CC */
    Default_Handler,    /* 15: Reserved */
    Default_Handler,    /* 16: TIM3 */
    Default_Handler,    /* 17: Reserved */
    Default_Handler,    /* 18: Reserved */
    Default_Handler,    /* 19: TIM14 */
    Default_Handler,    /* 20: TIM15 */
    Default_Handler,    /* 21: TIM16 */
    Default_Handler,    /* 22: TIM17 */
    Default_Handler,    /* 23: I2C1 */
    Default_Handler,    /* 24: I2C2 */
    Default_Handler,    /* 25: SPI1 */
    Default_Handler,    /* 26: SPI2 */
    Default_Handler,    /* 27: USART1 */
    Default_Handler     /* 28: USART2 */
};

void initClock()
{
// This is potentially a dangerous function as it could
// result in a system with an invalid clock signal - result: a stuck system
        // Set the PLL up
        // First ensure PLL is disabled
        RCC->CR &= ~(1<<24);
        while( (RCC->CR & (1 <<25))); // wait for PLL ready to be cleared

  // Warning here: if system clock is greater than 24MHz then wait-state(s) need to be
        // inserted into Flash memory interface
        Flash->ACR |= (1 << 0);
        Flash->ACR &=~((1 << 2) | (1<<1));
        // Turn on FLASH prefetch buffer
        Flash->ACR |= (1 << 4);
        // set PLL multiplier to 12 (yielding 48MHz)
        RCC->CFGR &= ~((1<<21) | (1<<20) | (1<<19) | (1<<18));
        RCC->CFGR |= ((1<<21) | (1<<19) ); 

        // Need to limit ADC clock to below 14MHz so will change ADC prescaler to 4
        RCC->CFGR |= (1<<14);

// Do the following to push HSI clock out on PA8 (MCO)
// for measurement purposes.  Should be 8MHz or thereabouts (verified with oscilloscope)
/*
        RCC_CFGR |= ( (1<<26) | (1<<24) );
        RCC_AHBENR |= (1<<17);
        GPIOA_MODER |= (1<<17);
*/
        // and turn the PLL back on again
        RCC->CR |= (1<<24);        
        // set PLL as system clock source 
        RCC->CFGR |= (1<<1);
}

void init()
{
    unsigned char *src;
    unsigned char *dest;
    unsigned len;

    // initialise clock
    //initClock();

    // do global/static data initialization
    src= &INIT_DATA_VALUES;
    dest= &INIT_DATA_START;
    len= &INIT_DATA_END-&INIT_DATA_START;
    while (len--) *dest++ = *src++;

    // zero out the uninitialized global/static variables
    dest = &BSS_START;
    len = &BSS_END - &BSS_START;
    while (len--) *dest++=0;

    main();
}

void Default_Handler()
{
    while(1);
}

main.c

//
// Based on example code by Frank Duignan
//

#include <stdint.h>
#include "../include/stm32f031x6.h"

// Utility function prototypes
void pinMode(GPIO_TypeDef *Port, uint32_t BitNumber, uint32_t Mode);
void enablePullUp(GPIO_TypeDef *Port, uint32_t BitNumber);
void delay(volatile uint32_t dly);

int main()
{
    RCC->AHBENR |= (1 << 18) + (1 << 17); // enable Ports A and B

    pinMode(GPIOA,0,1); // Make GPIOA bit 0 an output
    pinMode(GPIOA,1,1); // Make GPIOA bit 1 an output
    pinMode(GPIOA,2,1); // Make GPIOA bit 2 an output

    pinMode(GPIOB,3,1); // Make GPIOB bit 3 an output
    pinMode(GPIOB,4,0); // Make GPIOB bit 4 an input

    enablePullUp(GPIOB,4); // Turn on pull-up resistor for bit 4

    while(1)
    {
        GPIOA->ODR |= 1<<2; // set PA2
        delay(100000 + ((GPIOB->IDR & 1<<4) != 0)*100000);
        GPIOA->ODR &= ~(1<<2); // clear PA2
        delay(100000 + ((GPIOB->IDR & 1<<4) != 0)*100000);
    }
}

void enablePullUp(GPIO_TypeDef *Port, uint32_t BitNumber)
{
    Port->PUPDR = Port->PUPDR &~(3u << BitNumber*2); // clear pull-up resistor bits
    Port->PUPDR = Port->PUPDR | (1u << BitNumber*2); // set pull-up bit
}

void pinMode(GPIO_TypeDef *Port, uint32_t BitNumber, uint32_t Mode)
{
    uint32_t mode_value = Port->MODER;
    Mode = Mode << (2 * BitNumber);
    mode_value = mode_value & ~(3u << (BitNumber * 2));
    mode_value = mode_value | Mode;
    Port->MODER = mode_value;
}

void delay(volatile uint32_t dly)
{
    while(dly--);
}