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