Skip to content

Commit e580d22

Browse files
committed
Use the external crystal on SAMD21 again.
Also, re-enable calibration storage for CircuitPlayground Express. Tested with a 500hz PWMOut on Metro M0 with Saleae: * with crystal 500hz * with usb 500hz +- 0.1hz * without either 487hz += 0.1hz SAMD51 is skipped due to DFLL errata and the fact it defaults to a factory calibrated 48mhz that works fine for USB. Fixes #648
1 parent de61bd0 commit e580d22

File tree

5 files changed

+100
-69
lines changed

5 files changed

+100
-69
lines changed

ports/atmel-samd/peripherals/clocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,6 @@ bool clock_get_parent(uint8_t type, uint8_t index, uint8_t *p_type, uint8_t *p_i
7070
uint32_t clock_get_frequency(uint8_t type, uint8_t index);
7171
uint32_t clock_get_calibration(uint8_t type, uint8_t index);
7272
int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val);
73+
void save_usb_clock_calibration(void);
7374

7475
#endif // MICROPY_INCLUDED_ATMEL_SAMD_CLOCKS_H

ports/atmel-samd/peripherals/samd21/clocks.c

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,24 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <string.h>
28+
#include <stdlib.h>
29+
2730
#include "peripherals/clocks.h"
2831

29-
#include "hpl_gclk_config.h"
32+
#include "hal/include/hal_flash.h"
3033

3134
#include "bindings/samd/Clock.h"
3235
#include "shared-bindings/microcontroller/__init__.h"
3336

3437
#include "py/runtime.h"
3538

39+
#ifdef EXPRESS_BOARD
40+
#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - NVMCTRL_ROW_SIZE - CIRCUITPY_INTERNAL_NVM_SIZE)
41+
#else
42+
#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x010000 - NVMCTRL_ROW_SIZE - CIRCUITPY_INTERNAL_NVM_SIZE)
43+
#endif
44+
3645
bool gclk_enabled(uint8_t gclk) {
3746
common_hal_mcu_disable_interrupts();
3847
// Explicitly do a byte write so the peripheral knows we're just wanting to read the channel
@@ -102,17 +111,48 @@ static void init_clock_source_xosc32k(void) {
102111
while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY) {}
103112
}
104113

105-
static void init_clock_source_dfll48m(void) {
114+
static void init_clock_source_dfll48m_xosc(void) {
115+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
116+
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
117+
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(0x1f / 4) |
118+
SYSCTRL_DFLLMUL_FSTEP(0xff / 4) |
119+
SYSCTRL_DFLLMUL_MUL(48000000 / 32768);
120+
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos;
121+
if (coarse == 0x3f) {
122+
coarse = 0x1f;
123+
}
124+
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) |
125+
SYSCTRL_DFLLVAL_FINE(512);
126+
127+
SYSCTRL->DFLLCTRL.reg = 0;
128+
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
129+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE |
130+
SYSCTRL_DFLLCTRL_ENABLE;
131+
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
132+
while (GCLK->STATUS.bit.SYNCBUSY) {}
133+
}
134+
135+
static void init_clock_source_dfll48m_usb(void) {
106136
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
107137
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
108138
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) |
109139
SYSCTRL_DFLLMUL_FSTEP(1) |
110140
SYSCTRL_DFLLMUL_MUL(48000);
111141
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos;
112-
if (coarse == 0x3f)
142+
if (coarse == 0x3f) {
113143
coarse = 0x1f;
144+
}
145+
uint32_t fine = 512;
146+
#ifdef CALIBRATE_CRYSTALLESS
147+
// This is stored in an NVM page after the text and data storage but before
148+
// the optional file system. The first 16 bytes are the identifier for the
149+
// section.
150+
if (strcmp((char*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, "CIRCUITPYTHON1") == 0) {
151+
fine = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
152+
}
153+
#endif
114154
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) |
115-
SYSCTRL_DFLLVAL_FINE(512);
155+
SYSCTRL_DFLLVAL_FINE(fine);
116156
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS |
117157
SYSCTRL_DFLLCTRL_USBCRM |
118158
SYSCTRL_DFLLCTRL_MODE |
@@ -130,9 +170,16 @@ void clock_init(void)
130170
init_clock_source_osc32k();
131171
}
132172

173+
if (board_has_crystal()) {
174+
enable_clock_generator(3, GCLK_GENCTRL_SRC_XOSC32K_Val, 1);
175+
connect_gclk_to_peripheral(3, GCLK_CLKCTRL_ID_DFLL48_Val);
176+
init_clock_source_dfll48m_xosc();
177+
} else {
178+
init_clock_source_dfll48m_usb();
179+
}
180+
133181
enable_clock_generator(0, GCLK_GENCTRL_SRC_DFLL48M_Val, 1);
134182
enable_clock_generator(1, GCLK_GENCTRL_SRC_DFLL48M_Val, 150);
135-
init_clock_source_dfll48m();
136183
if (board_has_crystal()) {
137184
enable_clock_generator(2, GCLK_GENCTRL_SRC_XOSC32K_Val, 32);
138185
} else {
@@ -316,6 +363,41 @@ int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val) {
316363
return -2; // calibration is read only
317364
}
318365

366+
void save_usb_clock_calibration(void) {
367+
#ifndef CALIBRATE_CRYSTALLESS
368+
return;
369+
#endif
370+
// If we are on USB lets double check our fine calibration for the clock and
371+
// save the new value if its different enough.
372+
SYSCTRL->DFLLSYNC.bit.READREQ = 1;
373+
uint16_t saved_calibration = 0x1ff;
374+
if (strcmp((char*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, "CIRCUITPYTHON1") == 0) {
375+
saved_calibration = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
376+
}
377+
while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
378+
// TODO(tannewt): Run the mass storage stuff if this takes a while.
379+
}
380+
int16_t current_calibration = SYSCTRL->DFLLVAL.bit.FINE;
381+
if (abs(current_calibration - saved_calibration) > 10) {
382+
// Copy the full internal config page to memory.
383+
uint8_t page_buffer[NVMCTRL_ROW_SIZE];
384+
memcpy(page_buffer, (uint8_t*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, NVMCTRL_ROW_SIZE);
385+
386+
// Modify it.
387+
memcpy(page_buffer, "CIRCUITPYTHON1", 15);
388+
// First 16 bytes (0-15) are ID. Little endian!
389+
page_buffer[16] = current_calibration & 0xff;
390+
page_buffer[17] = current_calibration >> 8;
391+
392+
// Write it back.
393+
// We don't use features that use any advanced NVMCTRL features so we can fake the descriptor
394+
// whenever we need it instead of storing it long term.
395+
struct flash_descriptor desc;
396+
desc.dev.hw = NVMCTRL;
397+
flash_write(&desc, (uint32_t) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, page_buffer, NVMCTRL_ROW_SIZE);
398+
}
399+
}
400+
319401
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
320402
CLOCK_SOURCE(XOSC);
321403
CLOCK_SOURCE(GCLKIN);

ports/atmel-samd/peripherals/samd51/clocks.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ void clock_init(void) {
123123
enable_clock_generator_sync(5, GCLK_GENCTRL_SRC_DFLL_Val, 24, false);
124124

125125
init_clock_source_dpll0();
126+
127+
// Do this after all static clock init so that they aren't used dynamically.
128+
init_dynamic_clocks();
126129
}
127130

128131
static bool clk_enabled(uint8_t clk) {
@@ -203,6 +206,7 @@ static uint32_t dpll_get_frequency(uint8_t index) {
203206
break;
204207
case 0x2: // XOSC0
205208
case 0x3: // XOSC1
209+
default:
206210
return 0; // unknown
207211
}
208212

@@ -335,6 +339,10 @@ int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val) {
335339
return -2;
336340
}
337341

342+
343+
void save_usb_clock_calibration(void) {
344+
}
345+
338346
#include <instance/can0.h>
339347
#include <instance/can1.h>
340348
#include <instance/i2s.h>

ports/atmel-samd/supervisor/filesystem.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@
3232

3333
#include "flash_api.h"
3434

35-
#ifdef EXPRESS_BOARD
36-
// #include "common-hal/touchio/TouchIn.h"
37-
#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x100 - CIRCUITPY_INTERNAL_NVM_SIZE)
38-
#else
39-
#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x010000 - 0x100 - CIRCUITPY_INTERNAL_NVM_SIZE)
40-
#endif
41-
4235
fs_user_mount_t fs_user_mount_flash;
4336
mp_vfs_mount_t mp_vfs_mount_flash;
4437

ports/atmel-samd/supervisor/port.c

Lines changed: 4 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "peripherals/dma.h"
6363
#include "shared-bindings/rtc/__init__.h"
6464
#include "tick.h"
65+
#include "usb.h"
6566

6667
#ifdef CIRCUITPY_GAMEPAD_TICKS
6768
#include "shared-module/gamepad/__init__.h"
@@ -184,7 +185,6 @@ safe_mode_t port_init(void) {
184185
_pm_init();
185186
#endif
186187
clock_init();
187-
init_dynamic_clocks();
188188

189189
board_init();
190190

@@ -270,16 +270,6 @@ void reset_port(void) {
270270

271271
reset_all_pins();
272272

273-
// Set up debugging pins after reset_all_pins().
274-
275-
// Uncomment to init PIN_PA17 for debugging.
276-
// struct port_config pin_conf;
277-
// port_get_config_defaults(&pin_conf);
278-
//
279-
// pin_conf.direction = PORT_PIN_DIR_OUTPUT;
280-
// port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
281-
// port_pin_set_output_level(MICROPY_HW_LED1, false);
282-
283273
// Output clocks for debugging.
284274
// not supported by SAMD51G; uncomment for SAMD51J or update for 51G
285275
// #ifdef SAMD51
@@ -291,52 +281,9 @@ void reset_port(void) {
291281

292282
usb_hid_reset();
293283

294-
// #ifdef CALIBRATE_CRYSTALLESS
295-
// // If we are on USB lets double check our fine calibration for the clock and
296-
// // save the new value if its different enough.
297-
// if (mp_msc_enabled) {
298-
// SYSCTRL->DFLLSYNC.bit.READREQ = 1;
299-
// uint16_t saved_calibration = 0x1ff;
300-
// if (strcmp((char*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, "CIRCUITPYTHON1") == 0) {
301-
// saved_calibration = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
302-
// }
303-
// while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
304-
// // TODO(tannewt): Run the mass storage stuff if this takes a while.
305-
// }
306-
// int16_t current_calibration = SYSCTRL->DFLLVAL.bit.FINE;
307-
// if (abs(current_calibration - saved_calibration) > 10) {
308-
// enum status_code error_code;
309-
// uint8_t page_buffer[NVMCTRL_ROW_SIZE];
310-
// for (int i = 0; i < NVMCTRL_ROW_PAGES; i++) {
311-
// do
312-
// {
313-
// error_code = nvm_read_buffer(INTERNAL_CIRCUITPY_CONFIG_START_ADDR + i * NVMCTRL_PAGE_SIZE,
314-
// page_buffer + i * NVMCTRL_PAGE_SIZE,
315-
// NVMCTRL_PAGE_SIZE);
316-
// } while (error_code == STATUS_BUSY);
317-
// }
318-
// // If this is the first write, include the header.
319-
// if (strcmp((char*) page_buffer, "CIRCUITPYTHON1") != 0) {
320-
// memcpy(page_buffer, "CIRCUITPYTHON1", 15);
321-
// }
322-
// // First 16 bytes (0-15) are ID. Little endian!
323-
// page_buffer[16] = current_calibration & 0xff;
324-
// page_buffer[17] = current_calibration >> 8;
325-
// do
326-
// {
327-
// error_code = nvm_erase_row(INTERNAL_CIRCUITPY_CONFIG_START_ADDR);
328-
// } while (error_code == STATUS_BUSY);
329-
// for (int i = 0; i < NVMCTRL_ROW_PAGES; i++) {
330-
// do
331-
// {
332-
// error_code = nvm_write_buffer(INTERNAL_CIRCUITPY_CONFIG_START_ADDR + i * NVMCTRL_PAGE_SIZE,
333-
// page_buffer + i * NVMCTRL_PAGE_SIZE,
334-
// NVMCTRL_PAGE_SIZE);
335-
// } while (error_code == STATUS_BUSY);
336-
// }
337-
// }
338-
// }
339-
// #endif
284+
if (usb_connected()) {
285+
save_usb_clock_calibration();
286+
}
340287
}
341288

342289
/**

0 commit comments

Comments
 (0)