_ _ (_) ___ | |_ ____ | |/ _ \| __|_ / | | (_) | |_ / / _/ |\___/ \__/___| |__/
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
# 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
/* 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 = .;
}
//
// 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);
}
//
// 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--);
}