Advanced Distributed Systems module at HSLU
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

239 lines
7.9 KiB

/*
* Copyright (c) 2019, Erich Styger
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "platform.h"
#if PL_CONFIG_USE_HW_I2C
#include "McuLib.h"
#include "i2clib.h"
#include "fsl_i2c.h"
#include "fsl_gpio.h"
#include "fsl_port.h"
#include "McuFXOS8700.h"
#include "McuWait.h"
#if CONFIG_I2C_USE_PORT_B /* I2C on PBB uses I2C0 */
#define I2C_MASTER_BASEADDR I2C0
#define I2C_MASTER_CLK_SRC I2C0_CLK_SRC
#define I2C_MASTER_CLOCKING kCLOCK_PortB
#elif CONFIG_I2C_USE_PORT_E /* I2C on PTE uses I2C1 */
#define I2C_MASTER_BASEADDR I2C1
#define I2C_MASTER_CLK_SRC I2C1_CLK_SRC
#define I2C_MASTER_CLOCKING kCLOCK_PortE
#endif
#define I2C_MASTER_CLK_FREQ CLOCK_GetFreq(I2C_MASTER_CLK_SRC)
#define I2C_BAUDRATE 400000U
#define I2C_MASTER_SDA_GPIO SDA1_CONFIG_GPIO_NAME
#define I2C_MASTER_SDA_PORT SDA1_CONFIG_PORT_NAME
#define I2C_MASTER_SDA_PIN SDA1_CONFIG_PIN_NUMBER
#define I2C_MASTER_SCL_GPIO SCL1_CONFIG_GPIO_NAME
#define I2C_MASTER_SCL_PORT SCL1_CONFIG_PORT_NAME
#define I2C_MASTER_SCL_PIN SCL1_CONFIG_PIN_NUMBER
#define I2C_ADD_DELAY (1) /* needed for FXOS sensor? */
#define I2C_ADD_DELAY_US (10)
static uint8_t i2cSlaveDeviceAddr;
#if 0 /* not used */
uint8_t I2CLIB_ReadAddress(uint8_t i2cAddr, uint8_t *memAddr, uint8_t memAddrSize, uint8_t *data, uint16_t dataSize) {
i2c_master_transfer_t masterXfer;
status_t res;
memset(&masterXfer, 0, sizeof(masterXfer));
/* subAddress = memory address on device, data = data pointer.
start + slaveaddress(w) + subAddress + repeated start + slaveaddress(r) + rx data buffer + stop */
masterXfer.slaveAddress = i2cAddr;
masterXfer.direction = kI2C_Read;
masterXfer.subaddress = *memAddr;
masterXfer.subaddressSize = memAddrSize; /* assuming 1! */
masterXfer.data = data;
masterXfer.dataSize = dataSize;
masterXfer.flags = kI2C_TransferDefaultFlag;
res = I2C_MasterTransferBlocking(I2C_MASTER_BASEADDR, &masterXfer);
if (res!=kStatus_Success) {
return ERR_FAILED;
}
return ERR_OK;
}
uint8_t I2CLIB_WriteAddress(uint8_t i2cAddr, uint8_t *memAddr, uint8_t memAddrSize, uint8_t *data, uint16_t dataSize) {
i2c_master_transfer_t masterXfer;
status_t res;
memset(&masterXfer, 0, sizeof(masterXfer));
/* subAddress = memory address in device, data = data pointer.
start + slaveaddress(w) + subAddress + length of data buffer + data buffer + stop*/
masterXfer.slaveAddress = i2cAddr;
masterXfer.direction = kI2C_Write;
masterXfer.subaddress = *memAddr;
masterXfer.subaddressSize = memAddrSize;
masterXfer.data = data;
masterXfer.dataSize = dataSize;
masterXfer.flags = kI2C_TransferDefaultFlag;
res = I2C_MasterTransferBlocking(I2C_MASTER_BASEADDR, &masterXfer);
if (res!=kStatus_Success) {
return ERR_FAILED;
}
return ERR_OK;
}
#endif
uint8_t I2CLIB_SendBlock(void *Ptr, uint16_t Siz, uint16_t *Snt) {
status_t status;
I2C_MasterClearStatusFlags(I2C_MASTER_BASEADDR, kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StartDetectFlag | kI2C_StopDetectFlag);
status = I2C_MasterStart(I2C_MASTER_BASEADDR, i2cSlaveDeviceAddr, kI2C_Write);
if (status!=kStatus_Success) {
return ERR_FAILED;
}
#if I2C_ADD_DELAY
McuWait_Waitus(I2C_ADD_DELAY_US);
#endif
status = I2C_MasterWriteBlocking(I2C_MASTER_BASEADDR, Ptr, Siz, kI2C_TransferNoStartFlag|kI2C_TransferNoStopFlag);
if (status!=kStatus_Success) {
return ERR_FAILED;
}
*Snt = Siz;
return ERR_OK;
}
uint8_t I2CLIB_RecvBlock(void *Ptr, uint16_t Siz, uint16_t *Rcv) {
status_t status;
status = I2C_MasterRepeatedStart(I2C_MASTER_BASEADDR, i2cSlaveDeviceAddr, kI2C_Read);
if (status!=kStatus_Success) {
return ERR_FAILED;
}
#if I2C_ADD_DELAY
McuWait_Waitus(I2C_ADD_DELAY_US);
#endif
status = I2C_MasterReadBlocking(I2C_MASTER_BASEADDR, Ptr, Siz, kI2C_TransferDefaultFlag);
if (status!=kStatus_Success) {
return ERR_FAILED;
}
*Rcv = Siz;
return ERR_OK;
}
uint8_t I2CLIB_SendStop(void) {
status_t status;
status = I2C_MasterStop(I2C_MASTER_BASEADDR);
if (status!=kStatus_Success) {
return ERR_FAILED;
}
return ERR_OK;
}
uint8_t I2CLIB_SelectSlave(uint8_t Slv) {
i2cSlaveDeviceAddr = Slv;
return ERR_OK;
}
static void I2CLIB_ReleaseBus(void) {
uint8_t i = 0;
gpio_pin_config_t pin_config;
port_pin_config_t i2c_pin_config = {0};
/* Config pin mux as gpio */
i2c_pin_config.pullSelect = kPORT_PullUp;
i2c_pin_config.mux = kPORT_MuxAsGpio;
pin_config.pinDirection = kGPIO_DigitalOutput;
pin_config.outputLogic = 1U;
CLOCK_EnableClock(I2C_MASTER_CLOCKING);
PORT_SetPinConfig(I2C_MASTER_SCL_PORT, I2C_MASTER_SCL_PIN, &i2c_pin_config);
PORT_SetPinConfig(I2C_MASTER_SDA_PORT, I2C_MASTER_SDA_PIN, &i2c_pin_config);
GPIO_PinInit(I2C_MASTER_SCL_GPIO, I2C_MASTER_SCL_PIN, &pin_config);
GPIO_PinInit(I2C_MASTER_SDA_GPIO, I2C_MASTER_SDA_PIN, &pin_config);
/* Drive SDA low first to simulate a start */
GPIO_PinWrite(I2C_MASTER_SDA_GPIO, I2C_MASTER_SDA_PIN, 0U);
McuWait_Waitus(10);
/* Send 9 pulses on SCL and keep SDA high */
for (i = 0; i < 9; i++) {
GPIO_PinWrite(I2C_MASTER_SCL_GPIO, I2C_MASTER_SCL_PIN, 0U);
McuWait_Waitus(10);
GPIO_PinWrite(I2C_MASTER_SDA_GPIO, I2C_MASTER_SDA_PIN, 1U);
McuWait_Waitus(10);
GPIO_PinWrite(I2C_MASTER_SCL_GPIO, I2C_MASTER_SCL_PIN, 1U);
McuWait_Waitus(20);
}
/* Send stop */
GPIO_PinWrite(I2C_MASTER_SCL_GPIO, I2C_MASTER_SCL_PIN, 0U);
McuWait_Waitus(10);
GPIO_PinWrite(I2C_MASTER_SDA_GPIO, I2C_MASTER_SDA_PIN, 0U);
McuWait_Waitus(10);
GPIO_PinWrite(I2C_MASTER_SCL_GPIO, I2C_MASTER_SCL_PIN, 1U);
McuWait_Waitus(10);
GPIO_PinWrite(I2C_MASTER_SDA_GPIO, I2C_MASTER_SDA_PIN, 1U);
McuWait_Waitus(10);
}
static void I2CLIB_ConfigurePins(void) {
CLOCK_EnableClock(I2C_MASTER_CLOCKING);
/* I2C SCL Pin */
#if CONFIG_I2C_USE_PORT_B
PORT_SetPinMux(I2C_MASTER_SCL_PORT, I2C_MASTER_SCL_PIN, kPORT_MuxAlt2);
#elif CONFIG_I2C_USE_PORT_E
PORT_SetPinMux(I2C_MASTER_SCL_PORT, I2C_MASTER_SCL_PIN, kPORT_MuxAlt6);
#endif
I2C_MASTER_SCL_PORT->PCR[I2C_MASTER_SCL_PIN] = ((I2C_MASTER_SCL_PORT->PCR[I2C_MASTER_SCL_PIN] &
/* Mask bits to zero which are setting */
(~(PORT_PCR_PE_MASK | PORT_PCR_ODE_MASK | PORT_PCR_ISF_MASK)))
/* Pull Enable: Internal pullup or pulldown resistor is enabled on the corresponding pin. */
| (uint32_t)(PORT_PCR_PE_MASK)
/* Open Drain Enable: Open drain output is enabled on the corresponding pin, if the pin is
* configured as a digital output. */
| PORT_PCR_ODE(kPORT_OpenDrainEnable));
/* I2C SDA Pin */
#if CONFIG_I2C_USE_PORT_B
PORT_SetPinMux(I2C_MASTER_SDA_PORT, I2C_MASTER_SDA_PIN, kPORT_MuxAlt2);
#elif CONFIG_I2C_USE_PORT_E
PORT_SetPinMux(I2C_MASTER_SCL_PORT, I2C_MASTER_SDA_PIN, kPORT_MuxAlt6);
#endif
I2C_MASTER_SDA_PORT->PCR[I2C_MASTER_SDA_PIN] = ((I2C_MASTER_SDA_PORT->PCR[I2C_MASTER_SDA_PIN] &
/* Mask bits to zero which are setting */
(~(PORT_PCR_PE_MASK | PORT_PCR_ODE_MASK | PORT_PCR_ISF_MASK)))
/* Pull Enable: Internal pullup or pulldown resistor is enabled on the corresponding pin. */
| (uint32_t)(PORT_PCR_PE_MASK)
/* Open Drain Enable: Open drain output is enabled on the corresponding pin, if the pin is
* configured as a digital output. */
| PORT_PCR_ODE(kPORT_OpenDrainEnable));
}
void I2CLIB_Init(void) {
I2CLIB_ReleaseBus();
I2CLIB_ConfigurePins();
i2c_master_config_t masterConfig;
uint32_t sourceClock;
/*
* masterConfig->baudRate_Bps = 100000U;
* masterConfig->enableStopHold = false;
* masterConfig->glitchFilterWidth = 0U;
* masterConfig->enableMaster = true;
*/
I2C_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Bps = I2C_BAUDRATE;
sourceClock = I2C_MASTER_CLK_FREQ;
I2C_MasterInit(I2C_MASTER_BASEADDR, &masterConfig, sourceClock);
}
#endif /* PL_CONFIG_USE_HW_I2C */