128
|
1 import time
|
|
2 from devices import Device, registerDevice, STLinkException, Interface
|
138
|
3 import stlink
|
128
|
4
|
|
5 # F4 specifics:
|
|
6 STM32_FLASH_BASE = 0x08000000
|
|
7 STM32_SRAM_BASE = 0x20000000
|
|
8
|
|
9 # flash registers:
|
|
10 FLASH_F4_REGS_ADDR = 0x40023c00
|
|
11 FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04
|
|
12 FLASH_F4_SR = FLASH_F4_REGS_ADDR + 0x0c
|
|
13 FLASH_F4_CR = FLASH_F4_REGS_ADDR + 0x10
|
|
14
|
|
15 FLASH_F4_CR_START = 16
|
|
16 FLASH_F4_CR_LOCK = 31
|
|
17 FLASH_CR_PG = 0
|
|
18 FLASH_F4_CR_SER = 1
|
|
19 FLASH_CR_MER = 2
|
|
20 FLASH_F4_CR_SNB = 3
|
|
21 FLASH_F4_CR_SNB_MASK = 0x38
|
|
22 FLASH_F4_SR_BSY = 16
|
|
23
|
|
24 class Stm32F4(Device):
|
130
|
25 """
|
|
26 Implementation of the specifics of the STM32F4xx device series.
|
|
27 """
|
128
|
28 def __init__(self, iface):
|
129
|
29 super().__init__(iface)
|
255
|
30 self.logger = logging.getLogger('stm32')
|
246
|
31
|
129
|
32 def __str__(self):
|
130
|
33 return 'STM32F4 device size=0x{1:X} id=0x{0:X}'.format(\
|
|
34 self.UID, self.FlashSize)
|
246
|
35
|
130
|
36 def calculate_F4_sector(self, address):
|
|
37 sectorstarts = []
|
|
38 a = STM32_FLASH_BASE
|
|
39 for sectorsize in self.sectorsizes:
|
|
40 sectorstarts.append(a)
|
|
41 a += sectorsize
|
|
42 # linear search:
|
|
43 sec = 0
|
|
44 while sec < len(self.sectorsizes) and address >= sectorstarts[sec]:
|
|
45 sec += 1
|
|
46 sec -= 1 # one back.
|
|
47 return sec, self.sectorsizes[sec]
|
|
48
|
|
49 def calcSectors(self, address, size):
|
|
50 off = 0
|
|
51 sectors = []
|
|
52 while off < size:
|
|
53 sectornum, sectorsize = self.calculate_F4_sector(address + off)
|
|
54 sectors.append((sectornum, sectorsize))
|
|
55 off += sectorsize
|
|
56 return sectors
|
|
57 # Device registers:
|
|
58 @property
|
|
59 def UID(self):
|
|
60 uid_base = 0x1FFF7A10
|
|
61 uid1 = self.iface.read_debug32(uid_base)
|
|
62 uid2 = self.iface.read_debug32(uid_base + 0x4)
|
|
63 uid3 = self.iface.read_debug32(uid_base + 0x8)
|
|
64 return (uid3 << 64) | (uid2 << 32) | uid1
|
246
|
65
|
130
|
66 @property
|
|
67 def FlashSize(self):
|
|
68 f_id = self.iface.read_debug32(0x1FFF7A22)
|
|
69 f_id = f_id >> 16
|
|
70 return f_id * 1024
|
246
|
71
|
138
|
72 @property
|
|
73 def Running(self):
|
|
74 return self.iface.Status == stlink.CORE_RUNNING
|
246
|
75
|
128
|
76 # flashing commands:
|
|
77 def writeFlash(self, address, content):
|
130
|
78 flashsize = self.FlashSize
|
|
79 pagesize = min(self.sectorsizes)
|
128
|
80
|
|
81 # Check address range:
|
|
82 if address < STM32_FLASH_BASE:
|
|
83 raise STLinkException('Flashing below flash start')
|
|
84 if address + len(content) > STM32_FLASH_BASE + flashsize:
|
|
85 raise STLinkException('Flashing above flash size')
|
|
86 if address & 1 == 1:
|
|
87 raise STLinkException('Unaligned flash')
|
|
88 if len(content) & 1 == 1:
|
255
|
89 self.logger.warning('unaligned length, padding with zero')
|
128
|
90 content += bytes([0])
|
|
91 if address & (pagesize - 1) != 0:
|
|
92 raise STLinkException('Address not aligned with pagesize')
|
|
93 # erase required space
|
130
|
94 sectors = self.calcSectors(address, len(content))
|
255
|
95 self.logger.info('erasing {0} sectors'.format(len(sectors)))
|
128
|
96 for sector, secsize in sectors:
|
255
|
97 self.logger.info('erasing sector {0} of {1} bytes'.format(sector, secsize))
|
128
|
98 self.eraseFlashSector(sector)
|
|
99 # program pages:
|
|
100 self.unlockFlashIf()
|
|
101 self.writeFlashCrPsiz(2) # writes are 32 bits aligned
|
|
102 self.setFlashCrPg()
|
255
|
103 self.logger.info('writing {0} bytes'.format(len(content)), end='')
|
128
|
104 offset = 0
|
|
105 t1 = time.time()
|
|
106 while offset < len(content):
|
|
107 size = len(content) - offset
|
|
108 if size > 0x8000:
|
|
109 size = 0x8000
|
|
110 chunk = content[offset:offset + size]
|
|
111 while len(chunk) % 4 != 0:
|
|
112 chunk = chunk + bytes([0])
|
|
113 # Use simple mem32 writes:
|
|
114 self.iface.write_mem32(address + offset, chunk)
|
|
115 offset += size
|
|
116 print('.', end='', flush=True)
|
|
117 t2 = time.time()
|
|
118 print('Done!')
|
|
119 print('Speed: {0} bytes/second'.format(len(content)/(t2-t1)))
|
|
120 self.lockFlash()
|
|
121 # verfify program:
|
|
122 self.verifyFlash(address, content)
|
|
123 def eraseFlashSector(self, sector):
|
|
124 self.waitFlashBusy()
|
|
125 self.unlockFlashIf()
|
|
126 self.writeFlashCrSnb(sector)
|
|
127 self.setFlashCrStart()
|
|
128 self.waitFlashBusy()
|
|
129 self.lockFlash()
|
|
130 def eraseFlash(self):
|
|
131 self.waitFlashBusy()
|
|
132 self.unlockFlashIf()
|
|
133 self.setFlashCrMer()
|
|
134 self.setFlashCrStart()
|
|
135 self.waitFlashBusy()
|
|
136 self.clearFlashCrMer()
|
|
137 self.lockFlash()
|
|
138 def verifyFlash(self, address, content):
|
|
139 device_content = self.readFlash(address, len(content))
|
|
140 ok = content == device_content
|
|
141 print('Verify:', ok)
|
|
142 def readFlash(self, address, size):
|
|
143 print('Reading {1} bytes from 0x{0:X}'.format(address, size), end='')
|
|
144 offset = 0
|
|
145 tmp_size = 0x1800
|
|
146 t1 = time.time()
|
|
147 image = bytes()
|
|
148 while offset < size:
|
|
149 # Correct for last page:
|
|
150 if offset + tmp_size > size:
|
|
151 tmp_size = size - offset
|
|
152
|
|
153 # align size to 4 bytes:
|
|
154 aligned_size = tmp_size
|
|
155 while aligned_size % 4 != 0:
|
|
156 aligned_size += 1
|
|
157
|
|
158 mem = self.iface.read_mem32(address + offset, aligned_size)
|
|
159 image += mem[:tmp_size]
|
|
160
|
|
161 # indicate progress:
|
|
162 print('.', end='', flush=True)
|
|
163
|
|
164 # increase for next piece:
|
|
165 offset += tmp_size
|
|
166 t2 = time.time()
|
|
167 assert size == len(image)
|
|
168 print('Done!')
|
|
169 print('Speed: {0} bytes/second'.format(size/(t2-t1)))
|
|
170 return image
|
|
171
|
|
172 def waitFlashBusy(self):
|
246
|
173 """ block until flash operation completes. """
|
|
174 while self.isFlashBusy():
|
|
175 time.sleep(0.01)
|
128
|
176 def isFlashLocked(self):
|
|
177 cr = self.readFlashCr()
|
|
178 mask = 1 << FLASH_F4_CR_LOCK
|
|
179 return cr & mask == mask
|
|
180 def unlockFlashIf(self):
|
130
|
181 FLASH_KEY1, FLASH_KEY2 = 0x45670123, 0xcdef89ab
|
128
|
182 if self.isFlashLocked():
|
|
183 self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY1)
|
|
184 self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY2)
|
|
185 if self.isFlashLocked():
|
|
186 raise STLinkException('Failed to unlock')
|
|
187 def lockFlash(self):
|
|
188 x = self.readFlashCr() | (1 << FLASH_F4_CR_LOCK)
|
|
189 self.writeFlashCr(x)
|
|
190 def readFlashSr(self):
|
|
191 return self.iface.read_debug32(FLASH_F4_SR)
|
|
192 def readFlashCr(self):
|
|
193 return self.iface.read_debug32(FLASH_F4_CR)
|
|
194 def writeFlashCr(self, x):
|
|
195 self.iface.write_debug32(FLASH_F4_CR, x)
|
|
196 def writeFlashCrSnb(self, sector):
|
|
197 x = self.readFlashCr()
|
|
198 x &= ~FLASH_F4_CR_SNB_MASK
|
|
199 x |= sector << FLASH_F4_CR_SNB
|
|
200 x |= 1 << FLASH_F4_CR_SER
|
|
201 self.writeFlashCr(x)
|
|
202 def setFlashCrMer(self):
|
|
203 x = self.readFlashCr()
|
|
204 x |= 1 << FLASH_CR_MER
|
|
205 self.writeFlashCr(x)
|
|
206 def setFlashCrPg(self):
|
|
207 x = self.readFlashCr()
|
|
208 x |= 1 << FLASH_CR_PG
|
|
209 self.writeFlashCr(x)
|
|
210 def writeFlashCrPsiz(self, n):
|
|
211 x = self.readFlashCr()
|
|
212 x &= (0x3 << 8)
|
|
213 x |= n << 8
|
|
214 self.writeFlashCr(x)
|
|
215 def clearFlashCrMer(self):
|
|
216 x = self.readFlashCr()
|
|
217 x &= ~(1 << FLASH_CR_MER)
|
|
218 self.writeFlashCr(x)
|
|
219 def setFlashCrStart(self):
|
|
220 x = self.readFlashCr()
|
|
221 x |= 1 << FLASH_F4_CR_START
|
|
222 self.writeFlashCr(x)
|
|
223 def isFlashBusy(self):
|
|
224 mask = 1 << FLASH_F4_SR_BSY
|
|
225 sr = self.readFlashSr()
|
|
226 # Check for error bits:
|
|
227 errorbits = {}
|
|
228 errorbits[7] = 'Programming sequence error'
|
|
229 errorbits[6] = 'Programming parallelism error'
|
|
230 errorbits[5] = 'Programming alignment error'
|
|
231 errorbits[4] = 'Write protection error'
|
|
232 errorbits[1] = 'Operation error'
|
|
233 #errorbits[0] = 'End of operation'
|
|
234 for bit, msg in errorbits.items():
|
|
235 if sr & (1 << bit) == (1 << bit):
|
|
236 raise STLinkException(msg)
|
|
237 return sr & mask == mask
|
|
238
|
131
|
239 @registerDevice(0x10016413)
|
|
240 class Stm32F40x(Stm32F4):
|
|
241 """ STM32F40x and STM32F41x device series """
|
|
242 def __init__(self, iface):
|
|
243 super().__init__(iface)
|
|
244 # Assert the proper size for this device:
|
|
245 assert self.FlashSize == 0x100000
|
|
246 """
|
|
247 from 0x8000000 to 0x80FFFFF
|
|
248 4 sectors of 0x4000 (16 kB)
|
|
249 1 sector of 0x10000 (64 kB)
|
|
250 7 of 0x20000 (128 kB)
|
|
251 """
|
|
252 self.sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7
|
|
253
|