summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-06-02 18:43:23 -0400
committerGitHub <noreply@github.com>2018-06-02 18:43:23 -0400
commit9a6a5ea2d989577edc74bf301390398ab2e133f9 (patch)
treea56ce01af7da9acc49c3ac430eae3c977e1eeec3
parent47b60fd3faad2567bc2c385f4940f293bc64db1d (diff)
parente580d22f4a63cb56834495620589e038e93e791a (diff)
Merge pull request #892 from tannewt/clock_w_crystal
Use the external crystal on SAMD21 again.
-rw-r--r--ports/atmel-samd/peripherals/clocks.h1
-rw-r--r--ports/atmel-samd/peripherals/samd21/clocks.c92
-rw-r--r--ports/atmel-samd/peripherals/samd51/clocks.c8
-rw-r--r--ports/atmel-samd/supervisor/filesystem.c7
-rw-r--r--ports/atmel-samd/supervisor/port.c61
5 files changed, 100 insertions, 69 deletions
diff --git a/ports/atmel-samd/peripherals/clocks.h b/ports/atmel-samd/peripherals/clocks.h
index 78b2e2e3d..22c166d3e 100644
--- a/ports/atmel-samd/peripherals/clocks.h
+++ b/ports/atmel-samd/peripherals/clocks.h
@@ -70,5 +70,6 @@ bool clock_get_parent(uint8_t type, uint8_t index, uint8_t *p_type, uint8_t *p_i
uint32_t clock_get_frequency(uint8_t type, uint8_t index);
uint32_t clock_get_calibration(uint8_t type, uint8_t index);
int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val);
+void save_usb_clock_calibration(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_CLOCKS_H
diff --git a/ports/atmel-samd/peripherals/samd21/clocks.c b/ports/atmel-samd/peripherals/samd21/clocks.c
index aad251a84..51b7ad993 100644
--- a/ports/atmel-samd/peripherals/samd21/clocks.c
+++ b/ports/atmel-samd/peripherals/samd21/clocks.c
@@ -24,15 +24,24 @@
* THE SOFTWARE.
*/
+#include <string.h>
+#include <stdlib.h>
+
#include "peripherals/clocks.h"
-#include "hpl_gclk_config.h"
+#include "hal/include/hal_flash.h"
#include "bindings/samd/Clock.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "py/runtime.h"
+#ifdef EXPRESS_BOARD
+#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - NVMCTRL_ROW_SIZE - CIRCUITPY_INTERNAL_NVM_SIZE)
+#else
+#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x010000 - NVMCTRL_ROW_SIZE - CIRCUITPY_INTERNAL_NVM_SIZE)
+#endif
+
bool gclk_enabled(uint8_t gclk) {
common_hal_mcu_disable_interrupts();
// 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) {
while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY) {}
}
-static void init_clock_source_dfll48m(void) {
+static void init_clock_source_dfll48m_xosc(void) {
+ SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
+ SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(0x1f / 4) |
+ SYSCTRL_DFLLMUL_FSTEP(0xff / 4) |
+ SYSCTRL_DFLLMUL_MUL(48000000 / 32768);
+ uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos;
+ if (coarse == 0x3f) {
+ coarse = 0x1f;
+ }
+ SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) |
+ SYSCTRL_DFLLVAL_FINE(512);
+
+ SYSCTRL->DFLLCTRL.reg = 0;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
+ SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE |
+ SYSCTRL_DFLLCTRL_ENABLE;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
+ while (GCLK->STATUS.bit.SYNCBUSY) {}
+}
+
+static void init_clock_source_dfll48m_usb(void) {
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) |
SYSCTRL_DFLLMUL_FSTEP(1) |
SYSCTRL_DFLLMUL_MUL(48000);
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos;
- if (coarse == 0x3f)
+ if (coarse == 0x3f) {
coarse = 0x1f;
+ }
+ uint32_t fine = 512;
+ #ifdef CALIBRATE_CRYSTALLESS
+ // This is stored in an NVM page after the text and data storage but before
+ // the optional file system. The first 16 bytes are the identifier for the
+ // section.
+ if (strcmp((char*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, "CIRCUITPYTHON1") == 0) {
+ fine = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
+ }
+ #endif
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) |
- SYSCTRL_DFLLVAL_FINE(512);
+ SYSCTRL_DFLLVAL_FINE(fine);
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS |
SYSCTRL_DFLLCTRL_USBCRM |
SYSCTRL_DFLLCTRL_MODE |
@@ -130,9 +170,16 @@ void clock_init(void)
init_clock_source_osc32k();
}
+ if (board_has_crystal()) {
+ enable_clock_generator(3, GCLK_GENCTRL_SRC_XOSC32K_Val, 1);
+ connect_gclk_to_peripheral(3, GCLK_CLKCTRL_ID_DFLL48_Val);
+ init_clock_source_dfll48m_xosc();
+ } else {
+ init_clock_source_dfll48m_usb();
+ }
+
enable_clock_generator(0, GCLK_GENCTRL_SRC_DFLL48M_Val, 1);
enable_clock_generator(1, GCLK_GENCTRL_SRC_DFLL48M_Val, 150);
- init_clock_source_dfll48m();
if (board_has_crystal()) {
enable_clock_generator(2, GCLK_GENCTRL_SRC_XOSC32K_Val, 32);
} else {
@@ -316,6 +363,41 @@ int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val) {
return -2; // calibration is read only
}
+void save_usb_clock_calibration(void) {
+ #ifndef CALIBRATE_CRYSTALLESS
+ return;
+ #endif
+ // If we are on USB lets double check our fine calibration for the clock and
+ // save the new value if its different enough.
+ SYSCTRL->DFLLSYNC.bit.READREQ = 1;
+ uint16_t saved_calibration = 0x1ff;
+ if (strcmp((char*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, "CIRCUITPYTHON1") == 0) {
+ saved_calibration = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
+ }
+ while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
+ // TODO(tannewt): Run the mass storage stuff if this takes a while.
+ }
+ int16_t current_calibration = SYSCTRL->DFLLVAL.bit.FINE;
+ if (abs(current_calibration - saved_calibration) > 10) {
+ // Copy the full internal config page to memory.
+ uint8_t page_buffer[NVMCTRL_ROW_SIZE];
+ memcpy(page_buffer, (uint8_t*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, NVMCTRL_ROW_SIZE);
+
+ // Modify it.
+ memcpy(page_buffer, "CIRCUITPYTHON1", 15);
+ // First 16 bytes (0-15) are ID. Little endian!
+ page_buffer[16] = current_calibration & 0xff;
+ page_buffer[17] = current_calibration >> 8;
+
+ // Write it back.
+ // We don't use features that use any advanced NVMCTRL features so we can fake the descriptor
+ // whenever we need it instead of storing it long term.
+ struct flash_descriptor desc;
+ desc.dev.hw = NVMCTRL;
+ flash_write(&desc, (uint32_t) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, page_buffer, NVMCTRL_ROW_SIZE);
+ }
+}
+
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
CLOCK_SOURCE(XOSC);
CLOCK_SOURCE(GCLKIN);
diff --git a/ports/atmel-samd/peripherals/samd51/clocks.c b/ports/atmel-samd/peripherals/samd51/clocks.c
index 29f9cb99c..37468a3f7 100644
--- a/ports/atmel-samd/peripherals/samd51/clocks.c
+++ b/ports/atmel-samd/peripherals/samd51/clocks.c
@@ -123,6 +123,9 @@ void clock_init(void) {
enable_clock_generator_sync(5, GCLK_GENCTRL_SRC_DFLL_Val, 24, false);
init_clock_source_dpll0();
+
+ // Do this after all static clock init so that they aren't used dynamically.
+ init_dynamic_clocks();
}
static bool clk_enabled(uint8_t clk) {
@@ -203,6 +206,7 @@ static uint32_t dpll_get_frequency(uint8_t index) {
break;
case 0x2: // XOSC0
case 0x3: // XOSC1
+ default:
return 0; // unknown
}
@@ -335,6 +339,10 @@ int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val) {
return -2;
}
+
+void save_usb_clock_calibration(void) {
+}
+
#include <instance/can0.h>
#include <instance/can1.h>
#include <instance/i2s.h>
diff --git a/ports/atmel-samd/supervisor/filesystem.c b/ports/atmel-samd/supervisor/filesystem.c
index 2ba29f279..8a6010951 100644
--- a/ports/atmel-samd/supervisor/filesystem.c
+++ b/ports/atmel-samd/supervisor/filesystem.c
@@ -32,13 +32,6 @@
#include "flash_api.h"
-#ifdef EXPRESS_BOARD
-// #include "common-hal/touchio/TouchIn.h"
-#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x100 - CIRCUITPY_INTERNAL_NVM_SIZE)
-#else
-#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x010000 - 0x100 - CIRCUITPY_INTERNAL_NVM_SIZE)
-#endif
-
fs_user_mount_t fs_user_mount_flash;
mp_vfs_mount_t mp_vfs_mount_flash;
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index e815d0f1e..3e8d5bcc7 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -62,6 +62,7 @@
#include "peripherals/dma.h"
#include "shared-bindings/rtc/__init__.h"
#include "tick.h"
+#include "usb.h"
#ifdef CIRCUITPY_GAMEPAD_TICKS
#include "shared-module/gamepad/__init__.h"
@@ -184,7 +185,6 @@ safe_mode_t port_init(void) {
_pm_init();
#endif
clock_init();
- init_dynamic_clocks();
board_init();
@@ -270,16 +270,6 @@ void reset_port(void) {
reset_all_pins();
- // Set up debugging pins after reset_all_pins().
-
- // Uncomment to init PIN_PA17 for debugging.
- // struct port_config pin_conf;
- // port_get_config_defaults(&pin_conf);
- //
- // pin_conf.direction = PORT_PIN_DIR_OUTPUT;
- // port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
- // port_pin_set_output_level(MICROPY_HW_LED1, false);
-
// Output clocks for debugging.
// not supported by SAMD51G; uncomment for SAMD51J or update for 51G
// #ifdef SAMD51
@@ -291,52 +281,9 @@ void reset_port(void) {
usb_hid_reset();
-// #ifdef CALIBRATE_CRYSTALLESS
-// // If we are on USB lets double check our fine calibration for the clock and
-// // save the new value if its different enough.
-// if (mp_msc_enabled) {
-// SYSCTRL->DFLLSYNC.bit.READREQ = 1;
-// uint16_t saved_calibration = 0x1ff;
-// if (strcmp((char*) INTERNAL_CIRCUITPY_CONFIG_START_ADDR, "CIRCUITPYTHON1") == 0) {
-// saved_calibration = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
-// }
-// while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
-// // TODO(tannewt): Run the mass storage stuff if this takes a while.
-// }
-// int16_t current_calibration = SYSCTRL->DFLLVAL.bit.FINE;
-// if (abs(current_calibration - saved_calibration) > 10) {
-// enum status_code error_code;
-// uint8_t page_buffer[NVMCTRL_ROW_SIZE];
-// for (int i = 0; i < NVMCTRL_ROW_PAGES; i++) {
-// do
-// {
-// error_code = nvm_read_buffer(INTERNAL_CIRCUITPY_CONFIG_START_ADDR + i * NVMCTRL_PAGE_SIZE,
-// page_buffer + i * NVMCTRL_PAGE_SIZE,
-// NVMCTRL_PAGE_SIZE);
-// } while (error_code == STATUS_BUSY);
-// }
-// // If this is the first write, include the header.
-// if (strcmp((char*) page_buffer, "CIRCUITPYTHON1") != 0) {
-// memcpy(page_buffer, "CIRCUITPYTHON1", 15);
-// }
-// // First 16 bytes (0-15) are ID. Little endian!
-// page_buffer[16] = current_calibration & 0xff;
-// page_buffer[17] = current_calibration >> 8;
-// do
-// {
-// error_code = nvm_erase_row(INTERNAL_CIRCUITPY_CONFIG_START_ADDR);
-// } while (error_code == STATUS_BUSY);
-// for (int i = 0; i < NVMCTRL_ROW_PAGES; i++) {
-// do
-// {
-// error_code = nvm_write_buffer(INTERNAL_CIRCUITPY_CONFIG_START_ADDR + i * NVMCTRL_PAGE_SIZE,
-// page_buffer + i * NVMCTRL_PAGE_SIZE,
-// NVMCTRL_PAGE_SIZE);
-// } while (error_code == STATUS_BUSY);
-// }
-// }
-// }
-// #endif
+ if (usb_connected()) {
+ save_usb_clock_calibration();
+ }
}
/**