-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathflash-programming.mu4
More file actions
165 lines (118 loc) · 4.91 KB
/
flash-programming.mu4
File metadata and controls
165 lines (118 loc) · 4.91 KB
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
| This file is part of muforth: https://muforth.dev/
|
| Copyright (c) 2002-2026 David Frech. (Read the LICENSE for details.)
loading STM32 flash programming
decimal
| Register conventions.
|
| r0 to r3 aka w x y z are scratch
| r4 is FLASH_REGS base address (fb)
| r5 is count (cnt)
( Tell the disassembler about these register names.)
-: ( reg)
15 and 3 *
z" w x y z fb cntr6 r7 r8 r9 r10r11r12rp lr pc " + 3 -trailing type ;
: flash-asm-regs [ #] is .reg ; flash-asm-regs
| These are useful for *all* kinds of i/o programming on an STM32. If we
| define them here, any code loaded after this can use them.
|
| STM32 peripherals are defined on 1 KiB boundaries.
meta
: >iobase ( io-reg - base) -1 Ki and ;
: >io ( io-reg - offset) [ 1 Ki 1- #] and ;
assembler
\a r5 constant cnt
| From flash register absolute address (equate) generate an io offset
| against the register holding the base address of the flash regs (r3).
: >fr ( flash-reg - offset base-reg) \m >io \a r4 ;
forth
| How much space do we want to use for the flashbuf? It can't be bigger
| than /page, and we don't want to use too much of the RAM, since I don't
| think the flash buf size is the limiting factor for programming speed.
|
| Let's use the lesser of 1 KiB and the page size (if it is defined).
1 Ki .ifdef /page /page min .then constant #flashbuf
| Leave room for 64 cells on sp stack; room for 256 bytes of flash
| programming code; round down to multiple of 256, then leave #flashbuf
| bytes of space for buffer.
( Start the flash routines *after* the flashbuf.)
dp0 64 \m cells - 256 - ( flash code) -256 and dup constant @flash-routines
#flashbuf - constant @flashbuf
.ifndef /page ( devices that erase based on a page *index*)
| Replace the standard flash erasure code - which expects uniformly-sized
| pages specified by *address* - with code that works for STM32 chips that
| use page *indexes* rather than addresses for erasure, and which might
| have pages of non-uniform size (eg, the F4 family).
| Print *both* the target address *and* the index of the page being erased.
: erase-page ( index 'target)
cr ." erase " u. ." (page " dup (u.) type ." )"
t.erase ;
| Before programming the *first* byte of a page, we erase the page.
|
| Given a target flash address, return page index and true if we should
| erase this address, and false otherwise. Every target that uses page
| indexes for erasure has to define this word:
| erase? ( 'target - index -1 | 0)
: ?erase ( 'target) dup erase? if swap erase-page ^ then drop ;
-: ( 'target len - 'target+len)
2dup + push over ?erase program-chunk pop ; is erase-program-chunk
| For testing the address-to-page-index mapping code, on families that use
| page indices, rather than addresses, for erasure.
.ifdef testing
: test-page ( 'target)
dup erase? if swap cr u. ." page " u. ^ then drop ;
| Test every 256 byte chunk of the flash to see where the page boundaries
| are. Make sure we get the correct values!
: test-pages
@flash #flash over + swap do i test-page 256 +loop ;
.then ( def testing)
.then ( ndef /page)
hex
__meta
ram here ( we are going to return here after compiling the flash routines.)
@flash-routines goto ( starting address of flash routines)
| Load the chip-family-specific programming code.
chip-family-path z" flash-programming.mu4" concat load-file
.ifdef testing
| w is byte count, x is dest address, y is src address, z is offset. Copy
| by words, not halfwords.
label copy-mem ( src dest count)
{ y x w } pop
0 z movs ( offset) w cnt mov ( save)
begin
z y w ldr z x w str 4 z z adds
cnt z cmp
u>= until
lr bx ;c
| For testing #retries.
label hang hang b ;c
label long 1 w movs #24 w w lsls
begin 1 w w subs 0= until lr bx ;c
.then ( testing)
| We make sure to disable interrupts before calling our code!
label execute-assembly
cpsid ( disable interrupts)
FLASH_ACR >iobase r4 lit ( set up flash register base address)
{ w } pop dsb isb w blx
.ifdef testing
{ cnt r4 z y x w } push
.then
0 bkpt ;c pool,
align ( make sure RAM region is word-aligned)
here @flash-routines - constant #flash-routines ( size of the code)
goto ( return to saved here)
__host
forth
.ifdef testing
: .rxregs ( cnt freg z y x w)
cr ." W X Y Z FREG CNT DP Elapsed"
( 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 )
cr .h32__ .h32__ .h32__ .h32__ .h32__ .h32__ dp@ .h32__
#retries @ .h32__ ;
.else ( not testing)
: .rxregs ;
.then ( testing)
( For quick and dirty execution of remote assembly code.)
: rx ( x0 .. xn 'code - y0 .. yn <regs>)
1+ ( thumb)
stack> \m execute-assembly runwait stack< .rxregs ;