Skip to content

Commit 56284bd

Browse files
committed
puya: add support for PY32F002B, PY32F003, PY32F030, PY32x07x
The flashing procedure and preparatory steps are very similar across PY32F002A, PY32F002B, PY32F003, PY32F030 and PY32x07x. There are some differences though that need to be handled: - The base address for the Configuration Bytes (factory calibration) is different between some of the families. - On PY32x07x the Configuration Bytes are spaced at 64-bit; for all other families they are spaced at 32-bit. - PY32F002B only supports 24MHz HSI and the corresponding Configuration Bytes are located at what would be the 4MHz entries (HSI_FS=0) for the other models. - On PY32F002B some of the flash timing values are sized differently and EPPARA0 in particular has a different layout because of that. - PY32F002B and PY32x07x do not have flash and RAM size stored at address 0x1fff0ffc and I didn't find obvious candidate so their sizes are hard-coded for now. The structure and values of the DBGMCU IDCODE register are undocumented. We use the DEV_ID / REV_ID split used by the vendor SDK together with IDCODE values we collected ourselves. Most the families (PY32F002A, PY32F003, PY32F030) share the same IDCODE value of 0x60001000 but the ones that need to be handled differently do have their own values. For PY32F002A et al. the EPPARA4 PRETPE mask value was kept the same as before (14 bits). The Reference Manual has conflicting information about it: EPPARA4 26:16 (which are 11 bits) is supposed to contain PRETPE 11:0 (which are 12 bits). FLASH_PRETPE, which is documented as having to be initialised from the EPPARA4 value, has 14 bits for PRETPE. The official Keil Device Family Pack v1.2.1 from Puya uses the full upper 16 bit of EPPARA4 so presumably the reserved bits are simply 0 and using the full 14 bit mask is probably fine. In addition to adjusting the calibration addresses based on the model, we now also write HSI_TRIM (using the corresponding factory calibration value like for the flash registers). While the Reference Manuals do not explicitly whether this is required for programming the flash, it can make a huge difference to the accuracy of the HSI clock (over 13% deviation were measured on one chip) and the vendor software does the same. Tested: - using ST-Link v2 clone directly and via BMDA - sequence: load, power cycle, compare, erase, power cycle, check empty - models: - PY32F002AF15P6 - PY32F002AL15S6 - PY32F002BD15S6 - PY32F002BF15P6 - PY32F003L24D6 - PY32F030F18P6 - PY32F030F38P6 - PY32M070K1BU7-C
1 parent d846786 commit 56284bd

File tree

1 file changed

+215
-34
lines changed

1 file changed

+215
-34
lines changed

src/target/puya.c

Lines changed: 215 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,70 @@
4242
#define PUYA_FLASH_START 0x08000000U
4343
#define PUYA_FLASH_PAGE_SIZE 128
4444

45-
/* Pile of timing parameters needed to make sure flash works,
46-
* see section "4.4. Flash configuration bytes" of the RM.
45+
/*
46+
* Pile of timing parameters needed to make sure flash works, see section "4.5. Flash configuration bytes" of the RM.
47+
*
48+
* The layout is very similar across devices. The start address differs and sometimes the entries are 64-bit aligned
49+
* rather than just 32-bit but otherwise the offsets are identical for entries that are present.
4750
*/
48-
#define PUYA_FLASH_TIMING_CAL_BASE 0x1fff0f1cU
51+
/* PY32F002A, PY32F003 */
52+
#define PUYA_TIMING_INFO_START_002A_003 0x1fff0f00u
53+
54+
/* PY32F002B (starting at page 2) */
55+
#define PUYA_TIMING_INFO_START_002B 0x1fff0100u
56+
57+
/* PY32[FM]07x */
58+
#define PUYA_TIMING_INFO_START_07X 0x1fff3200u
59+
60+
/* Start index for HSI_TRIM calibration values. */
61+
#define PUYA_FLASH_TIMING_HSITRIM_IDX 0x00U
62+
63+
/* Start index for EPPARA0…4 entries. */
64+
#define PUYA_FLASH_TIMING_EPPARA0_IDX 0x07U
65+
66+
/* PY32F002A, PY32F003 and PY32[FM]07x have the same layout. */
67+
#define PY32F0XX_EPPARA0_TS0_SHIFT 0U
68+
#define PY32F0XX_EPPARA0_TS0_MASK 0xffU
69+
#define PY32F0XX_EPPARA0_TS3_SHIFT 8U
70+
#define PY32F0XX_EPPARA0_TS3_MASK 0xffU
71+
#define PY32F0XX_EPPARA0_TS1_SHIFT 16U
72+
#define PY32F0XX_EPPARA0_TS1_MASK 0x1ffU
73+
#define PY32F0XX_EPPARA1_TS2P_SHIFT 0U
74+
#define PY32F0XX_EPPARA1_TS2P_MASK 0xffU
75+
#define PY32F0XX_EPPARA1_TPS3_SHIFT 16U
76+
#define PY32F0XX_EPPARA1_TPS3_MASK 0x7ffU
77+
#define PY32F0XX_EPPARA2_PERTPE_SHIFT 0U
78+
#define PY32F0XX_EPPARA2_PERTPE_MASK 0x1ffffU
79+
#define PY32F0XX_EPPARA3_SMERTPE_SHIFT 0U
80+
#define PY32F0XX_EPPARA3_SMERTPE_MASK 0x1ffffU
81+
#define PY32F0XX_EPPARA4_PRGTPE_SHIFT 0U
82+
#define PY32F0XX_EPPARA4_PRGTPE_MASK 0xffffU
83+
#define PY32F0XX_EPPARA4_PRETPE_SHIFT 16U
84+
/* The English version of PY32F002A Reference Manual says EPPARA4 26:16 (11 bit) are PRETPE[11:0] (12 bit) and
85+
* FLASH_PRETPE is 14 bit wide (0:13). However the Chinese version consistently has 14 bits for PRETPE everywhere and
86+
* that's also how the hardware behaves. */
87+
#define PY32F0XX_EPPARA4_PRETPE_MASK 0x3fffU
88+
89+
/* PY32F002B has a layout different from the other supported models. */
90+
#define PY32F002B_EPPARA0_TS0_SHIFT 0U
91+
#define PY32F002B_EPPARA0_TS0_MASK 0x1ffU
92+
#define PY32F002B_EPPARA0_TS3_SHIFT 9U
93+
#define PY32F002B_EPPARA0_TS3_MASK 0x1ffU
94+
#define PY32F002B_EPPARA0_TS1_SHIFT 18U
95+
#define PY32F002B_EPPARA0_TS1_MASK 0x3ffU
96+
#define PY32F002B_EPPARA1_TS2P_SHIFT 0U
97+
#define PY32F002B_EPPARA1_TS2P_MASK 0x1ffU
98+
#define PY32F002B_EPPARA1_TPS3_SHIFT 16U
99+
#define PY32F002B_EPPARA1_TPS3_MASK 0xfffU
100+
#define PY32F002B_EPPARA2_PERTPE_SHIFT 0U
101+
#define PY32F002B_EPPARA2_PERTPE_MASK 0x3ffffU
102+
#define PY32F002B_EPPARA3_SMERTPE_SHIFT 0U
103+
#define PY32F002B_EPPARA3_SMERTPE_MASK 0x3ffffU
104+
#define PY32F002B_EPPARA4_PRGTPE_SHIFT 0U
105+
#define PY32F002B_EPPARA4_PRGTPE_MASK 0xffffU
106+
#define PY32F002B_EPPARA4_PRETPE_SHIFT 16U
107+
#define PY32F002B_EPPARA4_PRETPE_MASK 0x3fffU
108+
49109
/* This config word is undocumented, but the Puya-ISP boot code
50110
* uses it to determine the valid flash/ram size.
51111
* (yes, this *does* include undocumented free extra flash/ram in the 002A)
@@ -91,14 +151,44 @@
91151
#define PUYA_RAM_START 0x20000000U
92152

93153
/* RCC */
94-
#define PUYA_RCC_BASE 0x40021000U
95-
#define PUYA_RCC_ICSCR (PUYA_RCC_BASE + 0x04U)
96-
#define PUYA_RCC_ICSCR_HSI_FS_SHIFT 13U
97-
#define PUYA_RCC_ICSCR_HSI_FS_MASK 7U
154+
#define PUYA_RCC_BASE 0x40021000U
155+
#define PUYA_RCC_ICSCR (PUYA_RCC_BASE + 0x04U)
156+
#define PUYA_RCC_ICSCR_HSI_FS_SHIFT 13U
157+
#define PUYA_RCC_ICSCR_HSI_FS_MASK 7U
158+
#define PUYA_RCC_ICSCR_HSI_TRIM_SHIFT 0U
159+
#define PUYA_RCC_ICSCR_HSI_TRIM_MASK 0x1fffU
98160

99161
/* DBG */
100162
#define PUYA_DBG_BASE 0x40015800U
101163
#define PUYA_DBG_IDCODE (PUYA_DBG_BASE + 0x00U)
164+
/*
165+
* The format and values of the IDCODE register are undocumented but the vendor SDK splits IDCODE into 11:0 DEV_ID and
166+
* 31:16 REV_ID.
167+
*/
168+
#define PUYA_DBG_IDCODE_DEV_ID_SHIFT 0U
169+
#define PUYA_DBG_IDCODE_DEV_ID_MASK 0xfffU
170+
#define PUYA_DBG_IDCODE_REV_ID_SHIFT 16U
171+
#define PUYA_DBG_IDCODE_REV_ID_MASK 0xffffU
172+
173+
/*
174+
* Observed IDCODE (0x40015800) and FLASH_RAM_SZ (0x1fff0ffc) values:
175+
*
176+
* | Model | IDCODE | FLASH_RAM_SZ |
177+
* |---------------------------+------------+--------------|
178+
* | PY32F002AF15P6 | 0x60001000 | 0xffec0013 |
179+
* | PY32F002AL15S6 | 0x60001000 | 0xffec0013 |
180+
* | PY32F002AW15U? | 0x60001000 | ? |
181+
* | PY32F002BD15S6 | 0x20220064 | 0x00000000 |
182+
* | PY32F002BF15P6 | 0x20220064 | 0x00000000 |
183+
* | PY32F003L24D6 | 0x60001000 | 0xfffe0001 |
184+
* | PY32F030F18P6 | 0x60001000 | 0xffc80037 |
185+
* | PY32F030F38P6 | 0x60001000 | 0xffc80037 |
186+
* | PY32M070K1BU7-C | 0x06188061 | n/a |
187+
*/
188+
/* PY32F002A, PY32F003, PY32F030 */
189+
#define PUYA_DEV_ID_PY32F0XX 0x000U
190+
#define PUYA_DEV_ID_PY32F002B 0x064U
191+
#define PUYA_DEV_ID_PY32X07X 0x061U
102192

103193
/*
104194
* Flash functions
@@ -114,18 +204,40 @@ bool puya_probe(target_s *target)
114204
size_t flash_size = 0U;
115205

116206
const uint32_t dbg_idcode = target_mem32_read32(target, PUYA_DBG_IDCODE);
117-
if ((dbg_idcode & 0xfffU) == 0) {
207+
const uint16_t dev_id = (dbg_idcode >> PUYA_DBG_IDCODE_DEV_ID_SHIFT) & PUYA_DBG_IDCODE_DEV_ID_MASK;
208+
switch (dev_id) {
209+
case PUYA_DEV_ID_PY32F0XX: {
118210
const uint32_t flash_ram_sz = target_mem32_read32(target, PUYA_FLASH_RAM_SZ);
119211
flash_size = (((flash_ram_sz >> PUYA_FLASH_SZ_SHIFT) & PUYA_FLASH_SZ_MASK) + 1) << PUYA_FLASH_UNIT_SHIFT;
120212
ram_size = (((flash_ram_sz >> PUYA_RAM_SZ_SHIFT) & PUYA_RAM_SZ_MASK) + 1) << PUYA_RAM_UNIT_SHIFT;
121-
// TODO: which part families does this actually correspond to?
122-
// Tested with a PY32F002AW15U which returns 0x60001000 in IDCODE
123-
target->driver = "PY32Fxxx";
124-
} else {
213+
target->driver = "PY32F0xx";
214+
break;
215+
}
216+
case PUYA_DEV_ID_PY32F002B:
217+
/*
218+
* 0x1fff0ffc contains 0; did not find any other location that looks like it might contain the flash
219+
* and RAM sizes. We'll hard-code the datasheet values for now. Both flash size and RAM size actually
220+
* match the datasheet value, unlike PY32F002A which (sometimes?) has more RAM and flash than
221+
* documented.
222+
*/
223+
flash_size = 24U * 1024U;
224+
ram_size = 3U * 1024U;
225+
target->driver = "PY32F002B";
226+
break;
227+
case PUYA_DEV_ID_PY32X07X:
228+
/* 0x1fff0ffc is in boot loader code. The vendor BSP references 0x1fff31fc as FLASHSIZE_BASE for
229+
* PY32[FM]07x but that location contains 0xffffffff on the PY32M070K1BU7. Hardcode the values for
230+
* now. */
231+
flash_size = 128U * 1024U;
232+
ram_size = 16U * 1024U;
233+
target->driver = "PY32x07x";
234+
break;
235+
default:
125236
DEBUG_TARGET("Unknown PY32 device %08" PRIx32 "\n", dbg_idcode);
126237
return false;
127238
}
128239

240+
target->part_id = dev_id;
129241
target_add_ram32(target, PUYA_RAM_START, ram_size);
130242
target_flash_s *flash = calloc(1, sizeof(*flash));
131243
if (!flash) { /* calloc failed: heap exhaustion */
@@ -151,33 +263,102 @@ static bool puya_flash_prepare(target_flash_s *flash)
151263
target_mem32_write32(flash->t, PUYA_FLASH_KEYR, PUYA_FLASH_KEYR_KEY1);
152264
target_mem32_write32(flash->t, PUYA_FLASH_KEYR, PUYA_FLASH_KEYR_KEY2);
153265

154-
uint8_t hsi_fs =
155-
(target_mem32_read32(flash->t, PUYA_RCC_ICSCR) >> PUYA_RCC_ICSCR_HSI_FS_SHIFT) & PUYA_RCC_ICSCR_HSI_FS_MASK;
266+
target_s *target = flash->t;
267+
uint32_t cal_base;
268+
/* On most models the configuration "bytes" are 32-bit aligned. Exceptions (64-bit alignment) are handled
269+
* below. */
270+
uint8_t cal_shift = 2;
271+
272+
switch (target->part_id) {
273+
case PUYA_DEV_ID_PY32F0XX: {
274+
cal_base = PUYA_TIMING_INFO_START_002A_003;
275+
break;
276+
}
277+
case PUYA_DEV_ID_PY32F002B:
278+
cal_base = PUYA_TIMING_INFO_START_002B;
279+
break;
280+
case PUYA_DEV_ID_PY32X07X:
281+
cal_base = PUYA_TIMING_INFO_START_07X;
282+
/* configuration bytes are 64-bit aligned rather than just 32-bit */
283+
cal_shift = 3;
284+
break;
285+
default:
286+
/* Should have never made it past probe */
287+
DEBUG_TARGET("Unknown PY32 device %08" PRIx32 "\n", target->part_id);
288+
return false;
289+
}
290+
291+
const uint32_t icscr_old = target_mem32_read32(flash->t, PUYA_RCC_ICSCR);
292+
/* Not all models support all frequencies but the mapping is
293+
* the same for all of them. */
294+
uint8_t hsi_fs = (icscr_old >> PUYA_RCC_ICSCR_HSI_FS_SHIFT) & PUYA_RCC_ICSCR_HSI_FS_MASK;
156295
if (hsi_fs > 4)
157296
hsi_fs = 0;
297+
if (target->part_id == PUYA_DEV_ID_PY32F002B) {
298+
/* PY32F002B only supports 24MHz HSI. The HSI_TRIM and EPPARA0 entries for 24MHz are at offset 0,
299+
* disregarding the HSI_FS value. */
300+
hsi_fs = 0;
301+
}
158302
DEBUG_TARGET("HSI frequency selection is %d\n", hsi_fs);
159303

160-
const uint32_t eppara0 = target_mem32_read32(flash->t, PUYA_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + 0);
161-
const uint32_t eppara1 = target_mem32_read32(flash->t, PUYA_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + 4);
162-
const uint32_t eppara2 = target_mem32_read32(flash->t, PUYA_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + 8);
163-
const uint32_t eppara3 = target_mem32_read32(flash->t, PUYA_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + 12);
164-
const uint32_t eppara4 = target_mem32_read32(flash->t, PUYA_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + 16);
165-
DEBUG_TARGET("PY32 flash timing cal 0: %08" PRIx32 "\n", eppara0);
166-
DEBUG_TARGET("PY32 flash timing cal 1: %08" PRIx32 "\n", eppara1);
167-
DEBUG_TARGET("PY32 flash timing cal 2: %08" PRIx32 "\n", eppara2);
168-
DEBUG_TARGET("PY32 flash timing cal 3: %08" PRIx32 "\n", eppara3);
169-
DEBUG_TARGET("PY32 flash timing cal 4: %08" PRIx32 "\n", eppara4);
170-
171-
target_mem32_write32(flash->t, PUYA_FLASH_TS0, eppara0 & 0xffU);
172-
target_mem32_write32(flash->t, PUYA_FLASH_TS1, (eppara0 >> 16U) & 0x1ffU);
173-
target_mem32_write32(flash->t, PUYA_FLASH_TS3, (eppara0 >> 8U) & 0xffU);
174-
target_mem32_write32(flash->t, PUYA_FLASH_TS2P, eppara1 & 0xffU);
175-
target_mem32_write32(flash->t, PUYA_FLASH_TPS3, (eppara1 >> 16U) & 0x7ffU);
176-
target_mem32_write32(flash->t, PUYA_FLASH_PERTPE, eppara2 & 0x1ffffU);
177-
target_mem32_write32(flash->t, PUYA_FLASH_SMERTPE, eppara3 & 0x1ffffU);
178-
target_mem32_write32(flash->t, PUYA_FLASH_PRGTPE, eppara4 & 0xffffU);
179-
target_mem32_write32(flash->t, PUYA_FLASH_PRETPE, (eppara4 >> 16U) & 0x3fffU);
304+
const uint32_t hsi_trim =
305+
target_mem32_read32(flash->t, cal_base + ((PUYA_FLASH_TIMING_HSITRIM_IDX + (hsi_fs * 5) + 0) << cal_shift));
306+
uint32_t eppara[5];
307+
for (uint32_t idx = 0; idx < 5; idx++) {
308+
eppara[idx] = target_mem32_read32(
309+
flash->t, cal_base + ((PUYA_FLASH_TIMING_EPPARA0_IDX + (hsi_fs * 5) + idx) << cal_shift));
310+
}
311+
DEBUG_TARGET("PY32 HSI trim value: %08" PRIx32 "\n", hsi_trim);
312+
DEBUG_TARGET("PY32 flash timing cal 0: %08" PRIx32 "\n", eppara[0]);
313+
DEBUG_TARGET("PY32 flash timing cal 1: %08" PRIx32 "\n", eppara[1]);
314+
DEBUG_TARGET("PY32 flash timing cal 2: %08" PRIx32 "\n", eppara[2]);
315+
DEBUG_TARGET("PY32 flash timing cal 3: %08" PRIx32 "\n", eppara[3]);
316+
DEBUG_TARGET("PY32 flash timing cal 4: %08" PRIx32 "\n", eppara[4]);
180317

318+
target_mem32_write32(flash->t, PUYA_RCC_ICSCR,
319+
(icscr_old & ~PUYA_RCC_ICSCR_HSI_TRIM_MASK) | (hsi_trim & PUYA_RCC_ICSCR_HSI_TRIM_MASK));
320+
switch (target->part_id) {
321+
case PUYA_DEV_ID_PY32F002B:
322+
target_mem32_write32(
323+
flash->t, PUYA_FLASH_TS0, (eppara[0] >> PY32F002B_EPPARA0_TS0_SHIFT) & PY32F002B_EPPARA0_TS0_MASK);
324+
target_mem32_write32(
325+
flash->t, PUYA_FLASH_TS1, (eppara[0] >> PY32F002B_EPPARA0_TS1_SHIFT) & PY32F002B_EPPARA0_TS1_MASK);
326+
target_mem32_write32(
327+
flash->t, PUYA_FLASH_TS3, (eppara[0] >> PY32F002B_EPPARA0_TS3_SHIFT) & PY32F002B_EPPARA0_TS3_MASK);
328+
target_mem32_write32(
329+
flash->t, PUYA_FLASH_TS2P, (eppara[1] >> PY32F002B_EPPARA1_TS2P_SHIFT) & PY32F002B_EPPARA1_TS2P_MASK);
330+
target_mem32_write32(
331+
flash->t, PUYA_FLASH_TPS3, (eppara[1] >> PY32F002B_EPPARA1_TPS3_SHIFT) & PY32F002B_EPPARA1_TPS3_MASK);
332+
target_mem32_write32(
333+
flash->t, PUYA_FLASH_PERTPE, (eppara[2] >> PY32F002B_EPPARA2_PERTPE_SHIFT) & PY32F002B_EPPARA2_PERTPE_MASK);
334+
target_mem32_write32(flash->t, PUYA_FLASH_SMERTPE,
335+
(eppara[3] >> PY32F002B_EPPARA3_SMERTPE_SHIFT) & PY32F002B_EPPARA3_SMERTPE_MASK);
336+
target_mem32_write32(
337+
flash->t, PUYA_FLASH_PRGTPE, (eppara[4] >> PY32F002B_EPPARA4_PRGTPE_SHIFT) & PY32F002B_EPPARA4_PRGTPE_MASK);
338+
target_mem32_write32(
339+
flash->t, PUYA_FLASH_PRETPE, (eppara[4] >> PY32F002B_EPPARA4_PRETPE_SHIFT) & PY32F002B_EPPARA4_PRETPE_MASK);
340+
break;
341+
default:
342+
target_mem32_write32(
343+
flash->t, PUYA_FLASH_TS0, (eppara[0] >> PY32F0XX_EPPARA0_TS0_SHIFT) & PY32F0XX_EPPARA0_TS0_MASK);
344+
target_mem32_write32(
345+
flash->t, PUYA_FLASH_TS1, (eppara[0] >> PY32F0XX_EPPARA0_TS1_SHIFT) & PY32F0XX_EPPARA0_TS1_MASK);
346+
target_mem32_write32(
347+
flash->t, PUYA_FLASH_TS3, (eppara[0] >> PY32F0XX_EPPARA0_TS3_SHIFT) & PY32F0XX_EPPARA0_TS3_MASK);
348+
target_mem32_write32(
349+
flash->t, PUYA_FLASH_TS2P, (eppara[1] >> PY32F0XX_EPPARA1_TS2P_SHIFT) & PY32F0XX_EPPARA1_TS2P_MASK);
350+
target_mem32_write32(
351+
flash->t, PUYA_FLASH_TPS3, (eppara[1] >> PY32F0XX_EPPARA1_TPS3_SHIFT) & PY32F0XX_EPPARA1_TPS3_MASK);
352+
target_mem32_write32(
353+
flash->t, PUYA_FLASH_PERTPE, (eppara[2] >> PY32F0XX_EPPARA2_PERTPE_SHIFT) & PY32F0XX_EPPARA2_PERTPE_MASK);
354+
target_mem32_write32(flash->t, PUYA_FLASH_SMERTPE,
355+
(eppara[3] >> PY32F0XX_EPPARA3_SMERTPE_SHIFT) & PY32F0XX_EPPARA3_SMERTPE_MASK);
356+
target_mem32_write32(
357+
flash->t, PUYA_FLASH_PRGTPE, (eppara[4] >> PY32F0XX_EPPARA4_PRGTPE_SHIFT) & PY32F0XX_EPPARA4_PRGTPE_MASK);
358+
target_mem32_write32(
359+
flash->t, PUYA_FLASH_PRETPE, (eppara[4] >> PY32F0XX_EPPARA4_PRETPE_SHIFT) & PY32F0XX_EPPARA4_PRETPE_MASK);
360+
break;
361+
}
181362
return true;
182363
}
183364

0 commit comments

Comments
 (0)