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