Skip to content
This repository was archived by the owner on Dec 11, 2022. It is now read-only.

Commit 53b2760

Browse files
committed
add unique serial number for USB descriptor and CMSIS-DAP DAP_Info
1 parent 26e96fd commit 53b2760

9 files changed

+265
-118
lines changed

DAP_config.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,15 @@ __STATIC_INLINE uint8_t DAP_GetProductString (char *str) {
157157
return (0U);
158158
}
159159

160+
extern char unique_id[17];
161+
160162
/** Get Serial Number string.
161163
\param str Pointer to buffer to store the string.
162164
\return String length.
163165
*/
164166
__STATIC_INLINE uint8_t DAP_GetSerNumString (char *str) {
165-
(void)str;
166-
return (0U);
167+
memcpy(str, unique_id, sizeof(unique_id));
168+
return sizeof(unique_id);
167169
}
168170

169171
///@}

bootcode.c

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2021 Peter Lawrence
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#include "bsp/board.h"
26+
#include "tusb.h"
27+
#include <rp2040.h>
28+
#include "hardware/resets.h"
29+
30+
/* this is code that runs before main() and cannot be used once execution reaches main() (since it exists in RAM we have not reserved) */
31+
32+
__attribute__ (( section(".bootc") )) static void pll_init(pll_hw_t *pll, uint32_t refdiv, uint32_t vco_freq, uint32_t post_div1, uint8_t post_div2)
33+
{
34+
uint32_t ref_mhz = XOSC_MHZ / refdiv;
35+
36+
// What are we multiplying the reference clock by to get the vco freq
37+
// (The regs are called div, because you divide the vco output and compare it to the refclk)
38+
uint32_t fbdiv = vco_freq / (ref_mhz * 1000000UL);
39+
40+
// fbdiv
41+
assert(fbdiv >= 16 && fbdiv <= 320);
42+
43+
// Check divider ranges
44+
assert((post_div1 >= 1 && post_div1 <= 7) && (post_div2 >= 1 && post_div2 <= 7));
45+
46+
// post_div1 should be >= post_div2
47+
// from appnote page 11
48+
// postdiv1 is designed to operate with a higher input frequency
49+
// than postdiv2
50+
assert(post_div2 <= post_div1);
51+
52+
// Check that reference frequency is no greater than vco / 16
53+
assert(ref_mhz <= (vco_freq / 16));
54+
55+
// Set up post dividers - div1 feeds into div2 so if div1 is 5 and div2 is 2 then you get a divide by 10
56+
uint32_t pdiv = (post_div1 << PLL_PRIM_POSTDIV1_LSB) |
57+
(post_div2 << PLL_PRIM_POSTDIV2_LSB);
58+
59+
uint32_t pll_reset = (pll_usb_hw == pll) ? RESETS_RESET_PLL_USB_BITS : RESETS_RESET_PLL_SYS_BITS;
60+
reset_block(pll_reset);
61+
unreset_block_wait(pll_reset);
62+
63+
// Turn off PLL in case it is already running
64+
pll->pwr = 0xffffffff;
65+
pll->fbdiv_int = 0;
66+
67+
pll->cs = refdiv;
68+
69+
// Put calculated value into feedback divider
70+
pll->fbdiv_int = fbdiv;
71+
72+
// Turn on PLL
73+
uint32_t power = PLL_PWR_PD_BITS | // Main power
74+
PLL_PWR_VCOPD_BITS; // VCO Power
75+
76+
hw_clear_bits(&pll->pwr, power);
77+
78+
// Wait for PLL to lock
79+
while (!(pll->cs & PLL_CS_LOCK_BITS));
80+
81+
// Set up post dividers
82+
pll->prim = pdiv;
83+
84+
// Turn on post divider
85+
hw_clear_bits(&pll->pwr, PLL_PWR_POSTDIVPD_BITS);
86+
}
87+
88+
/*
89+
This is a more streamlined alternative to the current pico-sdk based TinyUSB board support package.
90+
Sticking to C and avoiding all that C++ yields a much smaller executable.
91+
*/
92+
93+
/* overhaul of clock_configure() from pico-sdk to use much less memory */
94+
__attribute__ (( section(".bootc") )) bool simple_clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc, bool glitchless)
95+
{
96+
const uint32_t div = 0x100; /* always 1:1 ratio */
97+
98+
clock_hw_t *clock = &clocks_hw->clk[clk_index];
99+
100+
// If increasing divisor, set divisor before source. Otherwise set source
101+
// before divisor. This avoids a momentary overspeed when e.g. switching
102+
// to a faster source and increasing divisor to compensate.
103+
if (div > clock->div)
104+
clock->div = div;
105+
106+
// If switching a glitchless slice (ref or sys) to an aux source, switch
107+
// away from aux *first* to avoid passing glitches when changing aux mux.
108+
// Assume (!!!) glitchless source 0 is no faster than the aux source.
109+
if (glitchless)
110+
{
111+
hw_clear_bits(&clock->ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
112+
while (!(clock->selected & 1u));
113+
}
114+
// If no glitchless mux, cleanly stop the clock to avoid glitches
115+
// propagating when changing aux mux. Note it would be a really bad idea
116+
// to do this on one of the glitchless clocks (clk_sys, clk_ref).
117+
else
118+
{
119+
hw_clear_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
120+
}
121+
122+
// Set aux mux first, and then glitchless mux if this clock has one
123+
hw_write_masked(&clock->ctrl,
124+
(auxsrc << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB),
125+
CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS
126+
);
127+
128+
if (glitchless)
129+
{
130+
hw_write_masked(&clock->ctrl,
131+
src << CLOCKS_CLK_REF_CTRL_SRC_LSB,
132+
CLOCKS_CLK_REF_CTRL_SRC_BITS
133+
);
134+
while (!(clock->selected & (1u << src)));
135+
}
136+
137+
hw_set_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
138+
139+
// Now that the source is configured, we can trust that the user-supplied
140+
// divisor is a safe value.
141+
clock->div = div;
142+
143+
return true;
144+
}
145+
146+
__attribute__ (( section(".bootc") )) static void usb_clock_init(void)
147+
{
148+
hw_set_bits(&resets_hw->reset, RESETS_RESET_PLL_USB_BITS);
149+
hw_clear_bits(&resets_hw->reset, RESETS_RESET_PLL_USB_BITS);
150+
while (~resets_hw->reset_done & RESETS_RESET_PLL_USB_BITS);
151+
152+
pll_init(pll_usb_hw, 1, 480 * 1000000, 5, 2);
153+
154+
// CLK SYS = PLL USB (48MHz) / 1 = 48MHz
155+
simple_clock_configure(clk_sys,
156+
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
157+
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
158+
true);
159+
160+
// CLK USB = PLL USB (48MHz) / 1 = 48MHz
161+
simple_clock_configure(clk_usb,
162+
0, // No GLMUX
163+
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
164+
false);
165+
}
166+
167+
typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
168+
169+
#define rom_hword_as_ptr(rom_address) (void *)(uint32_t)(*(uint16_t *)rom_address)
170+
171+
__attribute__ (( section(".bootc") )) static void *rom_func_lookup(uint32_t code)
172+
{
173+
rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn)rom_hword_as_ptr(0x18);
174+
uint16_t *func_table = (uint16_t *)rom_hword_as_ptr(0x14);
175+
return rom_table_lookup(func_table, code);
176+
}
177+
178+
__attribute__ (( section(".bootc") )) static void *rom_data_lookup(uint32_t code)
179+
{
180+
rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn)rom_hword_as_ptr(0x18);
181+
uint16_t *data_table = (uint16_t *)rom_hword_as_ptr(0x16);
182+
return rom_table_lookup(data_table, code);
183+
}
184+
185+
__attribute__ (( section(".bootc") )) static uint32_t rom_table_code(char c1, char c2)
186+
{
187+
return (c2 << 8) | c1;
188+
}
189+
190+
typedef uint32_t (*pop_fn)(uint32_t);
191+
typedef void (*void_fn)(void);
192+
193+
extern char unique_id[17];
194+
195+
__attribute__ (( section(".bootc") )) void SystemInit(void)
196+
{
197+
void_fn connect_internal_flash = rom_func_lookup(rom_table_code('I', 'F'));
198+
void_fn flash_exit_xip = rom_func_lookup(rom_table_code('E', 'X'));
199+
200+
connect_internal_flash();
201+
flash_exit_xip();
202+
203+
hw_write_masked(&ioqspi_hw->io[1].ctrl,
204+
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB,
205+
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS
206+
);
207+
208+
/* Unique ID command and 32-bits of pipeline delay */
209+
for (int i = 0; i < 5; i++)
210+
{
211+
ssi_hw->dr0 = 0x4B;
212+
while (!(ssi_hw->sr & SSI_SR_RFNE_BITS));
213+
(void)ssi_hw->dr0;
214+
}
215+
/* read the 64-bits and write as hex chars */
216+
char *pnt = unique_id;
217+
for (int i = 0; i < 8; i++)
218+
{
219+
ssi_hw->dr0 = 0;
220+
while (!(ssi_hw->sr & SSI_SR_RFNE_BITS));
221+
uint8_t byte = ssi_hw->dr0;
222+
*pnt++ = "0123456789ABCDEF"[(byte >> 4) & 0xf];
223+
*pnt++ = "0123456789ABCDEF"[(byte >> 0) & 0xf];
224+
}
225+
226+
hw_write_masked(&ioqspi_hw->io[1].ctrl,
227+
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB,
228+
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS
229+
);
230+
231+
usb_clock_init();
232+
}

myboard.c

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -26,92 +26,7 @@
2626
#include "tusb.h"
2727
#include <rp2040.h>
2828

29-
#include "hardware/pll.h"
30-
31-
/*
32-
This is a more streamlined alternative to the current pico-sdk based TinyUSB board support package.
33-
Sticking to C and avoiding all that C++ yields a much smaller executable.
34-
*/
35-
36-
/* overhaul of clock_configure() from pico-sdk to use much less memory */
37-
bool simple_clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc, bool glitchless)
38-
{
39-
const uint32_t div = 0x100; /* always 1:1 ratio */
40-
41-
clock_hw_t *clock = &clocks_hw->clk[clk_index];
42-
43-
// If increasing divisor, set divisor before source. Otherwise set source
44-
// before divisor. This avoids a momentary overspeed when e.g. switching
45-
// to a faster source and increasing divisor to compensate.
46-
if (div > clock->div)
47-
clock->div = div;
48-
49-
// If switching a glitchless slice (ref or sys) to an aux source, switch
50-
// away from aux *first* to avoid passing glitches when changing aux mux.
51-
// Assume (!!!) glitchless source 0 is no faster than the aux source.
52-
if (glitchless)
53-
{
54-
hw_clear_bits(&clock->ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
55-
while (!(clock->selected & 1u));
56-
}
57-
// If no glitchless mux, cleanly stop the clock to avoid glitches
58-
// propagating when changing aux mux. Note it would be a really bad idea
59-
// to do this on one of the glitchless clocks (clk_sys, clk_ref).
60-
else
61-
{
62-
hw_clear_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
63-
}
64-
65-
// Set aux mux first, and then glitchless mux if this clock has one
66-
hw_write_masked(&clock->ctrl,
67-
(auxsrc << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB),
68-
CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS
69-
);
70-
71-
if (glitchless)
72-
{
73-
hw_write_masked(&clock->ctrl,
74-
src << CLOCKS_CLK_REF_CTRL_SRC_LSB,
75-
CLOCKS_CLK_REF_CTRL_SRC_BITS
76-
);
77-
while (!(clock->selected & (1u << src)));
78-
}
79-
80-
hw_set_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
81-
82-
// Now that the source is configured, we can trust that the user-supplied
83-
// divisor is a safe value.
84-
clock->div = div;
85-
86-
return true;
87-
}
88-
89-
static void usb_clock_init(void)
90-
{
91-
hw_set_bits(&resets_hw->reset, RESETS_RESET_PLL_USB_BITS);
92-
hw_clear_bits(&resets_hw->reset, RESETS_RESET_PLL_USB_BITS);
93-
while (~resets_hw->reset_done & RESETS_RESET_PLL_USB_BITS);
94-
95-
pll_init(pll_usb_hw, 1, 480 * 1000000, 5, 2);
96-
97-
// CLK SYS = PLL USB (48MHz) / 1 = 48MHz
98-
simple_clock_configure(clk_sys,
99-
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
100-
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
101-
true);
102-
103-
// CLK USB = PLL USB (48MHz) / 1 = 48MHz
104-
simple_clock_configure(clk_usb,
105-
0, // No GLMUX
106-
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
107-
false);
108-
}
109-
110-
void board_init(void)
111-
{
112-
usb_clock_init();
113-
}
114-
29+
void board_init(void) {}
11530
void irq_set_exclusive_handler(unsigned int num, void *handler) {}
11631

11732
/* cut out the middleman and map the interrupt directly to the handler */

pico-debug.hzp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
<file file_name="./usb_descriptors.c" />
1717
<file file_name="myboard.c" />
1818
<file file_name="spawn.c" />
19+
<file file_name="bootcode.c"/>
1920
</folder>
2021
<folder Name="hal">
2122
<file file_name="$(TOP)/hw/bsp/board.c" />
2223
<file file_name="$(TOP)/src/portable/raspberrypi/rp2040/rp2040_usb.c" />
23-
<file file_name="$(TOP)/hw/mcu/raspberrypi/pico-sdk/src/rp2_common/hardware_pll/pll.c" />
2424
</folder>
2525
<folder Name="CMSIS-DAP">
2626
<file file_name="./CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c" />

picodebug_MemoryMap.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<!DOCTYPE Board_Memory_Definition_File>
2-
<Root name="Cortex-M0">
3-
<MemorySegment start="0x2003BF00" size="0x4100" access="Read/Write" name="SRAM" />
2+
<Root name="pico-debug">
3+
<MemorySegment start="0x2003BD00" size="0x300" access="Read/Write" name="BOOT" />
4+
<MemorySegment start="0x2003C000" size="0x4000" access="Read/Write" name="SRAM" />
45
<MemorySegment start="0x15000000" size="0x4000" access="Read/Write" name="XIP_SRAM" />
56
</Root>

picodebug_Startup.s

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,14 @@ boot_entry:
5555
ldr r0, =0x14000000
5656
ldr r1, =0
5757
str r1, [r0]
58-
59-
/* copy initialized memory sections en masse into final destinations */
60-
ldr r0, =__vectors_load_start__
61-
ldr r1, =__vectors_start__
62-
ldr r2, =__rodata_end__
63-
cmp r0, r1
64-
beq copy_finished
65-
subs r2, r2, r1
66-
beq copy_finished
67-
copy_loop:
68-
ldrb r3, [r0]
69-
adds r0, r0, #1
70-
strb r3, [r1]
71-
adds r1, r1, #1
72-
subs r2, r2, #1
73-
bne copy_loop
74-
copy_finished:
58+
/* undocumented step to ensure XIP_SRAM is ready for accesses */
59+
ldr r1, [r0, #4]
7560
#endif
7661

62+
ldr r0, =__SRAM_segment_end__
63+
mov sp, r0
64+
bl SystemInit
65+
7766
ldr r2, =__vectors_start__ /* origin of where vector table now resides */
7867
ldr r1, [r2] /* load stack pointer from user app */
7968
ldr r0, [r2, #4] /* load reset address from user app */

0 commit comments

Comments
 (0)