/*************************************************************************** * Copyright (C) 2020 - 2023 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 #include pthread_mutex_t mutex; 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 */ pthread_mutex_init(&mutex, NULL); } 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); pthread_mutex_destroy(&mutex); } 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); } bool i2c0_lockDevice() { if(pthread_mutex_trylock(&mutex) == 0) { return true; } return false; } void i2c0_lockDeviceBlocking() { pthread_mutex_lock(&mutex); } void i2c0_releaseDevice() { pthread_mutex_unlock(&mutex); }