From 0f45c4adbbf7a307f90ebb2e9928e99e0de65eda Mon Sep 17 00:00:00 2001 From: Vasily Davydov Date: Tue, 4 Apr 2023 22:24:43 +0300 Subject: [PATCH] peripherals: add I2C lib [#2] --- source/shoh/src/peripherals/I2C.cpp | 160 ++++++++++++++++++++++++++++ source/shoh/src/peripherals/I2C.h | 33 ++++++ 2 files changed, 193 insertions(+) create mode 100644 source/shoh/src/peripherals/I2C.cpp create mode 100644 source/shoh/src/peripherals/I2C.h diff --git a/source/shoh/src/peripherals/I2C.cpp b/source/shoh/src/peripherals/I2C.cpp new file mode 100644 index 0000000..19a0b6f --- /dev/null +++ b/source/shoh/src/peripherals/I2C.cpp @@ -0,0 +1,160 @@ +/* + * I2C.cpp + * + * Created on: 21.2.2016 + * Author: krl + * Based on example provided by NXP Semiconductors. See copyright notice + * below. + */ + +/* + * @brief I2CM bus master example using polling mode + * + * @note + * Copyright(C) NXP Semiconductors, 2014 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licensor disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under + * any patent, copyright, mask work right, or any other intellectual property + * rights in or to any products. NXP Semiconductors reserves the right to make + * changes in the software without notification. NXP Semiconductors also makes + * no representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that + * it is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#include "I2C.h" + +I2C::I2C (const I2C_config &cfg) : device (nullptr) +{ + // if(cfg.device_number == 0) { + device = LPC_I2C0; + // board init must have been called before the pins can be configured + Chip_IOCON_PinMuxSet (LPC_IOCON, 0, 22, IOCON_DIGMODE_EN | cfg.i2c_mode); + Chip_IOCON_PinMuxSet (LPC_IOCON, 0, 23, IOCON_DIGMODE_EN | cfg.i2c_mode); + Chip_SWM_EnableFixedPin (SWM_FIXED_I2C0_SCL); + Chip_SWM_EnableFixedPin (SWM_FIXED_I2C0_SDA); + //} + // else { + // currently we support only I2C number 0 + //} + + if (LPC_I2C0) + { + /* Enable I2C clock and reset I2C peripheral - the boot ROM does not + do this */ + Chip_I2C_Init (LPC_I2C0); + + /* Setup clock rate for I2C */ + Chip_I2C_SetClockDiv (LPC_I2C0, cfg.clock_divider); + + /* Setup I2CM transfer rate */ + Chip_I2CM_SetBusSpeed (LPC_I2C0, cfg.speed); + + /* Enable Master Mode */ + Chip_I2CM_Enable (LPC_I2C0); + } +} + +I2C::~I2C () +{ + // TODO Auto-generated destructor stub +} + +bool +I2C::write (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize) +{ + return transaction (devAddr, txBuffPtr, txSize, nullptr, 0); +} + +bool +I2C::read (uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize) +{ + return transaction (devAddr, nullptr, 0, rxBuffPtr, rxSize); +} + +bool +I2C::transaction (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, + uint8_t *rxBuffPtr, uint16_t rxSize) +{ + I2CM_XFER_T i2cmXferRec; + + // make sure that master is idle + while (!Chip_I2CM_IsMasterPending (LPC_I2C0)) + ; + + /* Setup I2C transfer record */ + i2cmXferRec.slaveAddr = devAddr; + i2cmXferRec.status = 0; + i2cmXferRec.txSz = txSize; + i2cmXferRec.rxSz = rxSize; + i2cmXferRec.txBuff = txBuffPtr; + i2cmXferRec.rxBuff = rxBuffPtr; + + I2CM_XferBlocking (LPC_I2C0, &i2cmXferRec); + // Chip_I2CM_XferBlocking returns before stop condition is fully completed + // therefore we need to wait for master to be idle when doing back-to-back + // transactions (see beginning of the function) + + /* Test for valid operation */ + if (i2cmXferRec.status == I2CM_STATUS_OK) + { + return true; + } + else + { + return false; + } +} + +/* Transmit and Receive data in master mode */ +/* This duplicates (and combines) the functionality of Chip_I2CM_Xfer and + * Chip_I2CM_XferBlocking with a modification that allows us to do a zero + * length write (needed to use honeywell humidity/temp sensor) + */ +uint32_t +I2C::I2CM_XferBlocking (LPC_I2C_T *pI2C, I2CM_XFER_T *xfer) +{ + uint32_t ret = 0; + /* start transfer */ + + /* set the transfer status as busy */ + xfer->status = I2CM_STATUS_BUSY; + /* Clear controller state. */ + Chip_I2CM_ClearStatus (pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR); + /* Write Address and RW bit to data register */ + // Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0)); // + // original NXP version + // krl : both read and write lenght is 0 --> write (for honeywell temp + // sensor) + Chip_I2CM_WriteByte (pI2C, (xfer->slaveAddr << 1) + | (xfer->txSz == 0 && xfer->rxSz != 0)); + /* Enter to Master Transmitter mode */ + Chip_I2CM_SendStart (pI2C); + + while (ret == 0) + { + /* wait for status change interrupt */ + while (!Chip_I2CM_IsMasterPending (pI2C)) + { + } + /* call state change handler */ + ret = Chip_I2CM_XferHandler (pI2C, xfer); + } + return ret; +} diff --git a/source/shoh/src/peripherals/I2C.h b/source/shoh/src/peripherals/I2C.h new file mode 100644 index 0000000..910a596 --- /dev/null +++ b/source/shoh/src/peripherals/I2C.h @@ -0,0 +1,33 @@ +/* + * I2C.h + * + * Created on: 21.2.2016 + * Author: krl + */ + +#ifndef I2C_H_ +#define I2C_H_ + +#include "chip.h" + +struct I2C_config { + unsigned int device_number; + unsigned int speed; + unsigned int clock_divider; + unsigned int i2c_mode; + I2C_config(unsigned int dn, unsigned int sp, unsigned int cd): device_number(dn), speed(sp), clock_divider(cd), i2c_mode(IOCON_SFI2C_EN) {}; +}; + +class I2C { +public: + I2C(const I2C_config &cfg); + virtual ~I2C(); + bool transaction(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, uint8_t *rxBuffPtr, uint16_t rxSize); + bool write(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize); + bool read(uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize); +private: + LPC_I2C_T *device; + static uint32_t I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer); +}; + +#endif /* I2C_H_ */