#include "iic.h" /* Software I2C delay (microseconds), based on SysTick */ static void delayUs(uint16_t us) { uint32_t start = SysTick->VAL; uint32_t ticks = us * (SystemCoreClock / 1000000); if (start < ticks) { while (SysTick->VAL > start); while (SysTick->VAL < (SysTick->LOAD - (ticks - start))); } else { while ((SysTick->VAL < start) && (SysTick->VAL >= (start - ticks))); } } /* I2C Interface Initialization */ void iicInit(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); /* SDA - PA12, open-drain output */ GPIO_InitStruct.Pin = SDA_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct); /* SCL - PA11, push-pull output */ GPIO_InitStruct.Pin = SCL_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(SCL_GPIO_Port, &GPIO_InitStruct); IIC_SCL_H; IIC_SDA_H; } /* I2C Start Signal */ void iicStart(void) { IIC_SDA_H; IIC_SCL_H; delayUs(4); IIC_SDA_L; /* SCL high, SDA high->low = start */ } /* I2C Stop Signal */ void iicStop(void) { IIC_SDA_L; IIC_SCL_H; delayUs(4); IIC_SDA_H; /* SCL high, SDA low->high = stop */ } /* Wait for ACK: returns 0=OK, 1=timeout */ uint8_t iicWaitAck(void) { unsigned char timeout = 0; IIC_SDA_H; IIC_SCL_H; while (READ_SDA) { timeout++; if (timeout > 250) { iicStop(); return 1; } delayUs(2); } IIC_SCL_L; delayUs(20); return 0; } /* Send One Byte (MSB first), return ACK status: 0=ACK, 1=NACK/timeout */ uint8_t iicSendByteAck(uint8_t txd) { unsigned char t; IIC_SCL_L; for (t = 0; t < 8; t++) { IIC_SDA_OUT(((txd & 0x80) >> 7)); txd <<= 1; delayUs(2); IIC_SCL_H; delayUs(2); IIC_SCL_L; } return iicWaitAck(); } /* Send One Byte (MSB first), legacy API without ACK return */ void iicSendByte(uint8_t txd) { (void)iicSendByteAck(txd); } /* Read One Byte; ack=1 send ACK, ack=0 send NACK */ unsigned char iicReadByte(uint8_t ack) { unsigned char i; unsigned char receive = 0; IIC_SCL_L; delayUs(20); for (i = 0; i < 8; i++) { IIC_SCL_H; delayUs(20); receive <<= 1; if (READ_SDA) receive++; delayUs(20); IIC_SCL_L; delayUs(20); } if (!ack) { /* NACK */ IIC_SDA_H; IIC_SCL_H; delayUs(2); IIC_SCL_L; } else { /* ACK */ IIC_SDA_L; IIC_SCL_H; delayUs(2); IIC_SCL_L; IIC_SDA_H; } return receive; }