Skip to content

Commit b0ca148

Browse files
[arm] Flash programming supported on Nucleo-C031C6 board
The STM32C series chips are unlike the F0 and F3 parts in the way that they deal with erasing the flash. Instead of using an address - the address of the first byte of the page of flash to erase - they use an *index*. The C031 has 32 KiB of flash, divided into 2 KiB pages (or sectors). Thus the index is from 0 to 15. The flash i/o registers are laid out like the F407, which also uses indices to erase the flash, but it has non-uniform sector sizes, and they are quite large: I think the smallest one is 16 KiB. So the C031 falls in between. It uses small uniform pages, like the F0 and F3 parts, but erases (and programs) them more like the F407. Go figure. Something always has to change!
1 parent 8c9e53c commit b0ca148

6 files changed

Lines changed: 131 additions & 55 deletions

File tree

mu/target/ARM/board/nucleo-c031c6.mu4

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@ loading Nucleo-C031C6 board
77
ld! target/ARM/stm32/c0/31_6.mu4
88
ld target/ARM/debug/stlink-v2.mu4
99
ld target/ARM/debug/stlink-v2-interact.mu4
10+
11+
( Let's load the Forth kernel into flash, above the example code that is
12+
pre-programmed onto the board.)
13+
14+
hex
15+
flash @flash 4000 + dup region!
16+
ld target/ARM/v6-m/kernel-itc.mu4
17+
__meta
18+
ram

mu/target/ARM/debug/stlink-v2-interact.mu4

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ loading ST-LINK debug (interact)
77
hex
88

99
( Load the flash programming routines into ram.)
10-
.ndef #flashbuf .ndef no-flash-programming .and .if
11-
.ifdef /page ( chip has flash with uniform page size)
12-
ld target/ARM/stm32/flash-programming.mu4
13-
.else ( chip has sectored flash)
14-
ld target/ARM/stm32/flash-programming-sectored.mu4
15-
.then
10+
11+
.equates. .contains FLASH_AR .if ( chip uses *addresses* for erasing flash)
12+
ld target/ARM/stm32/flash-programming.mu4
13+
.else ( chip uses sector/page *indexes* for erasing flash)
14+
ld target/ARM/stm32/flash-programming-sectored.mu4
1615
.then
1716

1817
( Skip the rest of the file if no ST-LINK was found.)
@@ -59,26 +58,28 @@ hex
5958
st.connect dbg.halt
6059
[ h @ ram @flash-routines image+ swap h ! #] ( address in ram image)
6160
@flash-routines #flash-routines st.write ( copy code to ram)
62-
#flashbuf ; ( size of RAM flash buffer)
61+
#flashbuf ; ( return size of RAM flash buffer as chunk-size)
6362

6463
( Write unlock keys to FLASH_KEYR.)
6564
: st.flash-begin
66-
cdef_89ab 4567_0123 \m unlock rx ;
65+
cdef_89ab 4567_0123 \m stm32-flash-unlock rx ;
6766

6867
( Re-lock flash controller registers.)
69-
: st.flash-end \m lock rx ;
68+
: st.flash-end \m stm32-flash-lock rx ;
7069

7170
( stm32-erase takes a flash address for uniform page devices, and a sector
7271
number, for sectored devices. target/ARM/v6-m/flash.mu4 has already
7372
figured this out for us.)
7473

75-
: st.erase ( a | sector#) \m stm32-erase rx ;
74+
: st.erase ( a | sector#) \m stm32-flash-erase rx ;
7675

7776
( Copy buf contents to ram buffer, then write to flash from there.)
7877
: st.program ( buf a u)
7978
push ( u)
80-
swap @flashbuf r@ ( a buf flashbuf u) st.write ( copy chunk to target ram)
81-
@flashbuf swap pop ( flashbuf a u) \m stm32-flash-chunk rx ;
79+
( copy chunk to target ram, aligning copied data by 8 for STM32C parts)
80+
swap @flashbuf r@ ( a buf flashbuf u) 8 aligned-by st.write
81+
( program chunk into flash)
82+
@flashbuf swap pop ( flashbuf a u) \m stm32-flash-program rx ;
8283

8384
.then ( def no-flash-programming)
8485

mu/target/ARM/stm32/c0/31_6.mu4

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,37 @@ loading STM32C031x6 chip
1313
"2000_0000 constant @ram
1414
12 Ki constant #ram
1515

16-
2 Ki constant #bl-ram ( ram consumed by bootloader)
16+
-- 2 Ki constant #bl-ram ( ram consumed by bootloader)
1717

18-
( Flash programming doesn't use FLASH_AR; currently unsupported.)
19-
-d no-flash-programming
20-
1 Ki constant /page ( erase page size)
18+
( Programming the C031 flash is like programming the F407, except that the
19+
C031 has a uniform sector/page size of 2 KiB.)
20+
21+
( Given a target flash address, return a sector# and true if address is on
22+
a sector boundary, and return false otherwise.)
23+
24+
( XXX should this be called map-flash-sector ?)
25+
: lookup-flash-sector ( 'target - sector# -1 | 0)
26+
@flash - 2 Ki /mod ( mod quot)
27+
swap 0= if -1 ^ then drop 0 ;
28+
29+
( We need to define #flashbuf for the chip. Should be at least 256 but no
30+
more than 2 Ki, the page size. Since we don't have a lot of RAM on the
31+
chip, let's keep it small.)
32+
33+
256 constant #flashbuf
34+
35+
.ifdef testing
36+
37+
: test-sector ( 'target)
38+
dup lookup-flash-sector if swap cr u. ." sector " u. ^ then drop ;
39+
40+
( Test every 256 byte chunk of the flash to see where the sector boundaries
41+
are. Make sure we get the correct values!)
42+
43+
: test-sectors
44+
@flash #flash over + swap do i test-sector 256 +loop ;
45+
46+
.then
2147

2248
-- load peripheral equates etc
2349
ld target/ARM/stm32/c0/31_6-equates.mu4

mu/target/ARM/stm32/f4/07_g.mu4

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ loading STM32F407xG chip
3636
dup 64 Ki = if drop 4 -1 ^ then
3737
128 Ki - 128 5 sector? ;
3838

39+
( We need to define #flashbuf for the chip. Should be at least 256 but no
40+
more than the smallest sector. Since we have lots of RAM on the chip,
41+
let's make it pretty big.)
42+
43+
4 Ki constant #flashbuf
44+
3945
.ifdef testing
4046

4147
: test-sector ( 'target)

mu/target/ARM/stm32/flash-programming-sectored.mu4

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ forth
5858
: asm-regs [ #] is .reg ; asm-regs
5959

6060

61-
( Any chip with sectored flash probably has lots of RAM, so let's use a
62-
4 Ki ram flash buffer.)
61+
.ifndef #flashbuf
62+
z"
6363

64-
4 Ki constant #flashbuf
64+
Your chip is uses indices rather than addresses to specify the block of
65+
flash to erase. You need to define #flashbuf - the size of the RAM buffer
66+
used during flash programming. It should be no smaller than 256 bytes, and
67+
must be no bigger than the smallest sector or page in the flash." abort
68+
.then
6569

6670
( Leave room for 64 cells on sp stack; room for 256 bytes of flash
6771
programming code; round down to multiple of 256, then leave #flashbuf
@@ -78,51 +82,76 @@ ram here ( we are going to return here after compiling the flash routines.)
7882

7983
@flash-routines goto ( starting address of flash routines)
8084

81-
label unlock
82-
FLASH_ACR fr lit
85+
label stm32-flash-unlock
86+
FLASH_CR >iobase fr lit
8387
x w dpop2 FLASH_KEYR >io fr w str FLASH_KEYR >io fr x str
8488
0 w movs FLASH_CR >io fr w str ( clear any program/erase bits)
8589
lr bx ;c
8690
pool,
8791

88-
label lock
89-
80 ( LOCK) w movs
90-
FLASH_CR 3 + >io fr w strb
92+
label stm32-flash-lock
93+
0 w movs FLASH_CR >io fr w str ( clear any program/erase bits)
94+
80 ( LOCK) w movs FLASH_CR 3 + >io fr w strb ( lock CR)
9195
lr bx ;c
9296

97+
( w is flash sector to erase)
98+
label stm32-flash-erase ( sector#)
99+
FLASH_SR >io fr w ldrh FLASH_SR >io fr w strh ( clear any error bits)
100+
w dpop 3 w w lsls ( shift sector# up 3 bits)
101+
2 ( SER) w w adds FLASH_CR >io fr w str ( set SER + sector number)
102+
1 ( STRT) w movs FLASH_CR 2 + >io fr w strb ( set STRT bit)
103+
( fall thru) ;c
104+
105+
( Wait until flash command finishes.)
93106
label -busy
94107
x w rpush2
95108
1 ( BSY) w movs
96109
begin FLASH_SR 2 + >io fr x ldrb x w tst 0= until
97110
x w rpop2
98111
lr bx ;c
99112

100-
( w is flash sector to erase)
101-
label stm32-erase ( sector#)
113+
.ifdef stm32c031
114+
115+
( w is byte count, x is flash address,
116+
y is ram buffer address, z is offset.)
117+
label stm32-flash-program ( buf a u)
102118
lr rpush
103-
w dpop 3 w w lsls ( shift sector# up 3 bits)
104-
2 ( SER) w w adds FLASH_CR >io fr w str ( set SER + sector number)
105-
1 ( STRT) w movs FLASH_CR 2 + >io fr w strb ( set STRT bit)
106-
-busy bl
119+
FLASH_SR >io fr w ldrh FLASH_SR >io fr w strh ( clear any error bits)
120+
y x w dpop3
121+
1 ( PG) z movs FLASH_CR >io fr z str ( set PG bit)
122+
0 z movs ( offset)
123+
begin
124+
( unlike paged flash, we program by double-words!)
125+
z y top ldr z x top str 4 z z adds
126+
z y top ldr z x top str 4 z z adds
127+
-busy bl
128+
w z cmp
129+
u>= until
107130
pc rpop ;c
108131

132+
.then ( def stm32c031)
133+
134+
.ifdef stm32f407
135+
109136
( w is byte count, x is flash address,
110137
y is ram buffer address, z is offset.)
111-
label stm32-flash-chunk ( buf a u)
138+
label stm32-flash-program ( buf a u)
112139
lr rpush
140+
FLASH_SR >io fr w ldrh FLASH_SR >io fr w strh ( clear any error bits)
113141
y x w dpop3
114142
1 ( PG) z movs FLASH_CR >io fr z str ( set PG bit)
115143
2 ( psize) z movs FLASH_CR 1+ >io fr z strb ( psize=2; program by 32bit word)
116144
0 z movs ( offset)
117145
begin
118-
( unlike paged flash, we can program by words!)
119-
z y top ldr z x top str
120-
4 z z adds
146+
( unlike paged flash, we program by words!)
147+
z y top ldr z x top str 4 z z adds
121148
-busy bl
122149
w z cmp
123150
u>= until
124151
pc rpop ;c
125152

153+
.then ( def stm32f407)
154+
126155
.ifdef testing
127156

128157
( w is byte count, x is dest address, y is src address, z is offset. Copy

mu/target/ARM/stm32/flash-programming.mu4

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,14 @@ forth
5959

6060

6161
( How much space do we want to use for the flashbuf? It can't be bigger
62-
than /page, but we don't want it to be too much of a fraction of the
63-
RAM.)
62+
than /page, and we don't want to use too much of the RAM, since I don't
63+
think the flash buf size is the limiting factor for programming speed.
6464

65-
#ram 16 / /page min constant #flashbuf
65+
Let's use 256 if flash size is less than 32 KiB, and 1 KiB otherwise - or
66+
/page if it is smaller.)
67+
68+
#flash 32 Ki u< .if 256 .else 1 Ki .then /page min
69+
constant #flashbuf
6670

6771
( Leave room for 64 cells on sp stack; room for 256 bytes of flash
6872
programming code; round down to multiple of 256, then leave #flashbuf
@@ -79,40 +83,40 @@ ram here ( we are going to return here after compiling the flash routines.)
7983

8084
@flash-routines goto ( starting address of flash routines)
8185

82-
label unlock
83-
FLASH_ACR >iobase fr lit
86+
label stm32-flash-unlock
87+
FLASH_CR >iobase fr lit
8488
x w dpop2 FLASH_KEYR >io fr w str FLASH_KEYR >io fr x str
8589
0 w movs FLASH_CR >io fr w str ( clear any program/erase bits)
8690
lr bx ;c
8791
pool,
8892

89-
label lock
93+
label stm32-flash-lock
94+
0 w movs FLASH_CR >io fr w str ( clear any program/erase bits)
9095
80 ( LOCK) w movs FLASH_CR >io fr w str
9196
lr bx ;c
9297

98+
( w is flash page address to erase)
99+
label stm32-flash-erase ( flash-page-address)
100+
FLASH_SR >io fr w ldrb FLASH_SR >io fr w strb ( clear any error bits)
101+
w dpop
102+
2 ( PER) x movs FLASH_CR >io fr x str ( set PER)
103+
FLASH_AR >io fr w str ( set page erase address)
104+
42 ( STRT+PER) x movs FLASH_CR >io fr x str ( set STRT+PER)
105+
( fall thru) ;c
106+
107+
( Wait until flash command finishes.)
93108
label -busy
94109
x w rpush2
95110
1 ( BSY) w movs
96111
begin FLASH_SR >io fr x ldr x w tst 0= until
97112
x w rpop2
98113
lr bx ;c
99114

100-
( w is flash page address to erase)
101-
label stm32-erase ( flash-page-address)
102-
lr rpush
103-
w dpop
104-
2 ( PER) x movs FLASH_CR >io fr x str ( set PER)
105-
FLASH_AR >io fr w str ( set page erase address)
106-
42 ( STRT+PER) x movs FLASH_CR >io fr x str ( set STRT+PER)
107-
-busy bl
108-
pc rpop ;c
109-
110-
label stm32-mass-erase
111-
lr rpush
115+
label stm32-flash-mass-erase
116+
FLASH_SR >io fr w ldrb FLASH_SR >io fr w strb ( clear any error bits)
112117
4 ( MER) w movs FLASH_CR >io fr w str ( set MER)
113118
44 ( STRT+MER) w movs FLASH_CR >io fr w str ( set STRT+MER)
114-
-busy bl
115-
pc rpop ;c
119+
-busy b ;c
116120

117121
.ifdef bogus-and-untested
118122

@@ -149,8 +153,9 @@ label remove-read-protect ( key)
149153

150154
( w is byte count, x is flash address,
151155
y is ram buffer address, z is offset.)
152-
label stm32-flash-chunk ( buf a u)
156+
label stm32-flash-program ( buf a u)
153157
lr rpush
158+
FLASH_SR >io fr w ldrb FLASH_SR >io fr w strb ( clear any error bits)
154159
y x w dpop3
155160
1 ( PG) z movs FLASH_CR >io fr z str ( set PG bit)
156161
0 z movs ( offset)

0 commit comments

Comments
 (0)