diff --git a/meson.build b/meson.build
index c828c38d..97fb06cf 100644
--- a/meson.build
+++ b/meson.build
@@ -122,6 +122,7 @@ mk22fn512_src = ['platform/mcu/MK22FN512xxx12/boot/startup.c',
'platform/mcu/MK22FN512xxx12/drivers/gpio.c',
'platform/mcu/MK22FN512xxx12/drivers/delays.c',
'platform/mcu/MK22FN512xxx12/drivers/rtc.c',
+ 'platform/mcu/MK22FN512xxx12/drivers/I2C0.c',
'platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.c',
'platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.c',
'platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.c',
diff --git a/platform/mcu/MK22FN512xxx12/drivers/I2C0.c b/platform/mcu/MK22FN512xxx12/drivers/I2C0.c
new file mode 100644
index 00000000..214eb867
--- /dev/null
+++ b/platform/mcu/MK22FN512xxx12/drivers/I2C0.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include "I2C0.h"
+#include
+
+void i2c0_init()
+{
+ SIM->SCGC4 |= SIM_SCGC4_I2C0(1);
+
+ I2C0->A1 = 0; /* Module address when in slave mode */
+ I2C0->F = 0x2C; /* Divide bus clock by 576 */
+ I2C0->C1 |= I2C_C1_IICEN(1); /* Enable I2C module */
+}
+
+void i2c0_terminate()
+{
+ while(I2C0->S & I2C_S_BUSY(1)) ; /* Wait for bus free */
+
+ I2C0->C1 &= ~I2C_C1_IICEN(1);
+ SIM->SCGC4 &= ~SIM_SCGC4_I2C0(1);
+}
+
+void i2c0_write(uint8_t addr, void* buf, size_t len, bool sendStop)
+{
+ I2C0->C1 |= I2C_C1_TX_MASK /* Transmit data */
+ | I2C_C1_MST_MASK; /* Master mode */
+ I2C0->D = addr & 0xFE;
+
+ for(size_t i = 0; i < len; i++)
+ {
+ while((I2C0->S & I2C_S_IICIF_MASK) == 0) ; /* IICIF set on tx completion */
+ I2C0->S |= I2C_S_IICIF_MASK; /* Clear IICIF flag */
+ I2C0->D = ((char *) buf)[i];
+ }
+
+ while((I2C0->S & I2C_S_IICIF_MASK) == 0) ; /* Wait for last byte */
+ I2C0->S |= I2C_S_IICIF_MASK;
+
+ if(sendStop)
+ {
+ I2C0->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK);
+ while(I2C0->S & I2C_S_BUSY_MASK) ;
+ }
+}
+
+void i2c0_read(uint8_t addr, void* buf, size_t len)
+{
+ /* In case a stop was not sent, send a repeated start instead of a start. */
+ if(I2C0->C1 & I2C_C1_MST_MASK)
+ {
+ I2C0->C1 |= I2C_C1_RSTA_MASK
+ | I2C_C1_TX_MASK;
+ }
+ else
+ {
+ I2C0->C1 |= I2C_C1_TX_MASK
+ | I2C_C1_MST_MASK;
+ }
+
+ I2C0->D = addr | 0x01;
+
+ while((I2C0->S & I2C_S_IICIF_MASK) == 0) ; /* Wait end of address transfer */
+ I2C0->S |= I2C_S_IICIF_MASK; /* Clear IICIF flag */
+
+ I2C0->C1 &= ~I2C_C1_TX_MASK; /* Configure peripheral for data reception */
+ (void) I2C0->D; /* Flush RX with a dummy read, also clears TCF */
+
+ for(size_t i = 0; i < len - 1; i++)
+ {
+ while((I2C0->S & I2C_S_IICIF_MASK) == 0) ;
+ I2C0->S |= I2C_S_IICIF_MASK;
+ ((char *) buf)[i] = I2C0->D;
+ }
+
+ /* Send NACK on last byte read */
+ I2C0->C1 |= I2C_C1_TXAK_MASK;
+
+ while((I2C0->S & I2C_S_IICIF_MASK) == 0) ;
+ I2C0->S |= I2C_S_IICIF_MASK;
+
+ /* All bytes received, send stop */
+ I2C0->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TXAK_MASK);
+
+ /* Read last byte */
+ ((char *) buf)[len - 1] = I2C0->D;
+
+ /* Wait until stop has been sent */
+ while(I2C0->S & I2C_S_BUSY_MASK) ;
+}
+
+bool i2c0_busy()
+{
+ return (I2C0->S & I2C_S_BUSY_MASK);
+}
diff --git a/platform/mcu/MK22FN512xxx12/drivers/I2C0.h b/platform/mcu/MK22FN512xxx12/drivers/I2C0.h
new file mode 100644
index 00000000..48ef5db6
--- /dev/null
+++ b/platform/mcu/MK22FN512xxx12/drivers/I2C0.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef I2C0_H
+#define I2C0_H
+
+#include
+#include
+#include
+
+/**
+ * Initialise I2C peripheral with a bus clock frequency of ~100kHz.
+ * NOTE: this driver does not configure the I2C GPIOs, which have to be put in
+ * alternate open drain mode by application code.
+ */
+void i2c0_init();
+
+/**
+ * Shut down I2C peripheral.
+ * NOTE: is left to application code to change the operating mode of the I2C
+ * GPIOs
+ */
+void i2c0_terminate();
+
+/**
+ * Write data to an I2C peripheral.
+ * @param addr: address of target peripheral.
+ * @param buf: pointer to buffer containing data to be sent.
+ * @param len: number of bytes to be sent.
+ * @param sendStop: set to true to generate a stop condition on transfer end.
+ */
+void i2c0_write(uint8_t addr, void *buf, size_t len, bool sendStop);
+
+/**
+ * Read data from an I2C peripheral.
+ * @param addr: address of target peripheral.
+ * @param buf: pointer to a buffer in which received data are written.
+ * @param len: number of bytes to be transferred.
+ */
+void i2c0_read(uint8_t addr, void *buf, size_t len);
+
+/**
+ * Check if I2C bus is already in use.
+ * @return true if bus is busy.
+ */
+bool i2c0_busy();
+
+#endif /* I2C0_H */