• STM32 Primer


    http://pandafruits.com/stm32_primer/stm32_primer_lib.php

    As I mentioned in the last section we need to do a bit more work to the infrastructure to make it more suitable for more realistic application development. While still making the same LED flashing, in this section I'll:

    • make the linker script more complete
    • use a startup file
    • use a timer interrupt to flash the LED
    • use some functions from ST's standard peripheral library

    The files involved in this section are:

    • an application source file - "main.c" file
    • s startup file - "startup.c"
    • a liker script - "timer_led.ld"
    • a makefile - "Makefile"
    • an OpenOcd configratrion file - "openocd.cfg"
    • a small bash script - "write_bin.sh"
    • STM32F10x standard peripheral library directory that can be downloaded here

    This time we look at the linker script first:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    /***************************************
     * stm32 timer led example timer_led.ld
     ***************************************/
     
    /* Memory layout for an STM32F103RB */
    MEMORY
    {
       FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
       RAM  (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
    }
     
    STACK_SIZE = 1024;
    _estack = ORIGIN(RAM) + LENGTH(RAM);
    _sstack = _estack - STACK_SIZE;
     
    /* Output sections */
    SECTIONS
    {
        .text :
        {
            /* All unused bytes set to 0xFF. */
            FILL (0xff)
     
            /* ISR Vector Table first */
            _isr_vectors_offs = . - 0x08000000;
            KEEP(*(.isr_vector))
     
            . = ALIGN(4);
            *(.text)        /* Program code */
            *(.text.*)
            *(.rodata)      /* Constants */
            *(.fini)   
            *(.rodata*)
            *(.glue_7) 
            *(.glue_7t)
            . = ALIGN(4);
            _etext = .;
     
            _sidata = _etext;
             
        } > FLASH
     
        /* Initialized global and static variables */
        .data :
        {
            FILL (0xff)
             
            . = ALIGN(4);
            _sdata = .;    
            *(.data)
            *(.data.*)
            . = ALIGN(4);
            _edata = .;
             
        } > RAM AT> FLASH
     
        /* Uninitialized global and static variables */
        .bss :
        {
            . = ALIGN(4);
            _sbss = .;
            *(.bss)
            *(.bss.*)
            *(COMMON)
            . = ALIGN(4);
     
            _ebss = .;
             
        } > RAM
     
        /* Stack */
        . = _sstack;
        .stack :
        {
            . = . + STACK_SIZE;
        } > RAM
    }

    Compared to last section, this linker script has more stuff in it. It now specifies the stack to be 1 Kbytes. It also has separate sections for initialized and uninitialized global and static variables. Before application starts execution, the initialized data in section '.data' will be copied from Flash to RAM, wherease RAM required by the the uninitialized data in section '.bss' will be allocated and zeroed - in the startup file:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    /************************************
     * stm32 timer led example startup.c
     ************************************/
     
    #include "stm32f10x.h"
     
    typedef void( *const intfunc )( void );
     
    #define WEAK __attribute__ ((weak))
     
    extern unsigned long _etext;
    extern unsigned long _sidata;
    extern unsigned long _sdata;
    extern unsigned long _edata;
    extern unsigned long _sbss;
    extern unsigned long _ebss;
    extern unsigned long _estack;
      
     
    void Reset_Handler(void) __attribute__((__interrupt__));
    void __Init_Data(void);
    void SystemInit (void);
    void Default_Handler(void);
     
    extern int main(void);
     
    /* Init Data
     * Loads data from addresses defined in linker file into RAM
     * Zero bss (statically allocated uninitialized variables)
     */
    void __Init_Data(void) {
        unsigned long *src, *dst;
        /* copy the data segment into ram */
        src = &_sidata;
        dst = &_sdata;
        if (src != dst)
            while(dst < &_edata)
                *(dst++) = *(src++);
     
        /* zero the bss segment */
        dst = &_sbss;
        while(dst < &_ebss)
            *(dst++) = 0;
    }
     
    /* This function is straight from the system_stm32f10x.c library file and
     * is called within the startup file:
     * 1. After each device reset the HSI is used as System clock source.
     * 2. This function assumes that an external 8MHz crystal is used to drive the System clock.
     */
    void SystemInit (void)
    {
        /* Reset the RCC clock configuration to the default reset state */
        /* Set HSION bit */
        RCC->CR |= (uint32_t)0x00000001;
        /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
        RCC->CFGR &= (uint32_t)0xF8FF0000;
        /* Reset HSEON, CSSON and PLLON bits */
        RCC->CR &= (uint32_t)0xFEF6FFFF;
        /* Reset HSEBYP bit */
        RCC->CR &= (uint32_t)0xFFFBFFFF;
        /* Disable all interrupts and clear pending bits  */
        RCC->CIR = 0x009F0000;
        /* Enable HSE */
        RCC->CR |= ((uint32_t)RCC_CR_HSEON);
        /* Wait till HSE is ready */
        do
        {
        } while ((RCC->CR & RCC_CR_HSERDY) == RESET);
        /* Configure the Flash Latency cycles and enable prefetch buffer */
        FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2;
        /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
        /* HCLK = SYSCLK, PCLK2 = HCLK, PCLK1 = HCLK / 2
         * If crystal is 16MHz, add in PLLXTPRE flag to prescale by 2
         */
        RCC->CFGR = (uint32_t)( RCC_CFGR_HPRE_DIV1  |
                                RCC_CFGR_PPRE2_DIV1 |
                                RCC_CFGR_PPRE1_DIV2 |
                                RCC_CFGR_PLLSRC_HSE |
                                RCC_CFGR_PLLMULL9 );
        /* Enable PLL */
        RCC->CR |= RCC_CR_PLLON;
        /* Wait till PLL is ready */
        while ((RCC->CR & RCC_CR_PLLRDY) == 0)
        {
        }
        /* Select PLL as system clock source */
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
        /* Wait till PLL is used as system clock source */
        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
        {
        }
    }
     
    void Reset_Handler(void) {
        /* Initialize data and bss */
        __Init_Data();
        extern uint32_t _isr_vectors_offs;
        SCB->VTOR = 0x08000000 | ((uint32_t)&_isr_vectors_offs & (uint32_t)0x1FFFFF80);
        SystemInit();
        while(1)
        {
          __Init_Data();
          main();
        }
        while(1) {}
    }
     
    void WEAK NMI_Handler(void);
    void WEAK HardFault_Handler(void);
    void WEAK MemManage_Handler(void);
    void WEAK BusFault_Handler(void);
    void WEAK UsageFault_Handler(void);
    void WEAK MemManage_Handler(void);
    void WEAK SVC_Handler(void);
    void WEAK DebugMon_Handler(void);
    void WEAK PendSV_Handler(void);
    void WEAK SysTick_Handler(void);
     
    void WEAK WWDG_IRQHandler(void);
    void WEAK PVD_IRQHandler(void);
    void WEAK TAMPER_IRQHandler(void);
    void WEAK RTC_IRQHandler(void);
    void WEAK FLASH_IRQHandler(void);
    void WEAK RCC_IRQHandler(void);
    void WEAK EXTI0_IRQHandler(void);
    void WEAK EXTI1_IRQHandler(void);
    void WEAK EXTI2_IRQHandler(void);
    void WEAK EXTI3_IRQHandler(void);
    void WEAK EXTI4_IRQHandler(void);
    void WEAK DMA1_Channel1_IRQHandler(void);
    void WEAK DMA1_Channel2_IRQHandler(void);
    void WEAK DMA1_Channel3_IRQHandler(void);
    void WEAK DMA1_Channel4_IRQHandler(void);
    void WEAK DMA1_Channel5_IRQHandler(void);
    void WEAK DMA1_Channel6_IRQHandler(void);
    void WEAK DMA1_Channel7_IRQHandler(void);
    void WEAK ADC1_2_IRQHandler(void);
    void WEAK USB_HP_CAN1_TX_IRQHandler(void);
    void WEAK USB_LP_CAN1_RX0_IRQHandler(void);
    void WEAK CAN1_RX1_IRQHandler(void);
    void WEAK CAN1_SCE_IRQHandler(void);
    void WEAK EXTI9_5_IRQHandler(void);
    void WEAK TIM1_BRK_IRQHandler(void);
    void WEAK TIM1_UP_IRQHandler(void);
    void WEAK TIM1_TRG_COM_IRQHandler(void);
    void WEAK TIM1_CC_IRQHandler(void);
    void WEAK TIM2_IRQHandler(void);
    void WEAK TIM3_IRQHandler(void);
    void WEAK TIM4_IRQHandler(void);
    void WEAK I2C1_EV_IRQHandler(void);
    void WEAK I2C1_ER_IRQHandler(void);
    void WEAK I2C2_EV_IRQHandler(void);
    void WEAK I2C2_ER_IRQHandler(void);
    void WEAK SPI1_IRQHandler(void);
    void WEAK SPI2_IRQHandler(void);
    void WEAK USART1_IRQHandler(void);
    void WEAK USART2_IRQHandler(void);
    void WEAK USART3_IRQHandler(void);
    void WEAK EXTI15_10_IRQHandler(void);
    void WEAK RTCAlarm_IRQHandler(void);
    void WEAK USBWakeUp_IRQHandler(void);
    void WEAK TIM8_BRK_IRQHandler(void);
    void WEAK TIM8_UP_IRQHandler(void);
    void WEAK TIM8_TRG_COM_IRQHandler(void);
    void WEAK TIM8_CC_IRQHandler(void);
    void WEAK ADC3_IRQHandler(void);
    void WEAK FSMC_IRQHandler(void);
    void WEAK SDIO_IRQHandler(void);
    void WEAK TIM5_IRQHandler(void);
    void WEAK SPI3_IRQHandler(void);
    void WEAK UART4_IRQHandler(void);
    void WEAK UART5_IRQHandler(void);
    void WEAK TIM6_IRQHandler(void);
    void WEAK TIM7_IRQHandler(void);
    void WEAK DMA2_Channel1_IRQHandler(void);
    void WEAK DMA2_Channel2_IRQHandler(void);
    void WEAK DMA2_Channel3_IRQHandler(void);
    void WEAK DMA2_Channel4_5_IRQHandler(void);
     
    __attribute__ ((section(".isr_vector")))
    void (* const g_pfnVectors[])(void) = {
        (intfunc)((unsigned long)&_estack), /* The stack pointer after relocation */
        Reset_Handler,              /* Reset Handler */
        NMI_Handler,                /* NMI Handler */
        HardFault_Handler,          /* Hard Fault Handler */
        MemManage_Handler,          /* MPU Fault Handler */
        BusFault_Handler,           /* Bus Fault Handler */
        UsageFault_Handler,         /* Usage Fault Handler */
        0,                          /* Reserved */
        0,                          /* Reserved */
        0,                          /* Reserved */
        0,                          /* Reserved */
        SVC_Handler,                /* SVCall Handler */
        DebugMon_Handler,           /* Debug Monitor Handler */
        0,                          /* Reserved */
        PendSV_Handler,             /* PendSV Handler */
        SysTick_Handler,            /* SysTick Handler */
     
        /* External Interrupts */
        WWDG_IRQHandler,            /* Window Watchdog */
        PVD_IRQHandler,             /* PVD through EXTI Line detect */
        TAMPER_IRQHandler,          /* Tamper */
        RTC_IRQHandler,             /* RTC */
        FLASH_IRQHandler,           /* Flash */
        RCC_IRQHandler,             /* RCC */
        EXTI0_IRQHandler,           /* EXTI Line 0 */
        EXTI1_IRQHandler,           /* EXTI Line 1 */
        EXTI2_IRQHandler,           /* EXTI Line 2 */
        EXTI3_IRQHandler,           /* EXTI Line 3 */
        EXTI4_IRQHandler,           /* EXTI Line 4 */
        DMA1_Channel1_IRQHandler,   /* DMA1 Channel 1 */
        DMA1_Channel2_IRQHandler,   /* DMA1 Channel 2 */
        DMA1_Channel3_IRQHandler,   /* DMA1 Channel 3 */
        DMA1_Channel4_IRQHandler,   /* DMA1 Channel 4 */
        DMA1_Channel5_IRQHandler,   /* DMA1 Channel 5 */
        DMA1_Channel6_IRQHandler,   /* DMA1 Channel 6 */
        DMA1_Channel7_IRQHandler,   /* DMA1 Channel 7 */
        ADC1_2_IRQHandler,          /* ADC1 & ADC2 */
        USB_HP_CAN1_TX_IRQHandler,  /* USB High Priority or CAN1 TX */
        USB_LP_CAN1_RX0_IRQHandler, /* USB Low  Priority or CAN1 RX0 */
        CAN1_RX1_IRQHandler,        /* CAN1 RX1 */
        CAN1_SCE_IRQHandler,        /* CAN1 SCE */
        EXTI9_5_IRQHandler,         /* EXTI Line 9..5 */
        TIM1_BRK_IRQHandler,        /* TIM1 Break */
        TIM1_UP_IRQHandler,         /* TIM1 Update */
        TIM1_TRG_COM_IRQHandler,    /* TIM1 Trigger and Commutation */
        TIM1_CC_IRQHandler,         /* TIM1 Capture Compare */
        TIM2_IRQHandler,            /* TIM2 */
        TIM3_IRQHandler,            /* TIM3 */
        TIM4_IRQHandler,            /* TIM4 */
        I2C1_EV_IRQHandler,         /* I2C1 Event */
        I2C1_ER_IRQHandler,         /* I2C1 Error */
        I2C2_EV_IRQHandler,         /* I2C2 Event */
        I2C2_ER_IRQHandler,         /* I2C2 Error */
        SPI1_IRQHandler,            /* SPI1 */
        SPI2_IRQHandler,            /* SPI2 */
        USART1_IRQHandler,          /* USART1 */
        USART2_IRQHandler,          /* USART2 */
        USART3_IRQHandler,          /* USART3 */
        EXTI15_10_IRQHandler,       /* EXTI Line 15..10 */
        RTCAlarm_IRQHandler,        /* RTC Alarm through EXTI Line */
        USBWakeUp_IRQHandler,       /* USB Wakeup from suspend */
        TIM8_BRK_IRQHandler,
        TIM8_UP_IRQHandler,
        TIM8_TRG_COM_IRQHandler,
        TIM8_CC_IRQHandler,
        ADC3_IRQHandler,
        FSMC_IRQHandler,
        SDIO_IRQHandler,
        TIM5_IRQHandler,
        SPI3_IRQHandler,
        UART4_IRQHandler,
        UART5_IRQHandler,
        TIM6_IRQHandler,
        TIM7_IRQHandler,
        DMA2_Channel1_IRQHandler,
        DMA2_Channel2_IRQHandler,
        DMA2_Channel3_IRQHandler,
        DMA2_Channel4_5_IRQHandler,
    };
     
    #pragma weak MMI_Handler                = Default_Handler
    #pragma weak MemManage_Handler          = Default_Handler
    #pragma weak BusFault_Handler           = Default_Handler
    #pragma weak UsageFault_Handler         = Default_Handler
    #pragma weak SVC_Handler                = Default_Handler
    #pragma weak DebugMon_Handler           = Default_Handler
    #pragma weak PendSV_Handler             = Default_Handler
    #pragma weak SysTick_Handler            = Default_Handler
    #pragma weak WWDG_IRQHandler            = Default_Handler
    #pragma weak PVD_IRQHandler             = Default_Handler
    #pragma weak TAMPER_IRQHandler          = Default_Handler
    #pragma weak RTC_IRQHandler             = Default_Handler
    #pragma weak FLASH_IRQHandler           = Default_Handler
    #pragma weak RCC_IRQHandler             = Default_Handler
    #pragma weak EXTI0_IRQHandler           = Default_Handler
    #pragma weak EXTI1_IRQHandler           = Default_Handler
    #pragma weak EXTI2_IRQHandler           = Default_Handler
    #pragma weak EXTI3_IRQHandler           = Default_Handler
    #pragma weak EXTI4_IRQHandler           = Default_Handler
    #pragma weak DMA1_Channel1_IRQHandler   = Default_Handler
    #pragma weak DMA1_Channel2_IRQHandler   = Default_Handler
    #pragma weak DMA1_Channel3_IRQHandler   = Default_Handler
    #pragma weak DMA1_Channel4_IRQHandler   = Default_Handler
    #pragma weak DMA1_Channel5_IRQHandler   = Default_Handler
    #pragma weak DMA1_Channel6_IRQHandler   = Default_Handler
    #pragma weak DMA1_Channel7_IRQHandler   = Default_Handler
    #pragma weak ADC1_2_IRQHandler          = Default_Handler
    #pragma weak USB_HP_CAN1_TX_IRQHandler  = Default_Handler
    #pragma weak USB_LP_CAN1_RX0_IRQHandler = Default_Handler
    #pragma weak CAN1_RX1_IRQHandler        = Default_Handler
    #pragma weak CAN1_SCE_IRQHandler        = Default_Handler
    #pragma weak EXTI9_5_IRQHandler         = Default_Handler
    #pragma weak TIM1_BRK_IRQHandler        = Default_Handler
    #pragma weak TIM1_UP_IRQHandler         = Default_Handler
    #pragma weak TIM1_TRG_COM_IRQHandler    = Default_Handler
    #pragma weak TIM1_CC_IRQHandler         = Default_Handler
    #pragma weak TIM2_IRQHandler            = Default_Handler
    #pragma weak TIM3_IRQHandler            = Default_Handler
    #pragma weak TIM4_IRQHandler            = Default_Handler
    #pragma weak I2C1_EV_IRQHandler         = Default_Handler
    #pragma weak I2C1_ER_IRQHandler         = Default_Handler
    #pragma weak I2C2_EV_IRQHandler         = Default_Handler
    #pragma weak I2C2_ER_IRQHandler         = Default_Handler
    #pragma weak SPI1_IRQHandler            = Default_Handler
    #pragma weak SPI2_IRQHandler            = Default_Handler
    #pragma weak USART1_IRQHandler          = Default_Handler
    #pragma weak USART2_IRQHandler          = Default_Handler
    #pragma weak USART3_IRQHandler          = Default_Handler
    #pragma weak EXTI15_10_IRQHandler       = Default_Handler
    #pragma weak RTCAlarm_IRQHandler        = Default_Handler
    #pragma weak USBWakeUp_IRQHandler       = Default_Handler
    #pragma weak TIM8_BRK_IRQHandler        = Default_Handler
    #pragma weak TIM8_UP_IRQHandler         = Default_Handler
    #pragma weak TIM8_TRG_COM_IRQHandler    = Default_Handler
    #pragma weak TIM8_CC_IRQHandler         = Default_Handler
    #pragma weak ADC3_IRQHandler            = Default_Handler
    #pragma weak FSMC_IRQHandler            = Default_Handler
    #pragma weak SDIO_IRQHandler            = Default_Handler
    #pragma weak TIM5_IRQHandler            = Default_Handler
    #pragma weak SPI3_IRQHandler            = Default_Handler
    #pragma weak UART4_IRQHandler           = Default_Handler
    #pragma weak UART5_IRQHandler           = Default_Handler
    #pragma weak TIM6_IRQHandler            = Default_Handler
    #pragma weak TIM7_IRQHandler            = Default_Handler
    #pragma weak DMA2_Channel1_IRQHandler   = Default_Handler
    #pragma weak DMA2_Channel2_IRQHandler   = Default_Handler
    #pragma weak DMA2_Channel3_IRQHandler   = Default_Handler
    #pragma weak DMA2_Channel4_5_IRQHandler = Default_Handler
     
    void Default_Handler(void) {
        while (1) {}
    }

    The startup file is actually not as complicated as it looks. Basically it does the following:

    • Set up system clocks in 'SystemInit'
    • Copy initialized global and static variables from Flash to RAM, and allocate and zero uninitialized global and static variables in RAM in function '__Init_Data'
    • Assign all but the reset interrupt to the default handler 'Default_Handler', which does nothing and can be overridden in application code by virtue of the "#pragma weak' directive

    Note also that I've included the header 'stm32f10x.h' for all those register name definitions.

    The 'openocd.cfg' file and the 'write_bin.sh' file are the same as the previous section so I won't list them here. The Makefile, of course, is different because we have two C files now:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    ####################################
    # stm32 timer led example Makefile
    ####################################
     
    PROGRAM = timer_led
     
    ENTRY_FILE = startup
     
    ENTRY_CFILE = $(ENTRY_FILE).c
    ENTRY_OFILE = $(ENTRY_FILE).o
     
    ALL_OFILES = main.o $(ENTRY_OFILE)
     
    TARGET_BIN = $(PROGRAM).bin
    TARGET_ELF = $(PROGRAM).elf
     
    CC = arm-none-eabi-gcc
    LD = arm-none-eabi-ld
    CP = arm-none-eabi-objcopy
     
    LKR_SCRIPT = $(PROGRAM).ld
     
    FAMILY = STM32F10X_MD
     
    DEFINES = -D$(FAMILY)
    INCLUDES = -I./Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/
                -I./Libraries/CMSIS/CM3/CoreSupport/
                -I./Libraries/STM32F10x_StdPeriph_Driver/inc
     
    CFLAGS  = -c -march=armv7-m -mcpu=cortex-m3 -mthumb
              -fno-common -nostdlib -fno-builtin -ffreestanding
              -Wall -O0 -g 
              $(DEFINES)
               
    LFLAGS  = -nostartfiles -T$(LKR_SCRIPT)
    CPFLAGS = -Obinary
     
    .PHONY: all clean write
     
    all: $(TARGET_BIN)
     
    $(TARGET_BIN): $(TARGET_ELF)
        $(CP) $(CPFLAGS) $< $@
         
    $(TARGET_ELF): $(ALL_OFILES)
        $(LD) $(LFLAGS) $(ALL_OFILES) -o $@
         
    main.o: main.c
        $(CC) $(INCLUDES) $(CFLAGS) main.c -o $@
     
    $(ENTRY_OFILE): $(ENTRY_CFILE)
        $(CC) $(INCLUDES) $(CFLAGS) $(ENTRY_CFILE) -o $@
     
    clean:
        rm -rf *.o *.elf *.bin
     
    write:
        ./write_bin.sh openocd.cfg $(TARGET_ELF)

    Also note that we need to specify the inclusion path for the library files in the compiler options. Finally, here's the main application code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    /*********************************
     * stm32 timer led example main.c
     ********************************/
     
    #include "stm32f10x.h"
    #include "stm32f10x_gpio.h"
    #include "stm32f10x_tim.h"
     
    /* User defined function prototypes */
    void GPIOA_Init(void);
    void TIM2_CC1_Init(void);
    void led_toggle(void);
     
    /* Prototypes for func. from stm32f10x lib. */
    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
    ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
    void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
     
    int main(void)
    {
        /* Initialize GPIOA PIN8 */
        GPIOA_Init();
         
        /* Initialize TIM2 Capture/Compare 1 in output compare mode */
        TIM2_CC1_Init();
         
        /* Toggle LED forever */
        while(1)
        {
            /* Do nothing, all happens in ISR */
        }
    }  
     
    /* Initialize GPIOA PIN8 */
    void GPIOA_Init(void)
    {
        /* Configuration info. for PORTA PIN8:
         * - Speed = 50MHz
         * - Push-pull output mode
         */
        GPIO_InitTypeDef gpioa_pin8_config = { GPIO_Pin_8,
                                               GPIO_Speed_50MHz,
                                               GPIO_Mode_Out_PP };
                                                 
        /* Enable PORT A clock */
        RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; 
        /* Configure PORTA PIN 8 */
        GPIO_Init(GPIOA, &gpioa_pin8_config);  
         
        /* Turn off LED to start with */
        GPIOA->BSRR = (uint32_t)1 << 8;   
    }
     
    /* Toggle LED */
    void led_toggle(void)
    {
        /* If PORTA BIT 8 clear, set it */
        if((GPIOA->ODR & (uint32_t)1<<8) == 0)
        {
            GPIOA->BSRR = (uint32_t)1 << 8;
        }
        /* If PORTA BIT 8 set, clear it */
        else
        {
            GPIOA->BRR = (uint32_t)1 << 8;
        }
    }
     
    /* Configure TIM2 Capture/Compare 1 to work in output compare mode
     * so that the red LED flashes at 1HZ (toggle every 0.5s) */
    void TIM2_CC1_Init(void)
    {
        /* Enable TIM2 clock */
        RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
        /* Enable TIM2 global interrupt */
        NVIC->ISER[0] |= 0x10000000;
         
        /* Frequency after prescalar = 72MHz/(7199+1) = 10KHz.
         * Compare register = 5000 so a compare match occurs every 0.5s.
         */
        TIM2->PSC = (uint16_t)7199;
        TIM2->CCR1 = (uint16_t)5000;
         
        /* Enable Capture/Compare 1 interrupt */
        TIM2->DIER |= (uint16_t)0x0002;
             
        /* Enable TIM2 counter (in upcount mode) */
        TIM2->CR1 |= (uint16_t)0x0001;  
    }
     
    /* Timer 2 Interrupt Service Routine */
    void TIM2_IRQHandler(void)
    {
        /* Toggle LED if TIM2's Capture/Compare 1 interrupt occurred. */
        if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
        {
            led_toggle();
            /* Clear TIM2's Capture/Compare 1 interrupt pending bit. */
            TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
            /* Increment compare register by 5000 so next interrupt
             * occurs in 0.5s */
            TIM2->CCR1 += (uint16_t)5000;
        }  
         
        /* ===== Other TIM2 interrupt types can go below ======
         * .........
         */
    }
     
    /* This function comes straight from stm32f10x_gpio.c. All it does is
     * configure a GPIO pin's speed and mode etc. but seems so complicated.
     */
    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
    {
      uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
      uint32_t tmpreg = 0x00, pinmask = 0x00;
      /* Check the parameters */
      /*
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
      assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin)); 
      */
       
    /*---------------------------- GPIO Mode Configuration -----------------------*/
      currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
      if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
      {
        /* Check the parameters */
        /* assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed)); */
        /* Output mode */
        currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
      }
    /*---------------------------- GPIO CRL Configuration ------------------------*/
      /* Configure the eight low port pins */
      if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
      {
        tmpreg = GPIOx->CRL;
        for (pinpos = 0x00; pinpos < 0x08; pinpos++)
        {
          pos = ((uint32_t)0x01) << pinpos;
          /* Get the port pins position */
          currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
          if (currentpin == pos)
          {
            pos = pinpos << 2;
            /* Clear the corresponding low control register bits */
            pinmask = ((uint32_t)0x0F) << pos;
            tmpreg &= ~pinmask;
            /* Write the mode configuration in the corresponding bits */
            tmpreg |= (currentmode << pos);
            /* Reset the corresponding ODR bit */
            if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
            {
              GPIOx->BRR = (((uint32_t)0x01) << pinpos);
            }
            else
            {
              /* Set the corresponding ODR bit */
              if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
              {
                GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
              }
            }
          }
        }
        GPIOx->CRL = tmpreg;
      }
    /*---------------------------- GPIO CRH Configuration ------------------------*/
      /* Configure the eight high port pins */
      if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
      {
        tmpreg = GPIOx->CRH;
        for (pinpos = 0x00; pinpos < 0x08; pinpos++)
        {
          pos = (((uint32_t)0x01) << (pinpos + 0x08));
          /* Get the port pins position */
          currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
          if (currentpin == pos)
          {
            pos = pinpos << 2;
            /* Clear the corresponding high control register bits */
            pinmask = ((uint32_t)0x0F) << pos;
            tmpreg &= ~pinmask;
            /* Write the mode configuration in the corresponding bits */
            tmpreg |= (currentmode << pos);
            /* Reset the corresponding ODR bit */
            if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
            {
              GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
            }
            /* Set the corresponding ODR bit */
            if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
            {
              GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
            }
          }
        }
        GPIOx->CRH = tmpreg;
      }
    }
     
    /* This function comes straight from stm32f10x_tim.c. It checks
     * whether interrupt TIM_IT in TIMx has occurred or not.
     */
    ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
    {
      ITStatus bitstatus = RESET; 
      uint16_t itstatus = 0x0, itenable = 0x0;
      /* Check the parameters */
      //assert_param(IS_TIM_ALL_PERIPH(TIMx));
      //assert_param(IS_TIM_GET_IT(TIM_IT));
        
      itstatus = TIMx->SR & TIM_IT;
       
      itenable = TIMx->DIER & TIM_IT;
      if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET))
      {
        bitstatus = SET;
      }
      else
      {
        bitstatus = RESET;
      }
      return bitstatus;
    }
     
    /* This function comes straight from stm32f10x_tim.c.
     * It clears the TIMx's TIM_IT interrupt pending bits.
     */
    void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
    {
      /* Check the parameters */
      //assert_param(IS_TIM_ALL_PERIPH(TIMx));
      //assert_param(IS_TIM_IT(TIM_IT));
      /* Clear the IT pending Bit */
      TIMx->SR = (uint16_t)~TIM_IT;
    }

    I have not compiled any library C files in this project. All the '#include' are just for peripheral register name definitions. Instead, I simply copy and pasted the functions I need for this application into the main file so that I could focus on what exactly is required to get the code working. To build and program:

    me@pandafruits:~$ make
    me@pandafruits:~$ make write
    

    The LED should flash at exactly 1Hz now. I'll do one more example with the UART next.

  • 相关阅读:
    CMake学习笔记
    右键添加"在此处打开命令窗口"菜单
    设置默认python模块源
    添加到附加组
    Unity宏处理
    挂载windows共享文件夹
    MacOS长按无效问题
    中文Locale
    笔记本用作无线路由器
    C# Winfrom iTextSharp 导出pdf 带二维码 表格嵌套 简单Dome
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/13916162.html
Copyright © 2020-2023  润新知