• STM32 Primer


    原文来自:http://pandafruits.com/stm32_primer/stm32_primer_minimal.php

    In this section I'll show how to get the STM32F103RB running with a minimal "hello world" example - a flashing LED. This example involves the following five files:

    • an application source file - "main.c" file
    • a liker script - "stm32_minimal.ld"
    • a makefile - "Makefile"
    • an OpenOcd configratrion file - "openocd.cfg"
    • a small bash script - "write_bin.sh"

    Technically, only the first two files are needed for a true "minimal" example; but the other three files greatly simplify the process of building and programming. First we look at the C 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
    /*******************************
     * stm32 minimal example main.c
     *******************************/
      
    /* memory and peripheral start addresses */
    #define FLASH_BASE      0x08000000
    #define SRAM_BASE       0x20000000
    #define PERIPH_BASE     0x40000000
     
    /* work out end of RAM address as initial stack pointer */
    #define SRAM_SIZE       20*1024     // STM32F103RB has 20 Kbye of RAM
    #define SRAM_END        (SRAM_BASE + SRAM_SIZE)
     
    /* LED connected to PIN 8 of GPIOA */
    #define LED_PIN         8
    #define OUTPUT_MODE     (0x10|0x03) // output mode: push-pull + 50MHz
     
    /* RCC peripheral addresses applicable to GPIOA */
    #define RCC_BASE        (PERIPH_BASE + 0x21000)
    #define RCC_APB2ENR     (*(volatile unsigned long*)(RCC_BASE + 0x18))
     
    /* GPIOA peripheral addresses */
    #define GPIOA_BASE      (PERIPH_BASE + 0x10800)
    #define GPIOA_CRL       (*(volatile unsigned long*)(GPIOA_BASE + 0x00))
    #define GPIOA_CRH       (*(volatile unsigned long*)(GPIOA_BASE + 0x04))
    #define GPIOA_BSRR      (*(volatile unsigned long*)(GPIOA_BASE + 0x10))
    #define GPIOA_BRR       (*(volatile unsigned long*)(GPIOA_BASE + 0x14))
     
    /* user functions */
    int main(void);
    void delay(unsigned long count);
     
    /* vector table */
    unsigned long *vector_table[] __attribute__((section(".vector_table"))) =
    {
        (unsigned long *)SRAM_END,   // initial stack pointer
        (unsigned long *)main        // main as Reset_Handler
    };
     
    int main()
    {
        /* enable clock on GPIOA peripheral */
        RCC_APB2ENR = 0x04;
         
        /* set LED pin output mode */
        //GPIOA_CRL |= OUTPUT_MODE << ((LED_PIN) << 2); // if pins 0 to 7
        GPIOA_CRH |= OUTPUT_MODE << ((LED_PIN-8) << 2); // if pins 8 to 15
     
        while(1)
        {
            GPIOA_BSRR = 1<<LED_PIN;  // set LED pin high
            delay(200000);
            GPIOA_BRR  = 1<<LED_PIN;  // set LED pin low
            delay(200000);
        }
    }
     
    void delay(unsigned long count)
    {
        while(count--);
    }

    The code is pretty much self-explanatory. Most of it are actually macros difining memory and peripheral addresses. ST supplies a library with all these done for us in header files, we'll use that in the next section in a moment. One important thing to note, though, is the vector table. The first two entries must be the top-of-stack address and the address of the reset handler. Next we look at the linker script:

    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
    /*****************************************
     * stm32 minimal example stm32_minimal.ld
     *****************************************/
      
    /* memory layout for an STM32F103RB */
    MEMORY
    {
        FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 128K
        SRAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 20K
    }
     
    /* output sections */
    SECTIONS
    {
        /* program code into FLASH */
        .text :
        {
            *(.vector_table)    /* Vector table */
            *(.text)            /* Program code */
        } >FLASH
     
        /* uninitialized global and static variables (which
           we don't have any in this example) into SRAM */
        .data :
        {
            *(.data)           
        } >SRAM
    }  

    Again, here we see that the vector table needs to be place before any application code in Flash. Also note that, because there is no global or static variables in the application code, the '.data' section is actually not needed. Now we take a look at the Makefile:

    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
    ##################################
    # stm32 minimal example Makefile
    ##################################
     
    CC = arm-none-eabi-gcc
    LD = arm-none-eabi-ld
    CP = arm-none-eabi-objcopy
     
    LKR_SCRIPT = stm32_minimal.ld
     
    CFLAGS  = -c -fno-common -O0 -g -mcpu=cortex-m3 -mthumb
    LFLAGS  = -nostartfiles -T$(LKR_SCRIPT)
    CPFLAGS = -Obinary
     
    all: main.bin
     
    main.o: main.c
        $(CC) $(CFLAGS) -o main.o main.c
     
    main.elf: main.o
        $(LD) $(LFLAGS) -o main.elf main.o
     
    main.bin: main.elf
        $(CP) $(CPFLAGS) main.elf main.bin
     
    clean:
        rm -rf *.o *.elf *.bin
     
    write:
        ./write_bin.sh openocd.cfg main.elf

    Noticed the command used to invoke the compiler - 'arm-none-eabi-gcc', the linker - 'arm-none-eabi-ld' and the object copy binary utility - 'arm-none-eabi-objcopy'? We installed these in the previous section. The last line './write_bin.sh openocd.cfg main.elf' runs a bash script that takes two arguments - an OpenOcd configuration file and a binary image to be programmed into the micro. We have seen the contents of 'openocd.cfg' in the previous section:

    1
    2
    3
    4
    5
    6
    7
    ##############################################
    # stm32 minimal example openocd.cfg
    # config file for J-link used with stm32f1x
    ##############################################
     
    source [find interface/jlink.cfg]
    source [find target/stm32f1x.cfg]

    And the bash script has the following contents:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/bin/bash
     
    ###################################################################
    # stm32 minimal example write_bin.sh
    # openocd commands to program the micro, invoked in the Makefile
    ###################################################################
    OPENOCD_CFG=$1
    BIN_IMAGE=$2
     
    killall -s 9 openocd
    openocd -f ${OPENOCD_CFG} -c init -c "reset halt" -c "flash write_image erase ${BIN_IMAGE}" -c "verify_image ${BIN_IMAGE}" -c reset -c shutdown

    All it does is first kill any OpenOcd process already running; then start a new one to read the config file sent as the first argument, find and write the binary image as specified in the second argument into the micro with multiple commands. Like what's in the Makefile, we could've typed all those commands one by one in the shell but that would be much more time-consuming.

    Now let's make the project:

    me@pandafruits:~$ make
    arm-none-eabi-gcc -c -fno-common -O0 -g -mcpu=cortex-m3 -mthumb -o main.o main.c
    arm-none-eabi-ld -nostartfiles -Tstm32_minimal.ld -o main.elf main.o
    arm-none-eabi-objcopy -Obinary main.elf main.bin
    me@pandafruits:~$ 
    

    There should be three more files in the directory: 'main.o', 'main.elf' and 'main.bin'. Let's JTAG the micro:

    me@pandafruits:~$ make write
    ./write_bin.sh openocd.cfg main.elf
    openocd: no process found
    Open On-Chip Debugger 0.5.0 (2011-12-03-08:57)
    Licensed under GNU GPL v2
    For bug reports, read
    	http://openocd.berlios.de/doc/doxygen/bugs.html
    Warn : Adapter driver 'jlink' did not declare which transports it allows; assuming legacy JTAG-only
    Info : only one transport option; autoselect 'jtag'
    1000 kHz
    adapter_nsrst_delay: 100
    jtag_ntrst_delay: 100
    cortex_m3 reset_config sysresetreq
    Info : J-Link initialization started / target CPU reset initiated
    Info : J-Link ARM V8 compiled Jan 12 2012 20:43:19
    Info : J-Link caps 0xb9ff7bbf
    Info : J-Link hw version 80000
    Info : J-Link hw type J-Link
    Info : J-Link max mem block 9440
    Info : J-Link configuration
    Info : USB-Address: 0x0
    Info : Kickstart power on JTAG-pin 19: 0x0
    Info : Vref = 3.313 TCK = 1 TDI = 0 TDO = 1 TMS = 0 SRST = 0 TRST = 0
    Info : J-Link JTAG Interface ready
    Info : clock speed 1000 kHz
    Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
    Info : JTAG tap: stm32.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
    Info : stm32.cpu: hardware has 6 breakpoints, 4 watchpoints
    Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
    Info : JTAG tap: stm32.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
    target state: halted
    target halted due to debug-request, current mode: Thread 
    xPSR: 0x01000000 pc: 0x08000008 msp: 0x20005000
    auto erase enabled
    Info : device id = 0x20036410
    Info : flash size = 128kbytes
    wrote 1024 bytes from file main.elf in 0.316950s (3.155 KiB/s)
    verified 148 bytes in 0.311988s (0.463 KiB/s)
    Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
    Info : JTAG tap: stm32.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
    shutdown command invoked
    

    The LED should be flashing now. Finally let's see if we could debug with GDB. First, do:

    me@pandafruits:~$ openocd
    Open On-Chip Debugger 0.5.0 (2011-12-03-08:57)
    Licensed under GNU GPL v2
    For bug reports, read
    	http://openocd.berlios.de/doc/doxygen/bugs.html
    Warn : Adapter driver 'jlink' did not declare which transports it allows; assuming legacy JTAG-only
    Info : only one transport option; autoselect 'jtag'
    1000 kHz
    adapter_nsrst_delay: 100
    jtag_ntrst_delay: 100
    cortex_m3 reset_config sysresetreq
    Info : J-Link initialization started / target CPU reset initiated
    Info : J-Link ARM V8 compiled Jan 12 2012 20:43:19
    Info : J-Link caps 0xb9ff7bbf
    Info : J-Link hw version 80000
    Info : J-Link hw type J-Link
    Info : J-Link max mem block 9440
    Info : J-Link configuration
    Info : USB-Address: 0x0
    Info : Kickstart power on JTAG-pin 19: 0x0
    Info : Vref = 3.313 TCK = 1 TDI = 0 TDO = 1 TMS = 0 SRST = 0 TRST = 0
    Info : J-Link JTAG Interface ready
    Info : clock speed 1000 kHz
    Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
    Info : JTAG tap: stm32.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
    Info : stm32.cpu: hardware has 6 breakpoints, 4 watchpoints
    
    

    With the OpenOcd server running, open a new terminal and connect to the server using telnet by doing:

    me@pandafruits:~$ telnet local host 4444
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    Open On-Chip Debugger
    >
    

    Enter 'reset halt' to halt the target:

    > reset halt
    JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
    JTAG tap: stm32.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
    target state: halted
    target halted due to debug-request, current mode: Thread 
    xPSR: 0x01000000 pc: 0x08000008 msp: 0x20005000
    >
    

    Now, open a third terminal and do:

    me@pandafruits:~$ arm-none-eabi-gdbtui --eval-command="target remote localhost:3333" main.elf

    You should see something similar to this:

    Let's try setting a couple of breakpoints so that we can turn the LED on and off from GDB. In my case the two lines in the code that turns the LED on and off are line 51 and line 53. So at the GDB command prompt I do:

    (gdb) break main.c:51
    Breakpoint 1 at 0x8000032: file main.c, line 51
    (gbd) break main.c:53
    Breakpoint 2 at 0x800004c: file main.c, line 53
    (gbd)
    

    Note the addresses of these breakpoints are pretty close to the beginning of the Flash, which is expected for such a small program. I can now step between the two breakpoints to turn the LED on and off by typing 'c' (for continue) in GDB:

    (gdb) c
    Continuing.
    Note: automatically using hardware breakpoints for read-only addresses.
    
    Breakpoint 1, main () at main.c:51
    (gdb) c
    Continuing.
    
    Breakpoint 2, main () at main.c:53
    (gdb) 
    

    When done, type 'q' to quit GDB.

    Great, in this section I've tried building, programming and debugging a STM32 micro with a minimal project. But there are some serious limitations. Among them are:

    • The linker script is not really complete, it doesn't accommodate data such as initialized global variables.
    • The stack size is not defined.
    • The vector table is not fully populated, which makes it hard to use interrupts.
    • All the peripheral register addresses were defined in 'main.c'.

    In the next section I'll show a more complete linker script, use a startup file and bring the STM32 peripheral library into the picture.

  • 相关阅读:
    jQuery学习笔记----入门
    软件工程(第二周)
    软件工程(第一周)
    memcached 学习进修
    iis设置http重置到https
    apk的api级别不要低于26
    DDD 学习记录
    net core 随笔
    vs2017 无法提交到tfs的 git存储库
    nopcommerce 4.1 core 学习 增加商城配置属性
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/13916151.html
Copyright © 2020-2023  润新知