From 56d56e901fe26013b42d7253808ab206d50895ff Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Mon, 28 Dec 2020 12:43:27 +0100 Subject: [PATCH] Driver for MK22FN512xx I2C0 peripheral --- meson.build | 1 + platform/mcu/MK22FN512xxx12/drivers/I2C0.c | 112 +++++++++++++++++++++ platform/mcu/MK22FN512xxx12/drivers/I2C0.h | 65 ++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 platform/mcu/MK22FN512xxx12/drivers/I2C0.c create mode 100644 platform/mcu/MK22FN512xxx12/drivers/I2C0.h 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 */