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)