diff --git a/firmware/.cproject b/firmware/.cproject
index 0ecdf0e97f..fc79473e60 100644
--- a/firmware/.cproject
+++ b/firmware/.cproject
@@ -205,7 +205,7 @@
-
+
@@ -288,7 +288,7 @@
-
+
diff --git a/firmware/chibios/os/hal/platforms/STM32/GPIOv1/pal_lld.c b/firmware/chibios/os/hal/platforms/STM32/GPIOv1/pal_lld.c
new file mode 100644
index 0000000000..f442dee7f7
--- /dev/null
+++ b/firmware/chibios/os/hal/platforms/STM32/GPIOv1/pal_lld.c
@@ -0,0 +1,184 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file STM32/GPIOv1/pal_lld.c
+ * @brief STM32F1xx GPIO low level driver code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#if STM32_HAS_GPIOG
+#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
+ RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
+ RCC_APB2ENR_IOPEEN | RCC_APB2ENR_IOPFEN | \
+ RCC_APB2ENR_IOPGEN | RCC_APB2ENR_AFIOEN)
+#elif STM32_HAS_GPIOE
+#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
+ RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
+ RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN)
+#else
+#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
+ RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
+ RCC_APB2ENR_AFIOEN)
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 I/O ports configuration.
+ * @details Ports A-D(E, F, G) clocks enabled, AFIO clock enabled.
+ *
+ * @param[in] config the STM32 ports configuration
+ *
+ * @notapi
+ */
+void _pal_lld_init(const PALConfig *config) {
+
+ /*
+ * Enables the GPIO related clocks.
+ */
+ rccEnableAPB2(APB2_EN_MASK, FALSE);
+
+ /*
+ * Initial GPIO setup.
+ */
+ GPIOA->ODR = config->PAData.odr;
+ GPIOA->CRH = config->PAData.crh;
+ GPIOA->CRL = config->PAData.crl;
+ GPIOB->ODR = config->PBData.odr;
+ GPIOB->CRH = config->PBData.crh;
+ GPIOB->CRL = config->PBData.crl;
+ GPIOC->ODR = config->PCData.odr;
+ GPIOC->CRH = config->PCData.crh;
+ GPIOC->CRL = config->PCData.crl;
+ GPIOD->ODR = config->PDData.odr;
+ GPIOD->CRH = config->PDData.crh;
+ GPIOD->CRL = config->PDData.crl;
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+ GPIOE->ODR = config->PEData.odr;
+ GPIOE->CRH = config->PEData.crh;
+ GPIOE->CRL = config->PEData.crl;
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+ GPIOF->ODR = config->PFData.odr;
+ GPIOF->CRH = config->PFData.crh;
+ GPIOF->CRL = config->PFData.crl;
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+ GPIOG->ODR = config->PGData.odr;
+ GPIOG->CRH = config->PGData.crh;
+ GPIOG->CRL = config->PGData.crl;
+#endif
+#endif
+#endif
+}
+
+/**
+ * @brief Pads mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note @p PAL_MODE_UNCONNECTED is implemented as push pull output at 2MHz.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port the port identifier
+ * @param[in] mask the group mask
+ * @param[in] mode the mode
+ *
+ * @notapi
+ */
+void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode) {
+ static const uint8_t cfgtab[] = {
+ 4, /* PAL_MODE_RESET, implemented as input.*/
+ 2, /* PAL_MODE_UNCONNECTED, implemented as push pull output 2MHz.*/
+ 4, /* PAL_MODE_INPUT */
+ 8, /* PAL_MODE_INPUT_PULLUP */
+ 8, /* PAL_MODE_INPUT_PULLDOWN */
+ 0, /* PAL_MODE_INPUT_ANALOG */
+ 3, /* PAL_MODE_OUTPUT_PUSHPULL, 50MHz.*/
+ 7, /* PAL_MODE_OUTPUT_OPENDRAIN, 50MHz.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 0xB, /* PAL_MODE_STM32_ALTERNATE_PUSHPULL, 50MHz.*/
+ 0xF, /* PAL_MODE_STM32_ALTERNATE_OPENDRAIN, 50MHz.*/
+ };
+ uint32_t mh, ml, crh, crl, cfg;
+ unsigned i;
+
+ if (mode == PAL_MODE_INPUT_PULLUP)
+ port->BSRR = mask;
+ else if (mode == PAL_MODE_INPUT_PULLDOWN)
+ port->BRR = mask;
+ cfg = cfgtab[mode];
+ mh = ml = crh = crl = 0;
+ for (i = 0; i < 8; i++) {
+ ml <<= 4;
+ mh <<= 4;
+ crl <<= 4;
+ crh <<= 4;
+ if ((mask & 0x0080) == 0)
+ ml |= 0xf;
+ else
+ crl |= cfg;
+ if ((mask & 0x8000) == 0)
+ mh |= 0xf;
+ else
+ crh |= cfg;
+ mask <<= 1;
+ }
+ port->CRH = (port->CRH & mh) | crh;
+ port->CRL = (port->CRL & ml) | crl;
+}
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/firmware/chibios/os/hal/platforms/STM32/GPIOv1/pal_lld.h b/firmware/chibios/os/hal/platforms/STM32/GPIOv1/pal_lld.h
new file mode 100644
index 0000000000..3beae53499
--- /dev/null
+++ b/firmware/chibios/os/hal/platforms/STM32/GPIOv1/pal_lld.h
@@ -0,0 +1,334 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file STM32/GPIOv1/pal_lld.h
+ * @brief STM32F1xx GPIO low level driver header.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#ifndef _PAL_LLD_H_
+#define _PAL_LLD_H_
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Unsupported modes and specific modes */
+/*===========================================================================*/
+
+/**
+ * @name STM32-specific I/O mode flags
+ * @{
+ */
+/**
+ * @brief STM32 specific alternate push-pull output mode.
+ */
+#define PAL_MODE_STM32_ALTERNATE_PUSHPULL 16
+
+/**
+ * @brief STM32 specific alternate open-drain output mode.
+ */
+#define PAL_MODE_STM32_ALTERNATE_OPENDRAIN 17
+/** @} */
+
+/*===========================================================================*/
+/* I/O Ports Types and constants. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO port setup info.
+ */
+typedef struct {
+ /** Initial value for ODR register.*/
+ uint32_t odr;
+ /** Initial value for CRL register.*/
+ uint32_t crl;
+ /** Initial value for CRH register.*/
+ uint32_t crh;
+} stm32_gpio_setup_t;
+
+/**
+ * @brief STM32 GPIO static initializer.
+ * @details An instance of this structure must be passed to @p palInit() at
+ * system startup time in order to initialize the digital I/O
+ * subsystem. This represents only the initial setup, specific pads
+ * or whole ports can be reprogrammed at later time.
+ */
+typedef struct {
+ /** @brief Port A setup data.*/
+ stm32_gpio_setup_t PAData;
+ /** @brief Port B setup data.*/
+ stm32_gpio_setup_t PBData;
+ /** @brief Port C setup data.*/
+ stm32_gpio_setup_t PCData;
+ /** @brief Port D setup data.*/
+ stm32_gpio_setup_t PDData;
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+ /** @brief Port E setup data.*/
+ stm32_gpio_setup_t PEData;
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+ /** @brief Port F setup data.*/
+ stm32_gpio_setup_t PFData;
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+ /** @brief Port G setup data.*/
+ stm32_gpio_setup_t PGData;
+#endif
+#endif
+#endif
+} PALConfig;
+
+/**
+ * @brief Width, in bits, of an I/O port.
+ */
+#define PAL_IOPORTS_WIDTH 16
+
+/**
+ * @brief Whole port mask.
+ * @details This macro specifies all the valid bits into a port.
+ */
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
+
+/**
+ * @brief Digital I/O port sized unsigned type.
+ */
+typedef uint32_t ioportmask_t;
+
+/**
+ * @brief Digital I/O modes.
+ */
+typedef uint32_t iomode_t;
+
+/**
+ * @brief Port Identifier.
+ * @details This type can be a scalar or some kind of pointer, do not make
+ * any assumption about it, use the provided macros when populating
+ * variables of this type.
+ */
+typedef GPIO_TypeDef * ioportid_t;
+
+/*===========================================================================*/
+/* I/O Ports Identifiers. */
+/* The low level driver wraps the definitions already present in the STM32 */
+/* firmware library. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO port A identifier.
+ */
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+#define IOPORT1 GPIOA
+#endif
+
+/**
+ * @brief GPIO port B identifier.
+ */
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+#define IOPORT2 GPIOB
+#endif
+
+/**
+ * @brief GPIO port C identifier.
+ */
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+#define IOPORT3 GPIOC
+#endif
+
+/**
+ * @brief GPIO port D identifier.
+ */
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+#define IOPORT4 GPIOD
+#endif
+
+/**
+ * @brief GPIO port E identifier.
+ */
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+#define IOPORT5 GPIOE
+#endif
+
+/**
+ * @brief GPIO port F identifier.
+ */
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+#define IOPORT6 GPIOF
+#endif
+
+/**
+ * @brief GPIO port G identifier.
+ */
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+#define IOPORT7 GPIOG
+#endif
+
+/*===========================================================================*/
+/* Implementation, some of the following macros could be implemented as */
+/* functions, if so please put them in pal_lld.c. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO ports subsystem initialization.
+ *
+ * @notapi
+ */
+#define pal_lld_init(config) _pal_lld_init(config)
+
+/**
+ * @brief Reads an I/O port.
+ * @details This function is implemented by reading the GPIO IDR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The port bits.
+ *
+ * @notapi
+ */
+#define pal_lld_readport(port) ((port)->IDR)
+
+/**
+ * @brief Reads the output latch.
+ * @details This function is implemented by reading the GPIO ODR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The latched logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readlatch(port) ((port)->ODR)
+
+/**
+ * @brief Writes on a I/O port.
+ * @details This function is implemented by writing the GPIO ODR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be written on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_writeport(port, bits) ((port)->ODR = (bits))
+
+/**
+ * @brief Sets a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be ORed on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_setport(port, bits) ((port)->BSRR = (bits))
+
+/**
+ * @brief Clears a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BRR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be cleared on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_clearport(port, bits) ((port)->BRR = (bits))
+
+/**
+ * @brief Writes a group of bits.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset the group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group
+ * width are masked.
+ *
+ * @notapi
+ */
+#define pal_lld_writegroup(port, mask, offset, bits) \
+ ((port)->BSRR = ((~(bits) & (mask)) << (16 + (offset))) | \
+ (((bits) & (mask)) << (offset)))
+
+/**
+ * @brief Pads group mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] mode group mode
+ *
+ * @notapi
+ */
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
+ _pal_lld_setgroupmode(port, mask << offset, mode)
+
+/**
+ * @brief Writes a logical state on an output pad.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] bit logical value, the value must be @p PAL_LOW or
+ * @p PAL_HIGH
+ *
+ * @notapi
+ */
+#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
+
+extern const PALConfig pal_default_config;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _pal_lld_init(const PALConfig *config);
+ void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PAL */
+
+#endif /* _PAL_LLD_H_ */
+
+/** @} */
diff --git a/firmware/chibios/os/hal/platforms/STM32/RTCv1/rtc_lld.c b/firmware/chibios/os/hal/platforms/STM32/RTCv1/rtc_lld.c
new file mode 100644
index 0000000000..6980dbd6b2
--- /dev/null
+++ b/firmware/chibios/os/hal/platforms/STM32/RTCv1/rtc_lld.c
@@ -0,0 +1,329 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file STM32/RTCv1/rtc_lld.c
+ * @brief STM32 RTC subsystem low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC driver identifier.
+ */
+RTCDriver RTCD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Wait for synchronization of RTC registers with APB1 bus.
+ * @details This function must be invoked before trying to read RTC registers
+ * in the backup domain: DIV, CNT, ALR. CR registers can always
+ * be read.
+ *
+ * @notapi
+ */
+#define rtc_lld_apb1_sync() {while ((RTC->CRL & RTC_CRL_RSF) == 0);}
+
+/**
+ * @brief Wait for for previous write operation complete.
+ * @details This function must be invoked before writing to any RTC registers
+ *
+ * @notapi
+ */
+#define rtc_lld_wait_write() {while ((RTC->CRL & RTC_CRL_RTOFF) == 0);}
+
+/**
+ * @brief Acquires write access to RTC registers.
+ * @details Before writing to the backup domain RTC registers the previous
+ * write operation must be completed. Use this function before
+ * writing to PRL, CNT, ALR registers.
+ *
+ * @notapi
+ */
+#define rtc_lld_acquire() {rtc_lld_wait_write(); RTC->CRL |= RTC_CRL_CNF;}
+
+/**
+ * @brief Releases write access to RTC registers.
+ *
+ * @notapi
+ */
+#define rtc_lld_release() {RTC->CRL &= ~RTC_CRL_CNF;}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(RTC_IRQHandler) {
+ uint16_t flags;
+
+ CH_IRQ_PROLOGUE();
+
+ /* This wait works only when AHB1 bus was previously powered off by any
+ reason (standby, reset, etc). In other cases it does nothing.*/
+ rtc_lld_apb1_sync();
+
+ /* Mask of all enabled and pending sources.*/
+ flags = RTC->CRH & RTC->CRL;
+ RTC->CRL &= ~(RTC_CRL_SECF | RTC_CRL_ALRF | RTC_CRL_OWF);
+
+ if (flags & RTC_CRL_SECF)
+ RTCD1.callback(&RTCD1, RTC_EVENT_SECOND);
+
+ if (flags & RTC_CRL_ALRF)
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM);
+
+ if (flags & RTC_CRL_OWF)
+ RTCD1.callback(&RTCD1, RTC_EVENT_OVERFLOW);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Load value of RTCCLK to prescaler registers.
+ * @note The pre-scaler must not be set on every reset as RTC clock
+ * counts are lost when it is set.
+ * @note This function designed to be called from
+ * hal_lld_backup_domain_init(). Because there is only place
+ * where possible to detect BKP domain reset event reliably.
+ *
+ * @notapi
+ */
+void rtc_lld_set_prescaler(void){
+ rtc_lld_acquire();
+ RTC->PRLH = (uint16_t)((STM32_RTCCLK - 1) >> 16) & 0x000F;
+ RTC->PRLL = (uint16_t)(((STM32_RTCCLK - 1)) & 0xFFFF);
+ rtc_lld_release();
+}
+
+/**
+ * @brief Initialize RTC.
+ *
+ * @notapi
+ */
+void rtc_lld_init(void){
+
+ /* RSF bit must be cleared by software after an APB1 reset or an APB1 clock
+ stop. Otherwise its value will not be actual. */
+ RTC->CRL &= ~RTC_CRL_RSF;
+
+ /* Required because access to PRL.*/
+ rtc_lld_apb1_sync();
+
+ /* All interrupts initially disabled.*/
+ rtc_lld_wait_write();
+ RTC->CRH = 0;
+
+ /* Callback initially disabled.*/
+ RTCD1.callback = NULL;
+
+ /* IRQ vector permanently assigned to this driver.*/
+ nvicEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(STM32_RTC_IRQ_PRIORITY));
+}
+
+/**
+ * @brief Set current time.
+ * @note Fractional part will be silently ignored. There is no possibility
+ * to change it on STM32F1xx platform.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) {
+
+ (void)rtcp;
+
+ rtc_lld_acquire();
+ RTC->CNTH = (uint16_t)(timespec->tv_sec >> 16);
+ RTC->CNTL = (uint16_t)(timespec->tv_sec & 0xFFFF);
+ rtc_lld_release();
+}
+
+/**
+ * @brief Get current time.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) {
+ (void)rtcp;
+
+ uint32_t time_frac;
+
+ /* Required because access to CNT and DIV.*/
+ rtc_lld_apb1_sync();
+
+ /* Loops until two consecutive read returning the same value.*/
+ do {
+ timespec->tv_sec = ((uint32_t)(RTC->CNTH) << 16) + RTC->CNTL;
+ time_frac = (((uint32_t)RTC->DIVH) << 16) + (uint32_t)RTC->DIVL;
+ } while ((timespec->tv_sec) != (((uint32_t)(RTC->CNTH) << 16) + RTC->CNTL));
+
+ timespec->tv_msec = (uint16_t)(((STM32_RTCCLK - 1 - time_frac) * 1000) /
+ STM32_RTCCLK);
+}
+
+/**
+ * @brief Set alarm time.
+ *
+ * @note Default value after BKP domain reset is 0xFFFFFFFF
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[in] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec) {
+
+ (void)rtcp;
+ (void)alarm;
+
+ rtc_lld_acquire();
+ if (alarmspec != NULL) {
+ RTC->ALRH = (uint16_t)(alarmspec->tv_sec >> 16);
+ RTC->ALRL = (uint16_t)(alarmspec->tv_sec & 0xFFFF);
+ }
+ else {
+ RTC->ALRH = 0;
+ RTC->ALRL = 0;
+ }
+ rtc_lld_release();
+}
+
+/**
+ * @brief Get current alarm.
+ * @note If an alarm has not been set then the returned alarm specification
+ * is not meaningful.
+ *
+ * @note Default value after BKP domain reset is 0xFFFFFFFF.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[out] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec) {
+
+ (void)rtcp;
+ (void)alarm;
+
+ /* Required because access to ALR.*/
+ rtc_lld_apb1_sync();
+
+ alarmspec->tv_sec = ((RTC->ALRH << 16) + RTC->ALRL);
+}
+
+/**
+ * @brief Enables or disables RTC callbacks.
+ * @details This function enables or disables callbacks, use a @p NULL pointer
+ * in order to disable a callback.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] callback callback function pointer or @p NULL
+ *
+ * @notapi
+ */
+void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
+
+ if (callback != NULL) {
+
+ /* IRQ sources enabled only after setting up the callback.*/
+ rtcp->callback = callback;
+
+ rtc_lld_wait_write();
+ RTC->CRL &= ~(RTC_CRL_OWF | RTC_CRL_ALRF | RTC_CRL_SECF);
+ RTC->CRH = RTC_CRH_OWIE | RTC_CRH_ALRIE | RTC_CRH_SECIE;
+ }
+ else {
+ rtc_lld_wait_write();
+ RTC->CRH = 0;
+
+ /* Callback set to NULL only after disabling the IRQ sources.*/
+ rtcp->callback = NULL;
+ }
+}
+
+#include "chrtclib.h"
+
+/**
+ * @brief Get current time in format suitable for usage in FatFS.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @return FAT time value.
+ *
+ * @api
+ */
+uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp) {
+ uint32_t fattime;
+ struct tm timp;
+
+ rtcGetTimeTm(rtcp, &timp);
+
+ fattime = (timp.tm_sec) >> 1;
+ fattime |= (timp.tm_min) << 5;
+ fattime |= (timp.tm_hour) << 11;
+ fattime |= (timp.tm_mday) << 16;
+ fattime |= (timp.tm_mon + 1) << 21;
+ fattime |= (timp.tm_year - 80) << 25;
+
+ return fattime;
+}
+#endif /* HAL_USE_RTC */
+
+/** @} */
diff --git a/firmware/chibios/os/hal/platforms/STM32/RTCv1/rtc_lld.h b/firmware/chibios/os/hal/platforms/STM32/RTCv1/rtc_lld.h
new file mode 100644
index 0000000000..69508d60a4
--- /dev/null
+++ b/firmware/chibios/os/hal/platforms/STM32/RTCv1/rtc_lld.h
@@ -0,0 +1,187 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file STM32/RTCv1/rtc_lld.h
+ * @brief STM32F1xx RTC subsystem low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#ifndef _RTC_LLD_H_
+#define _RTC_LLD_H_
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief This RTC implementation supports callbacks.
+ */
+#define RTC_SUPPORTS_CALLBACKS TRUE
+
+/**
+ * @brief One alarm comparator available.
+ */
+#define RTC_ALARMS 1
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/*
+ * RTC driver system settings.
+ */
+#define STM32_RTC_IRQ_PRIORITY 15
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if HAL_USE_RTC && !STM32_HAS_RTC
+#error "RTC not present in the selected device"
+#endif
+
+#if STM32_RTCCLK == 0
+#error "RTC clock not enabled"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an RTC alarm time stamp.
+ */
+typedef struct RTCAlarm RTCAlarm;
+
+/**
+ * @brief Type of a structure representing an RTC callbacks config.
+ */
+typedef struct RTCCallbackConfig RTCCallbackConfig;
+
+/**
+ * @brief Type of an RTC alarm.
+ * @details Meaningful on platforms with more than 1 alarm comparator.
+ */
+typedef uint32_t rtcalarm_t;
+
+/**
+ * @brief Type of an RTC event.
+ */
+typedef enum {
+ RTC_EVENT_SECOND = 0, /** Triggered every second. */
+ RTC_EVENT_ALARM = 1, /** Triggered on alarm. */
+ RTC_EVENT_OVERFLOW = 2 /** Triggered on counter overflow. */
+} rtcevent_t;
+
+/**
+ * @brief Type of a generic RTC callback.
+ */
+typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
+
+/**
+ * @brief Structure representing an RTC callbacks config.
+ */
+struct RTCCallbackConfig{
+ /**
+ * @brief Generic RTC callback pointer.
+ */
+ rtccb_t callback;
+};
+
+/**
+ * @brief Structure representing an RTC time stamp.
+ */
+struct RTCTime {
+ /**
+ * @brief Seconds since UNIX epoch.
+ */
+ uint32_t tv_sec;
+ /**
+ * @brief Fractional part.
+ */
+ uint32_t tv_msec;
+};
+
+/**
+ * @brief Structure representing an RTC alarm time stamp.
+ */
+struct RTCAlarm {
+ /**
+ * @brief Seconds since UNIX epoch.
+ */
+ uint32_t tv_sec;
+};
+
+/**
+ * @brief Structure representing an RTC driver.
+ */
+struct RTCDriver{
+ /**
+ * @brief Callback pointer.
+ */
+ rtccb_t callback;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern RTCDriver RTCD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void rtc_lld_set_prescaler(void);
+ void rtc_lld_init(void);
+ void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec);
+ void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec);
+ void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec);
+ void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec);
+ void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
+ uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_RTC */
+
+#endif /* _RTC_LLD_H_ */
+
+/** @} */