Newer
Older
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
#include "bootloader.h"
#include "bootloader_rcc.h"
#include "bootloader_gpio.h"
/* GPIO config options can be just computed instead of stored in a table:
* - port base address = 0x40020000 + (port * 0x400)
* - RCC port: AHB1ENR
* - RCC bit: same as port
*/
#define GPIO_BASE 0x40020000
#define GPIO_STEP 0x00000400
#define GPIO_REGOFF_MODER 0x000
#define GPIO_REGOFF_OTYPER 0x004
#define GPIO_REGOFF_OSPEEDER 0x008
#define GPIO_REGOFF_PUPDR 0x00C
#define GPIO_REGOFF_IDR 0x010
#define GPIO_REGOFF_ODR 0x014
#define GPIO_REGOFF_BSRR 0x018
#define GPIO_REGOFF_LCKR 0x01C
#define GPIO_REGOFF_AFRL 0x020
#define GPIO_REGOFF_AFRH 0x024
BOOTCODE void bootloader_gpio_init(uint32_t gpiodesc)
{
uint32_t line = (gpiodesc & GPIO_FLAGS_MASK_LINE) >> GPIO_FLAGS_SHIFT_LINE;
uint32_t port = (gpiodesc & GPIO_FLAGS_MASK_PORT) >> GPIO_FLAGS_SHIFT_PORT;
uint32_t base, val, dir;
//get port base address
if(port >= 10) return;
base = GPIO_BASE + (port * GPIO_STEP);
//Enable clock to GPIO peripheral
modreg32(RCC_AHB1ENR, 1<<port, 0);
dir = (gpiodesc & GPIO_FLAGS_MASK_MODE) >> GPIO_FLAGS_SHIFT_MODE;
//configure 1-bit ports
if(dir == 1) { //Output only
//Initial state
val = (gpiodesc & GPIO_FLAGS_MASK_INIT) >> GPIO_FLAGS_SHIFT_INIT;
bootloader_gpio_write(gpiodesc, val);
//Offset 04 OTYPER
val = (gpiodesc & GPIO_FLAGS_MASK_TYPE) >> GPIO_FLAGS_SHIFT_TYPE;
modreg32(base + GPIO_REGOFF_OTYPER, val << line, 1 << line);
}
//configure 2-bit ports
line += line;
//Offset 00 MODER
val = dir;
modreg32(base + GPIO_REGOFF_MODER, val << line, 3 << line);
if(dir == 1) { //Output only
//Offset 08 OSPEEDER
val = (gpiodesc & GPIO_FLAGS_MASK_SPD) >> GPIO_FLAGS_SHIFT_SPD;
modreg32(base + GPIO_REGOFF_OSPEEDER, val << line, 3 << line);
}
if(dir == 0) { //Input only
//Offset 0C PUPDR
val = (gpiodesc & GPIO_FLAGS_MASK_PULL) >> GPIO_FLAGS_SHIFT_PULL;
modreg32(base + GPIO_REGOFF_PUPDR, val << line, 3 << line);
}
//configure 4-bit ports
line += line;
//Offset 20 AFRL (for lines 0-7)
//Offset 24 AFRH (for lines 8-15)
val = (gpiodesc & GPIO_FLAGS_MASK_ALT) >> GPIO_FLAGS_SHIFT_ALT;
if(line < (8 << 2)) {
modreg32(base + GPIO_REGOFF_AFRL, val << line, 15 << line);
} else {
line -= 32;
modreg32(base + GPIO_REGOFF_AFRL, val << line, 15 << line);
}
}
BOOTCODE void bootloader_gpio_write(uint32_t gpio, int state)
{
uint32_t line = (gpio & GPIO_FLAGS_MASK_LINE) >> GPIO_FLAGS_SHIFT_LINE;
uint32_t port = (gpio & GPIO_FLAGS_MASK_PORT) >> GPIO_FLAGS_SHIFT_PORT;
uint32_t base;
//get port base address
if(port >= 10) return;
base = GPIO_BASE + (port * GPIO_STEP);
if(!state) line += 16; //access BR instead of BS
base += GPIO_REGOFF_BSRR;
putreg32(base, 1<<line);
}
BOOTCODE int bootloader_gpio_read(uint32_t gpio)
{
uint32_t line = (gpio & GPIO_FLAGS_MASK_LINE) >> GPIO_FLAGS_SHIFT_LINE;
uint32_t port = (gpio & GPIO_FLAGS_MASK_PORT) >> GPIO_FLAGS_SHIFT_PORT;
uint32_t base;
//get port base address
if(port >= 10) return;
base = GPIO_BASE + (port * GPIO_STEP);
return (getreg32(base + GPIO_REGOFF_IDR) >> line) & 1;
}