Blog on embedded programming

The trip to the dark side

Stm32f4 168 MHz Speedup

Hello everyone! Current post is based on clock control on stm32f4discovery post. Now, after some of new material has been read on the topic, I’m going to switch to the recommended maximum frequency of stm32f407 system clock - 168 MHz.

That’s easy enough. I’m going just to modify the init_clock routine from previous example by adding some configuration:

  • Flash: the higher the frequency the more clock cycles CPU needs to wait for flash reaction. There is a table in user manual, page 80 from which the value of this parameter can be taken. In our case it is 6 cycles or 5 so called “wait states”. The FLASH_ACR registry holds this parameter.
  • Power controller: to operate on 168 MHz the MC need voltage controller enabled and the voltage mode scale 1 to be selected. This is done on PWR_CR register.
  • The peripherals have clock frequency limits for normal operation. For high speed devices on APB2 it is 84 MHz and for low speed on APB1 - 42 MHz. So we need to set apropriate prescaling factors on RCC_CFGR register. They are 168 / 84 = 2 and 168 / 42 = 4 respectively.
  • Finally we configure, enable and select the main PLL as the source of a system clock. The output signal frequency of main PLL is calculated in such a way:

fout = (fin * N / M) / P

Where fin - is 8 MHz from HSE with external crystal, it is convenient to take M value the same as the fin and equal 8 in our case, P - takes minimum of 2

So, N = 168 * 2 = 336. All these factors are set in RCC_PLLCFGR register.

Please, checkout the code for details:

(speed_up.S) download
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
    .thumb
    .syntax     unified
    .cpu        cortex-m4

.include        "registers_and_bits.inc.S"

.section        .text
    .type       _reset, %function
_reset:
    bl          .Lstartup
    bl          .Linit_clock
    ldr         r0, =RCC_AHB1ENR        /* this register controls some part of peripherals' clock */
    ldr         r1, [r0]
    orr         r1, GPIODEN             /* enabling GPIOD clock */
    str         r1, [r0]
    ldr         r0, =GPIOD_MODER        /* GPIOD mode configuration register */
    ldr         r1, =MODER12_OUT        /* set 12 pin of GPIOD as output */
    str         r1, [r0]
    ldr         r0, =GPIOD_ODR          /* port output register */
    eor         r1, r1                  /* elegant way to clean register */
    eor         r2 ,r2
.Lblink:
    mov         r1, LED_GREEN
    str         r1, [r0]                /* setting LED_GREEN bit in GPIOD_ODR */
    bl          .Ldelay                 /* pause */
    eor         r1, r1
    str         r1, [r0]                /* clearing GPIOD_ODR */
    bl          .Ldelay                 /* pause */
    b           .Lblink                 /* and so on */
.Ldelay:
    movt        r2, DELAY
1:
    subs        r2, r2, 1               /* spend time substracting DELAY value by 1 */
    bne         1b                      /* '1b' means `look backward for label '1'` */

    bx          lr
.Lstartup:
    ldr         r0, =RCC_CR             /* resetting clock configuration to it's defaults */
    mov         r1, HSION               /* setting HSION bit */
    str         r1, [r0]
    ldr         r0, =RCC_CFGR           /* clearing RCC_CFGR register */
    mov         r1, 0
    str         r1, [r0]
    ldr         r0, =RCC_CR             /* clearing HSEON, CSSON, PLLON bits */
    ldr         r1, [r0]
    ldr         r2, =HSEON | CSSON | PLLON
    bic         r1, r2
    str         r1, [r0]
    ldr         r0, =RCC_PLLCFGR        /* setting the default value from datasheet */
    ldr         r1, =0x24003010
    str         r1, [r0]
    ldr         r0, =RCC_CR             /* clearing HSEBYP bit */
    ldr         r1, [r0]
    bic         r1, HSEBYP
    str         r1, [r0]
    ldr         r0, =RCC_CIR            /* disabling all interrupts */
    mov         r1, 0
    str         r1, [r0]
    bx          lr
.Linit_clock:
    ldr         r0, =RCC_CR             /* enabling HSE clock */
    ldr         r1, [r0]
    orr         r1, HSEON
    str         r1, [r0]
1:
    ldr         r1, [r0]                /* waiting for HSE to be ready */
    ands        r1, HSERDY
    beq         1b
    ldr         r0, =RCC_APB1ENR        /* enable power controller and */
    ldr         r1, [r0]                /* select regulator voltage scale mode 1*/
    orr         r1, PWREN               /* to be able to work on 168 MHz */
    str         r1, [r0]
    ldr         r0, =PWR_CR
    ldr         r1, [r0]
    orr         r1, VOS
    str         r1, [r0]
    ldr         r0, =RCC_CFGR           /* configuring peripherals clock prescaling */
    ldr         r1, [r0]
    bic         r1, RCC_CFGR_HPRE_DIV1  /* explicitly setting no devision for AHB */
    orr         r1, RCC_CFGR_PPRE2_DIV2 /* 168 / 2 <= 84 MHz for high speed devices */
    orr         r1, RCC_CFGR_PPRE1_DIV4 /* 168 / 4 <= 42 MHz for low speed devices */
    str         r1, [r0]
    ldr         r0, =RCC_PLLCFGR        /* configuring main PLL */
    ldr         r1, [r0]
    ldr         r2, =PLL_M | PLL_N << 6 | ((PLL_P >> 1) - 1) << 16 | PLLSRC | PLL_Q << 24
    orr         r1, r2
    str         r1, [r0]
    ldr         r0, =RCC_CR             /* enable main PLL */
    ldr         r1, [r0]
    orr         r1, PLLON
    str         r1, [r0]
1:
    ldr         r1, [r0]                /* wait for PLL to be ready */
    ands        r1, PLLRDY
    beq         1b
    ldr         r0, =FLASH_ACR          /* encreasing flash latency clock cycles amount */
    ldr         r1, [r0]                /* in general this parameter depends on Vdd and system clock frequency */
    ldr         r2, =ACR_LATENCY_5WS    /* in our case it is 6 cycles (or 5 "wait states") according to the manual */
    orr         r1, r2
    str         r1, [r0]
    ldr         r0, =RCC_CFGR           /* selecting PLL as a source */
    ldr         r1, [r0]
    orr         r1, SW1
    str         r1, [r0]
1:
    ldr         r1, [r0]
    and         r1, RCC_CFGR_SWS
    cmp         r1, SWS1
    bne         1b
    bx          lr
    .size       _reset, . - _reset


.section        .int_vector_table, "a", %progbits
    .type       basic_vectors, %object
basic_vectors:
    .word       _estack
    .word       _reset

    .size       basic_vectors, . - basic_vectors
(registers_and_bits.inc.S) download
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
    .equ        RCC_BASE,               0x40023800
    .equ        RCC_CR,                 RCC_BASE
    .equ        RCC_CFGR,               RCC_BASE + 0x08
    .equ        RCC_PLLCFGR,            RCC_BASE + 0x04
    .equ        RCC_AHB1ENR,            RCC_BASE + 0x30
    .equ        RCC_APB1ENR,            RCC_BASE + 0x40
    .equ        RCC_CIR,                RCC_BASE + 0x0C
    .equ        PWR_BASE,               0x40007000
    .equ        PWR_CR,                 PWR_BASE
    .equ        FLASH_BASE,             0x40023C00
    .equ        FLASH_ACR,              FLASH_BASE
    .equ        GPIOD_BASE,             0x40020C00
    .equ        GPIOD_MODER,            GPIOD_BASE
    .equ        GPIOD_ODR,              GPIOD_BASE + 0x14

    .equ        GPIODEN,                1 << 3
    .equ        MODER12_OUT,            1 << 24
    .equ        LED_GREEN,              1 << 12
    .equ        PLLON,                  1 << 24
    .equ        PLLRDY,                 1 << 25
    .equ        PLLSRC,                 1 << 22
    .equ        HSION,                  1
    .equ        HSEBYP,                 1 << 18
    .equ        HSEON,                  1 << 16
    .equ        HSERDY,                 1 << 17
    .equ        CSSON,                  1 << 19
    .equ        PWREN,                  1 << 28
    .equ        VOS,                    1 << 14
    .equ        SW0,                    1
    .equ        SW1,                    1 << 1
    .equ        SWS0,                   1 << 2
    .equ        SWS1,                   1 << 3

    .equ        PLL_M,                  8
    .equ        PLL_N,                  336
    .equ        PLL_P,                  2
    .equ        PLL_Q,                  7
    .equ        DELAY,                  0x5F
    .equ        ACR_LATENCY_5WS,        5

    .equ        RCC_PLLCFGR_PLLP,       ~(0x3 << 16)
    .equ        RCC_PLLCFGR_PLLM,       ~0x3F
    .equ        RCC_PLLCFGR_PLLN,       ~(0x1FF << 6)
    .equ        RCC_CFGR_HPRE_DIV1,     0xF << 4
    .equ        RCC_CFGR_PPRE2_DIV2,    0x8000
    .equ        RCC_CFGR_PPRE1_DIV4,    0x1400
    .equ        RCC_CFGR_SW,            3
    .equ        RCC_CFGR_SWS,           3 << 2

The executable is available to download.

Feel free to post your questions.