diff --git a/AUTHORS.txt b/AUTHORS.txt
index f6a91bd8..0e3de341 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -29,3 +29,6 @@ https://github.com/Codetector1374
Alex Lewontin aka alexclewontin
https://github.com/alexclewontin
+
+Ein Terakawa aka a_p_u_r_o
+https://github.com/elfmimi
diff --git a/os/hal/ports/NUMICRO/LLD/I2Cv1/driver.mk b/os/hal/ports/NUMICRO/LLD/I2Cv1/driver.mk
new file mode 100644
index 00000000..fde12385
--- /dev/null
+++ b/os/hal/ports/NUMICRO/LLD/I2Cv1/driver.mk
@@ -0,0 +1,9 @@
+ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/I2Cv1
diff --git a/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.c
new file mode 100644
index 00000000..359a2322
--- /dev/null
+++ b/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.c
@@ -0,0 +1,529 @@
+/*
+ ChibiOS - Copyright (C) 2019 Ein Terakawa
+ Copyright (C) 2014-2015 Fabio Utzig
+
+ 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 NUMICRO/hal_i2c_lld.c
+ * @brief NUMICRO I2C subsystem low level driver source.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define I2C_I2CON_STA I2C_I2CON_STA_Msk
+#define I2C_I2CON_STO I2C_I2CON_STO_Msk
+#define I2C_I2CON_SI I2C_I2CON_SI_Msk
+#define I2C_I2CON_AA I2C_I2CON_AA_Msk
+#define I2C_I2CON_STA_STO_SI_AA (I2C_I2CON_STA|I2C_I2CON_STO|I2C_I2CON_SI|I2C_I2CON_AA)
+#define I2C_Trigger(i2c, sta, sto, si, ack) ((i2c)->I2CON = (((i2c)->I2CON & ~(I2C_I2CON_STA_STO_SI_AA)) | ((sta)?(I2C_I2CON_STA):0) | ((sto)?(I2C_I2CON_STO):0) | ((si)?(I2C_I2CON_SI):0) | ((ack)?(I2C_I2CON_AA):0)))
+
+#define I2C_START(i2c) ((i2c)->I2CON = ((i2c)->I2CON | I2C_I2CON_SI) | I2C_I2CON_STA)
+#define I2C_STOP(i2c) ((i2c)->I2CON = ((i2c)->I2CON | I2C_I2CON_SI) | I2C_I2CON_STO)
+#define I2C_ENABLE(i2c) ((i2c)->I2CON = ((i2c)->I2CON | I2C_I2CON_ENS1_Msk))
+#define I2C_DISABLE(i2c) ((i2c)->I2CON = ((i2c)->I2CON & ~I2C_I2CON_ENS1_Msk))
+#define I2C_EnableInt(i2c) ((i2c)->I2CON = ((i2c)->I2CON | I2C_I2CON_EI_Msk))
+#define I2C_DisableInt(i2c) ((i2c)->I2CON = ((i2c)->I2CON & ~I2C_I2CON_EI_Msk))
+#define I2C_ClearTimeoutFlag(i2c) ((i2c)->I2CTOC = ((i2c)->I2CTOC | I2C_I2CTOC_TIF_Msk))
+#define I2C_GET_STATUS(i2c) ((i2c)->I2CSTATUS)
+#define I2C_SET_DATA(i2c, u8dat) ((i2c)->I2CDAT = (u8dat))
+#define I2C_GET_DATA(i2c) ((i2c)->I2CDAT)
+#define I2C_GET_TIMEOUT_FLAG(i2c) (((i2c)->I2CTOC & I2C_I2CTOC_TIF_Msk)?1:0)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief I2C0 driver identifier.
+ */
+#if NUMICRO_I2C_USE_I2C0 || defined(__DOXYGEN__)
+I2CDriver I2CD0;
+#endif
+
+/**
+ * @brief I2C1 driver identifier.
+ */
+#if NUMICRO_I2C_USE_I2C1 || defined(__DOXYGEN__)
+I2CDriver I2CD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static void i2c_config_frequency(I2CDriver *i2cp) {
+
+ uint8_t divisor;
+
+ if (i2cp->config != NULL)
+ divisor = (I2C_PCLK * 10 / (i2cp->config->clock * 4) + 5) / 10 - 1;
+ else
+ divisor = I2C_PCLK / 4 / 100000 - 1;
+
+ i2cp->i2c->I2CLK = divisor;
+}
+
+
+/**
+ * @brief Common IRQ handler.
+ * @note Tries hard to clear all the pending interrupt sources, we don't
+ * want to go through the whole ISR and have another interrupt soon
+ * after.
+ *
+ * @param[in] i2cp pointer to an I2CDriver
+ */
+static void serve_interrupt(I2CDriver *i2cp) {
+
+ I2C_TypeDef *i2c = i2cp->i2c;
+
+ if (I2C_GET_TIMEOUT_FLAG(i2c)) {
+ i2cp->errors |= I2C_TIMEOUT;
+ I2C_ClearTimeoutFlag(i2c);
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ return;
+ }
+
+ uint8_t status = (uint8_t)I2C_GET_STATUS(i2c);
+
+ if (status == 0x08 || status == 0x10) {
+ if (i2cp->intstate == STATE_STOP) {
+ I2C_DisableInt(i2c);
+ return;
+ }
+ i2cp->is_master = 1;
+ }
+
+ /* check if we're master or slave */
+ if (i2cp->is_master) {
+ /* master */
+
+ if (status == 0x38 || status == 0x68 || status == 0x78 || status == 0xB0) {
+ /* check if we lost arbitration */
+ i2cp->errors |= I2C_ARBITRATION_LOST;
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ /* TODO: may need to do more here, reset bus? */
+ /* Perhaps clear MST? */
+ i2cp->is_master = 0;
+ }
+ else if (status == 0x08 || status == 0x10) {
+ uint8_t op = (i2cp->intstate == STATE_SEND) ? 0 : 1;
+ I2C_SET_DATA(i2c, (i2cp->addr << 1) | op);
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ }
+ else if (status == 0x18 || status == 0x28) {
+ /* ACK */
+ if (i2cp->txbuf != NULL && i2cp->txidx < i2cp->txbytes) {
+ /* slave ACK'd and we want to send more */
+ I2C_SET_DATA(i2c, i2cp->txbuf[i2cp->txidx++]);
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ } else {
+ /* slave ACK'd and we are done sending */
+ if (i2cp->rxbuf != NULL && i2cp->rxbytes != 0) {
+ i2cp->intstate = STATE_RECV;
+ I2C_START(i2c); // should we use Repeat-START ?
+ } else {
+ i2cp->intstate = STATE_STOP;
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 1, /* SI */ 1, /* Ack */ 0);
+ /* this wakes up the waiting thread at the end of ISR */
+ _i2c_wakeup_isr(i2cp);
+ }
+ }
+ }
+ else if (status == 0x20 || status == 0x30) {
+ /* NAK */
+ i2cp->errors |= I2C_ACK_FAILURE;
+ i2cp->intstate = STATE_STOP;
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 1, /* SI */ 1, /* Ack */ 0); // go to Repeated-START state
+ }
+ else if (status == 0x40) {
+ /* ACK to read request */
+#if 1
+ if (i2cp->rxidx + 1 == i2cp->rxbytes) {
+ /* only one byte to receive */
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ } else {
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 1);
+ }
+#endif
+ }
+ else if (status == 0x50 || status == 0x58) {
+ /* one byte done */
+ if (i2cp->rxbuf == NULL || i2cp->rxidx >= i2cp->rxbytes) {
+ /* this is unexpected. */
+ i2cp->errors |= I2C_OVERRUN; // is this the apropriate error code?
+ i2cp->intstate = STATE_STOP;
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 1, /* SI */ 1, /* Ack */ 0);
+ }
+ else {
+ i2cp->rxbuf[i2cp->rxidx++] = I2C_GET_DATA(i2c);
+ if (i2cp->rxidx == i2cp->rxbytes) {
+ /* last byte done */
+ i2cp->intstate = STATE_STOP;
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 1, /* SI */ 1, /* Ack */ 0);
+_i2c_wakeup_isr(i2cp);
+ }
+ else if (i2cp->rxidx + 1 == i2cp->rxbytes) {
+ /* next byte is the last */
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ }
+ else {
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 0, /* SI */ 1, /* Ack */ 1);
+ }
+ }
+ }
+ else if (status == 0x48) {
+ /* NAK to read request */
+ i2cp->errors |= I2C_ACK_FAILURE;
+ i2cp->intstate = STATE_STOP;
+ I2C_Trigger(i2c, /* Start */ 0, /* Stop */ 1, /* SI */ 1, /* Ack */ 0);
+ }
+ else if (status == 0xF8) {
+ /* CAUTION! I2CSTATUS == 0xF8 won't trigger interrupt! */
+ /* everything completed */
+ // i2cp->is_master = 0;
+ // i2cp->intstate = STATE_STOP;
+ }
+ else {
+ /* need anything else? */
+ }
+ } else {
+ /* slave */
+
+ /* Not implemented yet */
+ }
+
+ /* Reset other interrupt sources */
+
+ /* Reset interrupt flag */
+
+ if (i2cp->errors != I2C_NO_ERROR)
+ _i2c_wakeup_error_isr(i2cp);
+ else if (i2cp->intstate == STATE_STOP && i2cp->is_master == 0)
+ _i2c_wakeup_isr(i2cp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if NUMICRO_I2C_USE_I2C0 || defined(__DOXYGEN__)
+
+OSAL_IRQ_HANDLER(NUMICRO_I2C0_IRQ_VECTOR) {
+
+ OSAL_IRQ_PROLOGUE();
+ serve_interrupt(&I2CD0);
+ OSAL_IRQ_EPILOGUE();
+}
+
+#endif
+
+#if NUMICRO_I2C_USE_I2C1 || defined(__DOXYGEN__)
+
+OSAL_IRQ_HANDLER(NUMICRO_I2C1_IRQ_VECTOR) {
+
+ OSAL_IRQ_PROLOGUE();
+ serve_interrupt(&I2CD1);
+ OSAL_IRQ_EPILOGUE();
+}
+
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level I2C driver initialization.
+ *
+ * @notapi
+ */
+void i2c_lld_init(void) {
+
+#if NUMICRO_I2C_USE_I2C0
+ i2cObjectInit(&I2CD0);
+ I2CD0.thread = NULL;
+ I2CD0.i2c = I2C0;
+ I2CD0.is_master = 0;
+ /* Select I2C0 Pins PF.2 and PF.3 as I2C0_SDA and I2C0_SCL*/
+#ifdef NUC123xxxANx
+ SYS->GPF_MFP |= 0x000C;
+ SYS->ALT_MFP1 = (SYS->ALT_MFP1 & 0xF0FFFFFF) | 0x0A000000;
+#endif
+#ifdef NUC123xxxAEx
+ SYS->GPF_MFPL = (SYS->GPF_MFPL & 0xFFFF00FF) | 0x00002200;
+#endif
+#endif
+
+#if NUMICRO_I2C_USE_I2C1
+ i2cObjectInit(&I2CD1);
+ I2CD1.thread = NULL;
+ I2CD1.i2c = I2C1;
+ I2CD1.is_master = 0;
+ /* Select I2C1 Pins PA.10 and PA.11 as I2C1_SDA and I2C1_SCL */
+#ifdef NUC123xxxANx
+ SYS->GPA_MFP |= 0x0C00;
+ SYS->ALT_MFP = (SYS->ALT_MFP & 0xFFFFE7FF) | 0x00000000;
+#endif
+#ifdef NUC123xxxAEx
+ SYS->GPA_MFPH = (SYS->GPA_MFPH & 0xFFFF00FF) | 0x00001100;
+#endif
+#endif
+
+}
+
+/**
+ * @brief Configures and activates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_start(I2CDriver *i2cp) {
+ /* We are already covered with osalSysLock() which is same as
+ * __disable_irq(). We don't need farther protection by osalSysDisable().
+ */
+
+ if (i2cp->state == I2C_STOP) {
+
+ /* TODO:
+ * The PORT must be enabled somewhere. The PIN multiplexer
+ * will map the I2C functionality to some PORT which must
+ * then be enabled. The easier way is enabling all PORTs at
+ * startup, which is currently being done in __early_init.
+ */
+#if NUMICRO_I2C_USE_I2C0
+ if (&I2CD0 == i2cp) {
+ /* Eable I2C0 Module Clock */
+ CLK->APBCLK |= CLK_APBCLK_I2C0_EN_Msk;
+ /* Reset I2C0 Module */
+ SYS->IPRSTC2 |= SYS_IPRSTC2_I2C0_RST_Msk;
+ SYS->IPRSTC2 &= ~SYS_IPRSTC2_I2C0_RST_Msk;
+ nvicEnableVector(NUMICRO_I2C0_IRQ_NUMBER, NUMICRO_I2C_I2C0_PRIORITY);
+ }
+#endif
+
+#if NUMICRO_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ /* Eable I2C1 Module Clock */
+ CLK->APBCLK |= CLK_APBCLK_I2C1_EN_Msk;
+ /* Reset I2C1 Module */
+ SYS->IPRSTC2 |= SYS_IPRSTC2_I2C1_RST_Msk;
+ SYS->IPRSTC2 &= ~SYS_IPRSTC2_I2C1_RST_Msk;
+ nvicEnableVector(NUMICRO_I2C1_IRQ_NUMBER, NUMICRO_I2C_I2C1_PRIORITY);
+ }
+#endif
+
+ // uint32_t bus_clock = i2cp->config ? i2cp->config->clock : 100000;
+ // I2C_Open(i2cp->i2c, bus_clock);
+ i2c_config_frequency(i2cp);
+ /* Enable I2Cx Module */
+ I2C_ENABLE(i2cp->i2c);
+ /* Enable Interrupt for I2Cx */
+ I2C_EnableInt(i2cp->i2c);
+ i2cp->intstate = STATE_STOP; // internal state
+ }
+}
+
+/**
+ * @brief Deactivates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_stop(I2CDriver *i2cp) {
+ /* We are already covered with osalSysLock() which is same as
+ * __disable_irq(). We don't need farther protection by osalSysDisable().
+ */
+
+ if (i2cp->state != I2C_STOP) {
+ /* Disable Interrupt for I2Cx */
+ I2C_DisableInt(i2cp->i2c);
+#if NUMICRO_I2C_USE_I2C0
+ if (&I2CD0 == i2cp) {
+ /* Reset I2C0 Module */
+ SYS->IPRSTC2 |= SYS_IPRSTC2_I2C0_RST_Msk;
+ SYS->IPRSTC2 &= ~SYS_IPRSTC2_I2C0_RST_Msk;
+ }
+#endif
+
+#if NUMICRO_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ /* Reset I2C1 Module */
+ SYS->IPRSTC2 |= SYS_IPRSTC2_I2C1_RST_Msk;
+ SYS->IPRSTC2 &= ~SYS_IPRSTC2_I2C1_RST_Msk;
+ }
+#endif
+
+ /* Disable I2Cx Module */
+ I2C_DISABLE(i2cp->i2c);
+
+#if NUMICRO_I2C_USE_I2C0
+ if (&I2CD0 == i2cp) {
+ nvicDisableVector(NUMICRO_I2C0_IRQ_NUMBER);
+ /* Disable I2C0 Module Clock */
+ CLK->APBCLK &= ~CLK_APBCLK_I2C0_EN_Msk;
+ }
+#endif
+
+#if NUMICRO_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ nvicDisableVector(NUMICRO_I2C1_IRQ_NUMBER);
+ /* Disable I2C1 Module Clock */
+ CLK->APBCLK &= ~CLK_APBCLK_I2C1_EN_Msk;
+ }
+#endif
+ }
+}
+
+static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ systime_t timeout) {
+
+ msg_t msg;
+ // systime_t start, end;
+
+ i2cp->errors = I2C_NO_ERROR;
+ i2cp->addr = addr;
+
+ i2cp->txbuf = txbuf;
+ i2cp->txbytes = txbytes;
+ i2cp->txidx = 0;
+
+ i2cp->rxbuf = rxbuf;
+ i2cp->rxbytes = rxbytes;
+ i2cp->rxidx = 0;
+
+ /* clear status flags */
+
+ /* acquire the bus */
+ /* check to see if we already have the bus */
+ if(i2cp->is_master) {
+
+ /* send repeated start */
+ I2C_START(i2cp->i2c);
+ while((uint8_t)I2C_GET_STATUS(i2cp->i2c) == 0xF8);
+
+ } else {
+ /* unlock during the wait, so that tasks with
+ * higher priority can get attention */
+ // osalSysUnlock();
+
+ /* wait until the bus is released */
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ // start = osalOsGetSystemTimeX();
+ // end = start + OSAL_MS2ST(NUMICRO_I2C_BUSY_TIMEOUT);
+ uint8_t status = (uint8_t)(I2C_GET_STATUS(i2cp->i2c));
+ if (status == 0x08 || status == 0x10) {
+ i2cp->is_master = 1;
+ I2C_EnableInt(i2cp->i2c);
+ } else {
+ I2C_Trigger(i2cp->i2c, /* Start */ 1, /* Stop */ 0, /* SI */ 1, /* Ack */ 0);
+ }
+ }
+
+ /* wait for the ISR to signal that the transmission (or receive if no transmission) phase is complete */
+
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+ if (msg == MSG_TIMEOUT) {
+ /* What to do here? */
+ // I2C_DisableInt(i2cp->i2c);
+ return msg;
+ }
+ i2cp->is_master = 0;
+
+ I2C_ClearTimeoutFlag(i2cp->i2c);
+
+ return msg;
+}
+
+/**
+ * @brief Receives data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ systime_t timeout) {
+
+ i2cp->intstate = STATE_RECV;
+ return _i2c_txrx_timeout(i2cp, addr, NULL, 0, rxbuf, rxbytes, timeout);
+}
+
+/**
+ * @brief Transmits data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ systime_t timeout) {
+
+ i2cp->intstate = STATE_SEND;
+ return _i2c_txrx_timeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, timeout);
+}
+
+#endif /* HAL_USE_I2C */
+
+/** @} */
diff --git a/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.h
new file mode 100644
index 00000000..6074be62
--- /dev/null
+++ b/os/hal/ports/NUMICRO/LLD/I2Cv1/hal_i2c_lld.h
@@ -0,0 +1,289 @@
+/*
+ ChibiOS - Copyright (C) 2019 Ein Terakawa
+ Copyright (C) 2014-2015 Fabio Utzig
+
+ 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 NUMICRO/hal_i2c_lld.h
+ * @brief NUMICRO I2C subsystem low level driver header.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#ifndef HAL_I2C_LLD_H_
+#define HAL_I2C_LLD_H_
+
+#include "hal.h"
+#include "NUC123.h"
+
+#if !defined(NUC123_I2C_USE_I2C0)
+#define NUC123_I2C_USE_I2C0 FALSE
+#endif
+
+#if !defined(NUC123_I2C_USE_I2C1)
+#define NUC123_I2C_USE_I2C1 FALSE
+#endif
+
+#define NUMICRO_HAS_I2C0 NUC123_HAS_I2C0
+#define NUMICRO_HAS_I2C1 NUC123_HAS_I2C1
+#define NUMICRO_I2C_USE_I2C0 NUC123_I2C_USE_I2C0
+#define NUMICRO_I2C_USE_I2C1 NUC123_I2C_USE_I2C1
+
+
+/**
+ * @name Wakeup status codes
+ * @{
+ */
+#define MSG_OK (msg_t)0 /**< @brief Normal wakeup message. */
+#define MSG_TIMEOUT (msg_t)-1 /**< @brief Wakeup caused by a timeout
+ condition. */
+#define MSG_RESET (msg_t)-2 /**< @brief Wakeup caused by a reset
+ condition. */
+#define MSG_UNDEFINED (msg_t)-3
+
+typedef int32_t msg_t; /**< Inter-thread message. */
+
+#if !defined(CH_CFG_ST_FREQUENCY)
+#define CH_CFG_ST_FREQUENCY 1000
+#endif
+#define MS2ST(msec) \
+ ((systime_t)(((((uint32_t)(msec)) * \
+ ((uint32_t)CH_CFG_ST_FREQUENCY)) + 999UL) / 1000UL))
+typedef uint32_t systime_t;
+
+#define NUMICRO_I2C0_IRQ_VECTOR NUC123_I2C0_HANDLER
+#define NUMICRO_I2C0_IRQ_NUMBER NUC123_I2C0_NUMBER
+#define NUMICRO_I2C1_IRQ_VECTOR NUC123_I2C1_HANDLER
+#define NUMICRO_I2C1_IRQ_NUMBER NUC123_I2C1_NUMBER
+
+#define I2C_PCLK SystemCoreClock /* Assume APBDIV == 0 */
+// #define I2C_PCLK (SystemCoreClock/2) /* Assume APBDIV == 1 */
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define STATE_STOP 0x00
+#define STATE_SEND 0x01
+#define STATE_RECV 0x02
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief I2C0 driver enable switch.
+ * @details If set to @p TRUE the support for I2C0 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(NUMICRO_I2C_USE_I2C0) || defined(__DOXYGEN__)
+#define NUMICRO_I2C_USE_I2C0 FALSE
+#endif
+
+/**
+ * @brief I2C1 driver enable switch.
+ * @details If set to @p TRUE the support for I2C1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(NUMICRO_I2C_USE_I2C1) || defined(__DOXYGEN__)
+#define NUMICRO_I2C_USE_I2C1 FALSE
+#endif
+/** @} */
+
+/**
+ * @brief I2C0 interrupt priority level setting.
+ */
+#if !defined(NUMICRO_I2C_I2C0_PRIORITY) || defined(__DOXYGEN__)
+#define NUMICRO_I2C_I2C0_PRIORITY 2
+#endif
+
+/**
+ * @brief I2C1 interrupt priority level setting.
+ */
+#if !defined(NUMICRO_I2C_I2C1_PRIORITY) || defined(__DOXYGEN__)
+#define NUMICRO_I2C_I2C1_PRIORITY 2
+#endif
+
+/**
+ * @brief Timeout for external clearing BUSY bus (in ms).
+ */
+#if !defined(NUMICRO_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
+#define NUMICRO_I2C_BUSY_TIMEOUT 50
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/** @brief error checks */
+#if NUMICRO_I2C_USE_I2C0 && !NUMICRO_HAS_I2C0
+#error "I2C0 not present in the selected device"
+#endif
+
+#if NUMICRO_I2C_USE_I2C1 && !NUMICRO_HAS_I2C1
+#error "I2C1 not present in the selected device"
+#endif
+
+
+#if !(NUMICRO_I2C_USE_I2C0 || NUMICRO_I2C_USE_I2C1)
+#error "I2C driver activated but no I2C peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/* @brief Type representing I2C address. */
+typedef uint8_t i2caddr_t;
+
+/* @brief Type of I2C Driver condition flags. */
+typedef uint32_t i2cflags_t;
+
+/* @brief Type used to control the ISR state machine. */
+typedef uint8_t intstate_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+
+/**
+ * @brief Driver configuration structure.
+ */
+typedef struct I2CConfig {
+
+ /* @brief Clock to be used for the I2C bus. */
+ uint32_t clock;
+
+} I2CConfig;
+
+/**
+ * @brief Type of a structure representing an I2C driver.
+ */
+typedef struct I2CDriver I2CDriver;
+
+typedef I2C_T I2C_TypeDef;
+
+/**
+ * @brief Structure representing an I2C driver.
+ */
+struct I2CDriver {
+ /**
+ * @brief Driver state.
+ */
+ i2cstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const I2CConfig *config;
+ /**
+ * @brief Error flags.
+ */
+ i2cflags_t errors;
+#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the bus.
+ */
+ mutex_t mutex;
+#endif /* I2C_USE_MUTUAL_EXCLUSION */
+#if defined(I2C_DRIVER_EXT_FIELDS)
+ I2C_DRIVER_EXT_FIELDS
+#endif
+ /* @brief Thread waiting for I/O completion. */
+ thread_reference_t thread;
+ /* @brief Current slave address without R/W bit. */
+ i2caddr_t addr;
+
+ /* End of the mandatory fields.*/
+
+ /* @brief Pointer to the buffer with data to send. */
+ const uint8_t *txbuf;
+ /* @brief Number of bytes of data to send. */
+ size_t txbytes;
+ /* @brief Current index in buffer when sending data. */
+ size_t txidx;
+ /* @brief Pointer to the buffer to put received data. */
+ uint8_t *rxbuf;
+ /* @brief Number of bytes of data to receive. */
+ size_t rxbytes;
+ /* @brief Current index in buffer when receiving data. */
+ size_t rxidx;
+ /* @brief Tracks current ISR state. */
+ intstate_t intstate;
+ /* @brief Low-level register access. */
+ I2C_TypeDef *i2c;
+ /* @brief If in master state or not. */
+ uint8_t is_master;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Get errors from I2C driver.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+
+#if NUMICRO_I2C_USE_I2C0
+extern I2CDriver I2CD0;
+#endif
+
+#if NUMICRO_I2C_USE_I2C1
+extern I2CDriver I2CD1;
+#endif
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void i2c_lld_init(void);
+ void i2c_lld_start(I2CDriver *i2cp);
+ void i2c_lld_stop(I2CDriver *i2cp);
+ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ systime_t timeout);
+ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ systime_t timeout);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_I2C */
+
+#endif /* HAL_I2C_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/ports/NUMICRO/NUC123/nuc123_isr.h b/os/hal/ports/NUMICRO/NUC123/nuc123_isr.h
index 250b2faf..64845736 100644
--- a/os/hal/ports/NUMICRO/NUC123/nuc123_isr.h
+++ b/os/hal/ports/NUMICRO/NUC123/nuc123_isr.h
@@ -81,17 +81,17 @@
/*
* I2S units.
*/
-#define NUC123_I2C1_HANDLER VectorB8
-#define NUC123_I2C1_NUMBER I2S_IRQn
+#define NUC123_I2S_HANDLER VectorB8
+#define NUC123_I2S_NUMBER I2S_IRQn
/*
* I2C units.
*/
-#define NUC123_I2C1_GLOBAL_HANDLER Vector88
-#define NUC123_I2C1_GLOBAL_NUMBER I2C0_IRQn
+#define NUC123_I2C0_HANDLER Vector88
+#define NUC123_I2C0_NUMBER I2C0_IRQn
-#define NUC123_I2C2_GLOBAL_HANDLER Vector8C
-#define NUC123_I2C2_GLOBAL_NUMBER I2C1_IRQn
+#define NUC123_I2C1_HANDLER Vector8C
+#define NUC123_I2C1_NUMBER I2C1_IRQn
/*
* TIM units.
diff --git a/os/hal/ports/NUMICRO/NUC123/nuc123_registry.h b/os/hal/ports/NUMICRO/NUC123/nuc123_registry.h
index a1ae53bd..2a52d1d6 100644
--- a/os/hal/ports/NUMICRO/NUC123/nuc123_registry.h
+++ b/os/hal/ports/NUMICRO/NUC123/nuc123_registry.h
@@ -112,20 +112,8 @@
#define NUC123_HAS_GPIOK FALSE
/* I2C attributes.*/
+#define NUC123_HAS_I2C0 TRUE
#define NUC123_HAS_I2C1 TRUE
-#define NUC123_I2C1_RX_DMA_MSK NUC123_DMA_STREAM_ID_MSK(1, 3)
-#define NUC123_I2C1_RX_DMA_CHN 0x00000200
-#define NUC123_I2C1_TX_DMA_MSK NUC123_DMA_STREAM_ID_MSK(1, 2)
-#define NUC123_I2C1_TX_DMA_CHN 0x00000020
-
-#define NUC123_HAS_I2C2 TRUE
-#define NUC123_I2C2_RX_DMA_MSK NUC123_DMA_STREAM_ID_MSK(1, 5)
-#define NUC123_I2C2_RX_DMA_CHN 0x00020000
-#define NUC123_I2C2_TX_DMA_MSK NUC123_DMA_STREAM_ID_MSK(1, 4)
-#define NUC123_I2C2_TX_DMA_CHN 0x00002000
-
-#define NUC123_HAS_I2C3 FALSE
-#define NUC123_HAS_I2C4 FALSE
/* QUADSPI attributes.*/
#define NUC123_HAS_QUADSPI1 FALSE
diff --git a/os/hal/ports/NUMICRO/NUC123/platform.mk b/os/hal/ports/NUMICRO/NUC123/platform.mk
index 93234a33..5fc04b14 100644
--- a/os/hal/ports/NUMICRO/NUC123/platform.mk
+++ b/os/hal/ports/NUMICRO/NUC123/platform.mk
@@ -16,6 +16,7 @@ include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1/driver.mk
include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/driver.mk
include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/USBv1/driver.mk
include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/SERIALv1/driver.mk
+include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/I2Cv1/driver.mk
# Shared variables
ALLCSRC += $(PLATFORMSRC)
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/Makefile b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/Makefile
new file mode 100644
index 00000000..235d95b8
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/Makefile
@@ -0,0 +1,212 @@
+##############################################################################
+# Build global options
+# NOTE: Can be overridden externally.
+#
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+ USE_OPT = -ggdb -g3 -gdwarf-3 -gstrict-dwarf -fomit-frame-pointer -falign-functions=16 -O
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+ USE_COPT =
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+ USE_CPPOPT = -fno-rtti
+endif
+
+# Enable this if you want the linker to remove unused code and data.
+ifeq ($(USE_LINK_GC),)
+ USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+ USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO).
+ifeq ($(USE_LTO),)
+ USE_LTO = yes
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+ USE_VERBOSE_COMPILE = no
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+ USE_SMART_BUILD = yes
+endif
+
+#
+# Build global options
+##############################################################################
+
+##############################################################################
+# Architecture or project specific options
+#
+
+# Stack size to be allocated to the Cortex-M process stack. This stack is
+# the stack used by the main() thread.
+ifeq ($(USE_PROCESS_STACKSIZE),)
+ USE_PROCESS_STACKSIZE = 0x400
+endif
+
+# Stack size to the allocated to the Cortex-M main/exceptions stack. This
+# stack is used for processing interrupts and exceptions.
+ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
+ USE_EXCEPTIONS_STACKSIZE = 0x400
+endif
+
+# Enables the use of FPU (no, softfp, hard).
+ifeq ($(USE_FPU),)
+ USE_FPU = no
+endif
+
+# FPU-related options.
+ifeq ($(USE_FPU_OPT),)
+ USE_FPU_OPT = -mfloat-abi=$(USE_FPU) -mfpu=fpv4-sp-d16
+endif
+
+#
+# Architecture or project specific options
+##############################################################################
+
+##############################################################################
+# Project, target, sources and paths
+#
+
+# Define project name here
+PROJECT = ch
+
+# Target settings.
+MCU = cortex-m0
+
+# Imported source files and paths.
+BASE_PATH := ../../../../../../..
+CHIBIOS := $(BASE_PATH)/ChibiOS/ChibiOS
+CHIBIOS_CONTRIB := $(BASE_PATH)/ChibiOS/ChibiOS-Contrib
+CONFDIR := ./cfg
+BUILDDIR := ./build
+DEPDIR := ./.dep
+
+# Licensing files.
+include $(CHIBIOS)/os/license/license.mk
+# Startup files.
+include $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_NUC123.mk
+# HAL-OSAL files (optional).
+include $(CHIBIOS)/os/hal/hal.mk
+include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/NUC123/platform.mk
+include $(CHIBIOS_CONTRIB)/os/hal/boards/NUTINY-SDK-NUC123-V2.0/board.mk
+#include $(CHIBIOS)/os/hal/osal/os-less/ARMCMx/osal.mk
+include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk
+# RTOS files (optional).
+#include $(CHIBIOS)/os/nil/nil.mk
+include $(CHIBIOS)/os/rt/rt.mk
+include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v6m.mk
+#include $(CHIBIOS)/os/common/ports/ARMv7-M/compilers/GCC/mk/port.mk
+# Auto-build files in ./source recursively.
+include $(CHIBIOS)/tools/mk/autobuild.mk
+# Other files (optional).
+#include $(CHIBIOS)/test/lib/test.mk
+#include $(CHIBIOS)/test/rt/rt_test.mk
+#include $(CHIBIOS)/test/oslib/oslib_test.mk
+
+# Define linker script file here
+LDSCRIPT= $(STARTUPLD_CONTRIB)/NUC123xD4xx0.ld
+
+# C sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CSRC = $(ALLCSRC) \
+ $(TESTSRC) \
+ main.c \
+ ssd1306.c
+
+# C++ sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CPPSRC = $(ALLCPPSRC)
+
+# List ASM source files here.
+ASMSRC = $(ALLASMSRC)
+
+# List ASM with preprocessor source files here.
+ASMXSRC = $(ALLXASMSRC)
+
+# Inclusion directories.
+INCDIR = $(CONFDIR) $(ALLINC) $(TESTINC)
+
+# Define C warning options here.
+CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
+
+# Define C++ warning options here.
+CPPWARN = -Wall -Wextra -Wundef
+
+#
+# Project, target, sources and paths
+##############################################################################
+
+##############################################################################
+# Start of user section
+#
+
+# List all user C define here, like -D_DEBUG=1
+UDEFS =
+
+# Define ASM defines here
+UADEFS =
+
+# List all user directories here
+UINCDIR =
+
+# List the user directory to look for the libraries here
+ULIBDIR =
+
+# List all user libraries here
+ULIBS =
+
+#
+# End of user section
+##############################################################################
+
+##############################################################################
+# Common rules
+#
+
+RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk
+include $(RULESPATH)/arm-none-eabi.mk
+include $(RULESPATH)/rules.mk
+
+#
+# Common rules
+##############################################################################
+
+##############################################################################
+# Custom rules
+#
+
+
+OPENOCD:=$(shell readlink -f `which openocd`)
+OPENOCDPATH:=$(shell dirname $(OPENOCD))/../share/openocd
+
+install-openocd-config:
+ rm $(OPENOCDPATH)/scripts/target/numicroM0.cfg && cp $(CHIBIOS_CONTRIB)/ext/numicroM0.cfg $(OPENOCDPATH)/scripts/target/
+
+connect:
+ openocd -f ../scripts/interface/nulink.cfg -f ../scripts/target/numicroM0.cfg
+
+flash: $(BUILDDIR)/$(PROJECT).elf
+ openocd -f ../scripts/interface/nulink.cfg -f ../scripts/target/numicroM0.cfg -c "program $< verify reset exit"
+
+
+
+
+#
+# Custom rules
+##############################################################################
+
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/chconf.h b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/chconf.h
new file mode 100644
index 00000000..6255a921
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/chconf.h
@@ -0,0 +1,773 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 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 rt/templates/chconf.h
+ * @brief Configuration file template.
+ * @details A copy of this file must be placed in each project directory, it
+ * contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef CHCONF_H
+#define CHCONF_H
+
+#define _CHIBIOS_RT_CONF_
+#define _CHIBIOS_RT_CONF_VER_6_1_
+
+/*===========================================================================*/
+/**
+ * @name System timers settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System time counter resolution.
+ * @note Allowed values are 16 or 32 bits.
+ */
+#if !defined(CH_CFG_ST_RESOLUTION)
+#define CH_CFG_ST_RESOLUTION 32
+#endif
+
+/**
+ * @brief System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ * setting also defines the system tick time unit.
+ */
+#if !defined(CH_CFG_ST_FREQUENCY)
+#define CH_CFG_ST_FREQUENCY 10000
+#endif
+
+/**
+ * @brief Time intervals data size.
+ * @note Allowed values are 16, 32 or 64 bits.
+ */
+#if !defined(CH_CFG_INTERVALS_SIZE)
+#define CH_CFG_INTERVALS_SIZE 32
+#endif
+
+/**
+ * @brief Time types data size.
+ * @note Allowed values are 16 or 32 bits.
+ */
+#if !defined(CH_CFG_TIME_TYPES_SIZE)
+#define CH_CFG_TIME_TYPES_SIZE 32
+#endif
+
+/**
+ * @brief Time delta constant for the tick-less mode.
+ * @note If this value is zero then the system uses the classic
+ * periodic tick. This value represents the minimum number
+ * of ticks that is safe to specify in a timeout directive.
+ * The value one is not valid, timeouts are rounded up to
+ * this value.
+ */
+#if !defined(CH_CFG_ST_TIMEDELTA)
+#define CH_CFG_ST_TIMEDELTA 0
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ * threads before preemption occurs. Setting this value to zero
+ * disables the preemption for threads with equal priority and the
+ * round robin becomes cooperative. Note that higher priority
+ * threads can still preempt, the kernel is always preemptive.
+ * @note Disabling the round robin preemption makes the kernel more compact
+ * and generally faster.
+ * @note The round robin preemption is not supported in tickless mode and
+ * must be set to zero in that case.
+ */
+#if !defined(CH_CFG_TIME_QUANTUM)
+#define CH_CFG_TIME_QUANTUM 0
+#endif
+
+/**
+ * @brief Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ * does not spawn the idle thread. The application @p main()
+ * function becomes the idle thread and must implement an
+ * infinite loop.
+ */
+#if !defined(CH_CFG_NO_IDLE_THREAD)
+#define CH_CFG_NO_IDLE_THREAD FALSE
+#endif
+
+#if !defined(CH_CFG_MAX_THREADS)
+#define CH_CFG_MAX_THREADS 8
+#endif
+
+#if !defined(CH_CFG_AUTOSTART_THREADS)
+#define CH_CFG_AUTOSTART_THREADS TRUE
+#endif
+
+#if !defined(CH_CFG_THREAD_EXT_FIELDS)
+#define CH_CFG_THREAD_EXT_FIELDS /* Add threads custom fields here.*/
+#endif
+
+#define CH_CFG_THREAD_EXT_INIT_HOOK(tr) { \
+ /* Add custom threads initialization code here.*/ \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ * is used when two possible implementations exist.
+ *
+ * @note This is not related to the compiler optimization options.
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_OPTIMIZE_SPEED)
+#define CH_CFG_OPTIMIZE_SPEED TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Time Measurement APIs.
+ * @details If enabled then the time measurement APIs are included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_TM)
+#define CH_CFG_USE_TM FALSE
+#endif
+
+/**
+ * @brief Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_REGISTRY)
+#define CH_CFG_USE_REGISTRY TRUE
+#endif
+
+/**
+ * @brief Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_WAITEXIT)
+#define CH_CFG_USE_WAITEXIT TRUE
+#endif
+
+/**
+ * @brief Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_SEMAPHORES)
+#define CH_CFG_USE_SEMAPHORES TRUE
+#endif
+
+/**
+ * @brief Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ * priority rather than in FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special
+ * requirements.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY)
+#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE
+#endif
+
+/**
+ * @brief Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MUTEXES)
+#define CH_CFG_USE_MUTEXES TRUE
+#endif
+
+/**
+ * @brief Enables recursive behavior on mutexes.
+ * @note Recursive mutexes are heavier and have an increased
+ * memory footprint.
+ *
+ * @note The default is @p FALSE.
+ * @note Requires @p CH_CFG_USE_MUTEXES.
+ */
+#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE)
+#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
+#endif
+
+/**
+ * @brief Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_MUTEXES.
+ */
+#if !defined(CH_CFG_USE_CONDVARS)
+#define CH_CFG_USE_CONDVARS FALSE
+#endif
+
+/**
+ * @brief Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ * specification are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_CONDVARS.
+ */
+#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT)
+#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE
+#endif
+
+/**
+ * @brief Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_EVENTS)
+#define CH_CFG_USE_EVENTS TRUE
+#endif
+
+/**
+ * @brief Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ * are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_EVENTS.
+ */
+#if !defined(CH_CFG_USE_EVENTS_TIMEOUT)
+#define CH_CFG_USE_EVENTS_TIMEOUT TRUE
+#endif
+
+/**
+ * @brief Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MESSAGES)
+#define CH_CFG_USE_MESSAGES TRUE
+#endif
+
+/**
+ * @brief Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ * FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special
+ * requirements.
+ * @note Requires @p CH_CFG_USE_MESSAGES.
+ */
+#if !defined(CH_CFG_USE_MESSAGES_PRIORITY)
+#define CH_CFG_USE_MESSAGES_PRIORITY FALSE
+#endif
+
+/**
+ * @brief Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_WAITEXIT.
+ * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
+ */
+#if !defined(CH_CFG_USE_DYNAMIC)
+#define CH_CFG_USE_DYNAMIC TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name OSLIB options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ * included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#if !defined(CH_CFG_USE_MAILBOXES)
+#define CH_CFG_USE_MAILBOXES TRUE
+#endif
+
+/**
+ * @brief Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MEMCORE)
+#define CH_CFG_USE_MEMCORE TRUE
+#endif
+
+/**
+ * @brief Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ * then the whole available RAM is used. The core memory is made
+ * available to the heap allocator and/or can be used directly through
+ * the simplified core memory allocator.
+ *
+ * @note In order to let the OS manage the whole RAM the linker script must
+ * provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note Requires @p CH_CFG_USE_MEMCORE.
+ */
+#if !defined(CH_CFG_MEMCORE_SIZE)
+#define CH_CFG_MEMCORE_SIZE 0
+#endif
+
+/**
+ * @brief Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
+ * @p CH_CFG_USE_SEMAPHORES.
+ * @note Mutexes are recommended.
+ */
+#if !defined(CH_CFG_USE_HEAP)
+#define CH_CFG_USE_HEAP TRUE
+#endif
+
+/**
+ * @brief Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MEMPOOLS)
+#define CH_CFG_USE_MEMPOOLS TRUE
+#endif
+
+/**
+ * @brief Objects FIFOs APIs.
+ * @details If enabled then the objects FIFOs APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_OBJ_FIFOS)
+#define CH_CFG_USE_OBJ_FIFOS TRUE
+#endif
+
+/**
+ * @brief Pipes APIs.
+ * @details If enabled then the pipes APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_PIPES)
+#define CH_CFG_USE_PIPES TRUE
+#endif
+
+/**
+ * @brief Objects Caches APIs.
+ * @details If enabled then the objects caches APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_OBJ_CACHES)
+#define CH_CFG_USE_OBJ_CACHES TRUE
+#endif
+
+/**
+ * @brief Delegate threads APIs.
+ * @details If enabled then the delegate threads APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_DELEGATES)
+#define CH_CFG_USE_DELEGATES TRUE
+#endif
+
+/**
+ * @brief Jobs Queues APIs.
+ * @details If enabled then the jobs queues APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_JOBS)
+#define CH_CFG_USE_JOBS TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Objects factory options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Objects Factory APIs.
+ * @details If enabled then the objects factory APIs are included in the
+ * kernel.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_CFG_USE_FACTORY)
+#define CH_CFG_USE_FACTORY TRUE
+#endif
+
+/**
+ * @brief Maximum length for object names.
+ * @details If the specified length is zero then the name is stored by
+ * pointer but this could have unintended side effects.
+ */
+#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH)
+#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8
+#endif
+
+/**
+ * @brief Enables the registry of generic objects.
+ */
+#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY)
+#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE
+#endif
+
+/**
+ * @brief Enables factory for generic buffers.
+ */
+#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS)
+#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE
+#endif
+
+/**
+ * @brief Enables factory for semaphores.
+ */
+#if !defined(CH_CFG_FACTORY_SEMAPHORES)
+#define CH_CFG_FACTORY_SEMAPHORES TRUE
+#endif
+
+/**
+ * @brief Enables factory for mailboxes.
+ */
+#if !defined(CH_CFG_FACTORY_MAILBOXES)
+#define CH_CFG_FACTORY_MAILBOXES TRUE
+#endif
+
+/**
+ * @brief Enables factory for objects FIFOs.
+ */
+#if !defined(CH_CFG_FACTORY_OBJ_FIFOS)
+#define CH_CFG_FACTORY_OBJ_FIFOS TRUE
+#endif
+
+/**
+ * @brief Enables factory for Pipes.
+ */
+#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__)
+#define CH_CFG_FACTORY_PIPES TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Debug option, kernel statistics.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_STATISTICS)
+#define CH_DBG_STATISTICS FALSE
+#endif
+
+/**
+ * @brief Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ * at runtime.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_SYSTEM_STATE_CHECK)
+#define CH_DBG_SYSTEM_STATE_CHECK FALSE
+#endif
+
+/**
+ * @brief Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ * parameters are activated.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_CHECKS)
+#define CH_DBG_ENABLE_CHECKS FALSE
+#endif
+
+/**
+ * @brief Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ * activated. This includes consistency checks inside the kernel,
+ * runtime anomalies and port-defined checks.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_ASSERTS)
+#define CH_DBG_ENABLE_ASSERTS FALSE
+#endif
+
+/**
+ * @brief Debug option, trace buffer.
+ * @details If enabled then the trace buffer is activated.
+ *
+ * @note The default is @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#if !defined(CH_DBG_TRACE_MASK)
+#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED
+#endif
+
+/**
+ * @brief Trace buffer entries.
+ * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
+ * different from @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#if !defined(CH_DBG_TRACE_BUFFER_SIZE)
+#define CH_DBG_TRACE_BUFFER_SIZE 128
+#endif
+
+/**
+ * @brief Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note The default is @p FALSE.
+ * @note The stack check is performed in a architecture/port dependent way.
+ * It may not be implemented or some ports.
+ * @note The default failure mode is to halt the system with the global
+ * @p panic_msg variable set to @p NULL.
+ */
+#if !defined(CH_DBG_ENABLE_STACK_CHECK)
+#define CH_DBG_ENABLE_STACK_CHECK FALSE
+#endif
+
+/**
+ * @brief Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ * value when a thread is created. This can be useful for the
+ * runtime measurement of the used stack.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_FILL_THREADS)
+#define CH_DBG_FILL_THREADS FALSE
+#endif
+
+/**
+ * @brief Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p thread_t structure that
+ * counts the system ticks occurred while executing the thread.
+ *
+ * @note The default is @p FALSE.
+ * @note This debug option is not currently compatible with the
+ * tickless mode.
+ */
+#if !defined(CH_DBG_THREADS_PROFILING)
+#define CH_DBG_THREADS_PROFILING FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System structure extension.
+ * @details User fields added to the end of the @p ch_system_t structure.
+ */
+#define CH_CFG_SYSTEM_EXTRA_FIELDS \
+ /* Add threads custom fields here.*/
+
+/**
+ * @brief System initialization hook.
+ * @details User initialization code added to the @p chSysInit() function
+ * just before interrupts are enabled globally.
+ */
+#define CH_CFG_SYSTEM_INIT_HOOK() { \
+ /* Add threads initialization code here.*/ \
+}
+
+/**
+ * @brief Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXTRA_FIELDS \
+ /* Add threads custom fields here.*/
+
+/**
+ * @brief Threads initialization hook.
+ * @details User initialization code added to the @p _thread_init() function.
+ *
+ * @note It is invoked from within @p _thread_init() and implicitly from all
+ * the threads creation APIs.
+ */
+#define CH_CFG_THREAD_INIT_HOOK(tp) { \
+ /* Add threads initialization code here.*/ \
+}
+
+/**
+ * @brief Threads finalization hook.
+ * @details User finalization code added to the @p chThdExit() API.
+ */
+#define CH_CFG_THREAD_EXIT_HOOK(tp) { \
+ /* Add threads finalization code here.*/ \
+}
+
+/**
+ * @brief Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \
+ /* Context switch code here.*/ \
+}
+
+/**
+ * @brief ISR enter hook.
+ */
+#define CH_CFG_IRQ_PROLOGUE_HOOK() { \
+ /* IRQ prologue code here.*/ \
+}
+
+/**
+ * @brief ISR exit hook.
+ */
+#define CH_CFG_IRQ_EPILOGUE_HOOK() { \
+ /* IRQ epilogue code here.*/ \
+}
+
+/**
+ * @brief Idle thread enter hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() { \
+ /* Idle-enter code here.*/ \
+}
+
+/**
+ * @brief Idle thread leave hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() { \
+ /* Idle-leave code here.*/ \
+}
+
+/**
+ * @brief Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#define CH_CFG_IDLE_LOOP_HOOK() { \
+ /* Idle loop code here.*/ \
+}
+
+/**
+ * @brief System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ * after processing the virtual timers queue.
+ */
+#define CH_CFG_SYSTEM_TICK_HOOK() { \
+ /* System tick event code here.*/ \
+}
+
+/**
+ * @brief System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ * the system is halted.
+ */
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
+ /* System halt code here.*/ \
+}
+
+/**
+ * @brief Trace hook.
+ * @details This hook is invoked each time a new record is written in the
+ * trace buffer.
+ */
+#define CH_CFG_TRACE_HOOK(tep) { \
+ /* Trace code here.*/ \
+}
+
+
+/** @} */
+
+/*===========================================================================*/
+/* Port-specific settings (override port settings defaulted in chcore.h). */
+/*===========================================================================*/
+
+#endif /* CHCONF_H */
+
+/** @} */
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/halconf.h b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/halconf.h
new file mode 100644
index 00000000..890a8575
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/halconf.h
@@ -0,0 +1,531 @@
+/*
+ ChibiOS - Copyright (C) 2020 Alex Lewontin
+
+ 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 templates/halconf.h
+ * @brief HAL configuration header.
+ * @details HAL configuration file, this file allows to enable or disable the
+ * various device drivers from your application. You may also use
+ * this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef HALCONF_H
+#define HALCONF_H
+
+#define _CHIBIOS_HAL_CONF_
+#define _CHIBIOS_HAL_CONF_VER_7_1_
+
+#include "mcuconf.h"
+
+/**
+ * @brief Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL TRUE
+#endif
+
+/**
+ * @brief Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC FALSE
+#endif
+
+/**
+ * @brief Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN FALSE
+#endif
+
+/**
+ * @brief Enables the cryptographic subsystem.
+ */
+#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__)
+#define HAL_USE_CRY FALSE
+#endif
+
+/**
+ * @brief Enables the DAC subsystem.
+ */
+#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
+#define HAL_USE_DAC FALSE
+#endif
+
+/**
+ * @brief Enables the EFlash subsystem.
+ */
+#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__)
+#define HAL_USE_EFL FALSE
+#endif
+
+/**
+ * @brief Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT FALSE
+#endif
+
+/**
+ * @brief Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C TRUE
+#endif
+
+/**
+ * @brief Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S FALSE
+#endif
+
+/**
+ * @brief Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU FALSE
+#endif
+
+/**
+ * @brief Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC FALSE
+#endif
+
+/**
+ * @brief Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI FALSE
+#endif
+
+/**
+ * @brief Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM FALSE
+#endif
+
+/**
+ * @brief Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC FALSE
+#endif
+
+/**
+ * @brief Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC FALSE
+#endif
+
+/**
+ * @brief Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL FALSE
+#endif
+
+/**
+ * @brief Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB FALSE
+#endif
+
+/**
+ * @brief Enables the SIO subsystem.
+ */
+#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__)
+#define HAL_USE_SIO FALSE
+#endif
+
+/**
+ * @brief Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI FALSE
+#endif
+
+/**
+ * @brief Enables the TRNG subsystem.
+ */
+#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__)
+#define HAL_USE_TRNG FALSE
+#endif
+
+/**
+ * @brief Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART FALSE
+#endif
+
+/**
+ * @brief Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB FALSE
+#endif
+
+/**
+ * @brief Enables the WDG subsystem.
+ */
+#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
+#define HAL_USE_WDG FALSE
+#endif
+
+/**
+ * @brief Enables the WSPI subsystem.
+ */
+#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__)
+#define HAL_USE_WSPI FALSE
+#endif
+
+/*===========================================================================*/
+/* PAL driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__)
+#define PAL_USE_CALLBACKS FALSE
+#endif
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__)
+#define PAL_USE_WAIT FALSE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE TRUE
+#endif
+
+/**
+ * @brief Enforces the driver to use direct callbacks rather than OSAL events.
+ */
+#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
+#define CAN_ENFORCE_USE_CALLBACKS FALSE
+#endif
+
+/*===========================================================================*/
+/* CRY driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the SW fall-back of the cryptographic driver.
+ * @details When enabled, this option, activates a fall-back software
+ * implementation for algorithms not supported by the underlying
+ * hardware.
+ * @note Fall-back implementations may not be present for all algorithms.
+ */
+#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__)
+#define HAL_CRY_USE_FALLBACK FALSE
+#endif
+
+/**
+ * @brief Makes the driver forcibly use the fall-back implementations.
+ */
+#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__)
+#define HAL_CRY_ENFORCE_FALLBACK FALSE
+#endif
+
+/*===========================================================================*/
+/* DAC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
+#define DAC_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define DAC_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the zero-copy API.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY FALSE
+#endif
+
+/**
+ * @brief Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS TRUE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ * This option is recommended also if the SPI driver does not
+ * use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING TRUE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of initialization attempts before rejecting the card.
+ * @note Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY 100
+#endif
+
+/**
+ * @brief Include support for MMC cards.
+ * @note MMC support is not yet implemented so this option must be kept
+ * at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT FALSE
+#endif
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING TRUE
+#endif
+
+/**
+ * @brief OCR initialization constant for V20 cards.
+ */
+#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__)
+#define SDC_INIT_OCR_V20 0x50FF8000U
+#endif
+
+/**
+ * @brief OCR initialization constant for non-V20 cards.
+ */
+#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__)
+#define SDC_INIT_OCR 0x80100000U
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ * default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE 38400
+#endif
+
+/**
+ * @brief Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ * buffers depending on the requirements of your application.
+ * @note The default is 16 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE 32
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting. */
+/*===========================================================================*/
+
+/**
+ * @brief Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ * the USB data endpoint maximum packet size.
+ * @note The default is 256 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE 256
+#endif
+
+/**
+ * @brief Serial over USB number of buffers.
+ * @note The default is 2 buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_NUMBER 2
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables circular transfers APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__)
+#define SPI_USE_CIRCULAR FALSE
+#endif
+
+/**
+ * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/**
+ * @brief Handling method for SPI CS line.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
+#endif
+
+/*===========================================================================*/
+/* UART driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT FALSE
+#endif
+
+/**
+ * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION FALSE
+#endif
+
+/*===========================================================================*/
+/* USB driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
+#define USB_USE_WAIT FALSE
+#endif
+
+/*===========================================================================*/
+/* WSPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__)
+#define WSPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define WSPI_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+#endif /* HALCONF_H */
+
+/** @} */
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/mcuconf.h b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/mcuconf.h
new file mode 100644
index 00000000..81390aaf
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/mcuconf.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2016 Stephane D'Alu
+
+ 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.
+*/
+
+#ifndef _MCUCONF_H_
+#define _MCUCONF_H_
+
+/*
+ * Board setting
+ */
+
+/*
+ * HAL driver system settings.
+ */
+
+#define NUC123_I2C_USE_I2C0 TRUE
+#define NUC123_I2C_USE_I2C1 TRUE
+
+#define NUC123_MCUCONF
+
+#endif /* _MCUCONF_H_ */
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/osalconf.h b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/osalconf.h
new file mode 100644
index 00000000..666d0c37
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/cfg/osalconf.h
@@ -0,0 +1,67 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 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 templates/halconf.h
+ * @brief Bare-metal OSAL configuration header.
+ *
+ * @addtogroup OSAL_CONF
+ * @{
+ */
+
+#ifndef OSALCONF_H
+#define OSALCONF_H
+
+/**
+ * @brief Frequency in Hertz of the system tick.
+ */
+#if !defined(OSAL_ST_FREQUENCY) || defined(__DOXYGEN__)
+#define OSAL_ST_FREQUENCY 10000
+#endif
+
+/**
+ * @brief Enables OSAL assertions.
+ */
+#if !defined(OSAL_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
+#define OSAL_DBG_ENABLE_ASSERTS FALSE
+#endif
+
+/**
+ * @brief Enables OSAL functions parameters checks.
+ */
+#if !defined(OSAL_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
+#define OSAL_DBG_ENABLE_CHECKS FALSE
+#endif
+
+/**
+ * @brief OSAL initialization hook.
+ */
+#if !defined(OSAL_INIT_HOOK) || defined(__DOXYGEN__)
+#define OSAL_INIT_HOOK() { \
+}
+#endif
+
+/**
+ * @brief Idle loop hook macro.
+ */
+#if !defined(OSAL_IDLE_HOOK) || defined(__DOXYGEN__)
+#define OSAL_IDLE_HOOK() { \
+}
+#endif
+
+#endif /* OSALCONF_H */
+
+/** @} */
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/main.c b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/main.c
new file mode 100644
index 00000000..82c56d6b
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/main.c
@@ -0,0 +1,239 @@
+
+/*
+ Copyright (C) 2020 Ein Terakawa
+
+ 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.
+*/
+
+#include "hal.h"
+#include "ssd1306.h"
+
+static const uint8_t logo_bits[] = {
+ 0x00, 0x00, 0x00, 0x80, 0xF0, 0xF8, 0xFC, 0xFC,
+ 0xFE, 0x3E, 0x1E, 0x1E, 0x7E, 0x7C, 0x7C, 0x78,
+ 0x70, 0x40, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0x00,
+ 0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xC0, 0xE0, 0xE0,
+ 0xE0, 0xC0, 0x00, 0x00, 0xEE, 0xEE, 0xEE, 0xEE,
+ 0xEE, 0x00, 0x80, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE,
+ 0x1E, 0x1E, 0x1E, 0xFE, 0xFC, 0xFC, 0xF8, 0xF0,
+ 0x80, 0x60, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xDE,
+ 0x9E, 0xBE, 0xBC, 0xBC, 0x38, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x0F, 0x1F, 0x3F, 0x3F,
+ 0x7F, 0x7C, 0x78, 0x78, 0x7E, 0x3E, 0x3E, 0x3E,
+ 0x0E, 0x02, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00,
+ 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x1F, 0x79, 0x7F, 0x7F,
+ 0x7F, 0x3F, 0x0F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x00, 0x01, 0x0F, 0x1F, 0x3F, 0x3F, 0x7F,
+ 0x78, 0x78, 0x78, 0x7F, 0x3F, 0x3F, 0x1F, 0x0F,
+ 0x01, 0x04, 0x1C, 0x3D, 0x3D, 0x7D, 0x79, 0x7B,
+ 0x7B, 0x7F, 0x7F, 0x3F, 0x1F, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xF8, 0xC0, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0x00, 0x80, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE,
+ 0x3E, 0x1E, 0x1E, 0x7E, 0x7C, 0x7C, 0x78, 0x70,
+ 0x40, 0x00, 0x38, 0x38, 0x38, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x20, 0x38, 0x3C,
+ 0x3C, 0x3E, 0x9E, 0x9E, 0xFE, 0xFE, 0xFC, 0xF8,
+ 0x70, 0x00, 0x20, 0x38, 0x3C, 0xFC, 0xFE, 0xDE,
+ 0xDE, 0xFE, 0xFE, 0x7C, 0x78, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x01, 0x07, 0x1F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F,
+ 0x7F, 0x7C, 0x7C, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F,
+ 0x03, 0x00, 0x01, 0x0F, 0x1F, 0x3F, 0x3F, 0x7F,
+ 0x7C, 0x78, 0x78, 0x7E, 0x3E, 0x3E, 0x3E, 0x0E,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x70, 0x7C, 0x7E,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7B, 0x7B, 0x79, 0x79,
+ 0x78, 0x00, 0x04, 0x1C, 0x3C, 0x7D, 0x79, 0x79,
+ 0x79, 0x7F, 0x7F, 0x3F, 0x3F, 0x0E, 0x00, 0x00,
+};
+
+static void draw_logo(SSD1306_DRIVER *ssd1306, bool invert, char xx) {
+ uint8_t width = ssd1306->width;
+ uint8_t height = ssd1306->height;
+ uint8_t num_pages = height / 8;
+ uint8_t invert_bits = invert ? 0xff : 0x00;
+ uint8_t *buf = SSD1306_GET_FRAMEBUFFER(ssd1306);
+
+ for (uint8_t row = 0; row < num_pages; ++row) {
+ for (uint8_t x = 0; x < width; ++x) {
+ uint8_t dat = logo_bits[(128 - xx + x) % 128 + (row % 4) * width];
+ if (row / 2 % 2 == 0) {
+ dat ^= 0xff;
+ }
+ dat ^= invert_bits; /* Invert Imeage Bits */
+ if (true) {
+ /* Horizontal Addressing Mode */
+ buf[row * width + x] = dat;
+ } else {
+ /* Vertical Addressing Mode */
+ buf[x * num_pages + row] = dat;
+ }
+ }
+ }
+}
+
+#define I2C_CLK_FREQ 1000000
+static const I2CConfig i2ccfg = { I2C_CLK_FREQ };
+#if NUC123_I2C_USE_I2C0
+DEFINE_SSD1306_DRIVER(ssd1306_128x64, &I2CD0, SSD1306_ADDRESS, 128, 64, false);
+#endif
+#if NUC123_I2C_USE_I2C1
+DEFINE_SSD1306_DRIVER(ssd1306_128x32, &I2CD1, SSD1306_ADDRESS, 128, 32, true);
+#endif
+
+#if I2C_USE_MUTUAL_EXCLUSION
+#define ACQUIRE_BUS(oled_driver) i2cAcquireBus((oled_driver)->i2cd)
+#define RELEASE_BUS(oled_driver) i2cReleaseBus((oled_driver)->i2cd)
+#else
+#define ACQUIRE_BUS(oled_driver)
+#define RELEASE_BUS(oled_driver)
+#endif
+
+thread_reference_t thread1_ref = NULL;
+
+static THD_WORKING_AREA(waThread1, 128);
+static THD_FUNCTION(Thread1, arg) {
+ chRegSetThreadName("blinker");
+
+ (void)arg;
+ while (true) {
+ if(osalThreadSuspendS(&thread1_ref) == MSG_OK) {
+ OnboardLED_On();
+ }else{
+ OnboardLED_Off();
+ }
+ }
+}
+
+#define I2C_THREAD_STACK_SIZE 256
+#if NUC123_I2C_USE_I2C0
+static THD_WORKING_AREA(waThread2, I2C_THREAD_STACK_SIZE);
+static THD_FUNCTION(Thread2, arg) {
+ chRegSetThreadName("oled1");
+
+ SSD1306_DRIVER *ssd1306 = (SSD1306_DRIVER *)arg;
+ ssd1306->i2ccfg = &i2ccfg;
+ ACQUIRE_BUS(ssd1306);
+ ssd1306_init(ssd1306);
+ RELEASE_BUS(ssd1306);
+ char x = 0;
+ while (true) {
+ osalThreadSleepMilliseconds(127);
+ bool invert = false;
+ draw_logo(ssd1306, invert, x);
+ ACQUIRE_BUS(ssd1306);
+ ssd1306_data(ssd1306);
+ /* RELEASE_BUS(ssd1306); */
+ /* ACQUIRE_BUS(ssd1306); */
+ if (x % 16 == 12) {
+ ssd1306_display_off(ssd1306);
+ } else if (x % 16 == 0) {
+ ssd1306_display_on(ssd1306);
+ }
+ RELEASE_BUS(ssd1306);
+ x = (x + 1) % 128;
+ }
+}
+#endif
+
+#if NUC123_I2C_USE_I2C1
+static THD_WORKING_AREA(waThread3, I2C_THREAD_STACK_SIZE);
+static THD_FUNCTION(Thread3, arg) {
+ chRegSetThreadName("oled2");
+
+ SSD1306_DRIVER *ssd1306 = (SSD1306_DRIVER *)arg;
+ ssd1306->i2ccfg = &i2ccfg;
+ ACQUIRE_BUS(ssd1306);
+#if true
+ /* Workaround for some 128x32 OLED modules typically with black PCB. */
+ while (!ssd1306_init(ssd1306)) {
+ RELEASE_BUS(ssd1306);
+ osalThreadSleepMilliseconds(100);
+ ACQUIRE_BUS(ssd1306);
+ }
+#endif
+ ssd1306_init(ssd1306);
+ RELEASE_BUS(ssd1306);
+ char x = 0;
+ while (true) {
+ osalThreadSleepMilliseconds(131);
+ bool invert = true;
+ draw_logo(ssd1306, invert, x);
+ ACQUIRE_BUS(ssd1306);
+ ssd1306_data(ssd1306);
+ RELEASE_BUS(ssd1306);
+ x = (x - 1) % 128;
+ }
+}
+#endif
+
+/*
+ * Application entry point.
+ */
+int main(void) {
+
+ /*
+ * System initializations.
+ * - HAL initialization, this also initializes the configured device drivers
+ * and performs the board-specific initializations.
+ */
+ halInit();
+
+ /*
+ * chSysInit() will also enable interrupts.
+ */
+ chSysInit();
+
+ chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 2, Thread1, NULL);
+#if NUC123_I2C_USE_I2C0
+ chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO + 1, Thread2, &ssd1306_128x64);
+#endif
+#if NUC123_I2C_USE_I2C1
+ chThdCreateStatic(waThread3, sizeof(waThread3), NORMALPRIO + 1, Thread3, &ssd1306_128x32);
+#endif
+
+ while (true) {
+ osalThreadResumeS(&thread1_ref, MSG_OK);
+ osalThreadSleepMilliseconds(100);
+ osalThreadResumeS(&thread1_ref, MSG_RESET);
+ osalThreadSleepMilliseconds(400);
+ }
+}
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/readme.txt b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/readme.txt
new file mode 100644
index 00000000..0ef953c3
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/readme.txt
@@ -0,0 +1,26 @@
+*****************************************************************************
+** ChibiOS/HAL - I2C driver demo for NUC123. **
+*****************************************************************************
+
+** TARGET **
+
+The demo runs on a NUTINY-SDK-NUC123-V2.0 board with a NUC123SD4AN0 MCU.
+
+** The Demo **
+
+The application demonstrates the use of the NUC123 platform driver, and a little
+bit of the PAL. A successful run of the test involves the on-board LED blinking at 2 Hz
+(on for 100 ms, then off for 400 ms).
+
+
+** Board Setup **
+
+- Connect 128x32 OLED module to PA.10=I2C1_SDA and PA.11=I2C1_SCL .
+- Connect 128x64 OLED module to PF.2=I2C0_SDA and PF.3=I2C0_SCL .
+- If any of the OLED modules are absent, pull-up resistors are required instead.
+
+** Build Procedure **
+
+The demo has been tested using gcc version 9.3.1 (GNU Arm Embedded Toolchain 9-2020-q2-update).
+Just add overriding setting for TRGT in the command line in order to use specific version of GCC.
+for example: make -j TRGT=/opt/ARM/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi-
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c
new file mode 100644
index 00000000..f4b37c19
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c
@@ -0,0 +1,193 @@
+/*
+ Copyright (C) 2020 Ein Terakawa
+
+ 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.
+*/
+
+#include "hal.h"
+#include "ssd1306.h"
+#include "string.h"
+
+/* timeout value must be increased for i2cclk less than its default, 100kHz. */
+#define CMD_TRANSMIT_TIMEOUT TIME_MS2I(10)
+#define DATA_TRANSMIT_TIMEOUT TIME_MS2I(100)
+
+#define CTRL_CMD_STREAM 0x00
+#define CTRL_DATA_STREAM 0x40
+#define CTRL_CMD_SINGLE 0x80
+
+#define I2CD ((ssd1306)->i2cd)
+#define ADDR ((ssd1306)->i2caddr)
+
+#define send_cmd(ssd1306, ...) \
+ do { \
+ uint8_t buf[] = { CTRL_CMD_STREAM, __VA_ARGS__ }; \
+ bool _success = _send_cmd(I2CD, ADDR, buf, sizeof(buf)); \
+ if (!_success) goto done; \
+ } while(0)
+
+#define send_cmd_static(ssd1306, ...) \
+ do{ \
+ static const uint8_t buf[] = { CTRL_CMD_STREAM, __VA_ARGS__ }; \
+ bool _success = _send_cmd(I2CD, ADDR, buf, sizeof(buf)); \
+ if (!_success) goto done; \
+ } while(0)
+
+#define CMD1(c) c
+#define CMD2(c, d) c, d
+#define CMD3(c, d, e) c, d, e
+
+static bool _send_cmd(I2CDriver *i2cd, uint8_t addr, const uint8_t *buf, int len) {
+
+ msg_t status = i2cMasterTransmitTimeout(i2cd, addr,
+ buf, len, NULL, 0, CMD_TRANSMIT_TIMEOUT);
+
+ if (MSG_OK != status) {
+ /* i2cflags_t error_code = i2cGetErrors(i2cd); */
+ return false;
+ }
+
+ return true;
+}
+
+#define send_data(ssd1306, buf, len) \
+ do { \
+ bool _success = _send_data(I2CD, ADDR, buf, len); \
+ if (!_success) goto done; \
+ } while(0)
+
+static bool _send_data(I2CDriver *i2cd, uint8_t addr, const uint8_t *buf, int len) {
+ bool success = false;
+
+ msg_t status = i2cMasterTransmitTimeout(i2cd, addr,
+ buf, len, NULL, 0, DATA_TRANSMIT_TIMEOUT);
+
+ if (MSG_OK != status) {
+ /* i2cflags_t error_code = i2cGetErrors(I2CD); */
+ goto done;
+ }
+
+ success = true;
+
+done:
+ return success;
+}
+
+bool ssd1306_init(SSD1306_DRIVER *ssd1306) {
+ bool success = false;
+ uint8_t width = ssd1306->width;
+ uint8_t height = ssd1306->height;
+ uint8_t num_pages = height / 8;
+
+ i2cStart(I2CD, ssd1306->i2ccfg);
+
+ send_cmd_static(ssd1306,
+ CMD1(SetDisplayOff),
+ CMD1(DeactivateScroll),
+ CMD1(DisableEntireDisplayOn),
+ CMD2(SetOscFreqAndClkDiv, 0x80),
+ CMD2(SetDisplayOffset, 0x00),
+ CMD1(SetDisplayStartLine | 0x00),
+ CMD2(SetMemoryAddressMode, 0x00)); /* Horizontal Addressing Mode */
+
+ send_cmd(ssd1306, CMD2(SetMultiplexRatio, height - 1));
+
+ if (ssd1306->rotate180) {
+ /* rotate 180 degrees == upside down */
+ send_cmd_static(ssd1306,
+ CMD1(SetSegmentRemapReverse),
+ CMD1(SetComScanOrderReverse));
+ } else {
+ /* no rotation */
+ send_cmd_static(ssd1306,
+ CMD1(SetSegmentRemapNormal),
+ CMD1(SetComScanOrderNormal));
+ }
+
+ if (height == 32) {
+ /* 128x32 module uses SequentialComMode */
+ send_cmd_static(ssd1306, CMD2(SetComPins, 0x02));
+ } else {
+ /* 128x64 module uses AlternativeComMode */
+ send_cmd_static(ssd1306, CMD2(SetComPins, 0x12));
+ }
+
+ /* Clear Graphic Display Data RAM */
+ send_cmd(ssd1306,
+ CMD3(SetPageAddress, 0, num_pages - 1),
+ CMD3(SetColumnAddress, 0, width - 1));
+
+ uint8_t *buf = ssd1306->buf;
+ size_t len = SSD1306_PREAMBLE_LENGTH + num_pages * width;
+ memset(buf, 0, len);
+ buf[0] = CTRL_DATA_STREAM; /* need this byte proceeding the actual data */
+ send_data(ssd1306, buf, len);
+
+ send_cmd_static(ssd1306,
+ CMD2(SetPreChargePeriod, 0xC4),
+ CMD2(SetVcomhLevel, 0x20),
+ CMD1(SetNormalDisplay),
+ CMD2(SetContrastControl, 0x3F),
+ CMD2(ChargePumpSetting, 0x14),
+ CMD1(SetDisplayOn));
+
+ success = true;
+
+done:
+ i2cStop(I2CD);
+ return success;
+}
+
+bool ssd1306_data(SSD1306_DRIVER *ssd1306) {
+ bool success = false;
+ uint8_t width = ssd1306->width;
+ uint8_t height = ssd1306->height;
+ uint8_t num_pages = height / 8;
+
+ i2cStart(I2CD, ssd1306->i2ccfg);
+
+ /* Transfer to Graphic Display Data RAM */
+ send_cmd(ssd1306,
+ CMD3(SetPageAddress, 0, num_pages - 1),
+ CMD3(SetColumnAddress, 0, width - 1));
+
+ uint8_t *buf = ssd1306->buf;
+ size_t len = SSD1306_PREAMBLE_LENGTH + num_pages * width;
+ send_data(ssd1306, buf, len);
+
+ success = true;
+
+done:
+ i2cStop(I2CD);
+ return success;
+}
+
+bool ssd1306_display_on(SSD1306_DRIVER *ssd1306) {
+ bool success = false;
+ i2cStart(I2CD, ssd1306->i2ccfg);
+ send_cmd_static(ssd1306, CMD1(SetDisplayOn));
+ success = true;
+done:
+ i2cStop(I2CD);
+ return success;
+}
+
+bool ssd1306_display_off(SSD1306_DRIVER *ssd1306) {
+ bool success = false;
+ i2cStart(I2CD, ssd1306->i2ccfg);
+ send_cmd_static(ssd1306, CMD1(SetDisplayOff));
+ success = true;
+done:
+ i2cStop(I2CD);
+ return success;
+}
diff --git a/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.h b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.h
new file mode 100644
index 00000000..2ee7471a
--- /dev/null
+++ b/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.h
@@ -0,0 +1,90 @@
+#ifndef SSD1306_H
+#define SSD1306_H
+
+#include
+
+enum ssd1306_cmds {
+
+ /* Fundamental Command */
+ SetContrastControl = 0x81,
+ DisableEntireDisplayOn = 0xA4,
+ EnableEntireDisplayOn = 0xA5,
+ SetNormalDisplay = 0xA6,
+ SetInvertDisplay = 0xA7,
+ SetDisplayOff = 0xAE,
+ SetDisplayOn = 0xAF,
+
+ /* Charge Pump Command */
+ ChargePumpSetting = 0x8D,
+
+ /* Timing & Driving Scheme Setting Command */
+ SetOscFreqAndClkDiv = 0xD5,
+ SetPreChargePeriod = 0xD9,
+ SetVcomhLevel = 0xDB,
+
+ /* Addressing Setting Command */
+ SetMemoryAddressMode = 0x20,
+ SetColumnAddress = 0x21,
+ SetPageAddress = 0x22,
+ // SetLowColumn = 0x00, /* 0x00 - 0x0F */
+ // SetHighColumn = 0x10, /* 0x10 - 0x1F */
+ // SetPageStartAddress = 0xB0, /* 0xB0 - 0xB7 */
+
+ /* Hardware Configuration Command */
+ SetDisplayStartLine = 0x40, /* 0x40 - 0x7F */
+ SetSegmentRemapNormal = 0xA0,
+ SetSegmentRemapReverse = 0xA1,
+ SetMultiplexRatio = 0xA8,
+ SetComScanOrderNormal = 0xC0,
+ SetComScanOrderReverse = 0xC8,
+ SetDisplayOffset = 0xD3,
+ SetComPins = 0xDA,
+
+ /* Scrolling Command */
+ RightHorizontalScroll = 0x26,
+ LeftHorizontalScroll = 0x27,
+ VerticalAndRightHorizontalScroll = 0x29,
+ VerticalAndLeftHorizontalScroll = 0x2A,
+ DeactivateScroll = 0x2E,
+ ActivateScroll = 0x2F,
+ SetVerticalScrollArea = 0xA3,
+
+ /* Other Command */
+ NoOperation = 0xE3,
+};
+
+#ifndef SSD1306_ADDRESS
+/* for your reference (0x3C << 1) == 0x78 , (0x3D << 1) == 0x7A . */
+#define SSD1306_ADDRESS 0x3C
+#endif
+
+typedef struct I2CDriver I2CDriver;
+typedef struct I2CConfig I2CConfig;
+typedef struct SSD1306_DRIVER {
+ I2CDriver *i2cd;
+ I2CConfig const *i2ccfg;
+ uint8_t i2caddr;
+ uint8_t width;
+ uint8_t height;
+ bool rotate180;
+ uint8_t *buf;
+} SSD1306_DRIVER;
+
+#define SSD1306_PREAMBLE_LENGTH 1
+#define DEFINE_SSD1306_DRIVER(name, i2cd, addr, width, height, rotate180) \
+ _Static_assert(width == 128, "Only support width of 128 for simplicity."); \
+ _Static_assert(height == 32 || height == 64, "Only support height of 32 or 64 for simplicity."); \
+ uint8_t name##_buf[SSD1306_PREAMBLE_LENGTH + width * height / 8]; \
+ struct SSD1306_DRIVER name = { \
+ i2cd, NULL, addr, width, height, rotate180, name##_buf \
+ }
+
+#define SSD1306_GET_FRAMEBUFFER(ssd1306) \
+ (&((ssd1306)->buf[SSD1306_PREAMBLE_LENGTH]))
+
+bool ssd1306_init(SSD1306_DRIVER *ssd1306);
+bool ssd1306_data(SSD1306_DRIVER *ssd1306);
+bool ssd1306_display_on(SSD1306_DRIVER *ssd1306);
+bool ssd1306_display_off(SSD1306_DRIVER *ssd1306);
+
+#endif