summaryrefslogtreecommitdiff
path: root/atmel-samd
diff options
context:
space:
mode:
authorScott Shawcroft <scott.shawcroft@gmail.com>2017-01-26 18:05:46 -0800
committerScott Shawcroft <scott.shawcroft@gmail.com>2017-01-30 15:02:01 -0800
commite3f9ee839afb5a369779a30a96214c929e76911e (patch)
tree363c298b2de47fdfffdbcf1b8bdf78e128a72917 /atmel-samd
parent749d22b5e63696f67356884b0b35ecebbabb001e (diff)
Add frequency changing support to PWMOut.
You can either set it once up front, or set variable_frequency on custruction to indicate that the frequency must be able to change. This informs whether a timer can be shared amongst pins. This also adds persistent clock calibration on atmel-samd. Once the device has synced its clock frequency over USB it will remember that config value until USB is used again. This helps ensure the clock frequency is similar on and off USB. Lastly, this also corrects time.sleep() when on USB by correcting the tick counter.
Diffstat (limited to 'atmel-samd')
-rw-r--r--atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock.c6
-rw-r--r--atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock_feature.h2
-rw-r--r--atmel-samd/asf/sam0/drivers/system/system.c11
-rw-r--r--atmel-samd/asf/sam0/drivers/system/system.h3
-rw-r--r--atmel-samd/asf/sam0/drivers/tc/tc_sam_d_r/tc.c164
-rw-r--r--atmel-samd/asf/sam0/drivers/tcc/tcc.c36
-rw-r--r--atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c3
-rw-r--r--atmel-samd/boards/gemma_m0/mpconfigboard.h2
-rw-r--r--atmel-samd/boards/metro_m0_flash/mpconfigboard.mk2
-rw-r--r--atmel-samd/boards/samd21x18-bootloader-external-flash.ld9
-rw-r--r--atmel-samd/boards/samd21x18-bootloader.ld14
-rw-r--r--atmel-samd/boards/samd21x18-external-flash.ld10
-rw-r--r--atmel-samd/boards/samd21x18.ld2
-rw-r--r--atmel-samd/boards/trinket_m0/mpconfigboard.h2
-rw-r--r--atmel-samd/common-hal/nativeio/I2C.c3
-rw-r--r--atmel-samd/common-hal/nativeio/PWMOut.c318
-rw-r--r--atmel-samd/common-hal/nativeio/PWMOut.h32
-rw-r--r--atmel-samd/common-hal/nativeio/SPI.c3
-rw-r--r--atmel-samd/common-hal/nativeio/UART.c3
-rw-r--r--atmel-samd/common-hal/nativeio/types.h9
-rw-r--r--atmel-samd/internal_flash.c28
-rw-r--r--atmel-samd/main.c73
-rw-r--r--atmel-samd/mphalport.c8
-rw-r--r--atmel-samd/samd21_pins.c52
-rw-r--r--atmel-samd/tick.c4
25 files changed, 566 insertions, 233 deletions
diff --git a/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock.c b/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock.c
index 7dd6e4df3..777ac5b9b 100644
--- a/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock.c
+++ b/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock.c
@@ -772,7 +772,9 @@ static void _switch_peripheral_gclk(void)
* the OSC8M default enable can be disabled after system_clock_init. Make sure the
* clock switch successfully before disabling OSC8M.
*/
-void system_clock_init(void)
+// Added dfll_fine_calibration as a parameter so that the user program can save
+// and restore it.
+void system_clock_init(uint16_t dfll_fine_calibration)
{
/* Various bits in the INTFLAG register can be set to one at startup.
This will ensure that these bits are cleared */
@@ -904,7 +906,7 @@ void system_clock_init(void)
if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) {
dfll_conf.fine_max_step = 10;
- dfll_conf.fine_value = 0x1ff;
+ dfll_conf.fine_value = dfll_fine_calibration;
dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE;
dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK;
dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP;
diff --git a/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock_feature.h b/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock_feature.h
index a2c4bb60b..ee8890a31 100644
--- a/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock_feature.h
+++ b/atmel-samd/asf/sam0/drivers/system/clock/clock_samd21_r21_da/clock_feature.h
@@ -1262,7 +1262,7 @@ void system_clock_source_dpll_set_config(
* @{
*/
-void system_clock_init(void);
+void system_clock_init(uint16_t dfll_fine_calibration);
/**
* @}
diff --git a/atmel-samd/asf/sam0/drivers/system/system.c b/atmel-samd/asf/sam0/drivers/system/system.c
index 0121588dd..62f2d6463 100644
--- a/atmel-samd/asf/sam0/drivers/system/system.c
+++ b/atmel-samd/asf/sam0/drivers/system/system.c
@@ -59,13 +59,13 @@ void _system_dummy_init(void)
#if !defined(__DOXYGEN__)
# if defined(__GNUC__)
-void system_clock_init(void) WEAK __attribute__((alias("_system_dummy_init")));
+void system_clock_init(uint16_t dfll_fine_calibration) WEAK __attribute__((alias("_system_dummy_init")));
void system_board_init(void) WEAK __attribute__((alias("_system_dummy_init")));
void _system_events_init(void) WEAK __attribute__((alias("_system_dummy_init")));
void _system_extint_init(void) WEAK __attribute__((alias("_system_dummy_init")));
void _system_divas_init(void) WEAK __attribute__((alias("_system_dummy_init")));
# elif defined(__ICCARM__)
-void system_clock_init(void);
+void system_clock_init(uint16_t dfll_fine_calibration);
void system_board_init(void);
void _system_events_init(void);
void _system_extint_init(void);
@@ -91,10 +91,10 @@ void _system_divas_init(void);
* - Event system driver initialization (via the EVSYS module)
* - External Interrupt driver initialization (via the EXTINT module)
*/
-void system_init(void)
+void system_init(uint16_t dfll_fine_calibration)
{
/* Configure GCLK and clock sources according to conf_clocks.h */
- system_clock_init();
+ system_clock_init(dfll_fine_calibration);
/* Initialize board hardware */
system_board_init();
@@ -104,8 +104,7 @@ void system_init(void)
/* Initialize External hardware */
_system_extint_init();
-
+
/* Initialize DIVAS hardware */
_system_divas_init();
}
-
diff --git a/atmel-samd/asf/sam0/drivers/system/system.h b/atmel-samd/asf/sam0/drivers/system/system.h
index c6dd6e856..a0be5b705 100644
--- a/atmel-samd/asf/sam0/drivers/system/system.h
+++ b/atmel-samd/asf/sam0/drivers/system/system.h
@@ -555,7 +555,7 @@ static inline uint32_t system_get_device_id(void)
* @{
*/
-void system_init(void);
+void system_init(uint16_t dfll_fine_calibration);
/**
* @}
@@ -725,4 +725,3 @@ void system_init(void);
#endif
#endif /* SYSTEM_H_INCLUDED */
-
diff --git a/atmel-samd/asf/sam0/drivers/tc/tc_sam_d_r/tc.c b/atmel-samd/asf/sam0/drivers/tc/tc_sam_d_r/tc.c
index 546c36cd1..3d4a428b7 100644
--- a/atmel-samd/asf/sam0/drivers/tc/tc_sam_d_r/tc.c
+++ b/atmel-samd/asf/sam0/drivers/tc/tc_sam_d_r/tc.c
@@ -140,7 +140,7 @@ enum status_code tc_init(
/* Array of PM APBC mask bit position for different TC instances */
uint16_t inst_pm_apbmask[] = TC_INST_PM_APBCMASK;
- struct system_pinmux_config pin_config;
+ //struct system_pinmux_config pin_config;
struct system_gclk_chan_config gclk_chan_config;
#if TC_ASYNC == true
@@ -169,15 +169,15 @@ enum status_code tc_init(
return STATUS_ERR_INVALID_ARG;
}
#else
- /* Check if odd numbered TC modules are being configured in 32-bit
- * counter size. Only even numbered counters are allowed to be
- * configured in 32-bit counter size.
- */
- if ((config->counter_size == TC_COUNTER_SIZE_32BIT) &&
- ((instance + TC_INSTANCE_OFFSET) & 0x01)) {
- Assert(false);
- return STATUS_ERR_INVALID_ARG;
- }
+ // /* Check if odd numbered TC modules are being configured in 32-bit
+ // * counter size. Only even numbered counters are allowed to be
+ // * configured in 32-bit counter size.
+ // */
+ // if ((config->counter_size == TC_COUNTER_SIZE_32BIT) &&
+ // ((instance + TC_INSTANCE_OFFSET) & 0x01)) {
+ // Assert(false);
+ // return STATUS_ERR_INVALID_ARG;
+ // }
#endif
/* Make the counter size variable in the module_inst struct reflect
@@ -200,35 +200,35 @@ enum status_code tc_init(
return STATUS_ERR_DENIED;
}
- /* Set up the TC PWM out pin for channel 0 */
- if (config->pwm_channel[0].enabled) {
- system_pinmux_get_config_defaults(&pin_config);
- pin_config.mux_position = config->pwm_channel[0].pin_mux;
- pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
- system_pinmux_pin_set_config(
- config->pwm_channel[0].pin_out, &pin_config);
- }
-
- /* Set up the TC PWM out pin for channel 1 */
- if (config->pwm_channel[1].enabled) {
- system_pinmux_get_config_defaults(&pin_config);
- pin_config.mux_position = config->pwm_channel[1].pin_mux;
- pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
- system_pinmux_pin_set_config(
- config->pwm_channel[1].pin_out, &pin_config);
- }
+ // /* Set up the TC PWM out pin for channel 0 */
+ // if (config->pwm_channel[0].enabled) {
+ // system_pinmux_get_config_defaults(&pin_config);
+ // pin_config.mux_position = config->pwm_channel[0].pin_mux;
+ // pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
+ // system_pinmux_pin_set_config(
+ // config->pwm_channel[0].pin_out, &pin_config);
+ // }
+ //
+ // /* Set up the TC PWM out pin for channel 1 */
+ // if (config->pwm_channel[1].enabled) {
+ // system_pinmux_get_config_defaults(&pin_config);
+ // pin_config.mux_position = config->pwm_channel[1].pin_mux;
+ // pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
+ // system_pinmux_pin_set_config(
+ // config->pwm_channel[1].pin_out, &pin_config);
+ // }
/* Enable the user interface clock in the PM */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
inst_pm_apbmask[instance]);
- /* Enable the slave counter if counter_size is 32-bit */
- if ((config->counter_size == TC_COUNTER_SIZE_32BIT))
- {
- /* Enable the user interface clock in the PM */
- system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
- inst_pm_apbmask[instance + 1]);
- }
+ // /* Enable the slave counter if counter_size is 32-bit */
+ // if ((config->counter_size == TC_COUNTER_SIZE_32BIT))
+ // {
+ // /* Enable the user interface clock in the PM */
+ // system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
+ // inst_pm_apbmask[instance + 1]);
+ // }
/* Setup clock for module */
system_gclk_chan_get_config_defaults(&gclk_chan_config);
@@ -299,34 +299,34 @@ enum status_code tc_init(
/* Switch for TC counter size */
switch (module_inst->counter_size) {
case TC_COUNTER_SIZE_8BIT:
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT8.COUNT.reg =
- config->counter_8_bit.value;
-
-
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT8.PER.reg =
- config->counter_8_bit.period;
-
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT8.CC[0].reg =
- config->counter_8_bit.compare_capture_channel[0];
-
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT8.CC[1].reg =
- config->counter_8_bit.compare_capture_channel[1];
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT8.COUNT.reg =
+ // config->counter_8_bit.value;
+ //
+ //
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT8.PER.reg =
+ // config->counter_8_bit.period;
+ //
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT8.CC[0].reg =
+ // config->counter_8_bit.compare_capture_channel[0];
+ //
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT8.CC[1].reg =
+ // config->counter_8_bit.compare_capture_channel[1];
return STATUS_OK;
@@ -355,26 +355,26 @@ enum status_code tc_init(
return STATUS_OK;
case TC_COUNTER_SIZE_32BIT:
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT32.COUNT.reg
- = config->counter_32_bit.value;
-
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT32.CC[0].reg =
- config->counter_32_bit.compare_capture_channel[0];
-
- while (tc_is_syncing(module_inst)) {
- /* Wait for sync */
- }
-
- hw->COUNT32.CC[1].reg =
- config->counter_32_bit.compare_capture_channel[1];
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT32.COUNT.reg
+ // = config->counter_32_bit.value;
+ //
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT32.CC[0].reg =
+ // config->counter_32_bit.compare_capture_channel[0];
+ //
+ // while (tc_is_syncing(module_inst)) {
+ // /* Wait for sync */
+ // }
+ //
+ // hw->COUNT32.CC[1].reg =
+ // config->counter_32_bit.compare_capture_channel[1];
return STATUS_OK;
}
diff --git a/atmel-samd/asf/sam0/drivers/tcc/tcc.c b/atmel-samd/asf/sam0/drivers/tcc/tcc.c
index 6b5f8fb5c..e46cf287a 100644
--- a/atmel-samd/asf/sam0/drivers/tcc/tcc.c
+++ b/atmel-samd/asf/sam0/drivers/tcc/tcc.c
@@ -324,12 +324,12 @@ static inline void _tcc_build_ctrlb(
{
uint8_t ctrlb = 0;
- if (config->counter.oneshot) {
- ctrlb |= TCC_CTRLBSET_ONESHOT;
- }
- if (config->counter.direction == TCC_COUNT_DIRECTION_DOWN) {
- ctrlb |= TCC_CTRLBSET_DIR;
- }
+ // if (config->counter.oneshot) {
+ // ctrlb |= TCC_CTRLBSET_ONESHOT;
+ // }
+ // if (config->counter.direction == TCC_COUNT_DIRECTION_DOWN) {
+ // ctrlb |= TCC_CTRLBSET_DIR;
+ // }
*value_buffer = ctrlb;
}
@@ -606,18 +606,18 @@ enum status_code tcc_init(
system_gclk_chan_enable(_tcc_gclk_ids[module_index]);
/* Initialize pins */
- struct system_pinmux_config pin_config;
- for (i = 0; i < _tcc_ow_nums[module_index]; i ++) {
- if (!config->pins.enable_wave_out_pin[i]) {
- continue;
- }
-
- system_pinmux_get_config_defaults(&pin_config);
- pin_config.mux_position = config->pins.wave_out_pin_mux[i];
- pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
- system_pinmux_pin_set_config(
- config->pins.wave_out_pin[i], &pin_config);
- }
+ // struct system_pinmux_config pin_config;
+ // for (i = 0; i < _tcc_ow_nums[module_index]; i ++) {
+ // if (!config->pins.enable_wave_out_pin[i]) {
+ // continue;
+ // }
+ //
+ // system_pinmux_get_config_defaults(&pin_config);
+ // pin_config.mux_position = config->pins.wave_out_pin_mux[i];
+ // pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
+ // system_pinmux_pin_set_config(
+ // config->pins.wave_out_pin[i], &pin_config);
+ // }
/* Write to registers */
diff --git a/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c b/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c
index 767fe0c25..670fb0d61 100644
--- a/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c
+++ b/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c
@@ -49,6 +49,7 @@
extern uint32_t _sfixed;
extern uint32_t _efixed;
extern uint32_t _etext;
+extern uint32_t _sidata;
extern uint32_t _srelocate;
extern uint32_t _erelocate;
extern uint32_t _szero;
@@ -233,7 +234,7 @@ void Reset_Handler(void)
uint32_t *pSrc, *pDest;
/* Initialize the relocate segment */
- pSrc = &_etext;
+ pSrc = &_sidata;
pDest = &_srelocate;
if (pSrc != pDest) {
diff --git a/atmel-samd/boards/gemma_m0/mpconfigboard.h b/atmel-samd/boards/gemma_m0/mpconfigboard.h
index dff412b6e..165522fab 100644
--- a/atmel-samd/boards/gemma_m0/mpconfigboard.h
+++ b/atmel-samd/boards/gemma_m0/mpconfigboard.h
@@ -1,6 +1,6 @@
#define USB_REPL
-#define MICROPY_HW_BOARD_NAME "Adafruit Gemma M0 (Experimental)"
+#define MICROPY_HW_BOARD_NAME "Adafruit Gemma M0"
#define MICROPY_HW_MCU_NAME "samd21e18"
#define MICROPY_HW_APA102_MOSI &pin_PA04
diff --git a/atmel-samd/boards/metro_m0_flash/mpconfigboard.mk b/atmel-samd/boards/metro_m0_flash/mpconfigboard.mk
index 8b6d61bbb..4b508957d 100644
--- a/atmel-samd/boards/metro_m0_flash/mpconfigboard.mk
+++ b/atmel-samd/boards/metro_m0_flash/mpconfigboard.mk
@@ -1,4 +1,4 @@
-LD_FILE = boards/samd21x18-bootloader-external-flash.ld
+LD_FILE = boards/samd21x18-external-flash.ld
USB_VID = 0x239A
USB_PID = 0x8015
diff --git a/atmel-samd/boards/samd21x18-bootloader-external-flash.ld b/atmel-samd/boards/samd21x18-bootloader-external-flash.ld
index 574dbb001..a6be02f90 100644
--- a/atmel-samd/boards/samd21x18-bootloader-external-flash.ld
+++ b/atmel-samd/boards/samd21x18-bootloader-external-flash.ld
@@ -5,7 +5,7 @@
/* Specify the memory areas */
MEMORY
{
- FLASH (rx) : ORIGIN = 0x00000000 + 0x2000, LENGTH = 0x00040000 - 0x2000 /* Leave 8KiB for the bootloader. */
+ FLASH (rx) : ORIGIN = 0x00000000 + 0x2000, LENGTH = 0x00040000 - 0x2000 - 0x100 /* Leave 8KiB for the bootloader and 256b for config. */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
}
@@ -28,9 +28,14 @@ SECTIONS
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
- _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH
+ .ARM.exidx :
+ {
+ *(.ARM.exidx*)
+ *(.gnu.linkonce.armexidx.*)
+ _sidata = .; /* This is used by the startup in order to initialize the .data section */
+ } > FLASH
/* This is the initialized data section
The program executes knowing that the data is in the RAM
diff --git a/atmel-samd/boards/samd21x18-bootloader.ld b/atmel-samd/boards/samd21x18-bootloader.ld
index b43c292b1..4e3312bf0 100644
--- a/atmel-samd/boards/samd21x18-bootloader.ld
+++ b/atmel-samd/boards/samd21x18-bootloader.ld
@@ -5,7 +5,8 @@
/* Specify the memory areas */
MEMORY
{
- FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000 - 0x2000 - 0x010000 /* Leave 8KiB for the bootloader and 64k for the flash file system. */
+ /* Leave 8KiB for the bootloader, 256b for persistant config (clock), and 64k for the flash file system. */
+ FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000 - 0x2000 - 0x100 - 0x010000
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
}
@@ -28,9 +29,14 @@ SECTIONS
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
- _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH
+ .ARM.exidx :
+ {
+ *(.ARM.exidx*)
+ *(.gnu.linkonce.armexidx.*)
+ _sidata = .; /* This is used by the startup in order to initialize the .data section */
+ } > FLASH
/* This is the initialized data section
The program executes knowing that the data is in the RAM
@@ -39,14 +45,14 @@ SECTIONS
.data : AT ( _sidata )
{
. = ALIGN(4);
- _srelocate = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
+ _srelocate = .; /* create a global symbol at data start; used by startup code in order to initialize the .data section in RAM */
*(.ramfunc)
*(.ramfunc*)
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
- _erelocate = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
+ _erelocate = .; /* define a global symbol at data end; used by startup code in order to initialize the .data section in RAM */
} >RAM
/* Uninitialized data section */
diff --git a/atmel-samd/boards/samd21x18-external-flash.ld b/atmel-samd/boards/samd21x18-external-flash.ld
index 0c2e71df1..90cb6160a 100644
--- a/atmel-samd/boards/samd21x18-external-flash.ld
+++ b/atmel-samd/boards/samd21x18-external-flash.ld
@@ -5,7 +5,7 @@
/* Specify the memory areas */
MEMORY
{
- FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 /* 256 KiB */
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 - 0x100 /* 256 KiB but leave 256b for config */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
}
@@ -28,9 +28,15 @@ SECTIONS
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
- _sidata = _etext; /* This is used by the startup in order to initialize the .data section */
} >FLASH
+ .ARM.exidx :
+ {
+ *(.ARM.exidx*)
+ *(.gnu.linkonce.armexidx.*)
+ _sidata = .; /* This is used by the startup in order to initialize the .data section */
+ } > FLASH
+
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
diff --git a/atmel-samd/boards/samd21x18.ld b/atmel-samd/boards/samd21x18.ld
index 995d2754f..98a24a811 100644
--- a/atmel-samd/boards/samd21x18.ld
+++ b/atmel-samd/boards/samd21x18.ld
@@ -5,7 +5,7 @@
/* Specify the memory areas */
MEMORY
{
- FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 - 0x010000 /* Leave 64k for the flash file system. */
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 - 0x100 - 0x010000 /* Leave 256b for config and 64k for the flash file system. */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
}
diff --git a/atmel-samd/boards/trinket_m0/mpconfigboard.h b/atmel-samd/boards/trinket_m0/mpconfigboard.h
index 35c7cceeb..e72b0a8eb 100644
--- a/atmel-samd/boards/trinket_m0/mpconfigboard.h
+++ b/atmel-samd/boards/trinket_m0/mpconfigboard.h
@@ -1,6 +1,6 @@
#define USB_REPL
-#define MICROPY_HW_BOARD_NAME "Adafruit Trinket M0 (Experimental)"
+#define MICROPY_HW_BOARD_NAME "Adafruit Trinket M0"
#define MICROPY_HW_MCU_NAME "samd21e18"
#define MICROPY_HW_APA102_MOSI &pin_PA01
diff --git a/atmel-samd/common-hal/nativeio/I2C.c b/atmel-samd/common-hal/nativeio/I2C.c
index 07e367baa..8e3615232 100644
--- a/atmel-samd/common-hal/nativeio/I2C.c
+++ b/atmel-samd/common-hal/nativeio/I2C.c
@@ -69,8 +69,7 @@ void common_hal_nativeio_i2c_construct(nativeio_i2c_obj_t *self,
}
}
if (sercom == NULL) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
- "No hardware support available with those pins."));
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid pins."));
}
config_i2c_master.pinmux_pad0 = sda_pinmux; // SDA
diff --git a/atmel-samd/common-hal/nativeio/PWMOut.c b/atmel-samd/common-hal/nativeio/PWMOut.c
index 82833fbba..a122fadb5 100644
--- a/atmel-samd/common-hal/nativeio/PWMOut.c
+++ b/atmel-samd/common-hal/nativeio/PWMOut.c
@@ -27,90 +27,308 @@
#include <stdint.h>
#include "py/runtime.h"
+#include "common-hal/nativeio/PWMOut.h"
#include "shared-bindings/nativeio/PWMOut.h"
#include "samd21_pins.h"
-void common_hal_nativeio_pwmout_construct(nativeio_pwmout_obj_t* self, const mcu_pin_obj_t* pin, uint16_t duty) {
+#undef ENABLE
+
+uint32_t target_timer_frequencies[TC_INST_NUM + TCC_INST_NUM];
+uint8_t timer_refcount[TC_INST_NUM + TCC_INST_NUM];
+const uint16_t prescaler[8] = {1, 2, 4, 8, 16, 64, 256, 1024};
+
+// This bitmask keeps track of which channels of a TCC are currently claimed.
+uint8_t tcc_channels[3] = {0xf0, 0xfc, 0xfc};
+
+void pwmout_reset(void) {
+ // Reset all but TC5
+ for (int i = 0; i < TC_INST_NUM + TCC_INST_NUM; i++) {
+ if (i == 5) {
+ target_timer_frequencies[i] = 1000;
+ timer_refcount[i] = 1;
+ } else {
+ target_timer_frequencies[i] = 0;
+ timer_refcount[i] = 0;
+ }
+ }
+ Tcc *tccs[TCC_INST_NUM] = TCC_INSTS;
+ for (int i = 0; i < TCC_INST_NUM; i++) {
+ tccs[i]->CTRLA.bit.SWRST = 1;
+ }
+ Tc *tcs[TC_INST_NUM] = TC_INSTS;
+ for (int i = 0; i < TC_INST_NUM; i++) {
+ if (tcs[i] == TC5) {
+ continue;
+ }
+ tcs[i]->COUNT16.CTRLA.bit.SWRST = 1;
+ }
+}
+
+bool channel_ok(const pin_timer_t* t, uint8_t index) {
+ return (!t->is_tc && (tcc_channels[index] & (1 << t->channel)) == 0) ||
+ t->is_tc;
+}
+
+void common_hal_nativeio_pwmout_construct(nativeio_pwmout_obj_t* self,
+ const mcu_pin_obj_t* pin,
+ uint16_t duty,
+ uint32_t frequency,
+ bool variable_frequency) {
self->pin = pin;
- self->using_primary_timer = true;
+ self->variable_frequency = variable_frequency;
if (pin->primary_timer.tc == 0 && pin->secondary_timer.tc == 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
- "PWM not supported on pin %q", self->pin->name));
+ "Invalid pin."));
}
- // TODO(tannewt): Support output on multiple timer channels at once.
- const pin_timer_t* t = &pin->primary_timer;
- if (t->is_tc) {
- struct tc_config config_tc;
- tc_get_config_defaults(&config_tc);
-
- config_tc.counter_size = TC_COUNTER_SIZE_8BIT;
- config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
- config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV256;
- config_tc.counter_8_bit.period = 0xff;
- config_tc.counter_8_bit.compare_capture_channel[t->channel] = duty;
+ if (frequency == 0 || frequency > 6000000) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "Invalid PWM frequency."));
+ }
- config_tc.pwm_channel[t->wave_output].enabled = true;
- config_tc.pwm_channel[t->wave_output].pin_out = pin->pin;
- config_tc.pwm_channel[t->wave_output].pin_mux = MUX_E;
+ uint16_t primary_timer_index = 0xff;
+ uint16_t secondary_timer_index = 0xff;
+ if (pin->primary_timer.tc != NULL) {
+ primary_timer_index = (((uint32_t) pin->primary_timer.tcc) - ((uint32_t) TCC0)) / 0x400;
+ }
+ if (pin->secondary_timer.tc != NULL) {
+ secondary_timer_index = (((uint32_t) pin->secondary_timer.tcc) - ((uint32_t) TCC0)) / 0x400;
+ }
- tc_init(&self->tc_instance, t->tc, &config_tc);
+ // Figure out which timer we are using.
- tc_enable(&self->tc_instance);
+ // First see if a timer is already going with the frequency we want and our
+ // channel is unused.
+ // NOTE(shawcroft): The enable bit is in the same position for TC and TCC so
+ // we treat them all as TCC for checking ENABLE.
+ const pin_timer_t* t = NULL;
+ uint8_t index = 0;
+ if (!variable_frequency &&
+ primary_timer_index != 0xff &&
+ target_timer_frequencies[primary_timer_index] == frequency &&
+ pin->primary_timer.tcc->CTRLA.bit.ENABLE == 1 &&
+ channel_ok(&pin->primary_timer, primary_timer_index)) {
+ t = &pin->primary_timer;
+ index = primary_timer_index;
+ } else if (!variable_frequency &&
+ secondary_timer_index != 0xff &&
+ target_timer_frequencies[secondary_timer_index] == frequency &&
+ pin->secondary_timer.tcc->CTRLA.bit.ENABLE == 1 &&
+ channel_ok(&pin->secondary_timer, secondary_timer_index)) {
+ t = &pin->secondary_timer;
+ index = secondary_timer_index;
} else {
- struct tcc_config config_tcc;
- tcc_get_config_defaults(&config_tcc, t->tcc);
+ // Pick an unused timer if available.
+
+ // Check the secondary timer first since its always a nicer TCC (when it
+ // exists)
+ if (pin->secondary_timer.tc != 0 &&
+ timer_refcount[secondary_timer_index] == 0 &&
+ pin->secondary_timer.tcc->CTRLA.bit.ENABLE == 0) {
+ t = &pin->secondary_timer;
+ index = secondary_timer_index;
+ } else if (pin->primary_timer.tc != 0 &&
+ (!pin->primary_timer.is_tc || pin->primary_timer.channel == 1) &&
+ timer_refcount[primary_timer_index] == 0) {
+ t = &pin->primary_timer;
+ index = primary_timer_index;
+ }
+ if (t == NULL) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "All timers in use."));
+ return;
+ }
+ uint8_t resolution = 0;
+ if (t->is_tc) {
+ resolution = 16;
+ } else {
+ resolution = 24;
+ }
+ // First determine the divisor that gets us the highest resolution.
+ uint32_t system_clock = system_cpu_clock_get_hz();
+ uint32_t top;
+ uint8_t divisor;
+ for (divisor = 0; divisor < 8; divisor++) {
+ top = (system_clock / prescaler[divisor] / frequency) - 1;
+ if (top < (1u << resolution)) {
+ break;
+ }
+ }
+ if (t->is_tc) {
+ struct tc_config config_tc;
+ tc_get_config_defaults(&config_tc);
- config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV256;
- config_tcc.counter.period = 0xFF;
- config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
- config_tcc.compare.match[t->channel] = duty;
+ config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
+ config_tc.clock_prescaler = TC_CTRLA_PRESCALER(divisor);
+ config_tc.wave_generation = TC_WAVE_GENERATION_MATCH_PWM;
+ config_tc.counter_16_bit.compare_capture_channel[0] = top;
- config_tcc.pins.enable_wave_out_pin[t->wave_output] = true;
- config_tcc.pins.wave_out_pin[t->wave_output] = pin->pin;
- config_tcc.pins.wave_out_pin_mux[t->wave_output] = MUX_E;
+ tc_init(&self->tc_instance, t->tc, &config_tc);
+ tc_enable(&self->tc_instance);
+ } else {
+ struct tcc_config config_tcc;
+ tcc_get_config_defaults(&config_tcc, t->tcc);
- tcc_init(&self->tcc_instance, t->tcc, &config_tcc);
+ config_tcc.counter.clock_prescaler = divisor;
+ config_tcc.counter.period = top;
+ config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
+
+ tcc_init(&self->tcc_instance, t->tcc, &config_tcc);
+ tcc_enable(&self->tcc_instance);
+ }
+
+ target_timer_frequencies[index] = frequency;
+ timer_refcount[index]++;
+ }
- tcc_enable(&self->tcc_instance);
+ if (!t->is_tc) {
+ if (variable_frequency) {
+ // We're changing frequency so claim all of the channels.
+ tcc_channels[index] = 0xff;
+ } else {
+ tcc_channels[index] |= (1 << t->channel);
+ }
}
+
+ self->timer = t;
+
+ // Connect the wave output to the outside world.
+ struct system_pinmux_config pin_config;
+ system_pinmux_get_config_defaults(&pin_config);
+ pin_config.mux_position = &self->pin->primary_timer == t ? MUX_E : MUX_F;
+ pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
+ system_pinmux_pin_set_config(pin->pin, &pin_config);
+
+ common_hal_nativeio_pwmout_set_duty_cycle(self, duty);
}
extern void common_hal_nativeio_pwmout_deinit(nativeio_pwmout_obj_t* self) {
- const pin_timer_t* t = &self->pin->primary_timer;
- if (!self->using_primary_timer) {
- t = &self->pin->secondary_timer;
+ const pin_timer_t* t = self->timer;
+ uint8_t index = (((uint32_t) t->tcc) - ((uint32_t) TCC0)) / 0x400;
+ timer_refcount[index]--;
+ if (!t->is_tc) {
+ tcc_channels[index] &= ~(1 << t->channel);
}
- if (t->is_tc) {
- tc_disable(&self->tc_instance);
- } else {
- tcc_disable(&self->tcc_instance);
+ if (timer_refcount[index] == 0) {
+ target_timer_frequencies[index] = 0;
+ if (t->is_tc) {
+ tc_disable(&self->tc_instance);
+ } else {
+ if (t->tcc == TCC0) {
+ tcc_channels[index] = 0xf0;
+ } else {
+ tcc_channels[index] = 0xfc;
+ }
+ tcc_disable(&self->tcc_instance);
+ tcc_reset(&self->tcc_instance);
+ }
}
reset_pin(self->pin->pin);
}
extern void common_hal_nativeio_pwmout_set_duty_cycle(nativeio_pwmout_obj_t* self, uint16_t duty) {
- const pin_timer_t* t = &self->pin->primary_timer;
- if (!self->using_primary_timer) {
- t = &self->pin->secondary_timer;
- }
- if (t->tcc != 0) {
- tcc_set_compare_value(&self->tcc_instance, t->channel, duty);
+ const pin_timer_t* t = self->timer;
+ if (t->is_tc) {
+ uint32_t top = ((uint32_t) t->tc->COUNT16.CC[0].reg + 1);
+ uint16_t adjusted_duty = top * duty / 0xffff;
+ tc_set_compare_value(&self->tc_instance, t->channel, adjusted_duty);
} else {
- tc_set_compare_value(&self->tc_instance, t->channel, duty);
+ uint32_t top = t->tcc->PER.reg + 1;
+ uint32_t adjusted_duty = ((uint64_t) top) * duty / 0xffff;
+ tcc_set_compare_value(&self->tcc_instance, t->channel, adjusted_duty);
}
}
uint16_t common_hal_nativeio_pwmout_get_duty_cycle(nativeio_pwmout_obj_t* self) {
- const pin_timer_t* t = &self->pin->primary_timer;
- if (!self->using_primary_timer) {
- t = &self->pin->secondary_timer;
+ const pin_timer_t* t = self->timer;
+ if (t->is_tc) {
+ uint16_t top = t->tc->COUNT16.CC[0].reg;
+ while (tc_is_syncing(&self->tc_instance)) {
+ /* Wait for sync */
+ }
+ uint16_t cv = t->tc->COUNT16.CC[t->channel].reg;
+ return cv * 0xffff / top;
+ } else {
+ uint32_t top = t->tcc->PER.reg;
+ uint32_t cv = 0;
+ if ((t->tcc->STATUS.vec.CCBV & (1 << t->channel)) != 0) {
+ cv = t->tcc->CCB[t->channel].reg;
+ } else {
+ cv = t->tcc->CC[t->channel].reg;
+ }
+ return cv * 0xffff / top;
}
- if (t->tcc != 0) {
- return tcc_get_capture_value(&self->tcc_instance, t->channel);
+}
+
+
+void common_hal_nativeio_pwmout_set_frequency(nativeio_pwmout_obj_t* self,
+ uint32_t frequency) {
+ if (frequency == 0 || frequency > 6000000) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "Invalid PWM frequency."));
+ }
+ const pin_timer_t* t = self->timer;
+ uint8_t resolution;
+ if (t->is_tc) {
+ resolution = 16;
+ } else {
+ resolution = 24;
+ }
+ uint32_t system_clock = system_cpu_clock_get_hz();
+ uint32_t new_top;
+ uint8_t new_divisor;
+ for (new_divisor = 0; new_divisor < 8; new_divisor++) {
+ new_top = (system_clock / prescaler[new_divisor] / frequency) - 1;
+ if (new_top < (1u << resolution)) {
+ break;
+ }
+ }
+ uint16_t old_duty = common_hal_nativeio_pwmout_get_duty_cycle(self);
+ uint8_t old_divisor;
+ if (t->is_tc) {
+ old_divisor = t->tc->COUNT16.CTRLA.bit.PRESCALER;
} else {
- return tc_get_capture_value(&self->tc_instance, t->channel);
+ old_divisor = t->tcc->CTRLA.bit.PRESCALER;
}
+ if (new_divisor != old_divisor) {
+ if (t->is_tc) {
+ tc_disable(&self->tc_instance);
+ t->tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor;
+ tc_enable(&self->tc_instance);
+ } else {
+ tcc_disable(&self->tcc_instance);
+ t->tcc->CTRLA.bit.PRESCALER = new_divisor;
+ tcc_enable(&self->tcc_instance);
+ }
+ }
+ if (t->is_tc) {
+ while (tc_is_syncing(&self->tc_instance)) {
+ /* Wait for sync */
+ }
+ t->tc->COUNT16.CC[0].reg = new_top;
+ } else {
+ tcc_set_top_value(&self->tcc_instance, new_top);
+ }
+
+ common_hal_nativeio_pwmout_set_duty_cycle(self, old_duty);
+}
+
+uint32_t common_hal_nativeio_pwmout_get_frequency(nativeio_pwmout_obj_t* self) {
+ uint32_t system_clock = system_cpu_clock_get_hz();
+ const pin_timer_t* t = self->timer;
+ uint32_t top;
+ uint8_t divisor;
+ if (t->is_tc) {
+ top = t->tc->COUNT16.CC[0].reg;
+ divisor = t->tc->COUNT16.CTRLA.bit.PRESCALER;
+ } else {
+ top = t->tcc->PER.reg;
+ divisor = t->tcc->CTRLA.bit.PRESCALER;
+ }
+ return (system_clock / prescaler[divisor]) / (top + 1);
+}
+
+bool common_hal_nativeio_pwmout_get_variable_frequency(nativeio_pwmout_obj_t* self) {
+ return self->variable_frequency;
}
diff --git a/atmel-samd/common-hal/nativeio/PWMOut.h b/atmel-samd/common-hal/nativeio/PWMOut.h
new file mode 100644
index 000000000..56994e519
--- /dev/null
+++ b/atmel-samd/common-hal/nativeio/PWMOut.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_NATIVEIO_PWMOUT_H__
+#define __MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_NATIVEIO_PWMOUT_H__
+
+void pwmout_reset(void);
+
+#endif // __MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_NATIVEIO_PWMOUT_H__
diff --git a/atmel-samd/common-hal/nativeio/SPI.c b/atmel-samd/common-hal/nativeio/SPI.c
index 70b096579..f24cd40a2 100644
--- a/atmel-samd/common-hal/nativeio/SPI.c
+++ b/atmel-samd/common-hal/nativeio/SPI.c
@@ -92,8 +92,7 @@ void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
}
}
if (sercom == NULL) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
- "No hardware support available with those pins."));
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid pins."));
}
// Depends on where MOSI and CLK are.
diff --git a/atmel-samd/common-hal/nativeio/UART.c b/atmel-samd/common-hal/nativeio/UART.c
index f82791199..8a6617315 100644
--- a/atmel-samd/common-hal/nativeio/UART.c
+++ b/atmel-samd/common-hal/nativeio/UART.c
@@ -162,8 +162,7 @@ void common_hal_nativeio_uart_construct(nativeio_uart_obj_t *self,
}
}
if (sercom == NULL) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
- "No hardware support available with those pins."));
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid pins."));
}
if (tx == NULL) {
tx_pad = 0;
diff --git a/atmel-samd/common-hal/nativeio/types.h b/atmel-samd/common-hal/nativeio/types.h
index 1f483eced..ad5205381 100644
--- a/atmel-samd/common-hal/nativeio/types.h
+++ b/atmel-samd/common-hal/nativeio/types.h
@@ -90,9 +90,12 @@ typedef struct {
typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t *pin;
- bool using_primary_timer;
- struct tc_module tc_instance;
- struct tcc_module tcc_instance;
+ const pin_timer_t* timer;
+ bool variable_frequency;
+ union {
+ struct tc_module tc_instance;
+ struct tcc_module tcc_instance;
+ };
} nativeio_pwmout_obj_t;
typedef struct {
diff --git a/atmel-samd/internal_flash.c b/atmel-samd/internal_flash.c
index d62b3a8ad..1ce38f0b0 100644
--- a/atmel-samd/internal_flash.c
+++ b/atmel-samd/internal_flash.c
@@ -45,26 +45,16 @@
#define INTERNAL_FLASH_PART1_START_BLOCK (0x1)
#define INTERNAL_FLASH_PART1_NUM_BLOCKS (TOTAL_INTERNAL_FLASH_SIZE / INTERNAL_FLASH_BLOCK_SIZE)
-static bool internal_flash_is_initialised = false;
-
void internal_flash_init(void) {
- if (!internal_flash_is_initialised) {
- struct nvm_config config_nvm;
- nvm_get_config_defaults(&config_nvm);
- config_nvm.manual_page_write = false;
- nvm_set_config(&config_nvm);
- internal_flash_is_initialised = true;
-
- // Activity LED for flash writes.
- #ifdef MICROPY_HW_LED_MSC
- struct port_config pin_conf;
- port_get_config_defaults(&pin_conf);
-
- pin_conf.direction = PORT_PIN_DIR_OUTPUT;
- port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf);
- port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
- #endif
- }
+ // Activity LED for flash writes.
+ #ifdef MICROPY_HW_LED_MSC
+ struct port_config pin_conf;
+ port_get_config_defaults(&pin_conf);
+
+ pin_conf.direction = PORT_PIN_DIR_OUTPUT;
+ port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf);
+ port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
+ #endif
}
uint32_t internal_flash_get_block_size(void) {
diff --git a/atmel-samd/main.c b/atmel-samd/main.c
index 561de8316..f05195f5b 100644
--- a/atmel-samd/main.c
+++ b/atmel-samd/main.c
@@ -17,16 +17,21 @@
#include "asf/common/services/sleepmgr/sleepmgr.h"
#include "asf/common/services/usb/udc/udc.h"
#include "asf/common2/services/delay/delay.h"
+#include "asf/sam0/drivers/nvm/nvm.h"
#include "asf/sam0/drivers/port/port.h"
#include "asf/sam0/drivers/sercom/usart/usart.h"
#include "asf/sam0/drivers/system/system.h"
#include <board.h>
#include "common-hal/nativeio/AnalogIn.h"
+#include "common-hal/nativeio/PWMOut.h"
#ifdef EXPRESS_BOARD
#include "common-hal/nativeio/types.h"
#include "QTouch/touch_api_ptc.h"
+#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x100)
+#else
+#define INTERNAL_CIRCUITPY_CONFIG_START_ADDR (0x00040000 - 0x010000 - 0x100)
#endif
#include "autoreset.h"
@@ -34,6 +39,7 @@
#include "rgb_led_status.h"
#include "tick.h"
+
fs_user_mount_t fs_user_mount_flash;
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
@@ -133,6 +139,8 @@ void reset_mp(void) {
extern nativeio_touchin_obj_t *active_touchin_obj[DEF_SELFCAP_NUM_CHANNELS];
extern touch_selfcap_config_t selfcap_config;
#endif
+extern volatile bool mp_msc_enabled;
+
void reset_samd21(void) {
// Reset all SERCOMs except the one being used by the SPI flash.
Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
@@ -173,6 +181,53 @@ void reset_samd21(void) {
system_pinmux_group_set_config(&(PORT->Group[0]), pin_mask[0] & ~MICROPY_PORT_A, &config);
system_pinmux_group_set_config(&(PORT->Group[1]), pin_mask[1] & ~MICROPY_PORT_B, &config);
+
+ pwmout_reset();
+
+ // 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);
+ }
+ }
+ }
}
bool maybe_run(const char* filename, pyexec_result_t* exec_result) {
@@ -405,7 +460,17 @@ void samd21_init(void) {
// Initialize the sleep manager
sleepmgr_init();
- system_init();
+ uint16_t dfll_fine_calibration = 0x1ff;
+ // 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) {
+ dfll_fine_calibration = ((uint16_t *) INTERNAL_CIRCUITPY_CONFIG_START_ADDR)[8];
+ }
+
+ // We pass in the DFLL fine calibration because we can't change it once the
+ // clock is going.
+ system_init(dfll_fine_calibration);
delay_init();
@@ -423,6 +488,12 @@ void samd21_init(void) {
// port_pin_set_output_level(MICROPY_HW_LED1, false);
rgb_led_status_init();
+
+ // Init the nvm controller.
+ struct nvm_config config_nvm;
+ nvm_get_config_defaults(&config_nvm);
+ config_nvm.manual_page_write = false;
+ nvm_set_config(&config_nvm);
}
int main(int argc, char **argv) {
diff --git a/atmel-samd/mphalport.c b/atmel-samd/mphalport.c
index a47063994..7fe06dd80 100644
--- a/atmel-samd/mphalport.c
+++ b/atmel-samd/mphalport.c
@@ -37,7 +37,8 @@ volatile bool mp_cdc_enabled = false;
extern struct usart_module usart_instance;
-static volatile bool mp_msc_enabled = false;
+// Read by main to know when USB is connected.
+volatile bool mp_msc_enabled = false;
bool mp_msc_enable()
{
mp_msc_enabled = true;
@@ -220,9 +221,8 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
void mp_hal_delay_ms(mp_uint_t delay) {
// If mass storage is enabled measure the time ourselves and run any mass
// storage transactions in the meantime.
- // TODO(tannewt): Break out of this delay on KeyboardInterrupt too.
if (mp_msc_enabled) {
- uint64_t start_tick = common_hal_time_monotonic();
+ uint64_t start_tick = ticks_ms;
uint64_t duration = 0;
while (duration < delay) {
#ifdef MICROPY_VM_HOOK_LOOP
@@ -232,7 +232,7 @@ void mp_hal_delay_ms(mp_uint_t delay) {
if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
break;
}
- duration = (common_hal_time_monotonic() - start_tick);
+ duration = (ticks_ms - start_tick);
}
} else {
delay_ms(delay);
diff --git a/atmel-samd/samd21_pins.c b/atmel-samd/samd21_pins.c
index b08f5a873..754509b96 100644
--- a/atmel-samd/samd21_pins.c
+++ b/atmel-samd/samd21_pins.c
@@ -69,6 +69,8 @@ void reset_pin(uint8_t pin) {
}
// Pins in datasheet order.
+// NOTE(tannewt): TC wave out 0 is commented out because the first channel is
+// used to vary the 16 bit timer's frequency.
#ifdef PIN_PA00
PIN(PA00, NO_ADC, NO_TOUCH,
TCC(TCC2, 0, 0),
@@ -127,7 +129,7 @@ PIN(PB07, TOUCH(ADC_POSITIVE_INPUT_PIN15), TOUCH(13),
#endif
#ifdef PIN_PB08
PIN(PB08, ADC_INPUT(ADC_POSITIVE_INPUT_PIN2), TOUCH(14),
- TC(TC4, 0, 0),
+ NO_TIMER, // TC(TC4, 0, 0),
NO_TIMER,
NO_SERCOM,
SERCOM(SERCOM4, 0));
@@ -197,7 +199,7 @@ PIN(PA11, ADC_INPUT(ADC_POSITIVE_INPUT_PIN19), NO_TOUCH,
#endif
#ifdef PIN_PB10
PIN(PB10, NO_ADC, NO_TOUCH,
- TC(TC5, 0, 0),
+ NO_TIMER, // TC(TC5, 0, 0),
TCC(TCC0, 0, 4),
NO_SERCOM,
SERCOM(SERCOM4, 2));
@@ -211,7 +213,7 @@ PIN(PB11, NO_ADC, NO_TOUCH,
#endif
#ifdef PIN_PB12
PIN(PB12, NO_ADC, NO_TOUCH,
- TC(TC4, 0, 0),
+ NO_TIMER, // TC(TC4, 0, 0),
TCC(TCC0, 2, 6),
SERCOM(SERCOM4, 0),
NO_SERCOM);
@@ -225,7 +227,7 @@ PIN(PB13, NO_ADC, NO_TOUCH,
#endif
#ifdef PIN_PB14
PIN(PB14, NO_ADC, NO_TOUCH,
- TC(TC5, 0, 0),
+ NO_TIMER, // TC(TC5, 0, 0),
NO_TIMER,
SERCOM(SERCOM4, 2),
NO_SERCOM);
@@ -255,7 +257,7 @@ PIN(PA13, NO_ADC, NO_TOUCH,
#endif
#ifdef PIN_PA14
PIN(PA14, NO_ADC, NO_TOUCH,
- TC(TC3, 0, 0),
+ NO_TIMER, // TC(TC3, 0, 0),
TCC(TCC0, 0, 4),
SERCOM(SERCOM2, 2),
#ifdef SERCOM4
@@ -286,29 +288,29 @@ PIN(PA16, NO_ADC, NO_TOUCH,
#endif
#ifdef PIN_PA17
PIN(PA17, NO_ADC, NO_TOUCH,
- TCC(TCC2, 1, 1),
- TCC(TCC0, 3, 7),
- SERCOM(SERCOM1, 1),
- SERCOM(SERCOM3, 1));
+ TCC(TCC2, 1, 1),
+ TCC(TCC0, 3, 7),
+ SERCOM(SERCOM1, 1),
+ SERCOM(SERCOM3, 1));
#endif
#ifdef PIN_PA18
PIN(PA18, NO_ADC, NO_TOUCH,
- TC(TC3, 0, 0),
- TCC(TCC0, 2, 2),
- SERCOM(SERCOM1, 2),
- SERCOM(SERCOM3, 2));
+ NO_TIMER, // TC(TC3, 0, 0),
+ TCC(TCC0, 2, 2),
+ SERCOM(SERCOM1, 2),
+ SERCOM(SERCOM3, 2));
#endif
#ifdef PIN_PA19
PIN(PA19, NO_ADC, NO_TOUCH,
- TC(TC3, 1, 1),
- TCC(TCC0, 3, 3),
- SERCOM(SERCOM1, 3),
- SERCOM(SERCOM3, 3));
+ TC(TC3, 1, 1),
+ TCC(TCC0, 3, 3),
+ SERCOM(SERCOM1, 3),
+ SERCOM(SERCOM3, 3));
#endif
#ifdef PIN_PB16
PIN(PB16, NO_ADC, NO_TOUCH,
#ifdef _SAMD21_TC6_INSTANCE_
- TC(TC6, 0, 0),
+ NO_TIMER, // TC(TC6, 0, 0),
#else
NO_TIMER,
#endif
@@ -319,7 +321,7 @@ PIN(PB16, NO_ADC, NO_TOUCH,
#ifdef PIN_PB17
PIN(PB17, NO_ADC, NO_TOUCH,
#ifdef _SAMD21_TC6_INSTANCE_
- TC(TC6, 0, 0),
+ TC(TC6, 1, 1),
#else
NO_TIMER,
#endif
@@ -330,7 +332,7 @@ PIN(PB17, NO_ADC, NO_TOUCH,
#ifdef PIN_PA20
PIN(PA20, NO_ADC, NO_TOUCH,
#ifdef _SAMD21_TC7_INSTANCE_
- TC(TC7, 0, 0),
+ NO_TIMER, // TC(TC7, 0, 0),
#else
NO_TIMER,
#endif
@@ -351,7 +353,7 @@ PIN(PA21, NO_ADC, NO_TOUCH,
#endif
#ifdef PIN_PA22
PIN(PA22, NO_ADC, NO_TOUCH,
- TC(TC4, 0, 0),
+ NO_TIMER, // TC(TC4, 0, 0),
TCC(TCC0, 0, 4),
SERCOM(SERCOM3, 0),
#ifdef SERCOM5
@@ -375,7 +377,7 @@ PIN(PA23, NO_ADC, NO_TOUCH,
#endif
#ifdef PIN_PA24
PIN(PA24, NO_ADC, NO_TOUCH,
- TC(TC5, 0, 0),
+ NO_TIMER, // TC(TC5, 0, 0),
TCC(TCC0, 2, 2),
SERCOM(SERCOM3, 2),
#ifdef SERCOM5
@@ -400,7 +402,7 @@ PIN(PA25, NO_ADC, NO_TOUCH,
#ifdef PIN_PB22
PIN(PB22, NO_ADC, NO_TOUCH,
#ifdef _SAMD21_TC7_INSTANCE_
- TC(TC7, 1, 1),
+ NO_TIMER, // TC(TC7, 0, 0),
#else
NO_TIMER,
#endif
@@ -464,7 +466,7 @@ PIN(PB31, NO_ADC, NO_TOUCH,
#ifdef PIN_PB00
PIN(PB00, ADC_INPUT(ADC_POSITIVE_INPUT_PIN8), TOUCH(6),
#ifdef _SAMD21_TC7_INSTANCE_
- TC(TC7, 0, 0),
+ NO_TIMER, // TC(TC7, 0, 0),
#else
NO_TIMER,
#endif
@@ -486,7 +488,7 @@ PIN(PB01, ADC_INPUT(ADC_POSITIVE_INPUT_PIN9), TOUCH(7),
#ifdef PIN_PB02
PIN(PB02, ADC_INPUT(ADC_POSITIVE_INPUT_PIN10), TOUCH(8),
#ifdef _SAMD21_TC6_INSTANCE_
- TC(TC6, 0, 0),
+ NO_TIMER, // TC(TC6, 0, 0),
#else
NO_TIMER,
#endif
diff --git a/atmel-samd/tick.c b/atmel-samd/tick.c
index cad69f080..d779f7fdc 100644
--- a/atmel-samd/tick.c
+++ b/atmel-samd/tick.c
@@ -23,9 +23,11 @@ void tick_init() {
struct tc_config config_tc;
tc_get_config_defaults(&config_tc);
config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
+ config_tc.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;
config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
- tc_set_top_value(&ms_timer, system_cpu_clock_get_hz() / 1000);
tc_init(&ms_timer, TC5, &config_tc);
+
+ tc_set_top_value(&ms_timer, system_cpu_clock_get_hz() / 1000 - 1);
tc_enable(&ms_timer);
tc_register_callback(&ms_timer, ms_tick, TC_CALLBACK_OVERFLOW);
tc_enable_callback(&ms_timer, TC_CALLBACK_OVERFLOW);