/* * 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 */