summaryrefslogtreecommitdiffstats
path: root/watch-library/hardware/hpl
diff options
context:
space:
mode:
authorAlexsander Akers <me@a2.io>2022-01-25 15:03:22 -0500
committerGitHub <noreply@github.com>2022-01-25 15:03:22 -0500
commitb8de35658ffd78ad8b22f91ccbbd3d63663afda9 (patch)
tree1f265ddfcc8e5abf0316b81b15f80bf5c70fa7b7 /watch-library/hardware/hpl
parent9e24f6c336773c7404139ab4db0eaab2f99504e2 (diff)
downloadSensor-Watch-b8de35658ffd78ad8b22f91ccbbd3d63663afda9.tar.gz
Sensor-Watch-b8de35658ffd78ad8b22f91ccbbd3d63663afda9.tar.bz2
Sensor-Watch-b8de35658ffd78ad8b22f91ccbbd3d63663afda9.zip
Sensor Watch Simulator (#35)
* Put something on screen * Use the 32bit watch_date_time repr to pass from JS * Implement periodic callbacks * Clear display on enabling * Hook up watch_set_led_color() to SVG (green-only) * Make debug output full-width * Remove default Emscripten canvas * Implement sleep and button clicks * Fix time zone conversion bug in beats-time app * Clean up warnings * Fix pin levels * Set time zone to browser value (if available) * Add basic backup data saving * Silence format specifier warnings in both targets * Remove unnecessary, copied files * Use RTC pointer to clear callbacks (if available) * Use preprocessor define to avoid hardcoding MOVEMENT_NUM_FACES * Change each face to const preprocessor definition * Remove Intl.DateTimeFormat usage * Update shell.html title, header * Add touch start/end event handlers on SVG buttons * Update shell.html * Update folder structure (shared, simulator, hardware under watch-library) * Tease out shared components from watch_slcd * Clean up simulator watch_slcd.c inline JS calls * Fix missing newlines at end of file * Add simulator warnings (except format, unused-paremter) * Implement remaining watch_rtc functions * Fix button bug on mouse down then drag out * Implement remaining watch_slcd functions * Link keyboard events to buttons (for keys A, L, M) * Rewrite event handling (mouse, touch, keyboard) in C * Set explicit text UTF-8 charset in shell.html * Address PR comments * Remove unused directories from include paths
Diffstat (limited to 'watch-library/hardware/hpl')
-rw-r--r--watch-library/hardware/hpl/core/hpl_core_m0plus_base.c202
-rw-r--r--watch-library/hardware/hpl/core/hpl_core_port.h63
-rw-r--r--watch-library/hardware/hpl/core/hpl_init.c74
-rw-r--r--watch-library/hardware/hpl/dmac/hpl_dmac.c244
-rw-r--r--watch-library/hardware/hpl/eic/hpl_eic.c255
-rw-r--r--watch-library/hardware/hpl/gclk/hpl_gclk.c164
-rw-r--r--watch-library/hardware/hpl/gclk/hpl_gclk_base.h87
-rw-r--r--watch-library/hardware/hpl/mclk/hpl_mclk.c46
-rwxr-xr-xwatch-library/hardware/hpl/nvmctrl/hpl_nvmctrl.c782
-rw-r--r--watch-library/hardware/hpl/osc32kctrl/hpl_osc32kctrl.c86
-rw-r--r--watch-library/hardware/hpl/oscctrl/hpl_oscctrl.c179
-rw-r--r--watch-library/hardware/hpl/pm/hpl_pm.c77
-rw-r--r--watch-library/hardware/hpl/pm/hpl_pm_base.h45
-rw-r--r--watch-library/hardware/hpl/port/hpl_gpio_base.h170
-rw-r--r--watch-library/hardware/hpl/sercom/hpl_sercom.c2932
-rw-r--r--watch-library/hardware/hpl/slcd/hpl_slcd.c289
-rw-r--r--watch-library/hardware/hpl/slcd/hpl_slcd_cm.h59
-rw-r--r--watch-library/hardware/hpl/systick/hpl_systick.c104
-rwxr-xr-xwatch-library/hardware/hpl/trng/hpl_trng.c110
19 files changed, 5968 insertions, 0 deletions
diff --git a/watch-library/hardware/hpl/core/hpl_core_m0plus_base.c b/watch-library/hardware/hpl/core/hpl_core_m0plus_base.c
new file mode 100644
index 00000000..cad2a662
--- /dev/null
+++ b/watch-library/hardware/hpl/core/hpl_core_m0plus_base.c
@@ -0,0 +1,202 @@
+/**
+ * \file
+ *
+ * \brief Core related functionality implementation.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_core.h>
+#include <hpl_irq.h>
+#include <hpl_reset.h>
+#include <hpl_sleep.h>
+#include <hpl_delay.h>
+#ifndef _UNIT_TEST_
+#include <utils.h>
+#endif
+#include <utils_assert.h>
+#include <peripheral_clk_config.h>
+
+#ifndef CONF_CPU_FREQUENCY
+#define CONF_CPU_FREQUENCY 1000000
+#endif
+
+#if CONF_CPU_FREQUENCY < 1000
+#define CPU_FREQ_POWER 3
+#elif CONF_CPU_FREQUENCY < 10000
+#define CPU_FREQ_POWER 4
+#elif CONF_CPU_FREQUENCY < 100000
+#define CPU_FREQ_POWER 5
+#elif CONF_CPU_FREQUENCY < 1000000
+#define CPU_FREQ_POWER 6
+#elif CONF_CPU_FREQUENCY < 10000000
+#define CPU_FREQ_POWER 7
+#elif CONF_CPU_FREQUENCY < 100000000
+#define CPU_FREQ_POWER 8
+#endif
+
+/**
+ * \brief The array of interrupt handlers
+ */
+struct _irq_descriptor *_irq_table[PERIPH_COUNT_IRQn];
+
+/**
+ * \brief Reset MCU
+ */
+void _reset_mcu(void)
+{
+ NVIC_SystemReset();
+}
+
+/**
+ * \brief Put MCU to sleep
+ */
+void _go_to_sleep(void)
+{
+ __DSB();
+ __WFI();
+}
+
+/**
+ * \brief Retrieve current IRQ number
+ */
+uint8_t _irq_get_current(void)
+{
+ return (uint8_t)__get_IPSR() - 16;
+}
+
+/**
+ * \brief Disable the given IRQ
+ */
+void _irq_disable(uint8_t n)
+{
+ NVIC_DisableIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Set the given IRQ
+ */
+void _irq_set(uint8_t n)
+{
+ NVIC_SetPendingIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Clear the given IRQ
+ */
+void _irq_clear(uint8_t n)
+{
+ NVIC_ClearPendingIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Enable the given IRQ
+ */
+void _irq_enable(uint8_t n)
+{
+ NVIC_EnableIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Register IRQ handler
+ */
+void _irq_register(const uint8_t n, struct _irq_descriptor *const irq)
+{
+ ASSERT(n < PERIPH_COUNT_IRQn);
+
+ _irq_table[n] = irq;
+}
+
+/**
+ * \brief Default interrupt handler for unused IRQs.
+ */
+void Default_Handler(void)
+{
+ while (1) {
+ }
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of us
+ */
+static inline uint32_t _get_cycles_for_us_internal(const uint16_t us, const uint32_t freq, const uint8_t power)
+{
+ switch (power) {
+ case 8:
+ return (us * (freq / 100000) - 1) / 10 + 1;
+ case 7:
+ return (us * (freq / 10000) - 1) / 100 + 1;
+ case 6:
+ return (us * (freq / 1000) - 1) / 1000 + 1;
+ case 5:
+ return (us * (freq / 100) - 1) / 10000 + 1;
+ case 4:
+ return (us * (freq / 10) - 1) / 100000 + 1;
+ default:
+ return (us * freq - 1) / 1000000 + 1;
+ }
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of us
+ */
+uint32_t _get_cycles_for_us(const uint16_t us)
+{
+ int32_t freq = hri_usbdevice_get_CTRLA_ENABLE_bit(USB) ? 8000000 : 4000000;
+ return _get_cycles_for_us_internal(us, freq, CPU_FREQ_POWER);
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of ms
+ */
+static inline uint32_t _get_cycles_for_ms_internal(const uint16_t ms, const uint32_t freq, const uint8_t power)
+{
+ switch (power) {
+ case 8:
+ return (ms * (freq / 100000)) * 100;
+ case 7:
+ return (ms * (freq / 10000)) * 10;
+ case 6:
+ return (ms * (freq / 1000));
+ case 5:
+ return (ms * (freq / 100) - 1) / 10 + 1;
+ case 4:
+ return (ms * (freq / 10) - 1) / 100 + 1;
+ default:
+ return (ms * freq - 1) / 1000 + 1;
+ }
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of ms
+ */
+uint32_t _get_cycles_for_ms(const uint16_t ms)
+{
+ int32_t freq = hri_usbdevice_get_CTRLA_ENABLE_bit(USB) ? 8000000 : 4000000;
+ return _get_cycles_for_ms_internal(ms, freq, CPU_FREQ_POWER);
+}
diff --git a/watch-library/hardware/hpl/core/hpl_core_port.h b/watch-library/hardware/hpl/core/hpl_core_port.h
new file mode 100644
index 00000000..33c18dd0
--- /dev/null
+++ b/watch-library/hardware/hpl/core/hpl_core_port.h
@@ -0,0 +1,63 @@
+/**
+ * \file
+ *
+ * \brief Core related functionality implementation.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef _HPL_CORE_PORT_H_INCLUDED
+#define _HPL_CORE_PORT_H_INCLUDED
+
+#include <peripheral_clk_config.h>
+
+/* It's possible to include this file in ARM ASM files (e.g., in FreeRTOS IAR
+ * portable implement, portasm.s -> FreeRTOSConfig.h -> hpl_core_port.h),
+ * there will be assembling errors.
+ * So the following things are not included for assembling.
+ */
+#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
+
+#ifndef _UNIT_TEST_
+#include <compiler.h>
+#endif
+
+/**
+ * \brief Check if it's in ISR handling
+ * \return \c true if it's in ISR
+ */
+static inline bool _is_in_isr(void)
+{
+ return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk);
+}
+
+#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
+
+void Default_Handler(void);
+
+#endif /* _HPL_CORE_PORT_H_INCLUDED */
diff --git a/watch-library/hardware/hpl/core/hpl_init.c b/watch-library/hardware/hpl/core/hpl_init.c
new file mode 100644
index 00000000..900cf420
--- /dev/null
+++ b/watch-library/hardware/hpl/core/hpl_init.c
@@ -0,0 +1,74 @@
+/**
+ * \file
+ *
+ * \brief HPL initialization related functionality implementation.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_gpio.h>
+#include <hpl_init.h>
+#include <hpl_gclk_base.h>
+#include <hpl_mclk_config.h>
+
+#include <hpl_dma.h>
+#include <hpl_dmac_config.h>
+
+/* Referenced GCLKs (out of 0~4), should be initialized firstly
+ */
+#define _GCLK_INIT_1ST 0x00000000
+/* Not referenced GCLKs, initialized last */
+#define _GCLK_INIT_LAST 0x0000001F
+
+/**
+ * \brief Initialize the hardware abstraction layer
+ */
+void _init_chip(void)
+{
+ hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, CONF_NVM_WAIT_STATE);
+
+ _set_performance_level(2);
+
+ _osc32kctrl_init_sources();
+ _oscctrl_init_sources();
+ _mclk_init();
+#if _GCLK_INIT_1ST
+ _gclk_init_generators_by_fref(_GCLK_INIT_1ST);
+#endif
+ _oscctrl_init_referenced_generators();
+ _gclk_init_generators_by_fref(_GCLK_INIT_LAST);
+
+#if CONF_DMAC_ENABLE
+ hri_mclk_set_AHBMASK_DMAC_bit(MCLK);
+ _dma_init();
+#endif
+
+#if (CONF_PORT_EVCTRL_PORT_0 | CONF_PORT_EVCTRL_PORT_1 | CONF_PORT_EVCTRL_PORT_2 | CONF_PORT_EVCTRL_PORT_3)
+ _port_event_init();
+#endif
+}
diff --git a/watch-library/hardware/hpl/dmac/hpl_dmac.c b/watch-library/hardware/hpl/dmac/hpl_dmac.c
new file mode 100644
index 00000000..c12e0254
--- /dev/null
+++ b/watch-library/hardware/hpl/dmac/hpl_dmac.c
@@ -0,0 +1,244 @@
+
+/**
+ * \file
+ *
+ * \brief Generic DMAC related functionality.
+ *
+ * Copyright (c) 2016-2019 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <compiler.h>
+#include <hpl_dma.h>
+#include <hpl_dmac_config.h>
+#include <utils.h>
+#include <utils_assert.h>
+#include <utils_repeat_macro.h>
+
+#if CONF_DMAC_ENABLE
+
+/* Section containing first descriptors for all DMAC channels */
+COMPILER_ALIGNED(16)
+DmacDescriptor _descriptor_section[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
+
+/* Section containing current descriptors for all DMAC channels */
+COMPILER_ALIGNED(16)
+DmacDescriptor _write_back_section[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
+
+/* Array containing callbacks for DMAC channels */
+static struct _dma_resource _resources[DMAC_CH_NUM];
+
+/* This macro DMAC configuration */
+#define DMAC_CHANNEL_CFG(i, n) \
+ {(CONF_DMAC_RUNSTDBY_##n << DMAC_CHCTRLA_RUNSTDBY_Pos) | (CONF_DMAC_ENABLE_##n << DMAC_CHCTRLA_ENABLE_Pos), \
+ DMAC_CHCTRLB_TRIGACT(CONF_DMAC_TRIGACT_##n) | DMAC_CHCTRLB_TRIGSRC(CONF_DMAC_TRIGSRC_##n) \
+ | DMAC_CHCTRLB_LVL(CONF_DMAC_LVL_##n) | (CONF_DMAC_EVOE_##n << DMAC_CHCTRLB_EVOE_Pos) \
+ | (CONF_DMAC_EVIE_##n << DMAC_CHCTRLB_EVIE_Pos) | DMAC_CHCTRLB_EVACT(CONF_DMAC_EVACT_##n), \
+ DMAC_BTCTRL_STEPSIZE(CONF_DMAC_STEPSIZE_##n) | (CONF_DMAC_STEPSEL_##n << DMAC_BTCTRL_STEPSEL_Pos) \
+ | (CONF_DMAC_DSTINC_##n << DMAC_BTCTRL_DSTINC_Pos) | (CONF_DMAC_SRCINC_##n << DMAC_BTCTRL_SRCINC_Pos) \
+ | DMAC_BTCTRL_BEATSIZE(CONF_DMAC_BEATSIZE_##n) | DMAC_BTCTRL_BLOCKACT(CONF_DMAC_BLOCKACT_##n) \
+ | DMAC_BTCTRL_EVOSEL(CONF_DMAC_EVOSEL_##n)},
+
+/* DMAC channel configuration */
+struct dmac_channel_cfg {
+ uint8_t ctrla;
+ uint32_t ctrlb;
+ uint16_t btctrl;
+};
+
+/* DMAC channel configurations */
+const static struct dmac_channel_cfg _cfgs[] = {REPEAT_MACRO(DMAC_CHANNEL_CFG, i, DMAC_CH_NUM)};
+
+/**
+ * \brief Initialize DMAC
+ */
+int32_t _dma_init(void)
+{
+ uint8_t i = 0;
+
+ hri_dmac_clear_CTRL_DMAENABLE_bit(DMAC);
+ hri_dmac_clear_CTRL_CRCENABLE_bit(DMAC);
+ hri_dmac_set_CHCTRLA_SWRST_bit(DMAC);
+
+ hri_dmac_write_CTRL_reg(DMAC,
+ (CONF_DMAC_LVLEN0 << DMAC_CTRL_LVLEN0_Pos) | (CONF_DMAC_LVLEN1 << DMAC_CTRL_LVLEN1_Pos)
+ | (CONF_DMAC_LVLEN2 << DMAC_CTRL_LVLEN2_Pos)
+ | (CONF_DMAC_LVLEN3 << DMAC_CTRL_LVLEN3_Pos));
+ hri_dmac_write_DBGCTRL_DBGRUN_bit(DMAC, CONF_DMAC_DBGRUN);
+
+ hri_dmac_write_QOSCTRL_reg(DMAC,
+ DMAC_QOSCTRL_WRBQOS(CONF_DMAC_WRBQOS) | DMAC_QOSCTRL_FQOS(CONF_DMAC_FQOS)
+ | DMAC_QOSCTRL_DQOS(CONF_DMAC_DQOS));
+
+ hri_dmac_write_PRICTRL0_reg(
+ DMAC,
+ DMAC_PRICTRL0_LVLPRI0(CONF_DMAC_LVLPRI0) | DMAC_PRICTRL0_LVLPRI1(CONF_DMAC_LVLPRI1)
+ | DMAC_PRICTRL0_LVLPRI2(CONF_DMAC_LVLPRI2) | DMAC_PRICTRL0_LVLPRI3(CONF_DMAC_LVLPRI3)
+ | (CONF_DMAC_RRLVLEN0 << DMAC_PRICTRL0_RRLVLEN0_Pos) | (CONF_DMAC_RRLVLEN1 << DMAC_PRICTRL0_RRLVLEN1_Pos)
+ | (CONF_DMAC_RRLVLEN2 << DMAC_PRICTRL0_RRLVLEN2_Pos) | (CONF_DMAC_RRLVLEN3 << DMAC_PRICTRL0_RRLVLEN3_Pos));
+ hri_dmac_write_BASEADDR_reg(DMAC, (uint32_t)_descriptor_section);
+ hri_dmac_write_WRBADDR_reg(DMAC, (uint32_t)_write_back_section);
+
+ for (; i < DMAC_CH_NUM; i++) {
+ hri_dmac_write_CHID_reg(DMAC, i);
+
+ hri_dmac_write_CHCTRLA_RUNSTDBY_bit(DMAC, _cfgs[i].ctrla & DMAC_CHCTRLA_RUNSTDBY);
+
+ hri_dmac_write_CHCTRLB_reg(DMAC, _cfgs[i].ctrlb);
+ hri_dmacdescriptor_write_BTCTRL_reg(&_descriptor_section[i], _cfgs[i].btctrl);
+ hri_dmacdescriptor_write_DESCADDR_reg(&_descriptor_section[i], 0x0);
+ }
+
+ NVIC_DisableIRQ(DMAC_IRQn);
+ NVIC_ClearPendingIRQ(DMAC_IRQn);
+ NVIC_EnableIRQ(DMAC_IRQn);
+
+ hri_dmac_set_CTRL_DMAENABLE_bit(DMAC);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable/disable DMA interrupt
+ */
+void _dma_set_irq_state(const uint8_t channel, const enum _dma_callback_type type, const bool state)
+{
+ hri_dmac_write_CHID_reg(DMAC, channel);
+
+ if (DMA_TRANSFER_COMPLETE_CB == type) {
+ hri_dmac_write_CHINTEN_TCMPL_bit(DMAC, state);
+ } else if (DMA_TRANSFER_ERROR_CB == type) {
+ hri_dmac_write_CHINTEN_TERR_bit(DMAC, state);
+ }
+}
+
+int32_t _dma_set_destination_address(const uint8_t channel, const void *const dst)
+{
+ hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], (uint32_t)dst);
+
+ return ERR_NONE;
+}
+
+int32_t _dma_set_source_address(const uint8_t channel, const void *const src)
+{
+ hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], (uint32_t)src);
+
+ return ERR_NONE;
+}
+
+int32_t _dma_set_next_descriptor(const uint8_t current_channel, const uint8_t next_channel)
+{
+ hri_dmacdescriptor_write_DESCADDR_reg(&_descriptor_section[current_channel],
+ (uint32_t)&_descriptor_section[next_channel]);
+
+ return ERR_NONE;
+}
+
+int32_t _dma_srcinc_enable(const uint8_t channel, const bool enable)
+{
+ hri_dmacdescriptor_write_BTCTRL_SRCINC_bit(&_descriptor_section[channel], enable);
+
+ return ERR_NONE;
+}
+
+int32_t _dma_set_data_amount(const uint8_t channel, const uint32_t amount)
+{
+ uint32_t address = hri_dmacdescriptor_read_DSTADDR_reg(&_descriptor_section[channel]);
+ uint8_t beat_size = hri_dmacdescriptor_read_BTCTRL_BEATSIZE_bf(&_descriptor_section[channel]);
+
+ if (hri_dmacdescriptor_get_BTCTRL_DSTINC_bit(&_descriptor_section[channel])) {
+ hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
+ }
+
+ address = hri_dmacdescriptor_read_SRCADDR_reg(&_descriptor_section[channel]);
+
+ if (hri_dmacdescriptor_get_BTCTRL_SRCINC_bit(&_descriptor_section[channel])) {
+ hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
+ }
+
+ hri_dmacdescriptor_write_BTCNT_reg(&_descriptor_section[channel], amount);
+
+ return ERR_NONE;
+}
+
+int32_t _dma_enable_transaction(const uint8_t channel, const bool software_trigger)
+{
+ hri_dmac_write_CHID_reg(DMAC, channel);
+ hri_dmacdescriptor_set_BTCTRL_VALID_bit(&_descriptor_section[channel]);
+ hri_dmac_set_CHCTRLA_ENABLE_bit(DMAC);
+ if (software_trigger) {
+ hri_dmac_set_SWTRIGCTRL_reg(DMAC, 1 << channel);
+ }
+
+ return ERR_NONE;
+}
+
+int32_t _dma_get_channel_resource(struct _dma_resource **resource, const uint8_t channel)
+{
+ *resource = &_resources[channel];
+
+ return ERR_NONE;
+}
+
+int32_t _dma_dstinc_enable(const uint8_t channel, const bool enable)
+{
+ hri_dmacdescriptor_write_BTCTRL_DSTINC_bit(&_descriptor_section[channel], enable);
+
+ return ERR_NONE;
+}
+
+/**
+ * \internal DMAC interrupt handler
+ */
+static inline void _dmac_handler(void)
+{
+ uint8_t channel = hri_dmac_read_INTPEND_ID_bf(DMAC);
+ uint8_t current_channel = hri_dmac_read_CHID_reg(DMAC);
+ uint8_t flag_status;
+ struct _dma_resource *tmp_resource = &_resources[channel];
+
+ hri_dmac_write_CHID_reg(DMAC, channel);
+ flag_status = hri_dmac_get_CHINTFLAG_reg(DMAC, DMAC_CHINTFLAG_MASK);
+
+ if (flag_status & DMAC_CHINTFLAG_TERR) {
+ hri_dmac_clear_CHINTFLAG_TERR_bit(DMAC);
+ tmp_resource->dma_cb.error(tmp_resource);
+ } else if (flag_status & DMAC_CHINTFLAG_TCMPL) {
+ hri_dmac_clear_CHINTFLAG_TCMPL_bit(DMAC);
+ tmp_resource->dma_cb.transfer_done(tmp_resource);
+ }
+ hri_dmac_write_CHID_reg(DMAC, current_channel);
+}
+
+/**
+ * \brief DMAC interrupt handler
+ */
+void DMAC_Handler(void)
+{
+ _dmac_handler();
+}
+
+#endif /* CONF_DMAC_ENABLE */
diff --git a/watch-library/hardware/hpl/eic/hpl_eic.c b/watch-library/hardware/hpl/eic/hpl_eic.c
new file mode 100644
index 00000000..2bd31615
--- /dev/null
+++ b/watch-library/hardware/hpl/eic/hpl_eic.c
@@ -0,0 +1,255 @@
+
+/**
+ * \file
+ *
+ * \brief EIC related functionality implementation.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <compiler.h>
+#include <hpl_eic_config.h>
+#include <hpl_ext_irq.h>
+#include <string.h>
+#include <utils.h>
+#include <utils_assert.h>
+
+#ifdef __MINGW32__
+#define ffs __builtin_ffs
+#endif
+#if defined(__CC_ARM) || defined(__ICCARM__)
+/* Find the first bit set */
+static int ffs(int v)
+{
+ int i, bit = 1;
+ for (i = 0; i < sizeof(int) * 8; i++) {
+ if (v & bit) {
+ return i + 1;
+ }
+ bit <<= 1;
+ }
+ return 0;
+}
+#endif
+
+/**
+ * \brief Invalid external interrupt and pin numbers
+ */
+#define INVALID_EXTINT_NUMBER 0xFF
+#define INVALID_PIN_NUMBER 0xFFFFFFFF
+
+#ifndef CONFIG_EIC_EXTINT_MAP
+/** Dummy mapping to pass compiling. */
+#define CONFIG_EIC_EXTINT_MAP \
+ { \
+ INVALID_EXTINT_NUMBER, INVALID_PIN_NUMBER \
+ }
+#endif
+
+#define EXT_IRQ_AMOUNT 6
+
+/**
+ * \brief EXTINTx and pin number map
+ */
+struct _eic_map {
+ uint8_t extint;
+ uint32_t pin;
+};
+
+/**
+ * \brief PIN and EXTINT map for enabled external interrupts
+ */
+static const struct _eic_map _map[] = {CONFIG_EIC_EXTINT_MAP};
+
+/**
+ * \brief The callback to upper layer's interrupt processing routine
+ */
+static void (*callback)(const uint32_t pin);
+
+static void _ext_irq_handler(void);
+
+/**
+ * \brief Initialize external interrupt module
+ */
+int32_t _ext_irq_init(void (*cb)(const uint32_t pin))
+{
+ if (!hri_eic_is_syncing(EIC, EIC_SYNCBUSY_SWRST)) {
+ if (hri_eic_get_CTRLA_reg(EIC, EIC_CTRLA_ENABLE)) {
+ hri_eic_clear_CTRLA_ENABLE_bit(EIC);
+ hri_eic_wait_for_sync(EIC, EIC_SYNCBUSY_ENABLE);
+ }
+ hri_eic_write_CTRLA_reg(EIC, EIC_CTRLA_SWRST);
+ }
+ hri_eic_wait_for_sync(EIC, EIC_SYNCBUSY_SWRST);
+
+ hri_eic_write_CTRLA_CKSEL_bit(EIC, CONF_EIC_CKSEL);
+
+ hri_eic_write_NMICTRL_reg(EIC,
+ (CONF_EIC_NMIFILTEN << EIC_NMICTRL_NMIFILTEN_Pos)
+ | EIC_NMICTRL_NMISENSE(CONF_EIC_NMISENSE) | EIC_ASYNCH_ASYNCH(CONF_EIC_NMIASYNCH)
+ | 0);
+
+ hri_eic_write_EVCTRL_reg(EIC,
+ (CONF_EIC_EXTINTEO0 << 0) | (CONF_EIC_EXTINTEO1 << 1) | (CONF_EIC_EXTINTEO2 << 2)
+ | (CONF_EIC_EXTINTEO3 << 3) | (CONF_EIC_EXTINTEO4 << 4) | (CONF_EIC_EXTINTEO5 << 5)
+ | (CONF_EIC_EXTINTEO6 << 6) | (CONF_EIC_EXTINTEO7 << 7) | (CONF_EIC_EXTINTEO8 << 8)
+ | (CONF_EIC_EXTINTEO9 << 9) | (CONF_EIC_EXTINTEO10 << 10) | (CONF_EIC_EXTINTEO11 << 11)
+ | (CONF_EIC_EXTINTEO12 << 12) | (CONF_EIC_EXTINTEO13 << 13)
+ | (CONF_EIC_EXTINTEO14 << 14) | (CONF_EIC_EXTINTEO15 << 15) | 0);
+ hri_eic_write_ASYNCH_reg(EIC,
+ (CONF_EIC_ASYNCH0 << 0) | (CONF_EIC_ASYNCH1 << 1) | (CONF_EIC_ASYNCH2 << 2)
+ | (CONF_EIC_ASYNCH3 << 3) | (CONF_EIC_ASYNCH4 << 4) | (CONF_EIC_ASYNCH5 << 5)
+ | (CONF_EIC_ASYNCH6 << 6) | (CONF_EIC_ASYNCH7 << 7) | (CONF_EIC_ASYNCH8 << 8)
+ | (CONF_EIC_ASYNCH9 << 9) | (CONF_EIC_ASYNCH10 << 10) | (CONF_EIC_ASYNCH11 << 11)
+ | (CONF_EIC_ASYNCH12 << 12) | (CONF_EIC_ASYNCH13 << 13) | (CONF_EIC_ASYNCH14 << 14)
+ | (CONF_EIC_ASYNCH15 << 15) | 0);
+
+ hri_eic_write_CONFIG_reg(EIC,
+ 0,
+ (CONF_EIC_FILTEN0 << EIC_CONFIG_FILTEN0_Pos) | EIC_CONFIG_SENSE0(CONF_EIC_SENSE0)
+ | (CONF_EIC_FILTEN1 << EIC_CONFIG_FILTEN1_Pos) | EIC_CONFIG_SENSE1(CONF_EIC_SENSE1)
+ | (CONF_EIC_FILTEN2 << EIC_CONFIG_FILTEN2_Pos) | EIC_CONFIG_SENSE2(CONF_EIC_SENSE2)
+ | (CONF_EIC_FILTEN3 << EIC_CONFIG_FILTEN3_Pos) | EIC_CONFIG_SENSE3(CONF_EIC_SENSE3)
+ | (CONF_EIC_FILTEN4 << EIC_CONFIG_FILTEN4_Pos) | EIC_CONFIG_SENSE4(CONF_EIC_SENSE4)
+ | (CONF_EIC_FILTEN5 << EIC_CONFIG_FILTEN5_Pos) | EIC_CONFIG_SENSE5(CONF_EIC_SENSE5)
+ | (CONF_EIC_FILTEN6 << EIC_CONFIG_FILTEN6_Pos) | EIC_CONFIG_SENSE6(CONF_EIC_SENSE6)
+ | (CONF_EIC_FILTEN7 << EIC_CONFIG_FILTEN7_Pos) | EIC_CONFIG_SENSE7(CONF_EIC_SENSE7)
+ | 0);
+
+ hri_eic_write_CONFIG_reg(EIC,
+ 1,
+ (CONF_EIC_FILTEN8 << EIC_CONFIG_FILTEN0_Pos) | EIC_CONFIG_SENSE0(CONF_EIC_SENSE8)
+ | (CONF_EIC_FILTEN9 << EIC_CONFIG_FILTEN1_Pos) | EIC_CONFIG_SENSE1(CONF_EIC_SENSE9)
+ | (CONF_EIC_FILTEN10 << EIC_CONFIG_FILTEN2_Pos) | EIC_CONFIG_SENSE2(CONF_EIC_SENSE10)
+ | (CONF_EIC_FILTEN11 << EIC_CONFIG_FILTEN3_Pos) | EIC_CONFIG_SENSE3(CONF_EIC_SENSE11)
+ | (CONF_EIC_FILTEN12 << EIC_CONFIG_FILTEN4_Pos) | EIC_CONFIG_SENSE4(CONF_EIC_SENSE12)
+ | (CONF_EIC_FILTEN13 << EIC_CONFIG_FILTEN5_Pos) | EIC_CONFIG_SENSE5(CONF_EIC_SENSE13)
+ | (CONF_EIC_FILTEN14 << EIC_CONFIG_FILTEN6_Pos) | EIC_CONFIG_SENSE6(CONF_EIC_SENSE14)
+ | (CONF_EIC_FILTEN15 << EIC_CONFIG_FILTEN7_Pos) | EIC_CONFIG_SENSE7(CONF_EIC_SENSE15)
+ | 0);
+
+ hri_eic_set_CTRLA_ENABLE_bit(EIC);
+ NVIC_DisableIRQ(EIC_IRQn);
+ NVIC_ClearPendingIRQ(EIC_IRQn);
+ NVIC_EnableIRQ(EIC_IRQn);
+
+ callback = cb;
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief De-initialize external interrupt module
+ */
+int32_t _ext_irq_deinit(void)
+{
+ NVIC_DisableIRQ(EIC_IRQn);
+ callback = NULL;
+
+ hri_eic_clear_CTRLA_ENABLE_bit(EIC);
+ hri_eic_set_CTRLA_SWRST_bit(EIC);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable / disable external irq
+ */
+int32_t _ext_irq_enable(const uint32_t pin, const bool enable)
+{
+ uint8_t extint = INVALID_EXTINT_NUMBER;
+ uint8_t i = 0;
+
+ for (; i < ARRAY_SIZE(_map); i++) {
+ if (_map[i].pin == pin) {
+ extint = _map[i].extint;
+ break;
+ }
+ }
+ if (INVALID_EXTINT_NUMBER == extint) {
+ return -1;
+ }
+
+ if (enable) {
+ hri_eic_set_INTEN_reg(EIC, 1ul << extint);
+ } else {
+ hri_eic_clear_INTEN_reg(EIC, 1ul << extint);
+ hri_eic_clear_INTFLAG_reg(EIC, 1ul << extint);
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Inter EIC interrupt handler
+ */
+static void _ext_irq_handler(void)
+{
+ volatile uint32_t flags = hri_eic_read_INTFLAG_reg(EIC);
+ int8_t pos;
+ uint32_t pin = INVALID_PIN_NUMBER;
+
+ hri_eic_clear_INTFLAG_reg(EIC, flags);
+
+ ASSERT(callback);
+
+ while (flags) {
+ pos = ffs(flags) - 1;
+ while (-1 != pos) {
+ uint8_t lower = 0, middle, upper = EXT_IRQ_AMOUNT;
+
+ while (upper >= lower) {
+ middle = (upper + lower) >> 1;
+ if (_map[middle].extint == pos) {
+ pin = _map[middle].pin;
+ break;
+ }
+ if (_map[middle].extint < pos) {
+ lower = middle + 1;
+ } else {
+ upper = middle - 1;
+ }
+ }
+
+ if (INVALID_PIN_NUMBER != pin) {
+ callback(pin);
+ }
+ flags &= ~(1ul << pos);
+ pos = ffs(flags) - 1;
+ }
+ flags = hri_eic_read_INTFLAG_reg(EIC);
+ hri_eic_clear_INTFLAG_reg(EIC, flags);
+ }
+}
+
+/**
+ * \brief EIC interrupt handler
+ */
+void EIC_Handler(void)
+{
+ _ext_irq_handler();
+}
diff --git a/watch-library/hardware/hpl/gclk/hpl_gclk.c b/watch-library/hardware/hpl/gclk/hpl_gclk.c
new file mode 100644
index 00000000..be66ef77
--- /dev/null
+++ b/watch-library/hardware/hpl/gclk/hpl_gclk.c
@@ -0,0 +1,164 @@
+
+/**
+ * \file
+ *
+ * \brief Generic Clock Controller related functionality.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_gclk_config.h>
+#include <hpl_gclk_base.h>
+#include <hpl_init.h>
+#include <utils_assert.h>
+
+/* Compatible naming definition */
+#ifndef GCLK_GENCTRL_SRC_DPLL
+#define GCLK_GENCTRL_SRC_DPLL GCLK_GENCTRL_SRC_FDPLL
+#endif
+
+/**
+ * \brief Initializes generators
+ */
+void _gclk_init_generators(void)
+{
+
+#if CONF_GCLK_GENERATOR_0_CONFIG == 1
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 0,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_0_DIV) | (CONF_GCLK_GEN_0_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_0_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_0_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_0_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_0_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_0_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_0_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_1_CONFIG == 1
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 1,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_1_DIV) | (CONF_GCLK_GEN_1_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_1_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_1_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_1_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_1_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_1_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_1_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_2_CONFIG == 1
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 2,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_2_DIV) | (CONF_GCLK_GEN_2_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_2_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_2_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_2_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_2_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_2_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_2_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_3_CONFIG == 1
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 3,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_3_DIV) | (CONF_GCLK_GEN_3_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_3_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_3_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_3_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_3_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_3_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_3_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_4_CONFIG == 1
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 4,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_4_DIV) | (CONF_GCLK_GEN_4_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_4_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_4_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_4_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_4_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_4_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_4_SOURCE);
+#endif
+}
+
+void _gclk_init_generators_by_fref(uint32_t bm)
+{
+
+#if CONF_GCLK_GENERATOR_0_CONFIG == 1
+ if (bm & (1ul << 0)) {
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 0,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_0_DIV) | (CONF_GCLK_GEN_0_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_0_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_0_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_0_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_0_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_0_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_0_SOURCE);
+ }
+#endif
+
+#if CONF_GCLK_GENERATOR_1_CONFIG == 1
+ if (bm & (1ul << 1)) {
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 1,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_1_DIV) | (CONF_GCLK_GEN_1_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_1_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_1_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_1_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_1_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_1_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_1_SOURCE);
+ }
+#endif
+
+#if CONF_GCLK_GENERATOR_2_CONFIG == 1
+ if (bm & (1ul << 2)) {
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 2,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_2_DIV) | (CONF_GCLK_GEN_2_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_2_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_2_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_2_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_2_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_2_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_2_SOURCE);
+ }
+#endif
+
+#if CONF_GCLK_GENERATOR_3_CONFIG == 1
+ if (bm & (1ul << 3)) {
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 3,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_3_DIV) | (CONF_GCLK_GEN_3_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_3_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_3_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_3_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_3_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_3_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_3_SOURCE);
+ }
+#endif
+
+#if CONF_GCLK_GENERATOR_4_CONFIG == 1
+ if (bm & (1ul << 4)) {
+ hri_gclk_write_GENCTRL_reg(
+ GCLK,
+ 4,
+ GCLK_GENCTRL_DIV(CONF_GCLK_GEN_4_DIV) | (CONF_GCLK_GEN_4_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+ | (CONF_GCLK_GEN_4_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_4_OE << GCLK_GENCTRL_OE_Pos)
+ | (CONF_GCLK_GEN_4_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_4_IDC << GCLK_GENCTRL_IDC_Pos)
+ | (CONF_GCLK_GENERATOR_4_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_4_SOURCE);
+ }
+#endif
+}
diff --git a/watch-library/hardware/hpl/gclk/hpl_gclk_base.h b/watch-library/hardware/hpl/gclk/hpl_gclk_base.h
new file mode 100644
index 00000000..3e7d2825
--- /dev/null
+++ b/watch-library/hardware/hpl/gclk/hpl_gclk_base.h
@@ -0,0 +1,87 @@
+/**
+ * \file
+ *
+ * \brief Generic Clock Controller.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef _HPL_GCLK_H_INCLUDED
+#define _HPL_GCLK_H_INCLUDED
+
+#include <compiler.h>
+#ifdef _UNIT_TEST_
+#include <hri_gclk1_v210_mock.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup gclk_group GCLK Hardware Proxy Layer
+ *
+ * \section gclk_hpl_rev Revision History
+ * - v0.0.0.1 Initial Commit
+ *
+ *@{
+ */
+
+/**
+ * \name HPL functions
+ */
+//@{
+/**
+ * \brief Enable clock on the given channel with the given clock source
+ *
+ * This function maps the given clock source to the given clock channel
+ * and enables channel.
+ *
+ * \param[in] channel The channel to enable clock for
+ * \param[in] source The clock source for the given channel
+ */
+static inline void _gclk_enable_channel(const uint8_t channel, const uint8_t source)
+{
+
+ hri_gclk_write_PCHCTRL_reg(GCLK, channel, source | GCLK_PCHCTRL_CHEN);
+}
+
+/**
+ * \brief Initialize GCLK generators by function references
+ * \param[in] bm Bit mapping for referenced generators,
+ * a bit 1 in position triggers generator initialization.
+ */
+void _gclk_init_generators_by_fref(uint32_t bm);
+
+//@}
+/**@}*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HPL_GCLK_H_INCLUDED */
diff --git a/watch-library/hardware/hpl/mclk/hpl_mclk.c b/watch-library/hardware/hpl/mclk/hpl_mclk.c
new file mode 100644
index 00000000..46e7c853
--- /dev/null
+++ b/watch-library/hardware/hpl/mclk/hpl_mclk.c
@@ -0,0 +1,46 @@
+/**
+ * \file
+ *
+ * \brief SAM Main Clock.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <compiler.h>
+#include <hpl_mclk_config.h>
+#include <hpl_init.h>
+
+/**
+ * \brief Initialize master clock generator
+ */
+void _mclk_init(void)
+{
+ void *hw = (void *)MCLK;
+ hri_mclk_write_BUPDIV_reg(hw, MCLK_BUPDIV_BUPDIV(CONF_MCLK_BUPDIV));
+ hri_mclk_write_CPUDIV_reg(hw, MCLK_CPUDIV_CPUDIV(CONF_MCLK_CPUDIV));
+}
diff --git a/watch-library/hardware/hpl/nvmctrl/hpl_nvmctrl.c b/watch-library/hardware/hpl/nvmctrl/hpl_nvmctrl.c
new file mode 100755
index 00000000..c1d42c5e
--- /dev/null
+++ b/watch-library/hardware/hpl/nvmctrl/hpl_nvmctrl.c
@@ -0,0 +1,782 @@
+
+/**
+ * \file
+ *
+ * \brief Non-Volatile Memory Controller
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_flash.h>
+#include <hpl_user_area.h>
+#include <string.h>
+#include <utils_assert.h>
+#include <utils.h>
+#include <hpl_nvmctrl_config.h>
+
+#define NVM_MEMORY ((volatile uint16_t *)FLASH_ADDR)
+
+/**
+ * \brief NVM configuration type
+ */
+struct nvm_configuration {
+ hri_nvmctrl_ctrlb_reg_t ctrlb; /*!< Control B Register */
+};
+
+/**
+ * \brief Array of NVM configurations
+ */
+static struct nvm_configuration _nvm
+ = {(CONF_NVM_CACHE << NVMCTRL_CTRLB_CACHEDIS_Pos) | (CONF_NVM_READ_MODE << NVMCTRL_CTRLB_READMODE_Pos)
+ | (CONF_NVM_SLEEPPRM << NVMCTRL_CTRLB_SLEEPPRM_Pos)};
+
+/*!< Pointer to hpl device */
+static struct _flash_device *_nvm_dev = NULL;
+
+static void _flash_erase_row(void *const hw, const uint32_t dst_addr, uint32_t nvmctrl_cmd);
+static void _flash_program(void *const hw, const uint32_t dst_addr, const uint8_t *buffer, const uint16_t size,
+ uint32_t nvmctrl_cmd);
+
+/**
+ * \brief Initialize NVM
+ */
+int32_t _flash_init(struct _flash_device *const device, void *const hw)
+{
+ ASSERT(device && (hw == NVMCTRL));
+ uint32_t ctrlb;
+
+ device->hw = hw;
+ ctrlb = _nvm.ctrlb & ~(NVMCTRL_CTRLB_RWS_Msk | NVMCTRL_CTRLB_MANW);
+ ctrlb |= hri_nvmctrl_get_CTRLB_reg(device->hw, NVMCTRL_CTRLB_RWS_Msk | NVMCTRL_CTRLB_MANW);
+ hri_nvmctrl_write_CTRLB_reg(device->hw, ctrlb);
+
+ _nvm_dev = device;
+ NVIC_DisableIRQ(NVMCTRL_IRQn);
+ NVIC_ClearPendingIRQ(NVMCTRL_IRQn);
+ NVIC_EnableIRQ(NVMCTRL_IRQn);
+ return ERR_NONE;
+}
+
+/**
+ * \brief De-initialize NVM
+ */
+void _flash_deinit(struct _flash_device *const device)
+{
+ device->hw = NULL;
+ NVIC_DisableIRQ(NVMCTRL_IRQn);
+}
+
+/**
+ * \brief Get the flash page size.
+ */
+uint32_t _flash_get_page_size(struct _flash_device *const device)
+{
+ (void)device;
+ return (uint32_t)NVMCTRL_PAGE_SIZE;
+}
+
+/**
+ * \brief Get the numbers of flash page.
+ */
+uint32_t _flash_get_total_pages(struct _flash_device *const device)
+{
+ (void)device;
+ return (uint32_t)FLASH_NB_OF_PAGES;
+}
+
+/**
+ * \brief Get the number of wait states for read and write operations.
+ */
+uint8_t _flash_get_wait_state(struct _flash_device *const device)
+{
+ return hri_nvmctrl_get_CTRLB_reg(device->hw, NVMCTRL_CTRLB_RWS_Msk);
+}
+
+/**
+ * \brief Set the number of wait states for read and write operations.
+ */
+void _flash_set_wait_state(struct _flash_device *const device, uint8_t state)
+{
+ hri_nvmctrl_write_CTRLB_RWS_bf(device->hw, state);
+}
+
+/**
+ * \brief Reads a number of bytes to a page in the internal Flash.
+ */
+void _flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length)
+{
+ uint32_t nvm_address = src_addr / 2;
+ uint32_t i;
+ uint16_t data;
+
+ /* Check if the module is busy */
+ while (!hri_nvmctrl_get_interrupt_READY_bit(device->hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* Clear flags */
+ hri_nvmctrl_clear_STATUS_reg(device->hw, NVMCTRL_STATUS_MASK);
+
+ /* Check whether byte address is word-aligned*/
+ if (src_addr % 2) {
+ data = NVM_MEMORY[nvm_address++];
+ buffer[0] = data >> 8;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ /* NVM _must_ be accessed as a series of 16-bit words, perform manual copy
+ * to ensure alignment */
+ while (i < length) {
+ data = NVM_MEMORY[nvm_address++];
+ buffer[i] = (data & 0xFF);
+ if (i < (length - 1)) {
+ buffer[i + 1] = (data >> 8);
+ }
+ i += 2;
+ }
+}
+
+/**
+ * \brief Writes a number of bytes to a page in the internal Flash.
+ */
+void _flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
+{
+ uint8_t tmp_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE];
+ uint32_t row_start_addr, row_end_addr;
+ uint32_t i, j, k;
+ uint32_t wr_start_addr = dst_addr;
+
+ do {
+ row_start_addr = wr_start_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
+ row_end_addr = row_start_addr + NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE - 1;
+
+ /* store the erase data into temp buffer before write */
+ for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
+ _flash_read(device, row_start_addr + i * NVMCTRL_PAGE_SIZE, tmp_buffer[i], NVMCTRL_PAGE_SIZE);
+ }
+
+ /* temp buffer update */
+ j = (wr_start_addr - row_start_addr) / NVMCTRL_PAGE_SIZE;
+ k = wr_start_addr - row_start_addr - j * NVMCTRL_PAGE_SIZE;
+ while ((wr_start_addr <= row_end_addr) && (length > 0)) {
+ tmp_buffer[j][k] = *buffer;
+ k = (k + 1) % NVMCTRL_PAGE_SIZE;
+ if (0 == k) {
+ j++;
+ }
+ wr_start_addr++;
+ buffer++;
+ length--;
+ }
+
+ /* erase row before write */
+ _flash_erase_row(device->hw, row_start_addr, NVMCTRL_CTRLA_CMD_ER);
+
+ /* write buffer to flash */
+ for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
+ _flash_program(device->hw,
+ row_start_addr + i * NVMCTRL_PAGE_SIZE,
+ tmp_buffer[i],
+ NVMCTRL_PAGE_SIZE,
+ NVMCTRL_CTRLA_CMD_WP);
+ }
+
+ } while (row_end_addr < (wr_start_addr + length - 1));
+}
+
+/**
+ * \brief Appends a number of bytes in the internal Flash.
+ */
+void _flash_append(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
+{
+ uint32_t page_start_addr = dst_addr & ~(NVMCTRL_PAGE_SIZE - 1);
+ uint32_t size;
+ uint32_t offset = 0;
+
+ if (dst_addr != page_start_addr) {
+ /* Need to write some data to the end of a page */
+ size = min(length, NVMCTRL_PAGE_SIZE - (dst_addr - page_start_addr));
+ _flash_program(device->hw, dst_addr, buffer, size, NVMCTRL_CTRLA_CMD_WP);
+ page_start_addr += NVMCTRL_PAGE_SIZE;
+ offset += size;
+ }
+
+ while (offset < length) {
+ size = min(length - offset, NVMCTRL_PAGE_SIZE);
+ _flash_program(device->hw, page_start_addr, buffer + offset, size, NVMCTRL_CTRLA_CMD_WP);
+ page_start_addr += NVMCTRL_PAGE_SIZE;
+ offset += size;
+ }
+}
+
+/**
+ * \brief Execute erase in the internal flash
+ */
+void _flash_erase(struct _flash_device *const device, uint32_t dst_addr, uint32_t page_nums)
+{
+ uint8_t tmp_buffer[NVMCTRL_PAGE_SIZE];
+ uint32_t row_start_addr;
+ uint32_t i;
+
+ row_start_addr = dst_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
+
+ memset(tmp_buffer, 0xFF, NVMCTRL_PAGE_SIZE);
+
+ /* when address is not aligned with row start address */
+ if (dst_addr != row_start_addr) {
+ row_start_addr += NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE;
+ for (i = 0; i < NVMCTRL_ROW_PAGES - 1; i++) {
+ _flash_write(device, dst_addr, tmp_buffer, NVMCTRL_PAGE_SIZE);
+ if (--page_nums == 0) {
+ return;
+ }
+ dst_addr += NVMCTRL_PAGE_SIZE;
+ if (dst_addr == row_start_addr) {
+ break;
+ }
+ }
+ }
+
+ while (page_nums >= NVMCTRL_ROW_PAGES) {
+ _flash_erase_row(device->hw, row_start_addr, NVMCTRL_CTRLA_CMD_ER);
+ row_start_addr += NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE;
+ page_nums -= NVMCTRL_ROW_PAGES;
+ }
+
+ if (page_nums != 0) {
+ for (i = 0; i < page_nums; i++) {
+ _flash_write(device, row_start_addr, tmp_buffer, NVMCTRL_PAGE_SIZE);
+ row_start_addr += NVMCTRL_PAGE_SIZE;
+ }
+ }
+}
+
+/**
+ * \brief Execute lock in the internal flash
+ */
+int32_t _flash_lock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums)
+{
+ uint32_t region_pages;
+ uint32_t row_start_addr;
+
+ region_pages = (uint32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
+ row_start_addr = dst_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
+
+ if ((page_nums != region_pages) || (dst_addr != row_start_addr)) {
+ return ERR_INVALID_ARG;
+ }
+
+ while (!hri_nvmctrl_get_interrupt_READY_bit(device->hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* Clear flags */
+ hri_nvmctrl_clear_STATUS_reg(device->hw, NVMCTRL_STATUS_MASK);
+
+ hri_nvmctrl_write_ADDR_reg(device->hw, dst_addr / 2);
+ hri_nvmctrl_write_CTRLA_reg(device->hw, NVMCTRL_CTRLA_CMD_LR | NVMCTRL_CTRLA_CMDEX_KEY);
+
+ return (int32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
+}
+
+/**
+ * \brief Execute unlock in the internal flash
+ */
+int32_t _flash_unlock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums)
+{
+ uint32_t region_pages;
+ uint32_t row_start_addr;
+
+ region_pages = (uint32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
+ row_start_addr = dst_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
+
+ if ((page_nums != region_pages) || (dst_addr != row_start_addr)) {
+ return ERR_INVALID_ARG;
+ }
+
+ while (!hri_nvmctrl_get_interrupt_READY_bit(device->hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* Clear flags */
+ hri_nvmctrl_clear_STATUS_reg(device->hw, NVMCTRL_STATUS_MASK);
+
+ hri_nvmctrl_write_ADDR_reg(device->hw, dst_addr / 2);
+ hri_nvmctrl_write_CTRLA_reg(device->hw, NVMCTRL_CTRLA_CMD_UR | NVMCTRL_CTRLA_CMDEX_KEY);
+
+ return (int32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
+}
+
+/**
+ * \brief check whether the region which is pointed by address
+ */
+bool _flash_is_locked(struct _flash_device *const device, const uint32_t dst_addr)
+{
+ uint16_t region_id;
+
+ /* Get region for given page */
+ region_id = dst_addr / (NVMCTRL_FLASH_SIZE / 16);
+
+ return !(hri_nvmctrl_get_LOCK_reg(device->hw, 1 << region_id));
+}
+
+/**
+ * \brief Enable/disable Flash interrupt
+ */
+void _flash_set_irq_state(struct _flash_device *const device, const enum _flash_cb_type type, const bool state)
+{
+ ASSERT(device);
+
+ if (FLASH_DEVICE_CB_READY == type) {
+ hri_nvmctrl_write_INTEN_READY_bit(device->hw, state);
+ } else if (FLASH_DEVICE_CB_ERROR == type) {
+ hri_nvmctrl_write_INTEN_ERROR_bit(device->hw, state);
+ }
+}
+
+/**
+ * \internal erase a row in flash
+ * \param[in] hw The pointer to hardware instance
+ * \param[in] dst_addr Destination page address to erase
+ */
+static void _flash_erase_row(void *const hw, const uint32_t dst_addr, uint32_t nvmctrl_cmd)
+{
+ while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* Clear flags */
+ hri_nvmctrl_clear_STATUS_reg(hw, NVMCTRL_STATUS_MASK);
+
+ /* Set address and command */
+ hri_nvmctrl_write_ADDR_reg(hw, dst_addr / 2);
+ hri_nvmctrl_write_CTRLA_reg(hw, nvmctrl_cmd | NVMCTRL_CTRLA_CMDEX_KEY);
+}
+
+/**
+ * \internal write a page in flash
+ * \param[in] hw The pointer to hardware instance
+ * \param[in] dst_addr Destination page address to write
+ * \param[in] buffer Pointer to buffer where the data to
+ * write is stored
+ * \param[in] size The size of data to write to a page
+ */
+static void _flash_program(void *const hw, const uint32_t dst_addr, const uint8_t *buffer, const uint16_t size,
+ uint32_t nvmctrl_cmd)
+{
+ ASSERT(!(dst_addr % 2));
+
+ uint32_t nvm_address = dst_addr / 2;
+ uint16_t i, data;
+
+ while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY);
+
+ while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* Clear flags */
+ hri_nvmctrl_clear_STATUS_reg(hw, NVMCTRL_STATUS_MASK);
+
+ for (i = 0; i < size; i += 2) {
+ data = buffer[i];
+ if (i < NVMCTRL_PAGE_SIZE - 1) {
+ data |= (buffer[i + 1] << 8);
+ }
+ NVM_MEMORY[nvm_address++] = data;
+ }
+
+ while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
+ /* Wait until this module isn't busy */
+ }
+
+ hri_nvmctrl_write_ADDR_reg(hw, dst_addr / 2);
+ hri_nvmctrl_write_CTRLA_reg(hw, nvmctrl_cmd | NVMCTRL_CTRLA_CMDEX_KEY);
+}
+
+/**
+ * \internal NVM interrupt handler
+ */
+void NVMCTRL_Handler(void)
+{
+ void *const hw = _nvm_dev->hw;
+
+ if (hri_nvmctrl_get_interrupt_READY_bit(hw)) {
+ if (NULL != _nvm_dev->flash_cb.ready_cb) {
+ _nvm_dev->flash_cb.ready_cb(_nvm_dev);
+ }
+ } else if (hri_nvmctrl_get_interrupt_ERROR_bit(hw)) {
+ hri_nvmctrl_clear_interrupt_ERROR_bit(hw);
+ if (NULL != _nvm_dev->flash_cb.error_cb) {
+ _nvm_dev->flash_cb.error_cb(_nvm_dev);
+ }
+ }
+}
+
+/*
+The NVM User Row contains calibration data that are automatically read at device
+power on.
+The NVM User Row can be read at address 0x804000.
+*/
+#ifndef _NVM_USER_ROW_BASE
+#define _NVM_USER_ROW_BASE 0x804000
+#endif
+#define _NVM_USER_ROW_N_BITS 64
+#define _NVM_USER_ROW_N_BYTES (_NVM_USER_ROW_N_BITS / 8)
+#define _NVM_USER_ROW_END (((uint8_t *)_NVM_USER_ROW_BASE) + _NVM_USER_ROW_N_BYTES - 1)
+#define _IS_NVM_USER_ROW(b) \
+ (((uint8_t *)(b) >= (uint8_t *)(_NVM_USER_ROW_BASE)) && ((uint8_t *)(b) <= (uint8_t *)(_NVM_USER_ROW_END)))
+#define _IN_NVM_USER_ROW(b, o) (((uint8_t *)(b) + (o)) <= (uint8_t *)(_NVM_USER_ROW_END))
+
+/*
+The NVM Software Calibration Area can be read at address 0x806020.
+The NVM Software Calibration Area can not be written.
+*/
+#ifndef _NVM_SW_CALIB_AREA_BASE
+#define _NVM_SW_CALIB_AREA_BASE 0x806020
+#endif
+#define _NVM_SW_CALIB_AREA_N_BITS 128
+#define _NVM_SW_CALIB_AREA_N_BYTES (_NVM_SW_CALIB_AREA_N_BITS / 8)
+#define _NVM_SW_CALIB_AREA_END (((uint8_t *)_NVM_SW_CALIB_AREA_BASE) + _NVM_SW_CALIB_AREA_N_BYTES - 1)
+#define _IS_NVM_SW_CALIB_AREA(b) \
+ (((uint8_t *)(b) >= (uint8_t *)_NVM_SW_CALIB_AREA_BASE) && ((uint8_t *)(b) <= (uint8_t *)_NVM_SW_CALIB_AREA_END))
+#define _IN_NVM_SW_CALIB_AREA(b, o) (((uint8_t *)(b) + (o)) <= (uint8_t *)(_NVM_SW_CALIB_AREA_END))
+
+/**
+ * \internal Read left aligned data bits
+ * \param[in] base Base address for the data
+ * \param[in] bit_offset Offset for the bitfield start
+ * \param[in] n_bits Number of bits in the bitfield
+ */
+static inline uint32_t _user_area_read_l32_bits(const volatile uint32_t *base, const uint32_t bit_offset,
+ const uint8_t n_bits)
+{
+ return base[bit_offset >> 5] & ((1 << n_bits) - 1);
+}
+
+/**
+ * \internal Read right aligned data bits
+ * \param[in] base Base address for the data
+ * \param[in] bit_offset Offset for the bitfield start
+ * \param[in] n_bits Number of bits in the bitfield
+ */
+static inline uint32_t _user_area_read_r32_bits(const volatile uint32_t *base, const uint32_t bit_offset,
+ const uint8_t n_bits)
+{
+ return (base[bit_offset >> 5] >> (bit_offset & 0x1F)) & ((1 << n_bits) - 1);
+}
+
+int32_t _user_area_read(const void *base, const uint32_t offset, uint8_t *buf, uint32_t size)
+{
+ ASSERT(buf);
+
+ /** Parameter check. */
+ if (_IS_NVM_USER_ROW(base)) {
+ if (!_IN_NVM_USER_ROW(base, offset)) {
+ return ERR_BAD_ADDRESS;
+ }
+ /* Cut off if request too many bytes */
+ if (!_IN_NVM_USER_ROW(base, offset + size - 1)) {
+ return ERR_INVALID_ARG;
+ }
+ } else if (_IS_NVM_SW_CALIB_AREA(base)) {
+ if (!_IN_NVM_SW_CALIB_AREA(base, offset)) {
+ return ERR_BAD_ADDRESS;
+ }
+ /* Cut off if request too many bytes */
+ if (!_IN_NVM_SW_CALIB_AREA(base, offset + size - 1)) {
+ return ERR_INVALID_ARG;
+ }
+ } else {
+ return ERR_UNSUPPORTED_OP;
+ }
+
+ /* Copy data */
+ memcpy(buf, ((uint8_t *)base) + offset, size);
+ return ERR_NONE;
+}
+
+uint32_t _user_area_read_bits(const void *base, const uint32_t bit_offset, const uint8_t n_bits)
+{
+ volatile uint32_t *mem_base = (volatile uint32_t *)base;
+ uint32_t l_off, l_bits;
+ uint32_t r_off, r_bits;
+
+ /** Parameter check. */
+ if (_IS_NVM_USER_ROW(base)) {
+ ASSERT(_IN_NVM_USER_ROW(base, bit_offset >> 3) && _IN_NVM_USER_ROW(base, (bit_offset + n_bits - 1) >> 3));
+ } else if (_IS_NVM_SW_CALIB_AREA(base)) {
+ ASSERT(_IN_NVM_SW_CALIB_AREA(base, bit_offset >> 3)
+ && _IN_NVM_SW_CALIB_AREA(base, (bit_offset + n_bits - 1) >> 3));
+ } else {
+ ASSERT(false);
+ }
+
+ /* Since the bitfield can cross 32-bits boundaries,
+ * left and right bits are read from 32-bit aligned address
+ * and then combined together. */
+ l_off = bit_offset & (~(32 - 1));
+ r_off = l_off + 32;
+ l_bits = 32 - (bit_offset & (32 - 1));
+ if (n_bits > l_bits) {
+ r_bits = n_bits - l_bits;
+ } else {
+ l_bits = n_bits;
+ r_bits = 0;
+ }
+ return _user_area_read_r32_bits(mem_base, bit_offset, l_bits)
+ + (_user_area_read_l32_bits(mem_base, r_off, r_bits) << l_bits);
+}
+
+/** \internal Write 64-bit user row
+ * \param[in] _row Pointer to 64-bit user row data.
+ */
+static int32_t _user_row_write_exec(const uint32_t *_row)
+{
+ Nvmctrl *hw = NVMCTRL;
+ uint32_t ctrlb = hri_nvmctrl_read_CTRLB_reg(NVMCTRL);
+
+ /* Denie if Security Bit is set */
+ if (hri_nvmctrl_get_STATUS_reg(hw, NVMCTRL_STATUS_SB)) {
+ return ERR_DENIED;
+ }
+
+ /* Do Save */
+
+ /* - Prepare. */
+ while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
+ /* Wait until this module isn't busy */
+ }
+ hri_nvmctrl_clear_STATUS_reg(hw, NVMCTRL_STATUS_MASK);
+ hri_nvmctrl_set_CTRLB_MANW_bit(hw);
+
+ /* - Erase AUX row. */
+ hri_nvmctrl_write_ADDR_reg(hw, (hri_nvmctrl_addr_reg_t)(_NVM_USER_ROW_BASE / 2));
+ hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_EAR | NVMCTRL_CTRLA_CMDEX_KEY);
+ while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* - Page buffer clear & write. */
+ hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY);
+ while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
+ /* Wait until this module isn't busy */
+ }
+ *((uint32_t *)NVMCTRL_AUX0_ADDRESS) = _row[0];
+ *(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1) = _row[1];
+
+ /* - Write AUX row. */
+ hri_nvmctrl_write_ADDR_reg(hw, (hri_nvmctrl_addr_reg_t)(_NVM_USER_ROW_BASE / 2));
+ hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_WAP | NVMCTRL_CTRLA_CMDEX_KEY);
+ while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
+ /* Wait until this module isn't busy */
+ }
+
+ /* Restore CTRLB */
+ hri_nvmctrl_write_CTRLB_reg(NVMCTRL, ctrlb);
+
+ return ERR_NONE;
+}
+
+int32_t _user_area_write(void *base, const uint32_t offset, const uint8_t *buf, const uint32_t size)
+{
+ uint32_t _row[2]; /* Copy of user row. */
+
+ /** Parameter check. */
+ if (_IS_NVM_USER_ROW(base)) {
+ if (!_IN_NVM_USER_ROW(base, offset)) {
+ return ERR_BAD_ADDRESS;
+ } else if (!_IN_NVM_USER_ROW(base, offset + size - 1)) {
+ return ERR_INVALID_ARG;
+ }
+ } else if (_IS_NVM_SW_CALIB_AREA(base)) {
+ return ERR_DENIED;
+ } else {
+ return ERR_UNSUPPORTED_OP;
+ }
+
+ memcpy(_row, base, 8); /* Store previous data. */
+ memcpy((uint8_t *)_row + offset, buf, size); /* Modify with buf data. */
+
+ return _user_row_write_exec(_row);
+}
+
+int32_t _user_area_write_bits(void *base, const uint32_t bit_offset, const uint32_t bits, const uint8_t n_bits)
+{
+ uint32_t _row[2]; /* Copy of user row. */
+ uint32_t l_off, l_bits;
+ uint32_t r_off, r_bits;
+
+ /** Parameter check. */
+ if (_IS_NVM_USER_ROW(base)) {
+ if (!_IN_NVM_USER_ROW(base, bit_offset >> 3)) {
+ return ERR_BAD_ADDRESS;
+ } else if (!_IN_NVM_USER_ROW(base, (bit_offset + n_bits - 1) >> 3)) {
+ return ERR_INVALID_ARG;
+ }
+ } else if (_IS_NVM_SW_CALIB_AREA(base)) {
+ return ERR_DENIED;
+ } else {
+ return ERR_UNSUPPORTED_OP;
+ }
+
+ /* Since the bitfield can cross 32-bits boundaries,
+ * left and right bits are splitted for 32-bit aligned address
+ * and then saved. */
+ l_off = bit_offset & (~(32 - 1));
+ r_off = l_off + 32;
+ l_bits = 32 - (bit_offset & (32 - 1));
+ if (n_bits > l_bits) {
+ r_bits = n_bits - l_bits;
+ } else {
+ l_bits = n_bits;
+ r_bits = 0;
+ }
+
+ memcpy(_row, base, 8); /* Store previous data. */
+ if (l_bits) {
+ uint32_t l_mask = ((1 << l_bits) - 1) << (bit_offset & (32 - 1));
+ _row[bit_offset >> 5] &= ~l_mask;
+ _row[bit_offset >> 5] |= (bits << (bit_offset & (32 - 1))) & l_mask;
+ }
+ if (r_bits) {
+ uint32_t r_mask = (1 << r_bits) - 1;
+ _row[r_off >> 5] &= ~r_mask;
+ _row[r_off >> 5] |= bits >> l_bits;
+ }
+ return _user_row_write_exec(_row);
+}
+
+/**
+ * \brief Return if given address is in Flash RWWEE array range.
+ */
+static bool _is_valid_rww_flash_address(uint32_t addr)
+{
+#define RWWEE_ADDR_START NVMCTRL_RWW_EEPROM_ADDR
+#define RWWEE_ADDR_END (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES)
+
+ if ((addr < NVMCTRL_RWW_EEPROM_ADDR)
+ || (addr > (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES))) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * \brief Get the RWWEE flash page size.
+ */
+uint32_t _rww_flash_get_page_size(struct _flash_device *const device)
+{
+ (void)device;
+ return (uint32_t)NVMCTRL_PAGE_SIZE;
+}
+
+/**
+ * \brief Get the total page numbers of RWWEE flash.
+ */
+uint32_t _rww_flash_get_total_pages(struct _flash_device *const device)
+{
+ (void)device;
+ return (uint32_t)NVMCTRL_RWWEE_PAGES;
+}
+
+/**
+ * \brief Reads a number of bytes in the internal RWWEE Flash.
+ */
+int32_t _rww_flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length)
+{
+ /* Check if the address is valid */
+ if (!_is_valid_rww_flash_address(src_addr) || !_is_valid_rww_flash_address(src_addr + length)) {
+ return ERR_BAD_ADDRESS;
+ }
+
+ _flash_read(device, src_addr, buffer, length);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Writes a number of bytes in the internal RWWEE Flash.
+ */
+int32_t _rww_flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
+{
+ uint8_t tmp_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE];
+ uint32_t row_start_addr, row_end_addr;
+ uint32_t i, j, k;
+ uint32_t wr_start_addr = dst_addr;
+
+ /* Check if the address is valid */
+ if (!_is_valid_rww_flash_address(dst_addr) || !_is_valid_rww_flash_address(dst_addr + length)) {
+ return ERR_BAD_ADDRESS;
+ }
+
+ do {
+ row_start_addr = wr_start_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
+ row_end_addr = row_start_addr + NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE - 1;
+
+ /* store the erase data into temp buffer before write */
+ for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
+ _rww_flash_read(device, row_start_addr + i * NVMCTRL_PAGE_SIZE, tmp_buffer[i], NVMCTRL_PAGE_SIZE);
+ }
+
+ /* temp buffer update */
+ j = (wr_start_addr - row_start_addr) / NVMCTRL_PAGE_SIZE;
+ k = wr_start_addr - row_start_addr - j * NVMCTRL_PAGE_SIZE;
+ while ((wr_start_addr <= row_end_addr) && (length > 0)) {
+ tmp_buffer[j][k] = *buffer;
+ k = (k + 1) % NVMCTRL_PAGE_SIZE;
+ if (0 == k) {
+ j++;
+ }
+ wr_start_addr++;
+ buffer++;
+ length--;
+ }
+
+ /* erase row before write */
+ _flash_erase_row(device->hw, row_start_addr, NVMCTRL_CTRLA_CMD_RWWEEER);
+
+ /* write buffer to flash */
+ for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
+ _flash_program(device->hw,
+ row_start_addr + i * NVMCTRL_PAGE_SIZE,
+ tmp_buffer[i],
+ NVMCTRL_PAGE_SIZE,
+ NVMCTRL_CTRLA_CMD_RWWEEWP);
+ }
+
+ } while (row_end_addr < (wr_start_addr + length - 1));
+
+ return ERR_NONE;
+}
diff --git a/watch-library/hardware/hpl/osc32kctrl/hpl_osc32kctrl.c b/watch-library/hardware/hpl/osc32kctrl/hpl_osc32kctrl.c
new file mode 100644
index 00000000..b6c624cc
--- /dev/null
+++ b/watch-library/hardware/hpl/osc32kctrl/hpl_osc32kctrl.c
@@ -0,0 +1,86 @@
+/**
+ * \file
+ *
+ * \brief SAM 32k Oscillators Controller.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <hpl_init.h>
+#include <compiler.h>
+#include <hpl_osc32kctrl_config.h>
+
+/**
+ * \brief Initialize 32 kHz clock sources
+ */
+void _osc32kctrl_init_sources(void)
+{
+ void * hw = (void *)OSC32KCTRL;
+ uint16_t calib = 0;
+
+#if CONF_XOSC32K_CONFIG == 1
+ hri_osc32kctrl_write_XOSC32K_reg(
+ hw,
+ OSC32KCTRL_XOSC32K_STARTUP(CONF_XOSC32K_STARTUP) | (CONF_XOSC32K_ONDEMAND << OSC32KCTRL_XOSC32K_ONDEMAND_Pos)
+ | (CONF_XOSC32K_RUNSTDBY << OSC32KCTRL_XOSC32K_RUNSTDBY_Pos)
+ | (CONF_XOSC32K_EN1K << OSC32KCTRL_XOSC32K_EN1K_Pos) | (CONF_XOSC32K_EN32K << OSC32KCTRL_XOSC32K_EN32K_Pos)
+ | (CONF_XOSC32K_XTALEN << OSC32KCTRL_XOSC32K_XTALEN_Pos)
+ | (CONF_XOSC32K_ENABLE << OSC32KCTRL_XOSC32K_ENABLE_Pos));
+
+ hri_osc32kctrl_write_CFDCTRL_reg(hw,
+ (CONF_XOSC32K_CFDEN << OSC32KCTRL_CFDCTRL_CFDEN_Pos)
+ | (CONF_XOSC32K_SWBEN << OSC32KCTRL_CFDCTRL_SWBACK_Pos));
+
+ hri_osc32kctrl_write_EVCTRL_reg(hw, (CONF_XOSC32K_CFDEO << OSC32KCTRL_EVCTRL_CFDEO_Pos));
+#endif
+
+#if CONF_OSCULP32K_CONFIG == 1
+ calib = hri_osc32kctrl_read_OSCULP32K_CALIB_bf(hw);
+ hri_osc32kctrl_write_OSCULP32K_reg(hw,
+#if CONF_OSC32K_CALIB_ENABLE == 1
+ OSC32KCTRL_OSCULP32K_CALIB(CONF_OSC32K_CALIB)
+#else
+ OSC32KCTRL_OSCULP32K_CALIB(calib)
+#endif
+ );
+#endif
+
+#if CONF_XOSC32K_CONFIG
+#if CONF_XOSC32K_ENABLE == 1 && CONF_XOSC32K_ONDEMAND == 0
+ while (!hri_osc32kctrl_get_STATUS_XOSC32KRDY_bit(hw))
+ ;
+#endif
+#if CONF_OSCULP32K_ULP32KSW == 1
+ hri_osc32kctrl_set_OSCULP32K_reg(hw, OSC32KCTRL_OSCULP32K_ULP32KSW);
+ while (!hri_osc32kctrl_get_STATUS_ULP32KSW_bit(hw))
+ ;
+#endif
+#endif
+
+ hri_osc32kctrl_write_RTCCTRL_reg(hw, OSC32KCTRL_RTCCTRL_RTCSEL(CONF_RTCCTRL));
+ (void)calib;
+}
diff --git a/watch-library/hardware/hpl/oscctrl/hpl_oscctrl.c b/watch-library/hardware/hpl/oscctrl/hpl_oscctrl.c
new file mode 100644
index 00000000..e11d70d8
--- /dev/null
+++ b/watch-library/hardware/hpl/oscctrl/hpl_oscctrl.c
@@ -0,0 +1,179 @@
+
+/**
+ * \file
+ *
+ * \brief SAM Oscillators Controller.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <compiler.h>
+#include <hpl_init.h>
+#include <hpl_oscctrl_config.h>
+
+/**
+ * \brief Initialize clock sources
+ */
+void _oscctrl_init_sources(void)
+{
+ void *hw = (void *)OSCCTRL;
+
+#if CONF_XOSC_CONFIG == 1
+ hri_oscctrl_write_XOSCCTRL_reg(
+ hw,
+ OSCCTRL_XOSCCTRL_STARTUP(CONF_XOSC_STARTUP) | (0 << OSCCTRL_XOSCCTRL_AMPGC_Pos)
+ | OSCCTRL_XOSCCTRL_GAIN(CONF_XOSC_GAIN) | (0 << OSCCTRL_XOSCCTRL_ONDEMAND_Pos)
+ | (CONF_XOSC_RUNSTDBY << OSCCTRL_XOSCCTRL_RUNSTDBY_Pos) | (CONF_XOSC_SWBEN << OSCCTRL_XOSCCTRL_SWBEN_Pos)
+ | (CONF_XOSC_CFDEN << OSCCTRL_XOSCCTRL_CFDEN_Pos) | (CONF_XOSC_XTALEN << OSCCTRL_XOSCCTRL_XTALEN_Pos)
+ | (CONF_XOSC_ENABLE << OSCCTRL_XOSCCTRL_ENABLE_Pos));
+
+ hri_oscctrl_write_EVCTRL_reg(hw, (CONF_XOSC_CFDEO << OSCCTRL_EVCTRL_CFDEO_Pos));
+#endif
+
+#if CONF_OSC16M_CONFIG == 1
+ hri_oscctrl_write_OSC16MCTRL_reg(hw,
+ (CONF_OSC16M_ONDEMAND << OSCCTRL_OSC16MCTRL_ONDEMAND_Pos)
+ | (CONF_OSC16M_RUNSTDBY << OSCCTRL_OSC16MCTRL_RUNSTDBY_Pos)
+ | (CONF_OSC16M_ENABLE << OSCCTRL_OSC16MCTRL_ENABLE_Pos)
+ | OSCCTRL_OSC16MCTRL_FSEL(CONF_OSC16M_FSEL));
+#endif
+
+#if CONF_XOSC_CONFIG == 1
+#if CONF_XOSC_ENABLE == 1
+ while (!hri_oscctrl_get_STATUS_XOSCRDY_bit(hw))
+ ;
+#endif
+#if CONF_XOSC_AMPGC == 1
+ hri_oscctrl_set_XOSCCTRL_AMPGC_bit(hw);
+#endif
+#if CONF_XOSC_ONDEMAND == 1
+ hri_oscctrl_set_XOSCCTRL_ONDEMAND_bit(hw);
+#endif
+#endif
+
+#if CONF_OSC16M_CONFIG == 1
+#if CONF_OSC16M_ENABLE == 1
+ while (!hri_oscctrl_get_STATUS_OSC16MRDY_bit(hw))
+ ;
+#endif
+#if CONF_OSC16M_ONDEMAND == 1
+ hri_oscctrl_set_OSC16MCTRL_ONDEMAND_bit(hw);
+#endif
+#endif
+ (void)hw;
+}
+
+void _oscctrl_init_referenced_generators(void)
+{
+ void * hw = (void *)OSCCTRL;
+ hri_oscctrl_dfllctrl_reg_t tmp = 0;
+
+#if CONF_DFLL_CONFIG == 1
+#if CONF_DFLL_OVERWRITE_CALIBRATION == 0
+#define NVM_DFLL_COARSE_POS 26
+#define NVM_DFLL_COARSE_SIZE 6
+ uint32_t coarse;
+ coarse = *((uint32_t *)(NVMCTRL_OTP5)) >> NVM_DFLL_COARSE_POS;
+#endif
+#if CONF_DFLL_USBCRM != 1 && CONF_DFLL_MODE != 0
+ hri_gclk_write_PCHCTRL_reg(GCLK, 0, (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(CONF_DFLL_GCLK));
+#endif
+ hri_oscctrl_write_DFLLCTRL_reg(hw, OSCCTRL_DFLLCTRL_ENABLE);
+ while (!hri_oscctrl_get_STATUS_DFLLRDY_bit(hw))
+ ;
+ hri_oscctrl_write_DFLLMUL_reg(hw,
+ OSCCTRL_DFLLMUL_CSTEP(CONF_DFLL_CSTEP) | OSCCTRL_DFLLMUL_FSTEP(CONF_DFLL_FSTEP)
+ | OSCCTRL_DFLLMUL_MUL(CONF_DFLL_MUL));
+ while (!hri_oscctrl_get_STATUS_DFLLRDY_bit(hw))
+ ;
+
+#if CONF_DFLL_OVERWRITE_CALIBRATION == 0
+ /* FINE is set to fixed value, which defined by DFLL48M Characteristics */
+ hri_oscctrl_write_DFLLVAL_reg(hw, OSCCTRL_DFLLVAL_COARSE(coarse) | OSCCTRL_DFLLVAL_FINE(512));
+#else
+ hri_oscctrl_write_DFLLVAL_reg(hw, OSCCTRL_DFLLVAL_COARSE(CONF_DFLL_COARSE) | OSCCTRL_DFLLVAL_FINE(CONF_DFLL_FINE));
+#endif
+
+ tmp = (CONF_DFLL_WAITLOCK << OSCCTRL_DFLLCTRL_WAITLOCK_Pos) | (CONF_DFLL_BPLCKC << OSCCTRL_DFLLCTRL_BPLCKC_Pos)
+ | (CONF_DFLL_QLDIS << OSCCTRL_DFLLCTRL_QLDIS_Pos) | (CONF_DFLL_CCDIS << OSCCTRL_DFLLCTRL_CCDIS_Pos)
+ | (CONF_DFLL_RUNSTDBY << OSCCTRL_DFLLCTRL_RUNSTDBY_Pos) | (CONF_DFLL_USBCRM << OSCCTRL_DFLLCTRL_USBCRM_Pos)
+ | (CONF_DFLL_LLAW << OSCCTRL_DFLLCTRL_LLAW_Pos) | (CONF_DFLL_STABLE << OSCCTRL_DFLLCTRL_STABLE_Pos)
+ | (CONF_DFLL_MODE << OSCCTRL_DFLLCTRL_MODE_Pos) | (CONF_DFLL_ENABLE << OSCCTRL_DFLLCTRL_ENABLE_Pos);
+ hri_oscctrl_write_DFLLCTRL_reg(hw, tmp);
+
+#endif
+
+#if CONF_DPLL_CONFIG == 1
+#if CONF_DPLL_REFCLK == 2
+ hri_gclk_write_PCHCTRL_reg(GCLK, 1, (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(CONF_DPLL_GCLK));
+#endif
+ hri_oscctrl_write_DPLLRATIO_reg(
+ hw, OSCCTRL_DPLLRATIO_LDRFRAC(CONF_DPLL_LDRFRAC) | OSCCTRL_DPLLRATIO_LDR(CONF_DPLL_LDR));
+ hri_oscctrl_write_DPLLCTRLB_reg(
+ hw,
+ OSCCTRL_DPLLCTRLB_DIV(CONF_DPLL_DIV) | (CONF_DPLL_LBYPASS << OSCCTRL_DPLLCTRLB_LBYPASS_Pos)
+ | OSCCTRL_DPLLCTRLB_LTIME(CONF_DPLL_LTIME) | OSCCTRL_DPLLCTRLB_REFCLK(CONF_DPLL_REFCLK)
+ | (CONF_DPLL_WUF << OSCCTRL_DPLLCTRLB_WUF_Pos) | (CONF_DPLL_LPEN << OSCCTRL_DPLLCTRLB_LPEN_Pos)
+ | OSCCTRL_DPLLCTRLB_FILTER(CONF_DPLL_FILTER));
+ hri_oscctrl_write_DPLLPRESC_reg(hw, OSCCTRL_DPLLPRESC_PRESC(CONF_DPLL_PRESC));
+ hri_oscctrl_write_DPLLCTRLA_reg(hw,
+ (0 << OSCCTRL_DPLLCTRLA_ONDEMAND_Pos)
+ | (CONF_DPLL_RUNSTDBY << OSCCTRL_DPLLCTRLA_RUNSTDBY_Pos)
+ | (CONF_DPLL_ENABLE << OSCCTRL_DPLLCTRLA_ENABLE_Pos));
+#endif
+
+#if CONF_DFLL_CONFIG == 1
+ if (hri_oscctrl_get_DFLLCTRL_MODE_bit(hw)) {
+ hri_oscctrl_status_reg_t status_mask = OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC;
+
+ while (hri_oscctrl_get_STATUS_reg(hw, status_mask) != status_mask)
+ ;
+ } else {
+ while (!hri_oscctrl_get_STATUS_DFLLRDY_bit(hw))
+ ;
+ }
+#if CONF_DFLL_ONDEMAND == 1
+ hri_oscctrl_set_DFLLCTRL_ONDEMAND_bit(hw);
+#endif
+#endif
+
+#if CONF_DPLL_CONFIG == 1
+#if CONF_DPLL_ENABLE == 1
+ while (!(hri_oscctrl_get_DPLLSTATUS_LOCK_bit(hw) || hri_oscctrl_get_DPLLSTATUS_CLKRDY_bit(hw)))
+ ;
+#endif
+#if CONF_DPLL_ONDEMAND == 1
+ hri_oscctrl_set_DPLLCTRLA_ONDEMAND_bit(hw);
+#endif
+#endif
+
+#if CONF_DFLL_CONFIG == 1
+ while (hri_gclk_read_SYNCBUSY_reg(GCLK))
+ ;
+#endif
+ (void)hw, (void)tmp;
+}
diff --git a/watch-library/hardware/hpl/pm/hpl_pm.c b/watch-library/hardware/hpl/pm/hpl_pm.c
new file mode 100644
index 00000000..d6439f1d
--- /dev/null
+++ b/watch-library/hardware/hpl/pm/hpl_pm.c
@@ -0,0 +1,77 @@
+
+/**
+ * \file
+ *
+ * \brief SAM Power manager
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_sleep.h>
+#include <hpl_reset.h>
+#include <hpl_init.h>
+
+/**
+ * \brief Retrieve the reset reason
+ */
+enum reset_reason _get_reset_reason(void)
+{
+ return (enum reset_reason)hri_rstc_read_RCAUSE_reg(RSTC);
+}
+
+/**
+ * \brief Set the sleep mode for the device
+ */
+int32_t _set_sleep_mode(const uint8_t mode)
+{
+ switch (mode) {
+ case 2: /* IDLE */
+ case 4: /* STANDBY */
+ case 5: /* BACKUP */
+ case 6: /* OFF */
+ hri_pm_write_SLEEPCFG_SLEEPMODE_bf(PM, mode);
+ break;
+ default:
+ return ERR_INVALID_ARG;
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Set performance level
+ */
+void _set_performance_level(const uint8_t level)
+{
+ if (hri_pm_get_PLCFG_PLSEL_bf(PM, PM_PLCFG_PLSEL_Msk) != level) {
+ hri_pm_clear_INTFLAG_reg(PM, 0xFF);
+ hri_pm_write_PLCFG_PLSEL_bf(PM, level);
+ while (!hri_pm_read_INTFLAG_reg(PM))
+ ;
+ }
+}
diff --git a/watch-library/hardware/hpl/pm/hpl_pm_base.h b/watch-library/hardware/hpl/pm/hpl_pm_base.h
new file mode 100644
index 00000000..5a50a914
--- /dev/null
+++ b/watch-library/hardware/hpl/pm/hpl_pm_base.h
@@ -0,0 +1,45 @@
+/**
+ * \file
+ *
+ * \brief SAM Power manager
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ */
+
+#ifndef _HPL_PM_BASE_H_INCLUDED
+#define _HPL_PM_BASE_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <utils_assert.h>
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _HPL_PM_BASE_H_INCLUDED */
diff --git a/watch-library/hardware/hpl/port/hpl_gpio_base.h b/watch-library/hardware/hpl/port/hpl_gpio_base.h
new file mode 100644
index 00000000..3cc1981f
--- /dev/null
+++ b/watch-library/hardware/hpl/port/hpl_gpio_base.h
@@ -0,0 +1,170 @@
+
+/**
+ * \file
+ *
+ * \brief SAM PORT.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <compiler.h>
+#include <hpl_gpio.h>
+#include <utils_assert.h>
+#include <hpl_port_config.h>
+
+/**
+ * \brief Set direction on port with mask
+ */
+static inline void _gpio_set_direction(const enum gpio_port port, const uint32_t mask,
+ const enum gpio_direction direction)
+{
+ switch (direction) {
+ case GPIO_DIRECTION_OFF:
+ hri_port_clear_DIR_reg(PORT_IOBUS, port, mask);
+ hri_port_write_WRCONFIG_reg(PORT, port, PORT_WRCONFIG_WRPINCFG | (mask & 0xffff));
+ hri_port_write_WRCONFIG_reg(
+ PORT, port, PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | ((mask & 0xffff0000) >> 16));
+ break;
+
+ case GPIO_DIRECTION_IN:
+ hri_port_clear_DIR_reg(PORT_IOBUS, port, mask);
+ hri_port_write_WRCONFIG_reg(PORT, port, PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_INEN | (mask & 0xffff));
+ hri_port_write_WRCONFIG_reg(PORT,
+ port,
+ PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_INEN
+ | ((mask & 0xffff0000) >> 16));
+ break;
+
+ case GPIO_DIRECTION_OUT:
+ hri_port_set_DIR_reg(PORT_IOBUS, port, mask);
+ hri_port_write_WRCONFIG_reg(PORT, port, PORT_WRCONFIG_WRPINCFG | (mask & 0xffff));
+ hri_port_write_WRCONFIG_reg(
+ PORT, port, PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | ((mask & 0xffff0000) >> 16));
+ break;
+
+ default:
+ ASSERT(false);
+ }
+}
+
+/**
+ * \brief Set output level on port with mask
+ */
+static inline void _gpio_set_level(const enum gpio_port port, const uint32_t mask, const bool level)
+{
+ if (level) {
+ hri_port_set_OUT_reg(PORT_IOBUS, port, mask);
+ } else {
+ hri_port_clear_OUT_reg(PORT_IOBUS, port, mask);
+ }
+}
+
+/**
+ * \brief Change output level to the opposite with mask
+ */
+static inline void _gpio_toggle_level(const enum gpio_port port, const uint32_t mask)
+{
+ hri_port_toggle_OUT_reg(PORT_IOBUS, port, mask);
+}
+
+/**
+ * \brief Get input levels on all port pins
+ */
+static inline uint32_t _gpio_get_level(const enum gpio_port port)
+{
+ uint32_t tmp;
+
+ CRITICAL_SECTION_ENTER();
+
+ uint32_t dir_tmp = hri_port_read_DIR_reg(PORT_IOBUS, port);
+
+ tmp = hri_port_read_IN_reg(PORT, port) & ~dir_tmp;
+ tmp |= hri_port_read_OUT_reg(PORT_IOBUS, port) & dir_tmp;
+
+ CRITICAL_SECTION_LEAVE();
+
+ return tmp;
+}
+
+/**
+ * \brief Set pin pull mode
+ */
+static inline void _gpio_set_pin_pull_mode(const enum gpio_port port, const uint8_t pin,
+ const enum gpio_pull_mode pull_mode)
+{
+ switch (pull_mode) {
+ case GPIO_PULL_OFF:
+ hri_port_clear_PINCFG_PULLEN_bit(PORT, port, pin);
+ break;
+
+ case GPIO_PULL_UP:
+ hri_port_clear_DIR_reg(PORT_IOBUS, port, 1U << pin);
+ hri_port_set_PINCFG_PULLEN_bit(PORT, port, pin);
+ hri_port_set_OUT_reg(PORT_IOBUS, port, 1U << pin);
+ break;
+
+ case GPIO_PULL_DOWN:
+ hri_port_clear_DIR_reg(PORT_IOBUS, port, 1U << pin);
+ hri_port_set_PINCFG_PULLEN_bit(PORT, port, pin);
+ hri_port_clear_OUT_reg(PORT_IOBUS, port, 1U << pin);
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+}
+
+/**
+ * \brief Set gpio pin function
+ */
+static inline void _gpio_set_pin_function(const uint32_t gpio, const uint32_t function)
+{
+ uint8_t port = GPIO_PORT(gpio);
+ uint8_t pin = GPIO_PIN(gpio);
+
+ if (function == GPIO_PIN_FUNCTION_OFF) {
+ hri_port_write_PINCFG_PMUXEN_bit(PORT, port, pin, false);
+
+ } else {
+ hri_port_write_PINCFG_PMUXEN_bit(PORT, port, pin, true);
+
+ if (pin & 1) {
+ // Odd numbered pin
+ hri_port_write_PMUX_PMUXO_bf(PORT, port, pin >> 1, function & 0xffff);
+ } else {
+ // Even numbered pin
+ hri_port_write_PMUX_PMUXE_bf(PORT, port, pin >> 1, function & 0xffff);
+ }
+ }
+}
+
+static inline void _port_event_init()
+{
+ hri_port_set_EVCTRL_reg(PORT, 0, CONF_PORTA_EVCTRL);
+ hri_port_set_EVCTRL_reg(PORT, 1, CONF_PORTB_EVCTRL);
+}
diff --git a/watch-library/hardware/hpl/sercom/hpl_sercom.c b/watch-library/hardware/hpl/sercom/hpl_sercom.c
new file mode 100644
index 00000000..f01476dc
--- /dev/null
+++ b/watch-library/hardware/hpl/sercom/hpl_sercom.c
@@ -0,0 +1,2932 @@
+
+/**
+ * \file
+ *
+ * \brief SAM Serial Communication Interface
+ *
+ * Copyright (c) 2014-2019 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <hpl_dma.h>
+#include <hpl_i2c_m_async.h>
+#include <hpl_i2c_m_sync.h>
+#include <hpl_i2c_s_async.h>
+#include <hpl_sercom_config.h>
+#include <hpl_spi_m_async.h>
+#include <hpl_spi_m_sync.h>
+#include <hpl_spi_s_async.h>
+#include <hpl_spi_s_sync.h>
+#include <hpl_usart_async.h>
+#include <hpl_usart_sync.h>
+#include <utils.h>
+#include <utils_assert.h>
+
+#ifndef CONF_SERCOM_0_USART_ENABLE
+#define CONF_SERCOM_0_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_1_USART_ENABLE
+#define CONF_SERCOM_1_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_2_USART_ENABLE
+#define CONF_SERCOM_2_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_3_USART_ENABLE
+#define CONF_SERCOM_3_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_4_USART_ENABLE
+#define CONF_SERCOM_4_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_5_USART_ENABLE
+#define CONF_SERCOM_5_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_6_USART_ENABLE
+#define CONF_SERCOM_6_USART_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_7_USART_ENABLE
+#define CONF_SERCOM_7_USART_ENABLE 0
+#endif
+
+/** Amount of SERCOM that is used as USART. */
+#define SERCOM_USART_AMOUNT \
+ (CONF_SERCOM_0_USART_ENABLE + CONF_SERCOM_1_USART_ENABLE + CONF_SERCOM_2_USART_ENABLE + CONF_SERCOM_3_USART_ENABLE \
+ + CONF_SERCOM_4_USART_ENABLE + CONF_SERCOM_5_USART_ENABLE + CONF_SERCOM_6_USART_ENABLE \
+ + CONF_SERCOM_7_USART_ENABLE)
+
+/**
+ * \brief Macro is used to fill usart configuration structure based on
+ * its number
+ *
+ * \param[in] n The number of structures
+ */
+#define SERCOM_CONFIGURATION(n) \
+ { \
+ n, \
+ SERCOM_USART_CTRLA_MODE(CONF_SERCOM_##n##_USART_MODE) \
+ | (CONF_SERCOM_##n##_USART_RUNSTDBY << SERCOM_USART_CTRLA_RUNSTDBY_Pos) \
+ | (CONF_SERCOM_##n##_USART_IBON << SERCOM_USART_CTRLA_IBON_Pos) \
+ | SERCOM_USART_CTRLA_SAMPR(CONF_SERCOM_##n##_USART_SAMPR) \
+ | SERCOM_USART_CTRLA_TXPO(CONF_SERCOM_##n##_USART_TXPO) \
+ | SERCOM_USART_CTRLA_RXPO(CONF_SERCOM_##n##_USART_RXPO) \
+ | SERCOM_USART_CTRLA_SAMPA(CONF_SERCOM_##n##_USART_SAMPA) \
+ | SERCOM_USART_CTRLA_FORM(CONF_SERCOM_##n##_USART_FORM) \
+ | (CONF_SERCOM_##n##_USART_CMODE << SERCOM_USART_CTRLA_CMODE_Pos) \
+ | (CONF_SERCOM_##n##_USART_CPOL << SERCOM_USART_CTRLA_CPOL_Pos) \
+ | (CONF_SERCOM_##n##_USART_DORD << SERCOM_USART_CTRLA_DORD_Pos), \
+ SERCOM_USART_CTRLB_CHSIZE(CONF_SERCOM_##n##_USART_CHSIZE) \
+ | (CONF_SERCOM_##n##_USART_SBMODE << SERCOM_USART_CTRLB_SBMODE_Pos) \
+ | (CONF_SERCOM_##n##_USART_CLODEN << SERCOM_USART_CTRLB_COLDEN_Pos) \
+ | (CONF_SERCOM_##n##_USART_SFDE << SERCOM_USART_CTRLB_SFDE_Pos) \
+ | (CONF_SERCOM_##n##_USART_ENC << SERCOM_USART_CTRLB_ENC_Pos) \
+ | (CONF_SERCOM_##n##_USART_PMODE << SERCOM_USART_CTRLB_PMODE_Pos) \
+ | (CONF_SERCOM_##n##_USART_TXEN << SERCOM_USART_CTRLB_TXEN_Pos) \
+ | (CONF_SERCOM_##n##_USART_RXEN << SERCOM_USART_CTRLB_RXEN_Pos), \
+ (uint16_t)(CONF_SERCOM_##n##_USART_BAUD_RATE), CONF_SERCOM_##n##_USART_FRACTIONAL, \
+ CONF_SERCOM_##n##_USART_RECEIVE_PULSE_LENGTH, CONF_SERCOM_##n##_USART_DEBUG_STOP_MODE, \
+ }
+
+/**
+ * \brief SERCOM USART configuration type
+ */
+struct usart_configuration {
+ uint8_t number;
+ hri_sercomusart_ctrla_reg_t ctrl_a;
+ hri_sercomusart_ctrlb_reg_t ctrl_b;
+ hri_sercomusart_baud_reg_t baud;
+ uint8_t fractional;
+ hri_sercomusart_rxpl_reg_t rxpl;
+ hri_sercomusart_dbgctrl_reg_t debug_ctrl;
+};
+
+#if SERCOM_USART_AMOUNT < 1
+/** Dummy array to pass compiling. */
+static struct usart_configuration _usarts[1] = {{0}};
+#else
+/**
+ * \brief Array of SERCOM USART configurations
+ */
+static struct usart_configuration _usarts[] = {
+#if CONF_SERCOM_0_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(0),
+#endif
+#if CONF_SERCOM_1_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(1),
+#endif
+#if CONF_SERCOM_2_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(2),
+#endif
+#if CONF_SERCOM_3_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(3),
+#endif
+#if CONF_SERCOM_4_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(4),
+#endif
+#if CONF_SERCOM_5_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(5),
+#endif
+#if CONF_SERCOM_6_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(6),
+#endif
+#if CONF_SERCOM_7_USART_ENABLE == 1
+ SERCOM_CONFIGURATION(7),
+#endif
+};
+#endif
+
+static uint8_t _get_sercom_index(const void *const hw);
+static uint8_t _sercom_get_irq_num(const void *const hw);
+static void _sercom_init_irq_param(const void *const hw, void *dev);
+static uint8_t _sercom_get_hardware_index(const void *const hw);
+
+static int32_t _usart_init(void *const hw);
+static inline void _usart_deinit(void *const hw);
+static uint16_t _usart_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
+ const enum usart_baud_rate_mode mode, const uint8_t fraction);
+static void _usart_set_baud_rate(void *const hw, const uint32_t baud_rate);
+static void _usart_set_data_order(void *const hw, const enum usart_data_order order);
+static void _usart_set_mode(void *const hw, const enum usart_mode mode);
+static void _usart_set_parity(void *const hw, const enum usart_parity parity);
+static void _usart_set_stop_bits(void *const hw, const enum usart_stop_bits stop_bits);
+static void _usart_set_character_size(void *const hw, const enum usart_character_size size);
+
+/**
+ * \brief Initialize synchronous SERCOM USART
+ */
+int32_t _usart_sync_init(struct _usart_sync_device *const device, void *const hw)
+{
+ ASSERT(device);
+
+ device->hw = hw;
+
+ return _usart_init(hw);
+}
+
+/**
+ * \brief Initialize asynchronous SERCOM USART
+ */
+int32_t _usart_async_init(struct _usart_async_device *const device, void *const hw)
+{
+ int32_t init_status;
+
+ ASSERT(device);
+
+ init_status = _usart_init(hw);
+ if (init_status) {
+ return init_status;
+ }
+ device->hw = hw;
+ _sercom_init_irq_param(hw, (void *)device);
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_EnableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief De-initialize SERCOM USART
+ */
+void _usart_sync_deinit(struct _usart_sync_device *const device)
+{
+ _usart_deinit(device->hw);
+}
+
+/**
+ * \brief De-initialize SERCOM USART
+ */
+void _usart_async_deinit(struct _usart_async_device *const device)
+{
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(device->hw));
+ _usart_deinit(device->hw);
+}
+
+/**
+ * \brief Calculate baud rate register value
+ */
+uint16_t _usart_sync_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
+ const enum usart_baud_rate_mode mode, const uint8_t fraction)
+{
+ return _usart_calculate_baud_rate(baud, clock_rate, samples, mode, fraction);
+}
+
+/**
+ * \brief Calculate baud rate register value
+ */
+uint16_t _usart_async_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
+ const enum usart_baud_rate_mode mode, const uint8_t fraction)
+{
+ return _usart_calculate_baud_rate(baud, clock_rate, samples, mode, fraction);
+}
+
+/**
+ * \brief Enable SERCOM module
+ */
+void _usart_sync_enable(struct _usart_sync_device *const device)
+{
+ hri_sercomusart_set_CTRLA_ENABLE_bit(device->hw);
+}
+
+/**
+ * \brief Enable SERCOM module
+ */
+void _usart_async_enable(struct _usart_async_device *const device)
+{
+ hri_sercomusart_set_CTRLA_ENABLE_bit(device->hw);
+}
+
+/**
+ * \brief Disable SERCOM module
+ */
+void _usart_sync_disable(struct _usart_sync_device *const device)
+{
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(device->hw);
+}
+
+/**
+ * \brief Disable SERCOM module
+ */
+void _usart_async_disable(struct _usart_async_device *const device)
+{
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(device->hw);
+}
+
+/**
+ * \brief Set baud rate
+ */
+void _usart_sync_set_baud_rate(struct _usart_sync_device *const device, const uint32_t baud_rate)
+{
+ _usart_set_baud_rate(device->hw, baud_rate);
+}
+
+/**
+ * \brief Set baud rate
+ */
+void _usart_async_set_baud_rate(struct _usart_async_device *const device, const uint32_t baud_rate)
+{
+ _usart_set_baud_rate(device->hw, baud_rate);
+}
+
+/**
+ * \brief Set data order
+ */
+void _usart_sync_set_data_order(struct _usart_sync_device *const device, const enum usart_data_order order)
+{
+ _usart_set_data_order(device->hw, order);
+}
+
+/**
+ * \brief Set data order
+ */
+void _usart_async_set_data_order(struct _usart_async_device *const device, const enum usart_data_order order)
+{
+ _usart_set_data_order(device->hw, order);
+}
+
+/**
+ * \brief Set mode
+ */
+void _usart_sync_set_mode(struct _usart_sync_device *const device, const enum usart_mode mode)
+{
+ _usart_set_mode(device->hw, mode);
+}
+
+/**
+ * \brief Set mode
+ */
+void _usart_async_set_mode(struct _usart_async_device *const device, const enum usart_mode mode)
+{
+ _usart_set_mode(device->hw, mode);
+}
+
+/**
+ * \brief Set parity
+ */
+void _usart_sync_set_parity(struct _usart_sync_device *const device, const enum usart_parity parity)
+{
+ _usart_set_parity(device->hw, parity);
+}
+
+/**
+ * \brief Set parity
+ */
+void _usart_async_set_parity(struct _usart_async_device *const device, const enum usart_parity parity)
+{
+ _usart_set_parity(device->hw, parity);
+}
+
+/**
+ * \brief Set stop bits mode
+ */
+void _usart_sync_set_stop_bits(struct _usart_sync_device *const device, const enum usart_stop_bits stop_bits)
+{
+ _usart_set_stop_bits(device->hw, stop_bits);
+}
+
+/**
+ * \brief Set stop bits mode
+ */
+void _usart_async_set_stop_bits(struct _usart_async_device *const device, const enum usart_stop_bits stop_bits)
+{
+ _usart_set_stop_bits(device->hw, stop_bits);
+}
+
+/**
+ * \brief Set character size
+ */
+void _usart_sync_set_character_size(struct _usart_sync_device *const device, const enum usart_character_size size)
+{
+ _usart_set_character_size(device->hw, size);
+}
+
+/**
+ * \brief Set character size
+ */
+void _usart_async_set_character_size(struct _usart_async_device *const device, const enum usart_character_size size)
+{
+ _usart_set_character_size(device->hw, size);
+}
+
+/**
+ * \brief Retrieve SERCOM usart status
+ */
+uint32_t _usart_sync_get_status(const struct _usart_sync_device *const device)
+{
+ return hri_sercomusart_read_STATUS_reg(device->hw);
+}
+
+/**
+ * \brief Retrieve SERCOM usart status
+ */
+uint32_t _usart_async_get_status(const struct _usart_async_device *const device)
+{
+ return hri_sercomusart_read_STATUS_reg(device->hw);
+}
+
+/**
+ * \brief Write a byte to the given SERCOM USART instance
+ */
+void _usart_sync_write_byte(struct _usart_sync_device *const device, uint8_t data)
+{
+ hri_sercomusart_write_DATA_reg(device->hw, data);
+}
+
+/**
+ * \brief Write a byte to the given SERCOM USART instance
+ */
+void _usart_async_write_byte(struct _usart_async_device *const device, uint8_t data)
+{
+ hri_sercomusart_write_DATA_reg(device->hw, data);
+}
+
+/**
+ * \brief Read a byte from the given SERCOM USART instance
+ */
+uint8_t _usart_sync_read_byte(const struct _usart_sync_device *const device)
+{
+ return hri_sercomusart_read_DATA_reg(device->hw);
+}
+
+/**
+ * \brief Check if USART is ready to send next byte
+ */
+bool _usart_sync_is_ready_to_send(const struct _usart_sync_device *const device)
+{
+ return hri_sercomusart_get_interrupt_DRE_bit(device->hw);
+}
+
+/**
+ * \brief Check if USART transmission complete
+ */
+bool _usart_sync_is_transmit_done(const struct _usart_sync_device *const device)
+{
+ return hri_sercomusart_get_interrupt_TXC_bit(device->hw);
+}
+
+/**
+ * \brief Check if USART is ready to send next byte
+ */
+bool _usart_async_is_byte_sent(const struct _usart_async_device *const device)
+{
+ return hri_sercomusart_get_interrupt_DRE_bit(device->hw);
+}
+
+/**
+ * \brief Check if there is data received by USART
+ */
+bool _usart_sync_is_byte_received(const struct _usart_sync_device *const device)
+{
+ return hri_sercomusart_get_interrupt_RXC_bit(device->hw);
+}
+
+/**
+ * \brief Set the state of flow control pins
+ */
+void _usart_sync_set_flow_control_state(struct _usart_sync_device *const device,
+ const union usart_flow_control_state state)
+{
+ (void)device;
+ (void)state;
+}
+
+/**
+ * \brief Set the state of flow control pins
+ */
+void _usart_async_set_flow_control_state(struct _usart_async_device *const device,
+ const union usart_flow_control_state state)
+{
+ (void)device;
+ (void)state;
+}
+
+/**
+ * \brief Retrieve the state of flow control pins
+ */
+union usart_flow_control_state _usart_sync_get_flow_control_state(const struct _usart_sync_device *const device)
+{
+ (void)device;
+ union usart_flow_control_state state;
+
+ state.value = 0;
+ state.bit.unavailable = 1;
+ return state;
+}
+
+/**
+ * \brief Retrieve the state of flow control pins
+ */
+union usart_flow_control_state _usart_async_get_flow_control_state(const struct _usart_async_device *const device)
+{
+ (void)device;
+ union usart_flow_control_state state;
+
+ state.value = 0;
+ state.bit.unavailable = 1;
+ return state;
+}
+
+/**
+ * \brief Enable data register empty interrupt
+ */
+void _usart_async_enable_byte_sent_irq(struct _usart_async_device *const device)
+{
+ hri_sercomusart_set_INTEN_DRE_bit(device->hw);
+}
+
+/**
+ * \brief Enable transmission complete interrupt
+ */
+void _usart_async_enable_tx_done_irq(struct _usart_async_device *const device)
+{
+ hri_sercomusart_set_INTEN_TXC_bit(device->hw);
+}
+
+/**
+ * \brief Retrieve ordinal number of the given sercom hardware instance
+ */
+static uint8_t _sercom_get_hardware_index(const void *const hw)
+{
+#ifdef _UNIT_TEST_
+ return ((uint32_t)hw - (uint32_t)SERCOM0) / sizeof(Sercom);
+#endif
+
+ return ((uint32_t)hw - (uint32_t)SERCOM0) >> 10;
+}
+
+/**
+ * \brief Retrieve ordinal number of the given SERCOM USART hardware instance
+ */
+uint8_t _usart_sync_get_hardware_index(const struct _usart_sync_device *const device)
+{
+ return _sercom_get_hardware_index(device->hw);
+}
+
+/**
+ * \brief Retrieve ordinal number of the given SERCOM USART hardware instance
+ */
+uint8_t _usart_async_get_hardware_index(const struct _usart_async_device *const device)
+{
+ return _sercom_get_hardware_index(device->hw);
+}
+
+/**
+ * \brief Enable/disable USART interrupt
+ */
+void _usart_async_set_irq_state(struct _usart_async_device *const device, const enum _usart_async_callback_type type,
+ const bool state)
+{
+ ASSERT(device);
+
+ if (USART_ASYNC_BYTE_SENT == type || USART_ASYNC_TX_DONE == type) {
+ hri_sercomusart_write_INTEN_DRE_bit(device->hw, state);
+ hri_sercomusart_write_INTEN_TXC_bit(device->hw, state);
+ } else if (USART_ASYNC_RX_DONE == type) {
+ hri_sercomusart_write_INTEN_RXC_bit(device->hw, state);
+ } else if (USART_ASYNC_ERROR == type) {
+ hri_sercomusart_write_INTEN_ERROR_bit(device->hw, state);
+ }
+}
+
+/**
+ * \internal Retrieve ordinal number of the given sercom hardware instance
+ *
+ * \param[in] hw The pointer to hardware instance
+
+ * \return The ordinal number of the given sercom hardware instance
+ */
+static uint8_t _get_sercom_index(const void *const hw)
+{
+ uint8_t sercom_offset = _sercom_get_hardware_index(hw);
+ uint8_t i;
+
+ for (i = 0; i < ARRAY_SIZE(_usarts); i++) {
+ if (_usarts[i].number == sercom_offset) {
+ return i;
+ }
+ }
+
+ ASSERT(false);
+ return 0;
+}
+
+/**
+ * \brief Init irq param with the given sercom hardware instance
+ */
+static void _sercom_init_irq_param(const void *const hw, void *dev)
+{
+ (void)hw;
+ (void)dev;
+}
+
+/**
+ * \internal Initialize SERCOM USART
+ *
+ * \param[in] hw The pointer to hardware instance
+ *
+ * \return The status of initialization
+ */
+static int32_t _usart_init(void *const hw)
+{
+ uint8_t i = _get_sercom_index(hw);
+
+ if (!hri_sercomusart_is_syncing(hw, SERCOM_USART_SYNCBUSY_SWRST)) {
+ uint32_t mode = _usarts[i].ctrl_a & SERCOM_USART_CTRLA_MODE_Msk;
+ if (hri_sercomusart_get_CTRLA_reg(hw, SERCOM_USART_CTRLA_ENABLE)) {
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+ }
+ hri_sercomusart_write_CTRLA_reg(hw, SERCOM_USART_CTRLA_SWRST | mode);
+ }
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_SWRST);
+
+ hri_sercomusart_write_CTRLA_reg(hw, _usarts[i].ctrl_a);
+ hri_sercomusart_write_CTRLB_reg(hw, _usarts[i].ctrl_b);
+ if ((_usarts[i].ctrl_a & SERCOM_USART_CTRLA_SAMPR(0x1)) || (_usarts[i].ctrl_a & SERCOM_USART_CTRLA_SAMPR(0x3))) {
+ ((Sercom *)hw)->USART.BAUD.FRAC.BAUD = _usarts[i].baud;
+ ((Sercom *)hw)->USART.BAUD.FRAC.FP = _usarts[i].fractional;
+ } else {
+ hri_sercomusart_write_BAUD_reg(hw, _usarts[i].baud);
+ }
+
+ hri_sercomusart_write_RXPL_reg(hw, _usarts[i].rxpl);
+ hri_sercomusart_write_DBGCTRL_reg(hw, _usarts[i].debug_ctrl);
+
+ return ERR_NONE;
+}
+
+/**
+ * \internal De-initialize SERCOM USART
+ *
+ * \param[in] hw The pointer to hardware instance
+ */
+static inline void _usart_deinit(void *const hw)
+{
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomusart_set_CTRLA_SWRST_bit(hw);
+}
+
+/**
+ * \internal Calculate baud rate register value
+ *
+ * \param[in] baud Required baud rate
+ * \param[in] clock_rate SERCOM clock frequency
+ * \param[in] samples The number of samples
+ * \param[in] mode USART mode
+ * \param[in] fraction A fraction value
+ *
+ * \return Calculated baud rate register value
+ */
+static uint16_t _usart_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
+ const enum usart_baud_rate_mode mode, const uint8_t fraction)
+{
+ if (USART_BAUDRATE_ASYNCH_ARITHMETIC == mode) {
+ return 65536 - ((uint64_t)65536 * samples * baud) / clock_rate;
+ }
+
+ if (USART_BAUDRATE_ASYNCH_FRACTIONAL == mode) {
+ return clock_rate / baud / samples + SERCOM_USART_BAUD_FRACFP_FP(fraction);
+ }
+
+ if (USART_BAUDRATE_SYNCH == mode) {
+ return clock_rate / baud / 2 - 1;
+ }
+
+ return 0;
+}
+
+/**
+ * \internal Set baud rate
+ *
+ * \param[in] device The pointer to USART device instance
+ * \param[in] baud_rate A baud rate to set
+ */
+static void _usart_set_baud_rate(void *const hw, const uint32_t baud_rate)
+{
+ bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
+
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+ hri_sercomusart_write_BAUD_reg(hw, baud_rate);
+ CRITICAL_SECTION_LEAVE()
+
+ hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
+}
+
+/**
+ * \internal Set data order
+ *
+ * \param[in] device The pointer to USART device instance
+ * \param[in] order A data order to set
+ */
+static void _usart_set_data_order(void *const hw, const enum usart_data_order order)
+{
+ bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
+
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+ hri_sercomusart_write_CTRLA_DORD_bit(hw, order);
+ CRITICAL_SECTION_LEAVE()
+
+ hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
+}
+
+/**
+ * \internal Set mode
+ *
+ * \param[in] device The pointer to USART device instance
+ * \param[in] mode A mode to set
+ */
+static void _usart_set_mode(void *const hw, const enum usart_mode mode)
+{
+ bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
+
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+ hri_sercomusart_write_CTRLA_CMODE_bit(hw, mode);
+ CRITICAL_SECTION_LEAVE()
+
+ hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
+}
+
+/**
+ * \internal Set parity
+ *
+ * \param[in] device The pointer to USART device instance
+ * \param[in] parity A parity to set
+ */
+static void _usart_set_parity(void *const hw, const enum usart_parity parity)
+{
+ bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
+
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+
+ if (USART_PARITY_NONE != parity) {
+ hri_sercomusart_set_CTRLA_FORM_bf(hw, 1);
+ } else {
+ hri_sercomusart_clear_CTRLA_FORM_bf(hw, 1);
+ }
+
+ hri_sercomusart_write_CTRLB_PMODE_bit(hw, parity);
+ CRITICAL_SECTION_LEAVE()
+
+ hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
+}
+
+/**
+ * \internal Set stop bits mode
+ *
+ * \param[in] device The pointer to USART device instance
+ * \param[in] stop_bits A stop bits mode to set
+ */
+static void _usart_set_stop_bits(void *const hw, const enum usart_stop_bits stop_bits)
+{
+ bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
+
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+ hri_sercomusart_write_CTRLB_SBMODE_bit(hw, stop_bits);
+ CRITICAL_SECTION_LEAVE()
+
+ hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
+}
+
+/**
+ * \internal Set character size
+ *
+ * \param[in] device The pointer to USART device instance
+ * \param[in] size A character size to set
+ */
+static void _usart_set_character_size(void *const hw, const enum usart_character_size size)
+{
+ bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
+
+ hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
+ hri_sercomusart_write_CTRLB_CHSIZE_bf(hw, size);
+ CRITICAL_SECTION_LEAVE()
+
+ if (enabled) {
+ hri_sercomusart_set_CTRLA_ENABLE_bit(hw);
+ }
+}
+
+ /* Sercom I2C implementation */
+
+#ifndef CONF_SERCOM_0_I2CM_ENABLE
+#define CONF_SERCOM_0_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_1_I2CM_ENABLE
+#define CONF_SERCOM_1_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_2_I2CM_ENABLE
+#define CONF_SERCOM_2_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_3_I2CM_ENABLE
+#define CONF_SERCOM_3_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_4_I2CM_ENABLE
+#define CONF_SERCOM_4_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_5_I2CM_ENABLE
+#define CONF_SERCOM_5_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_6_I2CM_ENABLE
+#define CONF_SERCOM_6_I2CM_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_7_I2CM_ENABLE
+#define CONF_SERCOM_7_I2CM_ENABLE 0
+#endif
+
+/** Amount of SERCOM that is used as I2C Master. */
+#define SERCOM_I2CM_AMOUNT \
+ (CONF_SERCOM_0_I2CM_ENABLE + CONF_SERCOM_1_I2CM_ENABLE + CONF_SERCOM_2_I2CM_ENABLE + CONF_SERCOM_3_I2CM_ENABLE \
+ + CONF_SERCOM_4_I2CM_ENABLE + CONF_SERCOM_5_I2CM_ENABLE + CONF_SERCOM_6_I2CM_ENABLE + CONF_SERCOM_7_I2CM_ENABLE)
+
+/**
+ * \brief Macro is used to fill i2cm configuration structure based on
+ * its number
+ *
+ * \param[in] n The number of structures
+ */
+#define I2CM_CONFIGURATION(n) \
+ { \
+ (n), \
+ (SERCOM_I2CM_CTRLA_MODE_I2C_MASTER) | (CONF_SERCOM_##n##_I2CM_RUNSTDBY << SERCOM_I2CM_CTRLA_RUNSTDBY_Pos) \
+ | (CONF_SERCOM_##n##_I2CM_SPEED << SERCOM_I2CM_CTRLA_SPEED_Pos) \
+ | (CONF_SERCOM_##n##_I2CM_MEXTTOEN << SERCOM_I2CM_CTRLA_MEXTTOEN_Pos) \
+ | (CONF_SERCOM_##n##_I2CM_SEXTTOEN << SERCOM_I2CM_CTRLA_SEXTTOEN_Pos) \
+ | (CONF_SERCOM_##n##_I2CM_INACTOUT << SERCOM_I2CM_CTRLA_INACTOUT_Pos) \
+ | (CONF_SERCOM_##n##_I2CM_LOWTOUT << SERCOM_I2CM_CTRLA_LOWTOUTEN_Pos) \
+ | (CONF_SERCOM_##n##_I2CM_SDAHOLD << SERCOM_I2CM_CTRLA_SDAHOLD_Pos), \
+ SERCOM_I2CM_CTRLB_SMEN, (uint32_t)(CONF_SERCOM_##n##_I2CM_BAUD_RATE), \
+ CONF_SERCOM_##n##_I2CM_DEBUG_STOP_MODE, CONF_SERCOM_##n##_I2CM_TRISE, CONF_GCLK_SERCOM##n##_CORE_FREQUENCY \
+ }
+
+#define ERROR_FLAG (1 << 7)
+#define SB_FLAG (1 << 1)
+#define MB_FLAG (1 << 0)
+
+#define CMD_STOP 0x3
+#define I2C_IDLE 0x1
+#define I2C_SM 0x0
+#define I2C_FM 0x1
+#define I2C_HS 0x2
+#define TEN_ADDR_FRAME 0x78
+#define TEN_ADDR_MASK 0x3ff
+#define SEVEN_ADDR_MASK 0x7f
+
+/**
+ * \brief SERCOM I2CM configuration type
+ */
+struct i2cm_configuration {
+ uint8_t number;
+ hri_sercomi2cm_ctrla_reg_t ctrl_a;
+ hri_sercomi2cm_ctrlb_reg_t ctrl_b;
+ hri_sercomi2cm_baud_reg_t baud;
+ hri_sercomi2cm_dbgctrl_reg_t dbgctrl;
+ uint16_t trise;
+ uint32_t clk; /* SERCOM peripheral clock frequency */
+};
+
+static inline int32_t _i2c_m_enable_implementation(void *hw);
+static int32_t _i2c_m_sync_init_impl(struct _i2c_m_service *const service, void *const hw);
+
+#if SERCOM_I2CM_AMOUNT < 1
+/** Dummy array to pass compiling. */
+static struct i2cm_configuration _i2cms[1] = {{0}};
+#else
+/**
+ * \brief Array of SERCOM I2CM configurations
+ */
+static struct i2cm_configuration _i2cms[] = {
+#if CONF_SERCOM_0_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(0),
+#endif
+#if CONF_SERCOM_1_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(1),
+#endif
+#if CONF_SERCOM_2_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(2),
+#endif
+#if CONF_SERCOM_3_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(3),
+#endif
+#if CONF_SERCOM_4_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(4),
+#endif
+#if CONF_SERCOM_5_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(5),
+#endif
+#if CONF_SERCOM_6_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(6),
+#endif
+#if CONF_SERCOM_7_I2CM_ENABLE == 1
+ I2CM_CONFIGURATION(7),
+#endif
+};
+#endif
+
+/**
+ * \internal Retrieve ordinal number of the given sercom hardware instance
+ *
+ * \param[in] hw The pointer to hardware instance
+
+ * \return The ordinal number of the given sercom hardware instance
+ */
+static int8_t _get_i2cm_index(const void *const hw)
+{
+ uint8_t sercom_offset = _sercom_get_hardware_index(hw);
+ uint8_t i;
+
+ for (i = 0; i < ARRAY_SIZE(_i2cms); i++) {
+ if (_i2cms[i].number == sercom_offset) {
+ return i;
+ }
+ }
+
+ ASSERT(false);
+ return -1;
+}
+
+static inline void _sercom_i2c_send_stop(void *const hw)
+{
+ hri_sercomi2cm_set_CTRLB_CMD_bf(hw, CMD_STOP);
+}
+
+/**
+ * \brief SERCOM I2CM analyze hardware status and transfer next byte
+ */
+static inline int32_t _sercom_i2c_sync_analyse_flags(void *const hw, uint32_t flags, struct _i2c_m_msg *const msg)
+{
+ int sclsm = hri_sercomi2cm_get_CTRLA_SCLSM_bit(hw);
+ uint16_t status = hri_sercomi2cm_read_STATUS_reg(hw);
+
+ if (flags & MB_FLAG) {
+ /* tx error */
+ if (status & SERCOM_I2CM_STATUS_ARBLOST) {
+ hri_sercomi2cm_clear_interrupt_MB_bit(hw);
+ msg->flags |= I2C_M_FAIL;
+ msg->flags &= ~I2C_M_BUSY;
+
+ if (status & SERCOM_I2CM_STATUS_BUSERR) {
+ return I2C_ERR_BUS;
+ }
+
+ return I2C_ERR_BAD_ADDRESS;
+ } else {
+ if (status & SERCOM_I2CM_STATUS_RXNACK) {
+
+ /* Slave rejects to receive more data */
+ if (msg->len > 0) {
+ msg->flags |= I2C_M_FAIL;
+ }
+
+ if (msg->flags & I2C_M_STOP) {
+ _sercom_i2c_send_stop(hw);
+ }
+
+ msg->flags &= ~I2C_M_BUSY;
+
+ return I2C_NACK;
+ }
+
+ if (msg->flags & I2C_M_TEN) {
+ hri_sercomi2cm_write_ADDR_reg(hw,
+ ((((msg->addr & TEN_ADDR_MASK) >> 8) | TEN_ADDR_FRAME) << 1) | I2C_M_RD
+ | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
+ msg->flags &= ~I2C_M_TEN;
+
+ return I2C_OK;
+ }
+
+ if (msg->len == 0) {
+ if (msg->flags & I2C_M_STOP) {
+ _sercom_i2c_send_stop(hw);
+ }
+
+ msg->flags &= ~I2C_M_BUSY;
+ } else {
+ hri_sercomi2cm_write_DATA_reg(hw, *msg->buffer);
+ msg->buffer++;
+ msg->len--;
+ }
+
+ return I2C_OK;
+ }
+ } else if (flags & SB_FLAG) {
+ if ((msg->len) && !(status & SERCOM_I2CM_STATUS_RXNACK)) {
+ msg->len--;
+
+ /* last byte, send nack */
+ if ((msg->len == 0 && !sclsm) || (msg->len == 1 && sclsm)) {
+ hri_sercomi2cm_set_CTRLB_ACKACT_bit(hw);
+ }
+
+ if (msg->len == 0) {
+ if (msg->flags & I2C_M_STOP) {
+ hri_sercomi2cm_clear_CTRLB_SMEN_bit(hw);
+ _sercom_i2c_send_stop(hw);
+ }
+
+ msg->flags &= ~I2C_M_BUSY;
+ }
+
+ /* Accessing DATA.DATA auto-triggers I2C bus operations.
+ * The operation performed depends on the state of
+ * CTRLB.ACKACT, CTRLB.SMEN
+ **/
+ *msg->buffer++ = hri_sercomi2cm_read_DATA_reg(hw);
+ } else {
+ hri_sercomi2cm_clear_interrupt_SB_bit(hw);
+ return I2C_NACK;
+ }
+
+ hri_sercomi2cm_clear_interrupt_SB_bit(hw);
+ }
+
+ return I2C_OK;
+}
+
+/**
+ * \brief Enable the i2c master module
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_async_enable(struct _i2c_m_async_device *const i2c_dev)
+{
+ ASSERT(i2c_dev);
+
+ return _i2c_m_enable_implementation(i2c_dev->hw);
+}
+
+/**
+ * \brief Disable the i2c master module
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_async_disable(struct _i2c_m_async_device *const i2c_dev)
+{
+ void *hw = i2c_dev->hw;
+
+ ASSERT(i2c_dev);
+ ASSERT(i2c_dev->hw);
+
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ hri_sercomi2cm_clear_CTRLA_ENABLE_bit(hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Set baudrate of master
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ * \param[in] clkrate The clock rate of i2c master, in KHz
+ * \param[in] baudrate The baud rate desired for i2c master, in KHz
+ */
+int32_t _i2c_m_async_set_baudrate(struct _i2c_m_async_device *const i2c_dev, uint32_t clkrate, uint32_t baudrate)
+{
+ uint32_t tmp;
+ void * hw = i2c_dev->hw;
+
+ if (hri_sercomi2cm_get_CTRLA_ENABLE_bit(hw)) {
+ return ERR_DENIED;
+ }
+
+ tmp = _get_i2cm_index(hw);
+ clkrate = _i2cms[tmp].clk / 1000;
+
+ if (i2c_dev->service.mode == I2C_STANDARD_MODE) {
+ tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
+ / (2 * baudrate));
+ hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
+ } else if (i2c_dev->service.mode == I2C_FASTMODE) {
+ tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
+ / (2 * baudrate));
+ hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
+ } else if (i2c_dev->service.mode == I2C_HIGHSPEED_MODE) {
+ tmp = (clkrate - 2 * baudrate) / (2 * baudrate);
+ hri_sercomi2cm_write_BAUD_HSBAUD_bf(hw, tmp);
+ } else {
+ /* error baudrate */
+ return ERR_INVALID_ARG;
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Retrieve IRQ number for the given hardware instance
+ */
+static uint8_t _sercom_get_irq_num(const void *const hw)
+{
+ return SERCOM0_IRQn + _sercom_get_hardware_index(hw);
+}
+
+/**
+ * \brief Initialize sercom i2c module to use in async mode
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_async_init(struct _i2c_m_async_device *const i2c_dev, void *const hw)
+{
+ int32_t init_status;
+
+ ASSERT(i2c_dev);
+
+ i2c_dev->hw = hw;
+
+ init_status = _i2c_m_sync_init_impl(&i2c_dev->service, hw);
+ if (init_status) {
+ return init_status;
+ }
+
+ _sercom_init_irq_param(hw, (void *)i2c_dev);
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_EnableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Deinitialize sercom i2c module
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_async_deinit(struct _i2c_m_async_device *const i2c_dev)
+{
+ ASSERT(i2c_dev);
+
+ hri_sercomi2cm_clear_CTRLA_ENABLE_bit(i2c_dev->hw);
+ hri_sercomi2cm_set_CTRLA_SWRST_bit(i2c_dev->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Transfer the slave address to bus, which will start the transfer
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+static int32_t _sercom_i2c_send_address(struct _i2c_m_async_device *const i2c_dev)
+{
+ void * hw = i2c_dev->hw;
+ struct _i2c_m_msg *msg = &i2c_dev->service.msg;
+ int sclsm = hri_sercomi2cm_get_CTRLA_SCLSM_bit(hw);
+
+ ASSERT(i2c_dev);
+
+ if (msg->len == 1 && sclsm) {
+ hri_sercomi2cm_set_CTRLB_ACKACT_bit(hw);
+ } else {
+ hri_sercomi2cm_clear_CTRLB_ACKACT_bit(hw);
+ }
+
+ /* ten bit address */
+ if (msg->addr & I2C_M_TEN) {
+ if (msg->flags & I2C_M_RD) {
+ msg->flags |= I2C_M_TEN;
+ }
+
+ hri_sercomi2cm_write_ADDR_reg(hw,
+ ((msg->addr & TEN_ADDR_MASK) << 1) | SERCOM_I2CM_ADDR_TENBITEN
+ | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
+ } else {
+ hri_sercomi2cm_write_ADDR_reg(hw,
+ ((msg->addr & SEVEN_ADDR_MASK) << 1) | (msg->flags & I2C_M_RD ? I2C_M_RD : 0x0)
+ | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Transfer data specified by msg
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ * \param[in] msg The pointer to i2c message
+ *
+ * \return Transfer status.
+ * \retval 0 Transfer success
+ * \retval <0 Transfer fail, return the error code
+ */
+int32_t _i2c_m_async_transfer(struct _i2c_m_async_device *i2c_dev, struct _i2c_m_msg *msg)
+{
+ int ret;
+
+ ASSERT(i2c_dev);
+ ASSERT(i2c_dev->hw);
+ ASSERT(msg);
+
+ if (msg->len == 0) {
+ return ERR_NONE;
+ }
+
+ if (i2c_dev->service.msg.flags & I2C_M_BUSY) {
+ return ERR_BUSY;
+ }
+
+ msg->flags |= I2C_M_BUSY;
+ i2c_dev->service.msg = *msg;
+ hri_sercomi2cm_set_CTRLB_SMEN_bit(i2c_dev->hw);
+
+ ret = _sercom_i2c_send_address(i2c_dev);
+
+ if (ret) {
+ i2c_dev->service.msg.flags &= ~I2C_M_BUSY;
+
+ return ret;
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Set callback to be called in interrupt handler
+ *
+ * \param[in] i2c_dev The pointer to master i2c device
+ * \param[in] type The callback type
+ * \param[in] func The callback function pointer
+ */
+int32_t _i2c_m_async_register_callback(struct _i2c_m_async_device *const i2c_dev, enum _i2c_m_async_callback_type type,
+ FUNC_PTR func)
+{
+ switch (type) {
+ case I2C_M_ASYNC_DEVICE_ERROR:
+ i2c_dev->cb.error = (_i2c_error_cb_t)func;
+ break;
+ case I2C_M_ASYNC_DEVICE_TX_COMPLETE:
+ i2c_dev->cb.tx_complete = (_i2c_complete_cb_t)func;
+ break;
+ case I2C_M_ASYNC_DEVICE_RX_COMPLETE:
+ i2c_dev->cb.rx_complete = (_i2c_complete_cb_t)func;
+ break;
+ default:
+ /* error */
+ break;
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Set stop condition on I2C
+ *
+ * \param i2c_dev Pointer to master i2c device
+ *
+ * \return Operation status
+ * \retval I2C_OK Operation was successfull
+ */
+int32_t _i2c_m_async_send_stop(struct _i2c_m_async_device *const i2c_dev)
+{
+ void *hw = i2c_dev->hw;
+
+ _sercom_i2c_send_stop(hw);
+
+ return I2C_OK;
+}
+
+/**
+ * \brief Get number of bytes left in transfer buffer
+ *
+ * \param i2c_dev Pointer to i2c master device
+ *
+ * \return Bytes left in buffer
+ * \retval =>0 Bytes left in buffer
+ */
+int32_t _i2c_m_async_get_bytes_left(struct _i2c_m_async_device *const i2c_dev)
+{
+ if (i2c_dev->service.msg.flags & I2C_M_BUSY) {
+ return i2c_dev->service.msg.len;
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Initialize sercom i2c module to use in sync mode
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_sync_init(struct _i2c_m_sync_device *const i2c_dev, void *const hw)
+{
+ ASSERT(i2c_dev);
+
+ i2c_dev->hw = hw;
+
+ return _i2c_m_sync_init_impl(&i2c_dev->service, hw);
+}
+
+/**
+ * \brief Deinitialize sercom i2c module
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_sync_deinit(struct _i2c_m_sync_device *const i2c_dev)
+{
+ ASSERT(i2c_dev);
+
+ hri_sercomi2cm_clear_CTRLA_ENABLE_bit(i2c_dev->hw);
+ hri_sercomi2cm_set_CTRLA_SWRST_bit(i2c_dev->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable the i2c master module
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_sync_enable(struct _i2c_m_sync_device *const i2c_dev)
+{
+ ASSERT(i2c_dev);
+
+ return _i2c_m_enable_implementation(i2c_dev->hw);
+}
+
+/**
+ * \brief Disable the i2c master module
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+int32_t _i2c_m_sync_disable(struct _i2c_m_sync_device *const i2c_dev)
+{
+ void *hw = i2c_dev->hw;
+
+ ASSERT(i2c_dev);
+ ASSERT(i2c_dev->hw);
+
+ hri_sercomi2cm_clear_CTRLA_ENABLE_bit(hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Set baudrate of master
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ * \param[in] clkrate The clock rate of i2c master, in KHz
+ * \param[in] baudrate The baud rate desired for i2c master, in KHz
+ */
+int32_t _i2c_m_sync_set_baudrate(struct _i2c_m_sync_device *const i2c_dev, uint32_t clkrate, uint32_t baudrate)
+{
+ uint32_t tmp;
+ void * hw = i2c_dev->hw;
+
+ if (hri_sercomi2cm_get_CTRLA_ENABLE_bit(hw)) {
+ return ERR_DENIED;
+ }
+
+ tmp = _get_i2cm_index(hw);
+ clkrate = _i2cms[tmp].clk / 1000;
+
+ if (i2c_dev->service.mode == I2C_STANDARD_MODE) {
+ tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
+ / (2 * baudrate));
+ hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
+ } else if (i2c_dev->service.mode == I2C_FASTMODE) {
+ tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
+ / (2 * baudrate));
+ hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
+ } else if (i2c_dev->service.mode == I2C_HIGHSPEED_MODE) {
+ tmp = (clkrate - 2 * baudrate) / (2 * baudrate);
+ hri_sercomi2cm_write_BAUD_HSBAUD_bf(hw, tmp);
+ } else {
+ /* error baudrate */
+ return ERR_INVALID_ARG;
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable/disable I2C master interrupt
+ */
+void _i2c_m_async_set_irq_state(struct _i2c_m_async_device *const device, const enum _i2c_m_async_callback_type type,
+ const bool state)
+{
+ if (I2C_M_ASYNC_DEVICE_TX_COMPLETE == type || I2C_M_ASYNC_DEVICE_RX_COMPLETE == type) {
+ hri_sercomi2cm_write_INTEN_SB_bit(device->hw, state);
+ hri_sercomi2cm_write_INTEN_MB_bit(device->hw, state);
+ } else if (I2C_M_ASYNC_DEVICE_ERROR == type) {
+ hri_sercomi2cm_write_INTEN_ERROR_bit(device->hw, state);
+ }
+}
+
+/**
+ * \brief Wait for bus response
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ * \param[in] flags Store the hardware response
+ *
+ * \return Bus response status.
+ * \retval 0 Bus response status OK
+ * \retval <0 Bus response fail
+ */
+inline static int32_t _sercom_i2c_sync_wait_bus(struct _i2c_m_sync_device *const i2c_dev, uint32_t *flags)
+{
+ uint32_t timeout = 65535;
+ void * hw = i2c_dev->hw;
+
+ do {
+ *flags = hri_sercomi2cm_read_INTFLAG_reg(hw);
+
+ if (timeout-- == 0) {
+ return I2C_ERR_BUS;
+ }
+ } while (!(*flags & MB_FLAG) && !(*flags & SB_FLAG));
+
+ return I2C_OK;
+}
+
+/**
+ * \brief Send the slave address to bus, which will start the transfer
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ */
+static int32_t _sercom_i2c_sync_send_address(struct _i2c_m_sync_device *const i2c_dev)
+{
+ void * hw = i2c_dev->hw;
+ struct _i2c_m_msg *msg = &i2c_dev->service.msg;
+ int sclsm = hri_sercomi2cm_get_CTRLA_SCLSM_bit(hw);
+ uint32_t flags;
+
+ ASSERT(i2c_dev);
+
+ if (msg->len == 1 && sclsm) {
+ hri_sercomi2cm_set_CTRLB_ACKACT_bit(hw);
+ } else {
+ hri_sercomi2cm_clear_CTRLB_ACKACT_bit(hw);
+ }
+
+ /* ten bit address */
+ if (msg->addr & I2C_M_TEN) {
+ if (msg->flags & I2C_M_RD) {
+ msg->flags |= I2C_M_TEN;
+ }
+
+ hri_sercomi2cm_write_ADDR_reg(hw,
+ ((msg->addr & TEN_ADDR_MASK) << 1) | SERCOM_I2CM_ADDR_TENBITEN
+ | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
+ } else {
+ hri_sercomi2cm_write_ADDR_reg(hw,
+ ((msg->addr & SEVEN_ADDR_MASK) << 1) | (msg->flags & I2C_M_RD ? I2C_M_RD : 0x0)
+ | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
+ }
+
+ _sercom_i2c_sync_wait_bus(i2c_dev, &flags);
+ return _sercom_i2c_sync_analyse_flags(hw, flags, msg);
+}
+
+/**
+ * \brief Transfer data specified by msg
+ *
+ * \param[in] i2c_dev The pointer to i2c device
+ * \param[in] msg The pointer to i2c message
+ *
+ * \return Transfer status.
+ * \retval 0 Transfer success
+ * \retval <0 Transfer fail or partial fail, return the error code
+ */
+int32_t _i2c_m_sync_transfer(struct _i2c_m_sync_device *const i2c_dev, struct _i2c_m_msg *msg)
+{
+ uint32_t flags;
+ int ret;
+ void * hw = i2c_dev->hw;
+
+ ASSERT(i2c_dev);
+ ASSERT(i2c_dev->hw);
+ ASSERT(msg);
+
+ if (i2c_dev->service.msg.flags & I2C_M_BUSY) {
+ return I2C_ERR_BUSY;
+ }
+
+ msg->flags |= I2C_M_BUSY;
+ i2c_dev->service.msg = *msg;
+ hri_sercomi2cm_set_CTRLB_SMEN_bit(hw);
+
+ ret = _sercom_i2c_sync_send_address(i2c_dev);
+
+ if (ret) {
+ i2c_dev->service.msg.flags &= ~I2C_M_BUSY;
+
+ return ret;
+ }
+
+ while (i2c_dev->service.msg.flags & I2C_M_BUSY) {
+ ret = _sercom_i2c_sync_wait_bus(i2c_dev, &flags);
+
+ if (ret) {
+ if (msg->flags & I2C_M_STOP) {
+ _sercom_i2c_send_stop(hw);
+ }
+
+ i2c_dev->service.msg.flags &= ~I2C_M_BUSY;
+
+ return ret;
+ }
+
+ ret = _sercom_i2c_sync_analyse_flags(hw, flags, &i2c_dev->service.msg);
+ }
+
+ return ret;
+}
+
+int32_t _i2c_m_sync_send_stop(struct _i2c_m_sync_device *const i2c_dev)
+{
+ void *hw = i2c_dev->hw;
+
+ _sercom_i2c_send_stop(hw);
+
+ return I2C_OK;
+}
+
+static inline int32_t _i2c_m_enable_implementation(void *const hw)
+{
+ int timeout = 65535;
+ int timeout_attempt = 4;
+
+ ASSERT(hw);
+
+ /* Enable interrupts */
+ hri_sercomi2cm_set_CTRLA_ENABLE_bit(hw);
+
+ while (hri_sercomi2cm_read_STATUS_BUSSTATE_bf(hw) != I2C_IDLE) {
+ timeout--;
+
+ if (timeout <= 0) {
+ if (--timeout_attempt)
+ timeout = 65535;
+ else
+ return I2C_ERR_BUSY;
+ hri_sercomi2cm_clear_STATUS_reg(hw, SERCOM_I2CM_STATUS_BUSSTATE(I2C_IDLE));
+ }
+ }
+ return ERR_NONE;
+}
+
+static int32_t _i2c_m_sync_init_impl(struct _i2c_m_service *const service, void *const hw)
+{
+ uint8_t i = _get_i2cm_index(hw);
+
+ if (!hri_sercomi2cm_is_syncing(hw, SERCOM_I2CM_SYNCBUSY_SWRST)) {
+ uint32_t mode = _i2cms[i].ctrl_a & SERCOM_I2CM_CTRLA_MODE_Msk;
+ if (hri_sercomi2cm_get_CTRLA_reg(hw, SERCOM_I2CM_CTRLA_ENABLE)) {
+ hri_sercomi2cm_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomi2cm_wait_for_sync(hw, SERCOM_I2CM_SYNCBUSY_ENABLE);
+ }
+ hri_sercomi2cm_write_CTRLA_reg(hw, SERCOM_I2CM_CTRLA_SWRST | mode);
+ }
+ hri_sercomi2cm_wait_for_sync(hw, SERCOM_I2CM_SYNCBUSY_SWRST);
+
+ hri_sercomi2cm_write_CTRLA_reg(hw, _i2cms[i].ctrl_a);
+ hri_sercomi2cm_write_CTRLB_reg(hw, _i2cms[i].ctrl_b);
+ hri_sercomi2cm_write_BAUD_reg(hw, _i2cms[i].baud);
+
+ service->mode = (_i2cms[i].ctrl_a & SERCOM_I2CM_CTRLA_SPEED_Msk) >> SERCOM_I2CM_CTRLA_SPEED_Pos;
+ hri_sercomi2cm_write_ADDR_HS_bit(hw, service->mode < I2C_HS ? 0 : 1);
+
+ service->trise = _i2cms[i].trise;
+
+ return ERR_NONE;
+}
+
+ /* SERCOM I2C slave */
+
+#ifndef CONF_SERCOM_0_I2CS_ENABLE
+#define CONF_SERCOM_0_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_1_I2CS_ENABLE
+#define CONF_SERCOM_1_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_2_I2CS_ENABLE
+#define CONF_SERCOM_2_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_3_I2CS_ENABLE
+#define CONF_SERCOM_3_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_4_I2CS_ENABLE
+#define CONF_SERCOM_4_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_5_I2CS_ENABLE
+#define CONF_SERCOM_5_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_6_I2CS_ENABLE
+#define CONF_SERCOM_6_I2CS_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_7_I2CS_ENABLE
+#define CONF_SERCOM_7_I2CS_ENABLE 0
+#endif
+
+/** Amount of SERCOM that is used as I2C Slave. */
+#define SERCOM_I2CS_AMOUNT \
+ (CONF_SERCOM_0_I2CS_ENABLE + CONF_SERCOM_1_I2CS_ENABLE + CONF_SERCOM_2_I2CS_ENABLE + CONF_SERCOM_3_I2CS_ENABLE \
+ + CONF_SERCOM_4_I2CS_ENABLE + CONF_SERCOM_5_I2CS_ENABLE + CONF_SERCOM_6_I2CS_ENABLE + CONF_SERCOM_7_I2CS_ENABLE)
+
+/**
+ * \brief Macro is used to fill I2C slave configuration structure based on
+ * its number
+ *
+ * \param[in] n The number of structures
+ */
+#define I2CS_CONFIGURATION(n) \
+ { \
+ n, \
+ SERCOM_I2CM_CTRLA_MODE_I2C_SLAVE | (CONF_SERCOM_##n##_I2CS_RUNSTDBY << SERCOM_I2CS_CTRLA_RUNSTDBY_Pos) \
+ | SERCOM_I2CS_CTRLA_SDAHOLD(CONF_SERCOM_##n##_I2CS_SDAHOLD) \
+ | (CONF_SERCOM_##n##_I2CS_SEXTTOEN << SERCOM_I2CS_CTRLA_SEXTTOEN_Pos) \
+ | (CONF_SERCOM_##n##_I2CS_SPEED << SERCOM_I2CS_CTRLA_SPEED_Pos) \
+ | (CONF_SERCOM_##n##_I2CS_SCLSM << SERCOM_I2CS_CTRLA_SCLSM_Pos) \
+ | (CONF_SERCOM_##n##_I2CS_LOWTOUT << SERCOM_I2CS_CTRLA_LOWTOUTEN_Pos), \
+ SERCOM_I2CS_CTRLB_SMEN | SERCOM_I2CS_CTRLB_AACKEN | SERCOM_I2CS_CTRLB_AMODE(CONF_SERCOM_##n##_I2CS_AMODE), \
+ (CONF_SERCOM_##n##_I2CS_GENCEN << SERCOM_I2CS_ADDR_GENCEN_Pos) \
+ | SERCOM_I2CS_ADDR_ADDR(CONF_SERCOM_##n##_I2CS_ADDRESS) \
+ | (CONF_SERCOM_##n##_I2CS_TENBITEN << SERCOM_I2CS_ADDR_TENBITEN_Pos) \
+ | SERCOM_I2CS_ADDR_ADDRMASK(CONF_SERCOM_##n##_I2CS_ADDRESS_MASK) \
+ }
+
+/**
+ * \brief Macro to check 10-bit addressing
+ */
+#define I2CS_7BIT_ADDRESSING_MASK 0x7F
+
+static int32_t _i2c_s_init(void *const hw);
+static int8_t _get_i2c_s_index(const void *const hw);
+static inline void _i2c_s_deinit(void *const hw);
+static int32_t _i2c_s_set_address(void *const hw, const uint16_t address);
+
+/**
+ * \brief SERCOM I2C slave configuration type
+ */
+struct i2cs_configuration {
+ uint8_t number;
+ hri_sercomi2cs_ctrla_reg_t ctrl_a;
+ hri_sercomi2cs_ctrlb_reg_t ctrl_b;
+ hri_sercomi2cs_addr_reg_t address;
+};
+
+#if SERCOM_I2CS_AMOUNT < 1
+/** Dummy array for compiling. */
+static struct i2cs_configuration _i2css[1] = {{0}};
+#else
+/**
+ * \brief Array of SERCOM I2C slave configurations
+ */
+static struct i2cs_configuration _i2css[] = {
+#if CONF_SERCOM_0_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(0),
+#endif
+#if CONF_SERCOM_1_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(1),
+#endif
+#if CONF_SERCOM_2_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(2),
+#endif
+#if CONF_SERCOM_3_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(3),
+#endif
+#if CONF_SERCOM_4_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(4),
+#endif
+#if CONF_SERCOM_5_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(5),
+#endif
+#if CONF_SERCOM_6_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(6),
+#endif
+#if CONF_SERCOM_7_I2CS_ENABLE == 1
+ I2CS_CONFIGURATION(7),
+#endif
+};
+#endif
+
+/**
+ * \brief Initialize synchronous I2C slave
+ */
+int32_t _i2c_s_sync_init(struct _i2c_s_sync_device *const device, void *const hw)
+{
+ int32_t status;
+
+ ASSERT(device);
+
+ status = _i2c_s_init(hw);
+ if (status) {
+ return status;
+ }
+ device->hw = hw;
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Initialize asynchronous I2C slave
+ */
+int32_t _i2c_s_async_init(struct _i2c_s_async_device *const device, void *const hw)
+{
+ int32_t init_status;
+
+ ASSERT(device);
+
+ init_status = _i2c_s_init(hw);
+ if (init_status) {
+ return init_status;
+ }
+
+ device->hw = hw;
+ _sercom_init_irq_param(hw, (void *)device);
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_EnableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+
+ // Enable Address Match and PREC interrupt by default.
+ hri_sercomi2cs_set_INTEN_AMATCH_bit(hw);
+ hri_sercomi2cs_set_INTEN_PREC_bit(hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Deinitialize synchronous I2C
+ */
+int32_t _i2c_s_sync_deinit(struct _i2c_s_sync_device *const device)
+{
+ _i2c_s_deinit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Deinitialize asynchronous I2C
+ */
+int32_t _i2c_s_async_deinit(struct _i2c_s_async_device *const device)
+{
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(device->hw));
+ _i2c_s_deinit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable I2C module
+ */
+int32_t _i2c_s_sync_enable(struct _i2c_s_sync_device *const device)
+{
+ hri_sercomi2cs_set_CTRLA_ENABLE_bit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable I2C module
+ */
+int32_t _i2c_s_async_enable(struct _i2c_s_async_device *const device)
+{
+ hri_sercomi2cs_set_CTRLA_ENABLE_bit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Disable I2C module
+ */
+int32_t _i2c_s_sync_disable(struct _i2c_s_sync_device *const device)
+{
+ hri_sercomi2cs_clear_CTRLA_ENABLE_bit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Disable I2C module
+ */
+int32_t _i2c_s_async_disable(struct _i2c_s_async_device *const device)
+{
+ hri_sercomi2cs_clear_CTRLA_ENABLE_bit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Check if 10-bit addressing mode is on
+ */
+int32_t _i2c_s_sync_is_10bit_addressing_on(const struct _i2c_s_sync_device *const device)
+{
+ return hri_sercomi2cs_get_ADDR_TENBITEN_bit(device->hw);
+}
+
+/**
+ * \brief Check if 10-bit addressing mode is on
+ */
+int32_t _i2c_s_async_is_10bit_addressing_on(const struct _i2c_s_async_device *const device)
+{
+ return hri_sercomi2cs_get_ADDR_TENBITEN_bit(device->hw);
+}
+
+/**
+ * \brief Set I2C slave address
+ */
+int32_t _i2c_s_sync_set_address(struct _i2c_s_sync_device *const device, const uint16_t address)
+{
+ return _i2c_s_set_address(device->hw, address);
+}
+
+/**
+ * \brief Set I2C slave address
+ */
+int32_t _i2c_s_async_set_address(struct _i2c_s_async_device *const device, const uint16_t address)
+{
+ return _i2c_s_set_address(device->hw, address);
+}
+
+/**
+ * \brief Write a byte to the given I2C instance
+ */
+void _i2c_s_sync_write_byte(struct _i2c_s_sync_device *const device, const uint8_t data)
+{
+ hri_sercomi2cs_write_DATA_reg(device->hw, data);
+}
+
+/**
+ * \brief Write a byte to the given I2C instance
+ */
+void _i2c_s_async_write_byte(struct _i2c_s_async_device *const device, const uint8_t data)
+{
+ hri_sercomi2cs_write_DATA_reg(device->hw, data);
+}
+
+/**
+ * \brief Read a byte from the given I2C instance
+ */
+uint8_t _i2c_s_sync_read_byte(const struct _i2c_s_sync_device *const device)
+{
+ return hri_sercomi2cs_read_DATA_reg(device->hw);
+}
+
+/**
+ * \brief Check if I2C is ready to send next byt
+ */
+bool _i2c_s_sync_is_byte_sent(const struct _i2c_s_sync_device *const device)
+{
+ return hri_sercomi2cs_get_interrupt_DRDY_bit(device->hw);
+}
+
+/**
+ * \brief Check if there is data received by I2C
+ */
+bool _i2c_s_sync_is_byte_received(const struct _i2c_s_sync_device *const device)
+{
+ return hri_sercomi2cs_get_interrupt_DRDY_bit(device->hw);
+}
+
+/**
+ * \brief Retrieve I2C slave status
+ */
+i2c_s_status_t _i2c_s_sync_get_status(const struct _i2c_s_sync_device *const device)
+{
+ return hri_sercomi2cs_read_STATUS_reg(device->hw);
+}
+
+/**
+ * \brief Clear the Data Ready interrupt flag
+ */
+int32_t _i2c_s_sync_clear_data_ready_flag(const struct _i2c_s_sync_device *const device)
+{
+ hri_sercomi2cs_clear_INTFLAG_DRDY_bit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Retrieve I2C slave status
+ */
+i2c_s_status_t _i2c_s_async_get_status(const struct _i2c_s_async_device *const device)
+{
+ return hri_sercomi2cs_read_STATUS_reg(device->hw);
+}
+
+/**
+ * \brief Abort data transmission
+ */
+int32_t _i2c_s_async_abort_transmission(const struct _i2c_s_async_device *const device)
+{
+ hri_sercomi2cs_clear_INTEN_DRDY_bit(device->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable/disable I2C slave interrupt
+ */
+int32_t _i2c_s_async_set_irq_state(struct _i2c_s_async_device *const device, const enum _i2c_s_async_callback_type type,
+ const bool state)
+{
+ ASSERT(device);
+
+ if (I2C_S_DEVICE_TX == type || I2C_S_DEVICE_RX_COMPLETE == type) {
+ hri_sercomi2cs_write_INTEN_DRDY_bit(device->hw, state);
+ } else if (I2C_S_DEVICE_ERROR == type) {
+ hri_sercomi2cs_write_INTEN_ERROR_bit(device->hw, state);
+ }
+
+ return ERR_NONE;
+}
+
+/**
+ * \internal Initalize i2c slave hardware
+ *
+ * \param[in] p The pointer to hardware instance
+ *
+ *\ return status of initialization
+ */
+static int32_t _i2c_s_init(void *const hw)
+{
+ int8_t i = _get_i2c_s_index(hw);
+ if (i == -1) {
+ return ERR_INVALID_ARG;
+ }
+
+ if (!hri_sercomi2cs_is_syncing(hw, SERCOM_I2CS_CTRLA_SWRST)) {
+ uint32_t mode = _i2css[i].ctrl_a & SERCOM_I2CS_CTRLA_MODE_Msk;
+ if (hri_sercomi2cs_get_CTRLA_reg(hw, SERCOM_I2CS_CTRLA_ENABLE)) {
+ hri_sercomi2cs_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomi2cs_wait_for_sync(hw, SERCOM_I2CS_SYNCBUSY_ENABLE);
+ }
+ hri_sercomi2cs_write_CTRLA_reg(hw, SERCOM_I2CS_CTRLA_SWRST | mode);
+ }
+ hri_sercomi2cs_wait_for_sync(hw, SERCOM_I2CS_SYNCBUSY_SWRST);
+
+ hri_sercomi2cs_write_CTRLA_reg(hw, _i2css[i].ctrl_a);
+ hri_sercomi2cs_write_CTRLB_reg(hw, _i2css[i].ctrl_b);
+ hri_sercomi2cs_write_ADDR_reg(hw, _i2css[i].address);
+
+ return ERR_NONE;
+}
+
+/**
+ * \internal Retrieve ordinal number of the given sercom hardware instance
+ *
+ * \param[in] hw The pointer to hardware instance
+ *
+ * \return The ordinal number of the given sercom hardware instance
+ */
+static int8_t _get_i2c_s_index(const void *const hw)
+{
+ uint8_t sercom_offset = _sercom_get_hardware_index(hw);
+ uint8_t i;
+
+ for (i = 0; i < ARRAY_SIZE(_i2css); i++) {
+ if (_i2css[i].number == sercom_offset) {
+ return i;
+ }
+ }
+
+ ASSERT(false);
+ return -1;
+}
+
+/**
+ * \internal De-initialize i2c slave
+ *
+ * \param[in] hw The pointer to hardware instance
+ */
+static inline void _i2c_s_deinit(void *const hw)
+{
+ hri_sercomi2cs_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomi2cs_set_CTRLA_SWRST_bit(hw);
+}
+
+/**
+ * \internal De-initialize i2c slave
+ *
+ * \param[in] hw The pointer to hardware instance
+ * \param[in] address Address to set
+ */
+static int32_t _i2c_s_set_address(void *const hw, const uint16_t address)
+{
+ bool enabled;
+
+ enabled = hri_sercomi2cs_get_CTRLA_ENABLE_bit(hw);
+
+ CRITICAL_SECTION_ENTER()
+ hri_sercomi2cs_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomi2cs_write_ADDR_ADDR_bf(hw, address);
+ CRITICAL_SECTION_LEAVE()
+
+ if (enabled) {
+ hri_sercomi2cs_set_CTRLA_ENABLE_bit(hw);
+ }
+
+ return ERR_NONE;
+}
+
+ /* Sercom SPI implementation */
+
+#ifndef SERCOM_USART_CTRLA_MODE_SPI_SLAVE
+#define SERCOM_USART_CTRLA_MODE_SPI_SLAVE (2 << 2)
+#endif
+
+#define SPI_DEV_IRQ_MODE 0x8000
+
+#define _SPI_CS_PORT_EXTRACT(cs) (((cs) >> 0) & 0xFF)
+#define _SPI_CS_PIN_EXTRACT(cs) (((cs) >> 8) & 0xFF)
+
+COMPILER_PACK_SET(1)
+/** Initialization configuration of registers. */
+struct sercomspi_regs_cfg {
+ uint32_t ctrla;
+ uint32_t ctrlb;
+ uint32_t addr;
+ uint8_t baud;
+ uint8_t dbgctrl;
+ uint16_t dummy_byte;
+ uint8_t n;
+};
+COMPILER_PACK_RESET()
+
+/** Build configuration from header macros. */
+#define SERCOMSPI_REGS(n) \
+ { \
+ (((CONF_SERCOM_##n##_SPI_DORD) << SERCOM_SPI_CTRLA_DORD_Pos) \
+ | (CONF_SERCOM_##n##_SPI_CPOL << SERCOM_SPI_CTRLA_CPOL_Pos) \
+ | (CONF_SERCOM_##n##_SPI_CPHA << SERCOM_SPI_CTRLA_CPHA_Pos) \
+ | (CONF_SERCOM_##n##_SPI_AMODE_EN ? SERCOM_SPI_CTRLA_FORM(2) : SERCOM_SPI_CTRLA_FORM(0)) \
+ | SERCOM_SPI_CTRLA_DOPO(CONF_SERCOM_##n##_SPI_TXPO) | SERCOM_SPI_CTRLA_DIPO(CONF_SERCOM_##n##_SPI_RXPO) \
+ | (CONF_SERCOM_##n##_SPI_IBON << SERCOM_SPI_CTRLA_IBON_Pos) \
+ | (CONF_SERCOM_##n##_SPI_RUNSTDBY << SERCOM_SPI_CTRLA_RUNSTDBY_Pos) \
+ | SERCOM_SPI_CTRLA_MODE(CONF_SERCOM_##n##_SPI_MODE)), /* ctrla */ \
+ ((CONF_SERCOM_##n##_SPI_RXEN << SERCOM_SPI_CTRLB_RXEN_Pos) \
+ | (CONF_SERCOM_##n##_SPI_MSSEN << SERCOM_SPI_CTRLB_MSSEN_Pos) \
+ | (CONF_SERCOM_##n##_SPI_SSDE << SERCOM_SPI_CTRLB_SSDE_Pos) \
+ | (CONF_SERCOM_##n##_SPI_PLOADEN << SERCOM_SPI_CTRLB_PLOADEN_Pos) \
+ | SERCOM_SPI_CTRLB_AMODE(CONF_SERCOM_##n##_SPI_AMODE) \
+ | SERCOM_SPI_CTRLB_CHSIZE(CONF_SERCOM_##n##_SPI_CHSIZE)), /* ctrlb */ \
+ (SERCOM_SPI_ADDR_ADDR(CONF_SERCOM_##n##_SPI_ADDR) \
+ | SERCOM_SPI_ADDR_ADDRMASK(CONF_SERCOM_##n##_SPI_ADDRMASK)), /* addr */ \
+ ((uint8_t)CONF_SERCOM_##n##_SPI_BAUD_RATE), /* baud */ \
+ (CONF_SERCOM_##n##_SPI_DBGSTOP << SERCOM_SPI_DBGCTRL_DBGSTOP_Pos), /* dbgctrl */ \
+ CONF_SERCOM_##n##_SPI_DUMMYBYTE, /* Dummy byte for SPI master mode */ \
+ n /* sercom number */ \
+ }
+
+#ifndef CONF_SERCOM_0_SPI_ENABLE
+#define CONF_SERCOM_0_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_1_SPI_ENABLE
+#define CONF_SERCOM_1_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_2_SPI_ENABLE
+#define CONF_SERCOM_2_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_3_SPI_ENABLE
+#define CONF_SERCOM_3_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_4_SPI_ENABLE
+#define CONF_SERCOM_4_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_5_SPI_ENABLE
+#define CONF_SERCOM_5_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_6_SPI_ENABLE
+#define CONF_SERCOM_6_SPI_ENABLE 0
+#endif
+#ifndef CONF_SERCOM_7_SPI_ENABLE
+#define CONF_SERCOM_7_SPI_ENABLE 0
+#endif
+
+/** Amount of SERCOM that is used as SPI */
+#define SERCOM_SPI_AMOUNT \
+ (CONF_SERCOM_0_SPI_ENABLE + CONF_SERCOM_1_SPI_ENABLE + CONF_SERCOM_2_SPI_ENABLE + CONF_SERCOM_3_SPI_ENABLE \
+ + CONF_SERCOM_4_SPI_ENABLE + CONF_SERCOM_5_SPI_ENABLE + CONF_SERCOM_6_SPI_ENABLE + CONF_SERCOM_7_SPI_ENABLE)
+
+#if SERCOM_SPI_AMOUNT < 1
+/** Dummy array for compiling. */
+static const struct sercomspi_regs_cfg sercomspi_regs[1] = {{0}};
+#else
+/** The SERCOM SPI configurations of SERCOM that is used as SPI. */
+static const struct sercomspi_regs_cfg sercomspi_regs[] = {
+#if CONF_SERCOM_0_SPI_ENABLE
+ SERCOMSPI_REGS(0),
+#endif
+#if CONF_SERCOM_1_SPI_ENABLE
+ SERCOMSPI_REGS(1),
+#endif
+#if CONF_SERCOM_2_SPI_ENABLE
+ SERCOMSPI_REGS(2),
+#endif
+#if CONF_SERCOM_3_SPI_ENABLE
+ SERCOMSPI_REGS(3),
+#endif
+#if CONF_SERCOM_4_SPI_ENABLE
+ SERCOMSPI_REGS(4),
+#endif
+#if CONF_SERCOM_5_SPI_ENABLE
+ SERCOMSPI_REGS(5),
+#endif
+#if CONF_SERCOM_6_SPI_ENABLE
+ SERCOMSPI_REGS(6),
+#endif
+#if CONF_SERCOM_7_SPI_ENABLE
+ SERCOMSPI_REGS(7),
+#endif
+};
+#endif
+
+/** \internal De-initialize SERCOM SPI
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ *
+ * \return De-initialization status
+ */
+static int32_t _spi_deinit(void *const hw)
+{
+ hri_sercomspi_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomspi_set_CTRLA_SWRST_bit(hw);
+
+ return ERR_NONE;
+}
+
+/** \internal Enable SERCOM SPI
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ *
+ * \return Enabling status
+ */
+static int32_t _spi_sync_enable(void *const hw)
+{
+ if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
+ return ERR_BUSY;
+ }
+
+ hri_sercomspi_set_CTRLA_ENABLE_bit(hw);
+
+ return ERR_NONE;
+}
+
+/** \internal Enable SERCOM SPI
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ *
+ * \return Enabling status
+ */
+static int32_t _spi_async_enable(void *const hw)
+{
+ _spi_sync_enable(hw);
+ NVIC_EnableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+
+ return ERR_NONE;
+}
+
+/** \internal Disable SERCOM SPI
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ *
+ * \return Disabling status
+ */
+static int32_t _spi_sync_disable(void *const hw)
+{
+ if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
+ return ERR_BUSY;
+ }
+ hri_sercomspi_clear_CTRLA_ENABLE_bit(hw);
+
+ return ERR_NONE;
+}
+
+/** \internal Disable SERCOM SPI
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ *
+ * \return Disabling status
+ */
+static int32_t _spi_async_disable(void *const hw)
+{
+ _spi_sync_disable(hw);
+ hri_sercomspi_clear_INTEN_reg(
+ hw, SERCOM_SPI_INTFLAG_ERROR | SERCOM_SPI_INTFLAG_RXC | SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE);
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+
+ return ERR_NONE;
+}
+
+/** \internal Set SERCOM SPI mode
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ * \param[in] mode The mode to set
+ *
+ * \return Setting mode status
+ */
+static int32_t _spi_set_mode(void *const hw, const enum spi_transfer_mode mode)
+{
+ uint32_t ctrla;
+
+ if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST | SERCOM_SPI_SYNCBUSY_ENABLE)) {
+ return ERR_BUSY;
+ }
+
+ ctrla = hri_sercomspi_read_CTRLA_reg(hw);
+ ctrla &= ~(SERCOM_SPI_CTRLA_CPOL | SERCOM_SPI_CTRLA_CPHA);
+ ctrla |= (mode & 0x3u) << SERCOM_SPI_CTRLA_CPHA_Pos;
+ hri_sercomspi_write_CTRLA_reg(hw, ctrla);
+
+ return ERR_NONE;
+}
+
+/** \internal Set SERCOM SPI baudrate
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ * \param[in] baud_val The baudrate to set
+ *
+ * \return Setting baudrate status
+ */
+static int32_t _spi_set_baudrate(void *const hw, const uint32_t baud_val)
+{
+ if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
+ return ERR_BUSY;
+ }
+
+ hri_sercomspi_write_BAUD_reg(hw, baud_val);
+
+ return ERR_NONE;
+}
+
+/** \internal Set SERCOM SPI char size
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ * \param[in] baud_val The baudrate to set
+ * \param[out] size Stored char size
+ *
+ * \return Setting char size status
+ */
+static int32_t _spi_set_char_size(void *const hw, const enum spi_char_size char_size, uint8_t *const size)
+{
+ /* Only 8-bit or 9-bit accepted */
+ if (!(char_size == SPI_CHAR_SIZE_8 || char_size == SPI_CHAR_SIZE_9)) {
+ return ERR_INVALID_ARG;
+ }
+
+ if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST | SERCOM_SPI_SYNCBUSY_CTRLB)) {
+ return ERR_BUSY;
+ }
+
+ hri_sercomspi_write_CTRLB_CHSIZE_bf(hw, char_size);
+ *size = (char_size == SPI_CHAR_SIZE_8) ? 1 : 2;
+
+ return ERR_NONE;
+}
+
+/** \internal Set SERCOM SPI data order
+ *
+ * \param[in] hw Pointer to the hardware register base.
+ * \param[in] baud_val The baudrate to set
+ *
+ * \return Setting data order status
+ */
+static int32_t _spi_set_data_order(void *const hw, const enum spi_data_order dord)
+{
+ uint32_t ctrla;
+
+ if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
+ return ERR_BUSY;
+ }
+
+ ctrla = hri_sercomspi_read_CTRLA_reg(hw);
+
+ if (dord == SPI_DATA_ORDER_LSB_1ST) {
+ ctrla |= SERCOM_SPI_CTRLA_DORD;
+ } else {
+ ctrla &= ~SERCOM_SPI_CTRLA_DORD;
+ }
+ hri_sercomspi_write_CTRLA_reg(hw, ctrla);
+
+ return ERR_NONE;
+}
+
+/** \brief Load SERCOM registers to init for SPI master mode
+ * The settings will be applied with default master mode, unsupported things
+ * are ignored.
+ * \param[in, out] hw Pointer to the hardware register base.
+ * \param[in] regs Pointer to register configuration values.
+ */
+static inline void _spi_load_regs_master(void *const hw, const struct sercomspi_regs_cfg *regs)
+{
+ ASSERT(hw && regs);
+ hri_sercomspi_write_CTRLA_reg(
+ hw, regs->ctrla & ~(SERCOM_SPI_CTRLA_IBON | SERCOM_SPI_CTRLA_ENABLE | SERCOM_SPI_CTRLA_SWRST));
+ hri_sercomspi_write_CTRLB_reg(
+ hw,
+ (regs->ctrlb
+ & ~(SERCOM_SPI_CTRLB_MSSEN | SERCOM_SPI_CTRLB_AMODE_Msk | SERCOM_SPI_CTRLB_SSDE | SERCOM_SPI_CTRLB_PLOADEN))
+ | (SERCOM_SPI_CTRLB_RXEN));
+ hri_sercomspi_write_BAUD_reg(hw, regs->baud);
+ hri_sercomspi_write_DBGCTRL_reg(hw, regs->dbgctrl);
+}
+
+/** \brief Load SERCOM registers to init for SPI slave mode
+ * The settings will be applied with default slave mode, unsupported things
+ * are ignored.
+ * \param[in, out] hw Pointer to the hardware register base.
+ * \param[in] regs Pointer to register configuration values.
+ */
+static inline void _spi_load_regs_slave(void *const hw, const struct sercomspi_regs_cfg *regs)
+{
+ ASSERT(hw && regs);
+ hri_sercomspi_write_CTRLA_reg(
+ hw, regs->ctrla & ~(SERCOM_SPI_CTRLA_IBON | SERCOM_SPI_CTRLA_ENABLE | SERCOM_SPI_CTRLA_SWRST));
+ hri_sercomspi_write_CTRLB_reg(hw,
+ (regs->ctrlb & ~(SERCOM_SPI_CTRLB_MSSEN))
+ | (SERCOM_SPI_CTRLB_RXEN | SERCOM_SPI_CTRLB_SSDE | SERCOM_SPI_CTRLB_PLOADEN));
+ hri_sercomspi_write_ADDR_reg(hw, regs->addr);
+ hri_sercomspi_write_DBGCTRL_reg(hw, regs->dbgctrl);
+ while (hri_sercomspi_is_syncing(hw, 0xFFFFFFFF))
+ ;
+}
+
+/** \brief Return the pointer to register settings of specific SERCOM
+ * \param[in] hw_addr The hardware register base address.
+ * \return Pointer to register settings of specific SERCOM.
+ */
+static inline const struct sercomspi_regs_cfg *_spi_get_regs(const uint32_t hw_addr)
+{
+ uint8_t n = _sercom_get_hardware_index((const void *)hw_addr);
+ uint8_t i;
+
+ for (i = 0; i < sizeof(sercomspi_regs) / sizeof(struct sercomspi_regs_cfg); i++) {
+ if (sercomspi_regs[i].n == n) {
+ return &sercomspi_regs[i];
+ }
+ }
+
+ return NULL;
+}
+
+int32_t _spi_m_sync_init(struct _spi_m_sync_dev *dev, void *const hw)
+{
+ const struct sercomspi_regs_cfg *regs = _spi_get_regs((uint32_t)hw);
+
+ ASSERT(dev && hw);
+
+ if (regs == NULL) {
+ return ERR_INVALID_ARG;
+ }
+
+ if (!hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
+ uint32_t mode = regs->ctrla & SERCOM_SPI_CTRLA_MODE_Msk;
+ if (hri_sercomspi_get_CTRLA_reg(hw, SERCOM_SPI_CTRLA_ENABLE)) {
+ hri_sercomspi_clear_CTRLA_ENABLE_bit(hw);
+ hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_ENABLE);
+ }
+ hri_sercomspi_write_CTRLA_reg(hw, SERCOM_SPI_CTRLA_SWRST | mode);
+ }
+ hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_SWRST);
+
+ dev->prvt = hw;
+
+ if ((regs->ctrla & SERCOM_SPI_CTRLA_MODE_Msk) == SERCOM_USART_CTRLA_MODE_SPI_SLAVE) {
+ _spi_load_regs_slave(hw, regs);
+ } else {
+ _spi_load_regs_master(hw, regs);
+ }
+
+ /* Load character size from default hardware configuration */
+ dev->char_size = ((regs->ctrlb & SERCOM_SPI_CTRLB_CHSIZE_Msk) == 0) ? 1 : 2;
+
+ dev->dummy_byte = regs->dummy_byte;
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_sync_init(struct _spi_s_sync_dev *dev, void *const hw)
+{
+ return _spi_m_sync_init(dev, hw);
+}
+
+int32_t _spi_m_async_init(struct _spi_async_dev *dev, void *const hw)
+{
+ struct _spi_async_dev *spid = dev;
+ /* Do hardware initialize. */
+ int32_t rc = _spi_m_sync_init((struct _spi_m_sync_dev *)dev, hw);
+
+ if (rc < 0) {
+ return rc;
+ }
+
+ _sercom_init_irq_param(hw, (void *)dev);
+ /* Initialize callbacks: must use them */
+ spid->callbacks.complete = NULL;
+ spid->callbacks.rx = NULL;
+ spid->callbacks.tx = NULL;
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+ NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(hw));
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_async_init(struct _spi_s_async_dev *dev, void *const hw)
+{
+ return _spi_m_async_init(dev, hw);
+}
+
+int32_t _spi_m_async_deinit(struct _spi_async_dev *dev)
+{
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
+ NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
+
+ return _spi_deinit(dev->prvt);
+}
+
+int32_t _spi_s_async_deinit(struct _spi_s_async_dev *dev)
+{
+ NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
+ NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
+
+ return _spi_deinit(dev->prvt);
+}
+
+int32_t _spi_m_sync_deinit(struct _spi_m_sync_dev *dev)
+{
+ return _spi_deinit(dev->prvt);
+}
+
+int32_t _spi_s_sync_deinit(struct _spi_s_sync_dev *dev)
+{
+ return _spi_deinit(dev->prvt);
+}
+
+int32_t _spi_m_sync_enable(struct _spi_m_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_sync_enable(dev->prvt);
+}
+
+int32_t _spi_s_sync_enable(struct _spi_s_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_sync_enable(dev->prvt);
+}
+
+int32_t _spi_m_async_enable(struct _spi_async_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_async_enable(dev->prvt);
+}
+
+int32_t _spi_s_async_enable(struct _spi_s_async_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_async_enable(dev->prvt);
+}
+
+int32_t _spi_m_sync_disable(struct _spi_m_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_sync_disable(dev->prvt);
+}
+
+int32_t _spi_s_sync_disable(struct _spi_s_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_sync_disable(dev->prvt);
+}
+
+int32_t _spi_m_async_disable(struct _spi_async_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_async_disable(dev->prvt);
+}
+
+int32_t _spi_s_async_disable(struct _spi_s_async_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_async_disable(dev->prvt);
+}
+
+int32_t _spi_m_sync_set_mode(struct _spi_m_sync_dev *dev, const enum spi_transfer_mode mode)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_mode(dev->prvt, mode);
+}
+
+int32_t _spi_m_async_set_mode(struct _spi_async_dev *dev, const enum spi_transfer_mode mode)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_mode(dev->prvt, mode);
+}
+
+int32_t _spi_s_async_set_mode(struct _spi_s_async_dev *dev, const enum spi_transfer_mode mode)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_mode(dev->prvt, mode);
+}
+
+int32_t _spi_s_sync_set_mode(struct _spi_s_sync_dev *dev, const enum spi_transfer_mode mode)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_mode(dev->prvt, mode);
+}
+
+int32_t _spi_calc_baud_val(struct spi_dev *dev, const uint32_t clk, const uint32_t baud)
+{
+ int32_t rc;
+ ASSERT(dev);
+ (void)dev;
+
+ /* Not accept 0es */
+ if (clk == 0 || baud == 0) {
+ return ERR_INVALID_ARG;
+ }
+
+ /* Check baudrate range of current assigned clock */
+ if (!(baud <= (clk >> 1) && baud >= (clk >> 8))) {
+ return ERR_INVALID_ARG;
+ }
+
+ rc = ((clk >> 1) / baud) - 1;
+ return rc;
+}
+
+int32_t _spi_m_sync_set_baudrate(struct _spi_m_sync_dev *dev, const uint32_t baud_val)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_baudrate(dev->prvt, baud_val);
+}
+
+int32_t _spi_m_async_set_baudrate(struct _spi_async_dev *dev, const uint32_t baud_val)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_baudrate(dev->prvt, baud_val);
+}
+
+int32_t _spi_m_sync_set_char_size(struct _spi_m_sync_dev *dev, const enum spi_char_size char_size)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
+}
+
+int32_t _spi_m_async_set_char_size(struct _spi_async_dev *dev, const enum spi_char_size char_size)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
+}
+
+int32_t _spi_s_async_set_char_size(struct _spi_s_async_dev *dev, const enum spi_char_size char_size)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
+}
+
+int32_t _spi_s_sync_set_char_size(struct _spi_s_sync_dev *dev, const enum spi_char_size char_size)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
+}
+
+int32_t _spi_m_sync_set_data_order(struct _spi_m_sync_dev *dev, const enum spi_data_order dord)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_data_order(dev->prvt, dord);
+}
+
+int32_t _spi_m_async_set_data_order(struct _spi_async_dev *dev, const enum spi_data_order dord)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_data_order(dev->prvt, dord);
+}
+
+int32_t _spi_s_async_set_data_order(struct _spi_s_async_dev *dev, const enum spi_data_order dord)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_data_order(dev->prvt, dord);
+}
+
+int32_t _spi_s_sync_set_data_order(struct _spi_s_sync_dev *dev, const enum spi_data_order dord)
+{
+ ASSERT(dev && dev->prvt);
+
+ return _spi_set_data_order(dev->prvt, dord);
+}
+
+/** Wait until SPI bus idle. */
+static inline void _spi_wait_bus_idle(void *const hw)
+{
+ while (!(hri_sercomspi_get_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE))) {
+ ;
+ }
+ hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE);
+}
+
+/** Holds run time information for message sync transaction. */
+struct _spi_trans_ctrl {
+ /** Pointer to transmitting data buffer. */
+ uint8_t *txbuf;
+ /** Pointer to receiving data buffer. */
+ uint8_t *rxbuf;
+ /** Count number of data transmitted. */
+ uint32_t txcnt;
+ /** Count number of data received. */
+ uint32_t rxcnt;
+ /** Data character size. */
+ uint8_t char_size;
+};
+
+/** Check interrupt flag of RXC and update transaction runtime information. */
+static inline bool _spi_rx_check_and_receive(void *const hw, const uint32_t iflag, struct _spi_trans_ctrl *ctrl)
+{
+ uint32_t data;
+
+ if (!(iflag & SERCOM_SPI_INTFLAG_RXC)) {
+ return false;
+ }
+
+ data = hri_sercomspi_read_DATA_reg(hw);
+
+ if (ctrl->rxbuf) {
+ *ctrl->rxbuf++ = (uint8_t)data;
+
+ if (ctrl->char_size > 1) {
+ *ctrl->rxbuf++ = (uint8_t)(data >> 8);
+ }
+ }
+
+ ctrl->rxcnt++;
+
+ return true;
+}
+
+/** Check interrupt flag of DRE and update transaction runtime information. */
+static inline void _spi_tx_check_and_send(void *const hw, const uint32_t iflag, struct _spi_trans_ctrl *ctrl,
+ uint16_t dummy)
+{
+ uint32_t data;
+
+ if (!(SERCOM_SPI_INTFLAG_DRE & iflag)) {
+ return;
+ }
+
+ if (ctrl->txbuf) {
+ data = *ctrl->txbuf++;
+
+ if (ctrl->char_size > 1) {
+ data |= (*ctrl->txbuf) << 8;
+ ctrl->txbuf++;
+ }
+ } else {
+ data = dummy;
+ }
+
+ ctrl->txcnt++;
+ hri_sercomspi_write_DATA_reg(hw, data);
+}
+
+/** Check interrupt flag of ERROR and update transaction runtime information. */
+static inline int32_t _spi_err_check(const uint32_t iflag, void *const hw)
+{
+ if (SERCOM_SPI_INTFLAG_ERROR & iflag) {
+ hri_sercomspi_clear_STATUS_reg(hw, ~0);
+ hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_ERROR);
+ return ERR_OVERFLOW;
+ }
+
+ return ERR_NONE;
+}
+
+int32_t _spi_m_sync_trans(struct _spi_m_sync_dev *dev, const struct spi_msg *msg)
+{
+ void * hw = dev->prvt;
+ int32_t rc = 0;
+ struct _spi_trans_ctrl ctrl = {msg->txbuf, msg->rxbuf, 0, 0, dev->char_size};
+
+ ASSERT(dev && hw);
+
+ /* If settings are not applied (pending), we can not go on */
+ if (hri_sercomspi_is_syncing(
+ hw, (SERCOM_SPI_SYNCBUSY_SWRST | SERCOM_SPI_SYNCBUSY_ENABLE | SERCOM_SPI_SYNCBUSY_CTRLB))) {
+ return ERR_BUSY;
+ }
+
+ /* SPI must be enabled to start synchronous transfer */
+ if (!hri_sercomspi_get_CTRLA_ENABLE_bit(hw)) {
+ return ERR_NOT_INITIALIZED;
+ }
+
+ for (;;) {
+ uint32_t iflag = hri_sercomspi_read_INTFLAG_reg(hw);
+
+ if (!_spi_rx_check_and_receive(hw, iflag, &ctrl)) {
+ /* In master mode, do not start next byte before previous byte received
+ * to make better output waveform */
+ if (ctrl.rxcnt >= ctrl.txcnt) {
+ _spi_tx_check_and_send(hw, iflag, &ctrl, dev->dummy_byte);
+ }
+ }
+
+ rc = _spi_err_check(iflag, hw);
+
+ if (rc < 0) {
+ break;
+ }
+ if (ctrl.txcnt >= msg->size && ctrl.rxcnt >= msg->size) {
+ rc = ctrl.txcnt;
+ break;
+ }
+ }
+ /* Wait until SPI bus idle */
+ _spi_wait_bus_idle(hw);
+
+ return rc;
+}
+
+int32_t _spi_m_async_enable_tx(struct _spi_async_dev *dev, bool state)
+{
+ void *hw = dev->prvt;
+
+ ASSERT(dev && hw);
+
+ if (state) {
+ hri_sercomspi_set_INTEN_DRE_bit(hw);
+ } else {
+ hri_sercomspi_clear_INTEN_DRE_bit(hw);
+ }
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_async_enable_tx(struct _spi_s_async_dev *dev, bool state)
+{
+ return _spi_m_async_enable_tx(dev, state);
+}
+
+int32_t _spi_m_async_enable_rx(struct _spi_async_dev *dev, bool state)
+{
+ void *hw = dev->prvt;
+
+ ASSERT(dev);
+ ASSERT(hw);
+
+ if (state) {
+ hri_sercomspi_set_INTEN_RXC_bit(hw);
+ } else {
+ hri_sercomspi_clear_INTEN_RXC_bit(hw);
+ }
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_async_enable_rx(struct _spi_s_async_dev *dev, bool state)
+{
+ return _spi_m_async_enable_rx(dev, state);
+}
+
+int32_t _spi_m_async_enable_tx_complete(struct _spi_async_dev *dev, bool state)
+{
+ ASSERT(dev && dev->prvt);
+
+ if (state) {
+ hri_sercomspi_set_INTEN_TXC_bit(dev->prvt);
+ } else {
+ hri_sercomspi_clear_INTEN_TXC_bit(dev->prvt);
+ }
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_async_enable_ss_detect(struct _spi_s_async_dev *dev, bool state)
+{
+ return _spi_m_async_enable_tx_complete(dev, state);
+}
+
+int32_t _spi_m_async_write_one(struct _spi_async_dev *dev, uint16_t data)
+{
+ ASSERT(dev && dev->prvt);
+
+ hri_sercomspi_write_DATA_reg(dev->prvt, data);
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_async_write_one(struct _spi_s_async_dev *dev, uint16_t data)
+{
+ ASSERT(dev && dev->prvt);
+
+ hri_sercomspi_write_DATA_reg(dev->prvt, data);
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_sync_write_one(struct _spi_s_sync_dev *dev, uint16_t data)
+{
+ ASSERT(dev && dev->prvt);
+
+ hri_sercomspi_write_DATA_reg(dev->prvt, data);
+
+ return ERR_NONE;
+}
+
+uint16_t _spi_m_async_read_one(struct _spi_async_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return hri_sercomspi_read_DATA_reg(dev->prvt);
+}
+
+uint16_t _spi_s_async_read_one(struct _spi_s_async_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return hri_sercomspi_read_DATA_reg(dev->prvt);
+}
+
+uint16_t _spi_s_sync_read_one(struct _spi_s_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return hri_sercomspi_read_DATA_reg(dev->prvt);
+}
+
+int32_t _spi_m_async_register_callback(struct _spi_async_dev *dev, const enum _spi_async_dev_cb_type cb_type,
+ const FUNC_PTR func)
+{
+ typedef void (*func_t)(void);
+ struct _spi_async_dev *spid = dev;
+
+ ASSERT(dev && (cb_type < SPI_DEV_CB_N));
+
+ func_t *p_ls = (func_t *)&spid->callbacks;
+ p_ls[cb_type] = (func_t)func;
+
+ return ERR_NONE;
+}
+
+int32_t _spi_s_async_register_callback(struct _spi_s_async_dev *dev, const enum _spi_s_async_dev_cb_type cb_type,
+ const FUNC_PTR func)
+{
+ return _spi_m_async_register_callback(dev, cb_type, func);
+}
+
+bool _spi_s_sync_is_tx_ready(struct _spi_s_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return hri_sercomi2cm_get_INTFLAG_reg(dev->prvt, SERCOM_SPI_INTFLAG_DRE);
+}
+
+bool _spi_s_sync_is_rx_ready(struct _spi_s_sync_dev *dev)
+{
+ ASSERT(dev && dev->prvt);
+
+ return hri_sercomi2cm_get_INTFLAG_reg(dev->prvt, SERCOM_SPI_INTFLAG_RXC);
+}
+
+bool _spi_s_sync_is_ss_deactivated(struct _spi_s_sync_dev *dev)
+{
+ void *hw = dev->prvt;
+
+ ASSERT(dev && hw);
+
+ if (hri_sercomi2cm_get_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC)) {
+ hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC);
+ return true;
+ }
+ return false;
+}
+
+bool _spi_s_sync_is_error(struct _spi_s_sync_dev *dev)
+{
+ void *hw = dev->prvt;
+
+ ASSERT(dev && hw);
+
+ if (hri_sercomi2cm_get_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_ERROR)) {
+ hri_sercomspi_clear_STATUS_reg(hw, SERCOM_SPI_STATUS_BUFOVF);
+ hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_ERROR);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * \brief Enable/disable SPI master interrupt
+ *
+ * param[in] device The pointer to SPI master device instance
+ * param[in] type The type of interrupt to disable/enable if applicable
+ * param[in] state Enable or disable
+ */
+void _spi_m_async_set_irq_state(struct _spi_async_dev *const device, const enum _spi_async_dev_cb_type type,
+ const bool state)
+{
+ ASSERT(device);
+
+ if (SPI_DEV_CB_ERROR == type) {
+ hri_sercomspi_write_INTEN_ERROR_bit(device->prvt, state);
+ }
+}
+
+/**
+ * \brief Enable/disable SPI slave interrupt
+ *
+ * param[in] device The pointer to SPI slave device instance
+ * param[in] type The type of interrupt to disable/enable if applicable
+ * param[in] state Enable or disable
+ */
+void _spi_s_async_set_irq_state(struct _spi_async_dev *const device, const enum _spi_async_dev_cb_type type,
+ const bool state)
+{
+ _spi_m_async_set_irq_state(device, type, state);
+}
diff --git a/watch-library/hardware/hpl/slcd/hpl_slcd.c b/watch-library/hardware/hpl/slcd/hpl_slcd.c
new file mode 100644
index 00000000..0f58b1f5
--- /dev/null
+++ b/watch-library/hardware/hpl/slcd/hpl_slcd.c
@@ -0,0 +1,289 @@
+/**
+ * \file
+ *
+ * \brief SLCD Segment Liquid Crystal Display Controller(Sync) functionality
+ * Implementation.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <utils_assert.h>
+#include <hpl_slcd_sync.h>
+#include <hpl_slcd_config.h>
+
+static int32_t _slcd_sync_set_segment(struct _slcd_sync_device *dev, const uint32_t com, const uint32_t seg,
+ const bool on);
+
+/**
+ * \brief SLCD configuration type
+ */
+struct slcd_configuration {
+ hri_slcd_ctrla_reg_t ctrla; /*!< Control A Register */
+ hri_slcd_ctrlb_reg_t ctrlb; /*!< Control B Register */
+ hri_slcd_ctrlc_reg_t ctrlc; /*!< Control C Register */
+ hri_slcd_ctrld_reg_t ctrld; /*!< Control D Register */
+};
+
+/**
+ * \brief Array of AC configurations
+ */
+static struct slcd_configuration _slcd
+ = {SLCD_CTRLA_DUTY(CONF_SLCD_COM_NUM) | CONF_SLCD_WMOD << SLCD_CTRLA_WMOD_Pos
+ | CONF_SLCD_RUNSTDBY << SLCD_CTRLA_RUNSTDBY_Pos | SLCD_CTRLA_PRESC(CONF_SLCD_PRESC)
+ | SLCD_CTRLA_CKDIV(CONF_SLCD_CKDIV) | SLCD_CTRLA_BIAS(CONF_SLCD_BIAS)
+ | CONF_SLCD_XVLCD << SLCD_CTRLA_XVLCD_Pos | SLCD_CTRLA_PRF(CONF_SLCD_PRF) | SLCD_CTRLA_RRF(CONF_SLCD_RRF),
+ CONF_SLCD_BBEN << SLCD_CTRLB_BBEN_Pos | SLCD_CTRLB_BBD(CONF_SLCD_BBD - 1),
+ SLCD_CTRLC_CTST(CONF_SLCD_CONTRAST_ADJUST),
+ SLCD_CTRLD_DISPEN};
+/**
+ * \brief Initialize SLCD Device Descriptor
+ */
+int32_t _slcd_sync_init(struct _slcd_sync_device *dev, void *const hw)
+{
+ if (!hri_slcd_is_syncing(hw, SLCD_SYNCBUSY_SWRST)) {
+ if (hri_slcd_get_CTRLA_ENABLE_bit(hw)) {
+ hri_slcd_clear_CTRLA_ENABLE_bit(hw);
+ hri_slcd_wait_for_sync(hw, SLCD_SYNCBUSY_ENABLE);
+ }
+ hri_slcd_write_CTRLA_reg(hw, SLCD_CTRLA_SWRST);
+ }
+ hri_slcd_wait_for_sync(hw, SLCD_SYNCBUSY_SWRST);
+
+ dev->hw = hw;
+ hri_slcd_write_CTRLA_reg(hw, _slcd.ctrla);
+ hri_slcd_write_CTRLB_reg(hw, _slcd.ctrlb);
+ hri_slcd_write_CTRLC_reg(hw, _slcd.ctrlc);
+ hri_slcd_write_CTRLD_reg(hw, _slcd.ctrld);
+ hri_slcd_write_LPENL_reg(hw, CONF_SLCD_LPENL);
+ hri_slcd_write_LPENH_reg(hw, CONF_SLCD_LPENH);
+ hri_slcd_write_SDATAL0_reg(hw, 0);
+ hri_slcd_write_SDATAH0_reg(hw, 0);
+ hri_slcd_write_SDATAL1_reg(hw, 0);
+ hri_slcd_write_SDATAH1_reg(hw, 0);
+ hri_slcd_write_SDATAL2_reg(hw, 0);
+ hri_slcd_write_SDATAH2_reg(hw, 0);
+ hri_slcd_write_SDATAL3_reg(hw, 0);
+ hri_slcd_write_SDATAH3_reg(hw, 0);
+ hri_slcd_write_SDATAL4_reg(hw, 0);
+ hri_slcd_write_SDATAH4_reg(hw, 0);
+ hri_slcd_write_SDATAL5_reg(hw, 0);
+ hri_slcd_write_SDATAH5_reg(hw, 0);
+ hri_slcd_write_SDATAL6_reg(hw, 0);
+ hri_slcd_write_SDATAH6_reg(hw, 0);
+ hri_slcd_write_SDATAL7_reg(hw, 0);
+ hri_slcd_write_SDATAH7_reg(hw, 0);
+ hri_slcd_set_BCFG_MODE_bit(dev->hw);
+ return ERR_NONE;
+}
+
+/**
+ * \brief DeInitialize SLCD Device Descriptor
+ */
+int32_t _slcd_sync_deinit(struct _slcd_sync_device *dev)
+{
+ hri_slcd_clear_CTRLA_ENABLE_bit(dev->hw);
+ hri_slcd_wait_for_sync(dev->hw, SLCD_SYNCBUSY_ENABLE);
+ hri_slcd_set_CTRLA_SWRST_bit(dev->hw);
+ dev->hw = NULL;
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Enable SLCD driver
+ *
+ * \param[in] dev SLCD device descriptor to be enabled
+ */
+int32_t _slcd_sync_enable(struct _slcd_sync_device *dev)
+{
+ hri_slcd_set_CTRLA_ENABLE_bit(dev->hw);
+ return ERR_NONE;
+}
+
+/**
+ * \brief Disable SLCD driver
+ */
+int32_t _slcd_sync_disable(struct _slcd_sync_device *dev)
+{
+ hri_slcd_clear_CTRLA_ENABLE_bit(dev->hw);
+ return ERR_NONE;
+}
+
+/**
+ * \brief Turn on a Segment
+ */
+int32_t _slcd_sync_seg_on(struct _slcd_sync_device *dev, uint32_t seg)
+{
+ return _slcd_sync_set_segment(dev, SLCD_COMNUM(seg), SLCD_SEGNUM(seg), true);
+}
+
+/**
+ * \brief Turn off a Segment
+ */
+int32_t _slcd_sync_seg_off(struct _slcd_sync_device *dev, uint32_t seg)
+{
+ return _slcd_sync_set_segment(dev, SLCD_COMNUM(seg), SLCD_SEGNUM(seg), false);
+}
+
+/**
+ * \brief Blink a Segment
+ */
+int32_t _slcd_sync_seg_blink(struct _slcd_sync_device *dev, uint32_t seg, const uint32_t period)
+{
+ if ((SLCD_COMNUM(seg) >= CONF_SLCD_COM_NUM) || (SLCD_SEGNUM(seg) >= CONF_SLCD_SEG_NUM)) {
+ return ERR_INVALID_ARG;
+ }
+ /* COM[0..7], Seg[0,1] support blink */
+ if (SLCD_SEGNUM(seg) >= 2) {
+ return ERR_INVALID_ARG;
+ }
+ /* Verify period */
+ if (period > SLCD_FC_MAX_MS || period < SLCD_FC_MIN_MS) {
+ return ERR_INVALID_ARG;
+ }
+ /* Set Period, use Frame Counter 0 for blink */
+ hri_slcd_clear_CTRLD_FC0EN_bit(dev->hw);
+ hri_slcd_wait_for_sync(dev->hw, SLCD_SYNCBUSY_CTRLD);
+ if (period <= SLCD_FC_BYPASS_MAX_MS) {
+ hri_slcd_set_FC0_reg(dev->hw, SLCD_FC0_PB | ((period / (1000 / SLCD_FRAME_FREQUENCY)) - 1));
+ } else {
+ hri_slcd_set_FC0_reg(dev->hw, (((period / (1000 / SLCD_FRAME_FREQUENCY)) / 8 - 1)));
+ }
+ hri_slcd_set_CTRLD_FC0EN_bit(dev->hw);
+
+ /* Set Blink Segments */
+ _slcd_sync_set_segment(dev, SLCD_COMNUM(seg), SLCD_SEGNUM(seg), true);
+ hri_slcd_clear_CTRLD_BLINK_bit(dev->hw);
+
+ hri_slcd_clear_CTRLA_ENABLE_bit(dev->hw);
+ hri_slcd_wait_for_sync(dev->hw, SLCD_SYNCBUSY_ENABLE);
+
+ /* Update BCFG */
+ if (SLCD_SEGNUM(seg) == 0) {
+ hri_slcd_set_BCFG_BSS0_bf(dev->hw, 1 << SLCD_COMNUM(seg));
+ } else {
+ hri_slcd_set_BCFG_BSS1_bf(dev->hw, 1 << SLCD_COMNUM(seg));
+ }
+ hri_slcd_set_CTRLA_ENABLE_bit(dev->hw);
+ hri_slcd_set_CTRLD_BLINK_bit(dev->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Start animation play by a segment array
+ */
+int32_t _slcd_sync_start_animation(struct _slcd_sync_device *dev, const uint32_t segs[], uint32_t len,
+ const uint32_t period)
+{
+ uint32_t i;
+ uint32_t csrlen = 0;
+ if (len > 16) {
+ return ERR_INVALID_ARG;
+ }
+ /* COM[0..7], Seg[2,3] support animation */
+ for (i = 0; i < len; i++) {
+ if ((SLCD_SEGNUM(segs[i]) != 2 && SLCD_SEGNUM(segs[i]) != 3)) {
+ return ERR_INVALID_ARG;
+ }
+ }
+ /* Verify period */
+ if (period > SLCD_FC_MAX_MS || period < SLCD_FC_MIN_MS) {
+ return ERR_INVALID_ARG;
+ }
+ /* Set Period */
+ _slcd_sync_set_animation_period(dev, period);
+
+ /* Set animation segments */
+ hri_slcd_clear_CTRLA_ENABLE_bit(dev->hw);
+ hri_slcd_clear_CTRLD_CSREN_bit(dev->hw);
+
+ hri_slcd_wait_for_sync(dev->hw, SLCD_SYNCBUSY_ENABLE | SLCD_SYNCBUSY_CTRLD);
+ hri_slcd_set_CSRCFG_FCS_bf(dev->hw, 1);
+ hri_slcd_write_CSRCFG_DATA_bf(dev->hw, 0);
+ for (i = 0; i < len; i++) {
+ hri_slcd_set_CSRCFG_DATA_bf(dev->hw, (1 << ((SLCD_COMNUM(segs[i]) * 2) + (SLCD_SEGNUM(segs[i]) - 2))));
+ if (((SLCD_COMNUM(segs[i]) * 2) + (SLCD_SEGNUM(segs[i]) - 2)) > csrlen) {
+ csrlen = (SLCD_COMNUM(segs[i]) * 2) + (SLCD_SEGNUM(segs[i]) - 2);
+ }
+ }
+ hri_slcd_set_CSRCFG_SIZE_bf(dev->hw, csrlen + 1);
+ hri_slcd_set_BCFG_MODE_bit(dev->hw);
+ hri_slcd_set_CTRLD_CSREN_bit(dev->hw);
+ hri_slcd_set_CTRLA_ENABLE_bit(dev->hw);
+
+ return ERR_NONE;
+}
+
+/**
+ * \brief Stop animation play by a segment array
+ */
+int32_t _slcd_sync_stop_animation(struct _slcd_sync_device *dev, const uint32_t segs[], uint32_t len)
+{
+ /* Not used because of the current version is not supported, Reserved */
+ (void)segs;
+ (void)len;
+ hri_slcd_wait_for_sync(dev->hw, SLCD_SYNCBUSY_CTRLD);
+ hri_slcd_clear_CTRLD_CSREN_bit(dev->hw);
+ return ERR_NONE;
+}
+
+/**
+ * \brief Set animation Frequency
+ */
+int32_t _slcd_sync_set_animation_period(struct _slcd_sync_device *dev, const uint32_t period)
+{
+ hri_slcd_clear_CTRLD_FC1EN_bit(dev->hw);
+ hri_slcd_wait_for_sync(dev->hw, SLCD_SYNCBUSY_CTRLD);
+ /* Use Frame Counter 1 for blink */
+ if (period <= SLCD_FC_BYPASS_MAX_MS) {
+ hri_slcd_set_FC1_reg(dev->hw, SLCD_FC1_PB | ((period / (1000 / SLCD_FRAME_FREQUENCY)) - 1));
+ } else {
+ hri_slcd_set_FC1_reg(dev->hw, (((period / (1000 / SLCD_FRAME_FREQUENCY)) / 8 - 1)));
+ }
+ hri_slcd_set_CTRLD_FC1EN_bit(dev->hw);
+ return ERR_NONE;
+}
+
+static int32_t _slcd_sync_set_segment(struct _slcd_sync_device *dev, const uint32_t com, const uint32_t seg,
+ const bool on)
+{
+ if ((SLCD_COMNUM(seg) >= CONF_SLCD_COM_NUM) || (SLCD_SEGNUM(seg) >= CONF_SLCD_SEG_NUM)) {
+ return ERR_INVALID_ARG;
+ }
+ /* Use register instead hri interface to optimization code */
+ if (on) {
+ ((uint32_t *)&(((Slcd *)dev->hw)->SDATAL0))[(com * 2) + (seg >> 5)]
+ |= (seg < 32) ? (1 << seg) : (1 << (seg >> 5));
+ } else {
+ ((uint32_t *)&(((Slcd *)dev->hw)->SDATAL0))[(com * 2) + (seg >> 5)]
+ &= ~((seg < 32) ? (1 << seg) : (1 << (seg >> 5)));
+ }
+
+ return ERR_NONE;
+}
diff --git a/watch-library/hardware/hpl/slcd/hpl_slcd_cm.h b/watch-library/hardware/hpl/slcd/hpl_slcd_cm.h
new file mode 100644
index 00000000..66dbde93
--- /dev/null
+++ b/watch-library/hardware/hpl/slcd/hpl_slcd_cm.h
@@ -0,0 +1,59 @@
+/**
+ * \file
+ *
+ * \brief SLCD Character Mapping declaration.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef HPL_SLCD_CM_H_INCLUDED
+#define HPL_SLCD_CM_H_INCLUDED
+
+#include <stdint.h>
+
+/* Character Mapping Struct */
+struct slcd_char_mapping {
+ uint32_t character : 8; /*!< ASCII character */
+ uint32_t mapping : 24; /*!< Mapping value */
+};
+
+/* SLCD Character settting Struct */
+struct slcd_char_setting {
+ uint8_t com_index; /*!< Common terminal index, start from 0 */
+ uint8_t seg_index; /*!< Segment terminal index, start from 0 */
+ uint8_t nseg; /*!< Number of Segment, this field is used to
+ indentify which segments line will be
+ used. For example, if char mapping from
+ COM1/SEG2 and nseg=2,size=7, then
+ COM1/SEG2, COM1/SEG3, COM2/SEG2,
+ COM2/SEG3, COM3/SEG2, COM3/SEG3,
+ COM4/SEG2 will be used for mapping
+ */
+ uint8_t size; /*!< char size, typical is 7/14/16 */
+};
+#endif /* HPL_SLCD_CM_H_INCLUDED */
diff --git a/watch-library/hardware/hpl/systick/hpl_systick.c b/watch-library/hardware/hpl/systick/hpl_systick.c
new file mode 100644
index 00000000..c2f3b29e
--- /dev/null
+++ b/watch-library/hardware/hpl/systick/hpl_systick.c
@@ -0,0 +1,104 @@
+
+/**
+ * \file
+ *
+ * \brief SysTick related functionality implementation.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_time_measure.h>
+#include <hpl_systick_config.h>
+#include <hpl_delay.h>
+
+/**
+ * \brief Initialize system time module
+ */
+void _system_time_init(void *const hw)
+{
+ (void)hw;
+ SysTick->LOAD = (0xFFFFFF << SysTick_LOAD_RELOAD_Pos);
+ SysTick->CTRL = (1 << SysTick_CTRL_ENABLE_Pos) | (CONF_SYSTICK_TICKINT << SysTick_CTRL_TICKINT_Pos)
+ | (1 << SysTick_CTRL_CLKSOURCE_Pos);
+}
+/**
+ * \brief Initialize delay functionality
+ */
+void _delay_init(void *const hw)
+{
+ _system_time_init(hw);
+}
+
+/**
+ * \brief De-initialize system time module
+ */
+void _system_time_deinit(void *const hw)
+{
+ (void)hw;
+ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
+}
+
+/**
+ * \brief Get system time
+ */
+system_time_t _system_time_get(const void *const hw)
+{
+ (void)hw;
+ return (system_time_t)SysTick->VAL;
+}
+
+/**
+ * \brief Get maximum possible system time
+ */
+system_time_t _system_time_get_max_time_value(const void *const hw)
+{
+ (void)hw;
+ return 0xFFFFFF;
+}
+/**
+ * \brief Delay loop to delay n number of cycles
+ */
+void _delay_cycles(void *const hw, uint32_t cycles)
+{
+ (void)hw;
+ uint8_t n = cycles >> 24;
+ uint32_t buf = cycles;
+
+ while (n--) {
+ SysTick->LOAD = 0xFFFFFF;
+ SysTick->VAL = 0xFFFFFF;
+ while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk))
+ ;
+ buf -= 0xFFFFFF;
+ }
+
+ SysTick->LOAD = buf;
+ SysTick->VAL = buf;
+ while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk))
+ ;
+}
diff --git a/watch-library/hardware/hpl/trng/hpl_trng.c b/watch-library/hardware/hpl/trng/hpl_trng.c
new file mode 100755
index 00000000..43ede044
--- /dev/null
+++ b/watch-library/hardware/hpl/trng/hpl_trng.c
@@ -0,0 +1,110 @@
+/**
+ * \file
+ *
+ * \brief True Random Number Generator
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <err_codes.h>
+#include <hpl_rand_sync.h>
+#include <hpl_trng_config.h>
+#include <utils_assert.h>
+
+static inline int32_t _trng_init(void *hw)
+{
+ if (hri_trng_get_CTRLA_reg(hw, TRNG_CTRLA_ENABLE)) {
+ return ERR_DENIED;
+ }
+ if (CONF_TRNG_RUNSTDBY) {
+ hri_trng_set_CTRLA_RUNSTDBY_bit(hw);
+ } else {
+ hri_trng_clear_CTRLA_RUNSTDBY_bit(hw);
+ }
+ if (CONF_TRNG_DATARDYEO) {
+ hri_trng_set_EVCTRL_DATARDYEO_bit(hw);
+ } else {
+ hri_trng_clear_EVCTRL_DATARDYEO_bit(hw);
+ }
+ return ERR_NONE;
+}
+
+int32_t _rand_sync_init(struct _rand_sync_dev *const dev, void *const hw)
+{
+ int32_t rc;
+
+ ASSERT(dev && hw);
+
+ rc = _trng_init(hw);
+ if (rc == ERR_NONE) {
+ dev->prvt = hw;
+ dev->n_bits = 32;
+ }
+ return rc;
+}
+
+void _rand_sync_deinit(struct _rand_sync_dev *const dev)
+{
+ _rand_sync_disable(dev);
+}
+
+int32_t _rand_sync_enable(struct _rand_sync_dev *const dev)
+{
+ ASSERT(dev);
+ ASSERT(dev->prvt);
+
+ hri_trng_set_CTRLA_ENABLE_bit(dev->prvt);
+ return ERR_NONE;
+}
+
+void _rand_sync_disable(struct _rand_sync_dev *const dev)
+{
+ ASSERT(dev);
+ ASSERT(dev->prvt);
+
+ hri_trng_clear_CTRLA_ENABLE_bit(dev->prvt);
+}
+
+int32_t _rand_sync_set_seed(struct _rand_sync_dev *const dev, const uint32_t seed)
+{
+ (void)dev;
+ (void)seed;
+ return ERR_UNSUPPORTED_OP;
+}
+
+uint32_t _rand_sync_read_one(const struct _rand_sync_dev *const dev)
+{
+ ASSERT(dev);
+ ASSERT(dev->prvt);
+ ASSERT(hri_trng_get_CTRLA_reg(dev->prvt, TRNG_CTRLA_ENABLE));
+
+ while (!hri_trng_get_INTFLAG_reg(dev->prvt, TRNG_INTFLAG_DATARDY)) {
+ /* Wait until data ready. */
+ }
+ return hri_trng_read_DATA_reg(dev->prvt);
+}