Dependencies:   DHT

Revision:
0:3adb31fbd547
diff -r 000000000000 -r 3adb31fbd547 tm_stm32f4_i2c.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tm_stm32f4_i2c.c	Tue Sep 18 07:25:30 2018 +0000
@@ -0,0 +1,393 @@
+/**	
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * | 
+ * | 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
+ * | 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 <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_stm32f4_i2c.h"
+
+/* Private variables */
+static uint32_t TM_I2C_Timeout;
+static uint32_t TM_I2C_INT_Clocks[3] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+
+/* Private defines */
+#define I2C_TRANSMITTER_MODE   0
+#define I2C_RECEIVER_MODE      1
+#define I2C_ACK_ENABLE         1
+#define I2C_ACK_DISABLE        0
+
+/* Private functions */
+static void TM_I2C1_INT_InitPins(TM_I2C_PinsPack_t pinspack);
+static void TM_I2C2_INT_InitPins(TM_I2C_PinsPack_t pinspack);
+static void TM_I2C3_INT_InitPins(TM_I2C_PinsPack_t pinspack);
+
+void TM_I2C_Init(I2C_TypeDef* I2Cx, TM_I2C_PinsPack_t pinspack, uint32_t clockSpeed) {
+	I2C_InitTypeDef I2C_InitStruct;
+	
+	if (I2Cx == I2C1) {
+		/* Enable clock */
+		RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
+		
+		/* Enable pins */
+		TM_I2C1_INT_InitPins(pinspack);
+		
+		/* Check clock, set the lowest clock your devices support on the same I2C but */
+		if (clockSpeed < TM_I2C_INT_Clocks[0]) {
+			TM_I2C_INT_Clocks[0] = clockSpeed;
+		}
+		
+		/* Set values */
+		I2C_InitStruct.I2C_ClockSpeed = TM_I2C_INT_Clocks[0];
+		I2C_InitStruct.I2C_AcknowledgedAddress = TM_I2C1_ACKNOWLEDGED_ADDRESS;
+		I2C_InitStruct.I2C_Mode = TM_I2C1_MODE;
+		I2C_InitStruct.I2C_OwnAddress1 = TM_I2C1_OWN_ADDRESS;
+		I2C_InitStruct.I2C_Ack = TM_I2C1_ACK;
+		I2C_InitStruct.I2C_DutyCycle = TM_I2C1_DUTY_CYCLE;
+	} else if (I2Cx == I2C2) {
+		/* Enable clock */
+		RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
+		
+		/* Enable pins */
+		TM_I2C2_INT_InitPins(pinspack);
+		
+		/* Check clock, set the lowest clock your devices support on the same I2C but */
+		if (clockSpeed < TM_I2C_INT_Clocks[1]) {
+			TM_I2C_INT_Clocks[1] = clockSpeed;
+		}
+		
+		/* Set values */
+		I2C_InitStruct.I2C_ClockSpeed = TM_I2C_INT_Clocks[1];
+		I2C_InitStruct.I2C_AcknowledgedAddress = TM_I2C2_ACKNOWLEDGED_ADDRESS;
+		I2C_InitStruct.I2C_Mode = TM_I2C2_MODE;
+		I2C_InitStruct.I2C_OwnAddress1 = TM_I2C2_OWN_ADDRESS;
+		I2C_InitStruct.I2C_Ack = TM_I2C2_ACK;
+		I2C_InitStruct.I2C_DutyCycle = TM_I2C2_DUTY_CYCLE;
+	} else if (I2Cx == I2C3) {
+		/* Enable clock */
+		RCC->APB1ENR |= RCC_APB1ENR_I2C3EN;
+		
+		/* Enable pins */
+		TM_I2C3_INT_InitPins(pinspack);
+		
+		/* Check clock, set the lowest clock your devices support on the same I2C but */
+		if (clockSpeed < TM_I2C_INT_Clocks[2]) {
+			TM_I2C_INT_Clocks[2] = clockSpeed;
+		}
+		
+		/* Set values */
+		I2C_InitStruct.I2C_ClockSpeed = TM_I2C_INT_Clocks[2];
+		I2C_InitStruct.I2C_AcknowledgedAddress = TM_I2C3_ACKNOWLEDGED_ADDRESS;
+		I2C_InitStruct.I2C_Mode = TM_I2C3_MODE;
+		I2C_InitStruct.I2C_OwnAddress1 = TM_I2C3_OWN_ADDRESS;
+		I2C_InitStruct.I2C_Ack = TM_I2C3_ACK;
+		I2C_InitStruct.I2C_DutyCycle = TM_I2C3_DUTY_CYCLE;
+	}
+	
+	/* Disable I2C first */
+	I2Cx->CR1 &= ~I2C_CR1_PE;
+	
+	/* Initialize I2C */
+	I2C_Init(I2Cx, &I2C_InitStruct);
+	
+	/* Enable I2C */
+	I2Cx->CR1 |= I2C_CR1_PE;
+}
+
+uint8_t TM_I2C_Read(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg) {
+	uint8_t received_data;
+	TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
+	TM_I2C_WriteData(I2Cx, reg);
+	TM_I2C_Stop(I2Cx);
+	TM_I2C_Start(I2Cx, address, I2C_RECEIVER_MODE, I2C_ACK_DISABLE);
+	received_data = TM_I2C_ReadNack(I2Cx);
+	return received_data;
+}
+
+void TM_I2C_ReadMulti(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) {
+	TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_ENABLE);
+	TM_I2C_WriteData(I2Cx, reg);
+	//TM_I2C_Stop(I2Cx);
+	TM_I2C_Start(I2Cx, address, I2C_RECEIVER_MODE, I2C_ACK_ENABLE);
+	while (count--) {
+		if (!count) {
+			/* Last byte */
+			*data++ = TM_I2C_ReadNack(I2Cx);
+		} else {
+			*data++ = TM_I2C_ReadAck(I2Cx);
+		}
+	}
+}
+
+uint8_t TM_I2C_ReadNoRegister(I2C_TypeDef* I2Cx, uint8_t address) {
+	uint8_t data;
+	TM_I2C_Start(I2Cx, address, I2C_RECEIVER_MODE, I2C_ACK_ENABLE);
+	/* Also stop condition happens */
+	data = TM_I2C_ReadNack(I2Cx);
+	return data;
+}
+
+void TM_I2C_ReadMultiNoRegister(I2C_TypeDef* I2Cx, uint8_t address, uint8_t* data, uint16_t count) {
+	TM_I2C_Start(I2Cx, address, I2C_RECEIVER_MODE, I2C_ACK_ENABLE);
+	while (count--) {
+		if (!count) {
+			/* Last byte */
+			*data = TM_I2C_ReadNack(I2Cx);
+		} else {
+			*data = TM_I2C_ReadAck(I2Cx);
+		}
+	}
+}
+
+void TM_I2C_Write(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t data) {
+	TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
+	TM_I2C_WriteData(I2Cx, reg);
+	TM_I2C_WriteData(I2Cx, data);
+	TM_I2C_Stop(I2Cx);
+}
+
+void TM_I2C_WriteMulti(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) {
+	TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
+	TM_I2C_WriteData(I2Cx, reg);
+	while (count--) {
+		TM_I2C_WriteData(I2Cx, *data++);
+	}
+	TM_I2C_Stop(I2Cx);
+}
+
+void TM_I2C_WriteNoRegister(I2C_TypeDef* I2Cx, uint8_t address, uint8_t data) {
+	TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
+	TM_I2C_WriteData(I2Cx, data);
+	TM_I2C_Stop(I2Cx);
+}
+
+void TM_I2C_WriteMultiNoRegister(I2C_TypeDef* I2Cx, uint8_t address, uint8_t* data, uint16_t count) {
+	TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
+	while (count--) {
+		TM_I2C_WriteData(I2Cx, *data++);
+	}
+	TM_I2C_Stop(I2Cx);
+}
+
+
+uint8_t TM_I2C_IsDeviceConnected(I2C_TypeDef* I2Cx, uint8_t address) {
+	uint8_t connected = 0;
+	/* Try to start, function will return 0 in case device will send ACK */
+	if (!TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_ENABLE)) {
+		connected = 1;
+	}
+	
+	/* STOP I2C */
+	TM_I2C_Stop(I2Cx);
+	
+	/* Return status */
+	return connected;
+}
+
+__weak void TM_I2C_InitCustomPinsCallback(I2C_TypeDef* I2Cx, uint16_t AlternateFunction) {
+	/* Custom user function. */
+	/* In case user needs functionality for custom pins, this function should be declared outside this library */
+}
+
+/* Private functions */
+int16_t TM_I2C_Start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction, uint8_t ack) {
+	/* Generate I2C start pulse */
+	I2Cx->CR1 |= I2C_CR1_START;
+	
+	/* Wait till I2C is busy */
+	TM_I2C_Timeout = TM_I2C_TIMEOUT;
+	while (!(I2Cx->SR1 & I2C_SR1_SB)) {
+		if (--TM_I2C_Timeout == 0x00) {
+			return 1;
+		}
+	}
+
+	/* Enable ack if we select it */
+	if (ack) {
+		I2Cx->CR1 |= I2C_CR1_ACK;
+	}
+
+	/* Send write/read bit */
+	if (direction == I2C_TRANSMITTER_MODE) {
+		/* Send address with zero last bit */
+		I2Cx->DR = address & ~I2C_OAR1_ADD0;
+		
+		/* Wait till finished */
+		TM_I2C_Timeout = TM_I2C_TIMEOUT;
+		while (!(I2Cx->SR1 & I2C_SR1_ADDR)) {
+			if (--TM_I2C_Timeout == 0x00) {
+				return 1;
+			}
+		}
+	}
+	if (direction == I2C_RECEIVER_MODE) {
+		/* Send address with 1 last bit */
+		I2Cx->DR = address | I2C_OAR1_ADD0;
+		
+		/* Wait till finished */
+		TM_I2C_Timeout = TM_I2C_TIMEOUT;
+		while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
+			if (--TM_I2C_Timeout == 0x00) {
+				return 1;
+			}
+		}
+	}
+	
+	/* Read status register to clear ADDR flag */
+	I2Cx->SR2;
+	
+	/* Return 0, everything ok */
+	return 0;
+}
+
+void TM_I2C_WriteData(I2C_TypeDef* I2Cx, uint8_t data) {
+	/* Wait till I2C is not busy anymore */
+	TM_I2C_Timeout = TM_I2C_TIMEOUT;
+	while (!(I2Cx->SR1 & I2C_SR1_TXE) && TM_I2C_Timeout) {
+		TM_I2C_Timeout--;
+	}
+	
+	/* Send I2C data */
+	I2Cx->DR = data;
+}
+
+uint8_t TM_I2C_ReadAck(I2C_TypeDef* I2Cx) {
+	uint8_t data;
+	
+	/* Enable ACK */
+	I2Cx->CR1 |= I2C_CR1_ACK;
+	
+	/* Wait till not received */
+	TM_I2C_Timeout = TM_I2C_TIMEOUT;
+	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)) {
+		if (--TM_I2C_Timeout == 0x00) {
+			return 1;
+		}
+	}
+	
+	/* Read data */
+	data = I2Cx->DR;
+	
+	/* Return data */
+	return data;
+}
+
+uint8_t TM_I2C_ReadNack(I2C_TypeDef* I2Cx) {
+	uint8_t data;
+	
+	/* Disable ACK */
+	I2Cx->CR1 &= ~I2C_CR1_ACK;
+	
+	/* Generate stop */
+	I2Cx->CR1 |= I2C_CR1_STOP;
+	
+	/* Wait till received */
+	TM_I2C_Timeout = TM_I2C_TIMEOUT;
+	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)) {
+		if (--TM_I2C_Timeout == 0x00) {
+			return 1;
+		}
+	}
+
+	/* Read data */
+	data = I2Cx->DR;
+	
+	/* Return data */
+	return data;
+}
+
+uint8_t TM_I2C_Stop(I2C_TypeDef* I2Cx) {
+	/* Wait till transmitter not empty */
+	TM_I2C_Timeout = TM_I2C_TIMEOUT;
+	while (((!(I2Cx->SR1 & I2C_SR1_TXE)) || (!(I2Cx->SR1 & I2C_SR1_BTF)))) {
+		if (--TM_I2C_Timeout == 0x00) {
+			return 1;
+		}
+	}
+	
+	/* Generate stop */
+	I2Cx->CR1 |= I2C_CR1_STOP;
+	
+	/* Return 0, everything ok */
+	return 0;
+}
+
+
+
+
+/* Private functions */
+static void TM_I2C1_INT_InitPins(TM_I2C_PinsPack_t pinspack) {
+	/* Init pins */
+#if defined(GPIOB)
+	if (pinspack == TM_I2C_PinsPack_1) {
+		TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_6 | GPIO_PIN_7, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C1);
+	}
+#endif
+#if defined(GPIOB)
+	if (pinspack == TM_I2C_PinsPack_2) {
+		TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_8 | GPIO_PIN_9, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C1);
+	}
+#endif
+#if defined(GPIOB)
+	if (pinspack == TM_I2C_PinsPack_3) {
+		TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_6 | GPIO_PIN_9, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C1);
+	}
+#endif
+	if (pinspack == TM_I2C_PinsPack_Custom) {
+		/* Init custom pins, callback function */
+		TM_I2C_InitCustomPinsCallback(I2C1, GPIO_AF_I2C1);
+	}
+}
+
+static void TM_I2C2_INT_InitPins(TM_I2C_PinsPack_t pinspack) {
+	/* Init pins */
+#if defined(GPIOB)
+	if (pinspack == TM_I2C_PinsPack_1) {
+		TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_10 | GPIO_PIN_11, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C2);
+	}
+#endif
+#if defined(GPIOF)
+	if (pinspack == TM_I2C_PinsPack_2) {
+		TM_GPIO_InitAlternate(GPIOF, GPIO_PIN_0 | GPIO_PIN_1, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C2);
+	}
+#endif
+#if defined(GPIOH)
+	if (pinspack == TM_I2C_PinsPack_3) {
+		TM_GPIO_InitAlternate(GPIOH, GPIO_PIN_4 | GPIO_PIN_5, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C2);
+	}
+#endif
+	if (pinspack == TM_I2C_PinsPack_Custom) {
+		/* Init custom pins, callback function */
+		TM_I2C_InitCustomPinsCallback(I2C2, GPIO_AF_I2C2);
+	}
+}
+
+static void TM_I2C3_INT_InitPins(TM_I2C_PinsPack_t pinspack) {
+	/* Init pins */
+#if defined(GPIOA) && defined(GPIOC)
+	if (pinspack == TM_I2C_PinsPack_1) {
+		TM_GPIO_InitAlternate(GPIOA, GPIO_PIN_8, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C3);
+		TM_GPIO_InitAlternate(GPIOC, GPIO_PIN_9, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C3);
+	}
+#endif
+#if defined(GPIOH)
+	if (pinspack == TM_I2C_PinsPack_2) {
+		TM_GPIO_InitAlternate(GPIOH, GPIO_PIN_7 | GPIO_PIN_8, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C3);
+	}
+#endif
+	if (pinspack == TM_I2C_PinsPack_Custom) {
+		/* Init custom pins, callback function */
+		TM_I2C_InitCustomPinsCallback(I2C3, GPIO_AF_I2C3);
+	}
+}