Compare commits

...

17 commits

Author SHA1 Message Date
e4161d7d6d Merge samd51 and samd54 directories
There were only trivial differences, which are accomodated via the new
headers sam_d5x_e5x/hri_[gm]clk.h that includes the correct underlying
header.
2020-06-23 10:38:40 -05:00
Jeff Epler
53e9084696 Add support for SAM E54 family MCUs
Rename SAMD51 macro to SAM_D5X_E5X, since it applies to D51 and E54 equally.
The official datasheet refers to "SAM D5x/E5x Family".
2020-06-21 13:46:34 -05:00
Dan Halbert
6b531fc923
Merge pull request #32 from tannewt/lower_power
Switch SAMDs to 32.768k inputs to the RTC
2020-03-24 19:33:46 -04:00
Scott Shawcroft
af5d3eafc4
Merge pull request #31 from jepler/timers-prereq
timers.h: Add prerequisite include
2020-03-24 15:42:12 -07:00
Scott Shawcroft
bfbc88fd6b
Clock SAMD21 RTC with 32.768khz 2020-03-17 12:09:01 -07:00
Scott Shawcroft
df39529b42
Switch from 1k RTC input to 32k output 2020-03-13 11:10:18 -07:00
f528240c2a timers.h: Add prerequisite include 2020-03-13 10:43:43 -05:00
Scott Shawcroft
e363863910
Merge pull request #30 from barawn/pb01_typos
fix typos in PB01 declaration
2020-03-03 10:03:21 -08:00
Patrick Allison
f9cff25530 fix typos in PB01 declaration 2020-02-28 09:18:39 -05:00
Dan Halbert
b89811f22a
Merge pull request #29 from jepler/samd51-dma-hang
samd51: Work around DMA hang
2020-01-02 18:35:31 -05:00
5ca3a8a02b Clean up comments and dead code
.. this involves inverting one condition, since the branch that needed
to be preserved was the 'else' branch
2019-12-31 11:07:29 -06:00
28ad937da2 dma: Detect hung audio DMA and restart it 2019-12-24 09:27:43 -06:00
168f636785 dma: Add to a comment that misled me 2019-12-24 09:27:33 -06:00
Scott Shawcroft
4c0deecf88
Merge pull request #27 from adafruit/de-circuitpython-clocks
Remove CircuitPython dependencies from clock code
2019-12-09 14:19:30 -08:00
Dan Halbert
bb26a4145c Remove CircuitPython dependencies from clock code 2019-12-06 14:23:18 -05:00
Scott Shawcroft
2ba5b20ba7
Merge pull request #26 from jepler/dac-clock
clocks: Provide a 12MHz clock for the DAC
2019-09-16 13:30:05 -07:00
7c1c7e3195 clocks: Provide a 12MHz clock for the DAC 2019-09-15 11:24:42 -05:00
22 changed files with 165 additions and 394 deletions

View file

@ -31,15 +31,17 @@
#include <stdint.h>
#include "include/sam.h"
#include "mpconfigboard.h" // for BOARD_HAS_CRYSTAL
#ifdef SAMD51
#ifdef SAM_D5X_E5X
#define CLOCK_48MHZ GCLK_GENCTRL_SRC_DFLL_Val
#endif
#ifdef SAMD21
#define CLOCK_48MHZ GCLK_GENCTRL_SRC_DFLL48M_Val
#endif
// Pass to clock_init() if fine calibration not known.
#define DEFAULT_DFLL48M_FINE_CALIBRATION 512
#define CORE_GCLK 0
uint8_t find_free_gclk(uint16_t divisor);
@ -54,15 +56,7 @@ void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral);
void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor);
void disable_clock_generator(uint8_t gclk);
static inline bool board_has_crystal(void) {
#ifdef BOARD_HAS_CRYSTAL
return BOARD_HAS_CRYSTAL == 1;
#else
return false;
#endif
}
void clock_init(void);
void clock_init(bool has_crystal, uint32_t dfll48m_fine_calibration);
void init_dynamic_clocks(void);
bool clock_get_enabled(uint8_t type, uint8_t index);
@ -70,6 +64,5 @@ 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

View file

@ -43,14 +43,14 @@ COMPILER_ALIGNED(16) static DmacDescriptor write_back_descriptors[DMA_CHANNEL_CO
#define FIRST_SERCOM_RX_TRIGSRC 0x01
#define FIRST_SERCOM_TX_TRIGSRC 0x02
#endif
#ifdef SAMD51
#ifdef SAM_D5X_E5X
#define FIRST_SERCOM_RX_TRIGSRC 0x04
#define FIRST_SERCOM_TX_TRIGSRC 0x05
#endif
void init_shared_dma(void) {
// Turn on the clocks
#ifdef SAMD51
#ifdef SAM_D5X_E5X
MCLK->AHBMASK.reg |= MCLK_AHBMASK_DMAC;
#endif
@ -89,7 +89,7 @@ static int32_t shared_dma_transfer(void* peripheral,
bool tx_active = false;
bool rx_active = false;
uint16_t beat_length = length;
#ifdef SAMD51
#ifdef SAM_D5X_E5X
if (peripheral == QSPI) {
// Check input alignment on word boundaries.
if ((((uint32_t) buffer_in) & 0x3) != 0 ||
@ -110,7 +110,6 @@ static int32_t shared_dma_transfer(void* peripheral,
} else {
#endif
// sercom index is incorrect for SAMD51
dma_configure(SHARED_TX_CHANNEL, sercom_index(peripheral) * 2 + FIRST_SERCOM_TX_TRIGSRC, false);
tx_active = true;
if (buffer_in != NULL) {
@ -118,7 +117,7 @@ static int32_t shared_dma_transfer(void* peripheral,
rx_active = true;
}
#ifdef SAMD51
#ifdef SAM_D5X_E5X
}
#endif
@ -128,7 +127,7 @@ static int32_t shared_dma_transfer(void* peripheral,
rx_descriptor->BTCTRL.reg = beat_size | DMAC_BTCTRL_DSTINC;
rx_descriptor->BTCNT.reg = beat_length;
rx_descriptor->SRCADDR.reg = ((uint32_t) src);
#ifdef SAMD51
#ifdef SAM_D5X_E5X
if (peripheral == QSPI) {
rx_descriptor->SRCADDR.reg = ((uint32_t) src + length);
}
@ -155,8 +154,6 @@ static int32_t shared_dma_transfer(void* peripheral,
if (sercom) {
SercomSpi *s = &((Sercom*) peripheral)->SPI;
s->INTFLAG.reg = SERCOM_SPI_INTFLAG_RXC | SERCOM_SPI_INTFLAG_DRE;
} else {
//QSPI->INTFLAG.reg = QSPI_INTFLAG_RXC | QSPI_INTFLAG_DRE;
}
// Start the RX job first so we don't miss the first byte. The TX job clocks
// the output.
@ -168,23 +165,41 @@ static int32_t shared_dma_transfer(void* peripheral,
}
if (sercom) {
//DMAC->SWTRIGCTRL.reg |= (1 << SHARED_TX_CHANNEL);
} else {
// Do a manual copy to trigger then DMA. We do 32-bit accesses to match the DMA.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
if (!sercom) {
if (rx_active) {
//buffer_in[0] = *src;
DMAC->SWTRIGCTRL.reg |= (1 << SHARED_RX_CHANNEL);
} else {
//*(uint32_t*)dest = ((uint32_t*) buffer_out)[0];
}
#pragma GCC diagnostic pop
}
// Channels cycle between Suspend -> Pending -> Busy and back while transfering. So, we check
// the channels transfer status for an error or completion.
#ifdef SAM_D5X_E5X
// Sometimes (silicon bug?) this DMA transfer never starts, and another channel sits with
// CHSTATUS.reg = 0x3 (BUSY | PENDING). On the other hand, this is a
// legitimate state for a DMA channel to be in (apparently), so we can't use that alone as a check.
// Instead, let's look at the ACTIVE flag. When DMA is hung, everything in ACTIVE is zeros.
bool is_okay = false;
for (int i=0; i<10 && !is_okay; i++) {
bool complete = true;
if (rx_active) {
if (DMAC->Channel[SHARED_RX_CHANNEL].CHSTATUS.reg & 0x3)
complete = false;
}
if (tx_active) {
if (DMAC->Channel[SHARED_TX_CHANNEL].CHSTATUS.reg & 0x3)
complete = false;
}
is_okay = is_okay || (DMAC->ACTIVE.bit.ABUSY || complete);
}
if (!is_okay) {
for (int i=0; i<AUDIO_DMA_CHANNEL_COUNT; i++) {
if(DMAC->Channel[i].CHCTRLA.bit.ENABLE) {
DMAC->Channel[i].CHCTRLA.bit.ENABLE = 0;
DMAC->Channel[i].CHCTRLA.bit.ENABLE = 1;
}
}
}
#endif
// busy-wait for the RX and TX DMAs to either complete or encounter an error
if (rx_active) {
while ((dma_transfer_status(SHARED_RX_CHANNEL) & 0x3) == 0) {}
}
@ -229,7 +244,7 @@ int32_t sercom_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_
return shared_dma_transfer(sercom, NULL, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, buffer, length, tx);
}
#ifdef SAMD51
#ifdef SAM_D5X_E5X
int32_t qspi_dma_write(uint32_t address, const uint8_t* buffer, uint32_t length) {
return shared_dma_transfer(QSPI, buffer, (uint32_t*) (QSPI_AHB + address), NULL, NULL, length, 0);
}

View file

@ -44,7 +44,7 @@ volatile bool audio_dma_in_use;
void init_shared_dma(void);
#ifdef SAMD51
#ifdef SAM_D5X_E5X
int32_t qspi_dma_write(uint32_t address, const uint8_t* buffer, uint32_t length);
int32_t qspi_dma_read(uint32_t address, uint8_t* buffer, uint32_t length);
#endif

View file

@ -44,14 +44,14 @@ void external_interrupt_handler(uint8_t channel) {
void configure_eic_channel(uint8_t eic_channel, uint32_t sense_setting) {
uint8_t config_index = eic_channel / 8;
uint8_t position = (eic_channel % 8) * 4;
#ifdef SAMD51
#ifdef SAM_D5X_E5X
eic_set_enable(false);
#endif
common_hal_mcu_disable_interrupts();
uint32_t masked_value = EIC->CONFIG[config_index].reg & ~(0xf << position);
EIC->CONFIG[config_index].reg = masked_value | (sense_setting << position);
common_hal_mcu_enable_interrupts();
#ifdef SAMD51
#ifdef SAM_D5X_E5X
eic_set_enable(true);
#endif
}
@ -68,7 +68,7 @@ void turn_on_eic_channel(uint8_t eic_channel, uint32_t sense_setting) {
void turn_off_eic_channel(uint8_t eic_channel) {
uint32_t mask = 1 << eic_channel;
EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos;
#ifdef SAMD51
#ifdef SAM_D5X_E5X
NVIC_DisableIRQ(EIC_0_IRQn + eic_channel);
NVIC_ClearPendingIRQ(EIC_0_IRQn + eic_channel);
#endif

View file

@ -52,7 +52,7 @@ typedef struct {
#define NUM_TIMERS_PER_PIN 2
#define NUM_ADC_PER_PIN 1
#endif
#ifdef SAMD51
#ifdef SAM_D5X_E5X
#define NUM_TIMERS_PER_PIN 3
#define NUM_ADC_PER_PIN 2
#endif
@ -73,8 +73,8 @@ typedef struct {
#ifdef SAMD21
#include "samd/samd21/pins.h"
#endif
#ifdef SAMD51
#include "samd/samd51/pins.h"
#ifdef SAM_D5X_E5X
#include "samd/sam_d5x_e5x/pins.h"
#endif
#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_PINS_H

View file

@ -26,7 +26,7 @@
#include "hal/include/hal_adc_sync.h"
#include "hpl/gclk/hpl_gclk_base.h"
#include "hri/hri_mclk_d51.h"
#include "hri_mclk.h"
// Do initialization and calibration setup needed for any use of the ADC.
// The reference and resolution should be set by the caller.

View file

@ -28,11 +28,6 @@
#include "hpl_gclk_config.h"
#include "bindings/samd/Clock.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "py/runtime.h"
bool gclk_enabled(uint8_t gclk) {
return GCLK->GENCTRL[gclk].bit.GENEN;
}
@ -81,13 +76,13 @@ void disable_clock_generator(uint8_t gclk) {
static void init_clock_source_osculp32k(void) {
// Calibration value is loaded at startup
OSC32KCTRL->OSCULP32K.bit.EN1K = 1;
OSC32KCTRL->OSCULP32K.bit.EN32K = 0;
OSC32KCTRL->OSCULP32K.bit.EN1K = 0;
OSC32KCTRL->OSCULP32K.bit.EN32K = 1;
}
static void init_clock_source_xosc32k(void) {
OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ONDEMAND |
OSC32KCTRL_XOSC32K_EN1K |
OSC32KCTRL_XOSC32K_EN32K |
OSC32KCTRL_XOSC32K_XTALEN |
OSC32KCTRL_XOSC32K_ENABLE |
OSC32KCTRL_XOSC32K_CGM(1);
@ -103,16 +98,17 @@ static void init_clock_source_dpll0(void)
while (!(OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK || OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY)) {}
}
void clock_init(void) {
void clock_init(bool has_crystal, uint32_t dfll48m_fine_calibration) {
// DFLL48M is enabled by default
// TODO: handle fine calibration data.
init_clock_source_osculp32k();
if (board_has_crystal()) {
if (has_crystal) {
init_clock_source_xosc32k();
OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K_Val;
OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K_Val;
} else {
OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K_Val;
OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K_Val;
}
MCLK->CPUDIV.reg = MCLK_CPUDIV_DIV(1);
@ -121,6 +117,7 @@ void clock_init(void) {
enable_clock_generator_sync(1, GCLK_GENCTRL_SRC_DFLL_Val, 1, false);
enable_clock_generator_sync(4, GCLK_GENCTRL_SRC_DPLL0_Val, 1, false);
enable_clock_generator_sync(5, GCLK_GENCTRL_SRC_DFLL_Val, 24, false);
enable_clock_generator_sync(6, GCLK_GENCTRL_SRC_DFLL_Val, 4, false);
init_clock_source_dpll0();
@ -338,143 +335,3 @@ 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>
#include <instance/sdhc1.h>
#include <instance/sercom6.h>
#include <instance/sercom7.h>
#include <instance/tcc4.h>
CLOCK_SOURCE(XOSC0);
CLOCK_SOURCE(XOSC1);
CLOCK_SOURCE(GCLKIN);
CLOCK_SOURCE(GCLKGEN1);
CLOCK_SOURCE(OSCULP32K);
CLOCK_SOURCE(XOSC32K);
CLOCK_SOURCE(DFLL);
CLOCK_SOURCE(DPLL0);
CLOCK_SOURCE(DPLL1);
CLOCK_GCLK_(OSCCTRL, DFLL48);
CLOCK_GCLK_(OSCCTRL, FDPLL0);
CLOCK_GCLK_(OSCCTRL, FDPLL1);
CLOCK_GCLK_(OSCCTRL, FDPLL032K); // GCLK_OSCCTRL_FDPLL1_32K, GCLK_SDHC0_SLOW, GCLK_SDHC1_SLOW, GCLK_SERCOM[0..7]_SLOW
CLOCK_GCLK(EIC);
CLOCK_GCLK_(FREQM, MSR);
// 6: GCLK_FREQM_REF
CLOCK_GCLK_(SERCOM0, CORE);
CLOCK_GCLK_(SERCOM1, CORE);
CLOCK(TC0_TC1, 1, 9);
CLOCK_GCLK(USB);
CLOCK_GCLK_(EVSYS, 0);
CLOCK_GCLK_(EVSYS, 1);
CLOCK_GCLK_(EVSYS, 2);
CLOCK_GCLK_(EVSYS, 3);
CLOCK_GCLK_(EVSYS, 4);
CLOCK_GCLK_(EVSYS, 5);
CLOCK_GCLK_(EVSYS, 6);
CLOCK_GCLK_(EVSYS, 7);
CLOCK_GCLK_(EVSYS, 8);
CLOCK_GCLK_(EVSYS, 9);
CLOCK_GCLK_(EVSYS, 10);
CLOCK_GCLK_(EVSYS, 11);
CLOCK_GCLK_(SERCOM2, CORE);
CLOCK_GCLK_(SERCOM3, CORE);
CLOCK(TCC0_TCC1, 1, 25);
CLOCK(TC2_TC3, 1, 26);
CLOCK_GCLK(CAN0);
CLOCK_GCLK(CAN1);
CLOCK(TCC2_TCC3, 1, 29);
CLOCK(TC4_TC5, 1, 30);
// CLOCK_GCLK(PDEC);
// CLOCK_GCLK(AC);
// CLOCK_GCLK(CCL);
CLOCK_GCLK_(SERCOM4, CORE);
CLOCK_GCLK_(SERCOM5, CORE);
CLOCK_GCLK_(SERCOM6, CORE);
CLOCK_GCLK_(SERCOM7, CORE);
CLOCK_GCLK(TCC4);
CLOCK(TC6_TC7, 1, 39);
CLOCK_GCLK(ADC0);
CLOCK_GCLK(ADC1);
CLOCK_GCLK(DAC);
CLOCK_GCLK_(I2S, 0);
CLOCK_GCLK_(I2S, 1);
// CLOCK_GCLK(SDHC0);
// CLOCK_GCLK(SDHC1);
// 47: GCLK_CM4_TRACE
CLOCK(SYSTICK, 2, 0);
CLOCK(CPU, 2, 1);
CLOCK(RTC, 2, 2);
STATIC const mp_rom_map_elem_t samd_clock_global_dict_table[] = {
CLOCK_ENTRY(XOSC0),
CLOCK_ENTRY(XOSC1),
CLOCK_ENTRY(GCLKIN),
CLOCK_ENTRY(GCLKGEN1),
CLOCK_ENTRY(OSCULP32K),
CLOCK_ENTRY(XOSC32K),
CLOCK_ENTRY(DFLL),
CLOCK_ENTRY(DPLL0),
CLOCK_ENTRY(DPLL1),
CLOCK_ENTRY_(OSCCTRL, DFLL48),
CLOCK_ENTRY_(OSCCTRL, FDPLL0),
CLOCK_ENTRY_(OSCCTRL, FDPLL1),
CLOCK_ENTRY_(OSCCTRL, FDPLL032K),
CLOCK_ENTRY(EIC),
CLOCK_ENTRY_(FREQM, MSR),
CLOCK_ENTRY_(SERCOM0, CORE),
CLOCK_ENTRY_(SERCOM1, CORE),
CLOCK_ENTRY(TC0_TC1),
CLOCK_ENTRY(USB),
CLOCK_ENTRY_(EVSYS, 0),
CLOCK_ENTRY_(EVSYS, 1),
CLOCK_ENTRY_(EVSYS, 2),
CLOCK_ENTRY_(EVSYS, 3),
CLOCK_ENTRY_(EVSYS, 4),
CLOCK_ENTRY_(EVSYS, 5),
CLOCK_ENTRY_(EVSYS, 6),
CLOCK_ENTRY_(EVSYS, 7),
CLOCK_ENTRY_(EVSYS, 8),
CLOCK_ENTRY_(EVSYS, 9),
CLOCK_ENTRY_(EVSYS, 10),
CLOCK_ENTRY_(EVSYS, 11),
CLOCK_ENTRY_(SERCOM2, CORE),
CLOCK_ENTRY_(SERCOM3, CORE),
CLOCK_ENTRY(TCC0_TCC1),
CLOCK_ENTRY(TC2_TC3),
CLOCK_ENTRY(CAN0),
CLOCK_ENTRY(CAN1),
CLOCK_ENTRY(TCC2_TCC3),
CLOCK_ENTRY(TC4_TC5),
// CLOCK_ENTRY(PDEC),
// CLOCK_ENTRY(AC),
// CLOCK_ENTRY(CCL),
CLOCK_ENTRY_(SERCOM4, CORE),
CLOCK_ENTRY_(SERCOM5, CORE),
CLOCK_ENTRY_(SERCOM6, CORE),
CLOCK_ENTRY_(SERCOM7, CORE),
CLOCK_ENTRY(TCC4),
CLOCK_ENTRY(TC6_TC7),
CLOCK_ENTRY(ADC0),
CLOCK_ENTRY(ADC1),
CLOCK_ENTRY(DAC),
CLOCK_ENTRY_(I2S, 0),
CLOCK_ENTRY_(I2S, 1),
// CLOCK_ENTRY(SDHC0),
// CLOCK_ENTRY(SDHC1),
CLOCK_ENTRY(SYSTICK),
CLOCK_ENTRY(CPU),
CLOCK_ENTRY(RTC),
};
MP_DEFINE_CONST_DICT(samd_clock_globals, samd_clock_global_dict_table);

View file

@ -30,7 +30,7 @@
#include "py/runtime.h"
#include "hri/hri_mclk_d51.h"
#include "hri_mclk.h"
void turn_on_event_system(void) {
hri_mclk_set_APBBMASK_EVSYS_bit(MCLK);

View file

@ -0,0 +1,36 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler 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_HRI_GCLK_H
#define MICROPY_INCLUDED_ATMEL_SAMD_HRI_GCLK_H
#ifdef SAMD51
#include "hri/hri_gclk_d51.h"
#else
#include "hri/hri_gclk_e54.h"
#endif
#endif

View file

@ -0,0 +1,36 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler 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_HRI_MCLK_H
#define MICROPY_INCLUDED_ATMEL_SAMD_HRI_MCLK_H
#ifdef SAMD51
#include "hri/hri_mclk_d51.h"
#else
#include "hri/hri_mclk_e54.h"
#endif
#endif

View file

@ -26,7 +26,7 @@
#include "hal/include/hal_adc_sync.h"
#include "hpl/gclk/hpl_gclk_base.h"
#include "hri/hri_mclk_d51.h"
#include "hri_mclk.h"
// The clock initializer values are rather random, so we need to put them in
// tables for lookup. We can't compute them.

View file

@ -31,7 +31,7 @@
#include "timer_handler.h"
#include "hri/hri_gclk_d51.h"
#include "hri_gclk.h"
const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2};
const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC0_GCLK_ID,

View file

@ -24,32 +24,19 @@
* THE SOFTWARE.
*/
#include <string.h>
#include <stdlib.h>
#include "hal_atomic.h"
#include "samd/clocks.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();
volatile hal_atomic_t atomic;
atomic_enter_critical(&atomic);
// Explicitly do a byte write so the peripheral knows we're just wanting to read the channel
// rather than write to it.
*((uint8_t*) &GCLK->GENCTRL.reg) = gclk;
while (GCLK->STATUS.bit.SYNCBUSY == 1) {}
bool enabled = GCLK->GENCTRL.bit.GENEN;
common_hal_mcu_enable_interrupts();
atomic_leave_critical(&atomic);
return enabled;
}
@ -135,7 +122,7 @@ static void init_clock_source_dfll48m_xosc(void) {
while (!SYSCTRL->PCLKSR.bit.DFLLLCKC || !SYSCTRL->PCLKSR.bit.DFLLLCKF) {}
}
static void init_clock_source_dfll48m_usb(void) {
static void init_clock_source_dfll48m_usb(uint32_t fine_calibration) {
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) |
@ -145,17 +132,8 @@ static void init_clock_source_dfll48m_usb(void) {
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(fine);
SYSCTRL_DFLLVAL_FINE(fine_calibration);
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS |
SYSCTRL_DFLLCTRL_USBCRM |
SYSCTRL_DFLLCTRL_MODE |
@ -164,28 +142,28 @@ static void init_clock_source_dfll48m_usb(void) {
while (GCLK->STATUS.bit.SYNCBUSY) {}
}
void clock_init(void)
void clock_init(bool has_crystal, uint32_t dfll48m_fine_calibration)
{
init_clock_source_osc8m();
if (board_has_crystal()) {
if (has_crystal) {
init_clock_source_xosc32k();
} else {
init_clock_source_osc32k();
}
if (board_has_crystal()) {
if (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();
init_clock_source_dfll48m_usb(dfll48m_fine_calibration);
}
enable_clock_generator(0, GCLK_GENCTRL_SRC_DFLL48M_Val, 1);
if (board_has_crystal()) {
enable_clock_generator(2, GCLK_GENCTRL_SRC_XOSC32K_Val, 32);
if (has_crystal) {
enable_clock_generator(2, GCLK_GENCTRL_SRC_XOSC32K_Val, 1);
} else {
enable_clock_generator(2, GCLK_GENCTRL_SRC_OSC32K_Val, 32);
enable_clock_generator(2, GCLK_GENCTRL_SRC_OSC32K_Val, 1);
}
// Do this after all static clock init so that they aren't used dynamically.
@ -193,29 +171,32 @@ void clock_init(void)
}
static bool clk_enabled(uint8_t clk) {
common_hal_mcu_disable_interrupts();
volatile hal_atomic_t atomic;
atomic_enter_critical(&atomic);
*((uint8_t*) &GCLK->CLKCTRL.reg) = clk;
while (GCLK->STATUS.bit.SYNCBUSY == 1) {}
bool enabled = GCLK->CLKCTRL.bit.CLKEN;
common_hal_mcu_enable_interrupts();
atomic_leave_critical(&atomic);
return enabled;
}
static uint8_t clk_get_generator(uint8_t clk) {
common_hal_mcu_disable_interrupts();
volatile hal_atomic_t atomic;
atomic_enter_critical(&atomic);
*((uint8_t*) &GCLK->CLKCTRL.reg) = clk;
while (GCLK->STATUS.bit.SYNCBUSY == 1) {}
uint8_t gen = GCLK->CLKCTRL.bit.GEN;
common_hal_mcu_enable_interrupts();
atomic_leave_critical(&atomic);
return gen;
}
static uint8_t generator_get_source(uint8_t gen) {
common_hal_mcu_disable_interrupts();
volatile hal_atomic_t atomic;
atomic_enter_critical(&atomic);
*((uint8_t*) &GCLK->GENCTRL.reg) = gen;
while (GCLK->STATUS.bit.SYNCBUSY == 1) {}
uint8_t src = GCLK->GENCTRL.bit.SRC;
common_hal_mcu_enable_interrupts();
atomic_leave_critical(&atomic);
return src;
}
@ -295,7 +276,8 @@ uint32_t clock_get_frequency(uint8_t type, uint8_t index) {
uint8_t gen = clk_get_generator(index);
common_hal_mcu_disable_interrupts();
volatile hal_atomic_t atomic;
atomic_enter_critical(&atomic);
*((uint8_t*) &GCLK->GENCTRL.reg) = gen;
*((uint8_t*) &GCLK->GENDIV.reg) = gen;
while (GCLK->STATUS.bit.SYNCBUSY == 1) {}
@ -309,7 +291,7 @@ uint32_t clock_get_frequency(uint8_t type, uint8_t index) {
if (!div)
div = 1;
}
common_hal_mcu_enable_interrupts();
atomic_leave_critical(&atomic);
return osc_get_frequency(src) / div;
}
@ -364,152 +346,3 @@ 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);
CLOCK_SOURCE(GCLKGEN1);
CLOCK_SOURCE(OSCULP32K);
#endif
CLOCK_SOURCE(OSC32K);
CLOCK_SOURCE(XOSC32K);
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
CLOCK_SOURCE(OSC8M);
CLOCK_SOURCE(DFLL48M);
CLOCK_SOURCE(DPLL96M);
CLOCK_GCLK_(SYSCTRL, DFLL48);
CLOCK_GCLK_(SYSCTRL, FDPLL);
CLOCK_GCLK_(SYSCTRL, FDPLL32K);
CLOCK_GCLK(WDT);
#endif
CLOCK_GCLK(RTC);
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
CLOCK_GCLK(EIC);
CLOCK_GCLK(USB);
CLOCK_GCLK_(EVSYS, 0);
CLOCK_GCLK_(EVSYS, 1);
CLOCK_GCLK_(EVSYS, 2);
CLOCK_GCLK_(EVSYS, 3);
CLOCK_GCLK_(EVSYS, 4);
CLOCK_GCLK_(EVSYS, 5);
CLOCK_GCLK_(EVSYS, 6);
CLOCK_GCLK_(EVSYS, 7);
CLOCK_GCLK_(EVSYS, 8);
CLOCK_GCLK_(EVSYS, 9);
CLOCK_GCLK_(EVSYS, 10);
CLOCK_GCLK_(EVSYS, 11);
CLOCK(SERCOMx_SLOW, 1, 19);
CLOCK_GCLK_(SERCOM0, CORE);
CLOCK_GCLK_(SERCOM1, CORE);
CLOCK_GCLK_(SERCOM2, CORE);
CLOCK_GCLK_(SERCOM3, CORE);
CLOCK_GCLK_(SERCOM4, CORE);
CLOCK_GCLK_(SERCOM5, CORE);
CLOCK(TCC0_TCC1, 1, 26);
CLOCK(TCC2_TCC3, 1, 27);
CLOCK(TC4_TC5, 1, 28);
CLOCK(TC6_TC7, 1, 29);
CLOCK_GCLK(ADC);
CLOCK_GCLK_(AC, DIG);
CLOCK_GCLK_(AC, ANA);
CLOCK_GCLK(DAC);
CLOCK_GCLK(PTC);
CLOCK_GCLK_(I2S, 0);
CLOCK_GCLK_(I2S, 1);
CLOCK(SYSTICK, 2, 0);
#endif
STATIC const mp_rom_map_elem_t samd_clock_global_dict_table[] = {
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
CLOCK_ENTRY(XOSC),
CLOCK_ENTRY(GCLKIN),
CLOCK_ENTRY(GCLKGEN1),
CLOCK_ENTRY(OSCULP32K),
#endif
CLOCK_ENTRY(OSC32K),
CLOCK_ENTRY(XOSC32K),
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
CLOCK_ENTRY(OSC8M),
CLOCK_ENTRY(DFLL48M),
CLOCK_ENTRY(DPLL96M),
CLOCK_ENTRY_(SYSCTRL, DFLL48),
CLOCK_ENTRY_(SYSCTRL, FDPLL),
CLOCK_ENTRY_(SYSCTRL, FDPLL32K),
CLOCK_ENTRY(WDT),
#endif
CLOCK_ENTRY(RTC),
#ifdef SAMD21_EXPOSE_ALL_CLOCKS
CLOCK_ENTRY(EIC),
CLOCK_ENTRY(USB),
CLOCK_ENTRY_(EVSYS, 0),
CLOCK_ENTRY_(EVSYS, 1),
CLOCK_ENTRY_(EVSYS, 2),
CLOCK_ENTRY_(EVSYS, 3),
CLOCK_ENTRY_(EVSYS, 4),
CLOCK_ENTRY_(EVSYS, 5),
CLOCK_ENTRY_(EVSYS, 6),
CLOCK_ENTRY_(EVSYS, 7),
CLOCK_ENTRY_(EVSYS, 8),
CLOCK_ENTRY_(EVSYS, 9),
CLOCK_ENTRY_(EVSYS, 10),
CLOCK_ENTRY_(EVSYS, 11),
CLOCK_ENTRY(SERCOMx_SLOW),
CLOCK_ENTRY_(SERCOM0, CORE),
CLOCK_ENTRY_(SERCOM1, CORE),
CLOCK_ENTRY_(SERCOM2, CORE),
CLOCK_ENTRY_(SERCOM3, CORE),
CLOCK_ENTRY_(SERCOM4, CORE),
CLOCK_ENTRY_(SERCOM5, CORE),
CLOCK_ENTRY(TCC0_TCC1),
CLOCK_ENTRY(TCC2_TCC3),
CLOCK_ENTRY(TC4_TC5),
CLOCK_ENTRY(TC6_TC7),
CLOCK_ENTRY(ADC),
CLOCK_ENTRY_(AC, DIG),
CLOCK_ENTRY_(AC, ANA),
CLOCK_ENTRY(DAC),
CLOCK_ENTRY(PTC),
CLOCK_ENTRY_(I2S, 0),
CLOCK_ENTRY_(I2S, 1),
CLOCK_ENTRY(SYSTICK),
#endif
};
MP_DEFINE_CONST_DICT(samd_clock_globals, samd_clock_global_dict_table);

View file

@ -496,13 +496,13 @@ PIN(PB00, EXTINT_CHANNEL(0), ADC_INPUT(8), TOUCH(6),
#if defined(PIN_PB01) && !defined(IGNORE_PIN_PB01)
PIN(PB01, EXTINT_CHANNEL(1), ADC_INPUT(9), TOUCH(7),
NO_SERCOM,
SERCOM(5, 3)),
SERCOM(5, 3),
#ifdef TC7
TC(7, 1),
#else
NO_TIMER,
#endif
NO_TIMER;
NO_TIMER);
#endif
#if defined(PIN_PB02) && !defined(IGNORE_PIN_PB02)
PIN(PB02, EXTINT_CHANNEL(2), ADC_INPUT(10), TOUCH(8),

View file

@ -95,7 +95,7 @@ void tc_reset(Tc* tc) {
}
}
#ifdef SAMD51
#ifdef SAM_D5X_E5X
#define TC_OFFSET 0
#endif
#ifdef SAMD21
@ -111,7 +111,7 @@ void TCC1_Handler(void) {
void TCC2_Handler(void) {
shared_timer_handler(false, 2);
}
// TC0 - TC2 only exist on the SAMD51
// TC0 - TC2 only exist on the SAM_D5X_E5X
#ifdef TC0
void TC0_Handler(void) {
shared_timer_handler(true, 0);

View file

@ -26,6 +26,7 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H
#define MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H
#include <stdbool.h>
#include "include/sam.h"
const uint16_t prescaler[8];
@ -35,7 +36,7 @@ const uint8_t tcc_cc_num[3];
const uint8_t tc_gclk_ids[TC_INST_NUM];
const uint8_t tcc_gclk_ids[3];
#endif
#ifdef SAMD51
#ifdef SAM_D5X_E5X
const uint8_t tcc_cc_num[5];
const uint8_t tc_gclk_ids[TC_INST_NUM];
const uint8_t tcc_gclk_ids[TCC_INST_NUM];