157 lines
2.7 KiB
C
157 lines
2.7 KiB
C
#ifndef _I2C_BITBANG_H
|
|
#define _I2C_BITBANG_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "ch32fun.h"
|
|
|
|
#ifndef I2C_SDA_PIN
|
|
#define I2C_SDA_PIN PA1
|
|
#endif
|
|
|
|
#ifndef I2C_SCL_PIN
|
|
#define I2C_SCL_PIN PA0
|
|
#endif
|
|
|
|
// decrease to 1 or 0 for Fast Mode (400kHz)
|
|
#ifndef I2C_DELAY_US
|
|
#define I2C_DELAY_US 3
|
|
#endif
|
|
|
|
#define I2C_ACK 0
|
|
#define I2C_NACK 1
|
|
|
|
#define SCL_HIGH() funDigitalWrite(I2C_SCL_PIN, 1)
|
|
#define SCL_LOW() funDigitalWrite(I2C_SCL_PIN, 0)
|
|
#define SDA_HIGH() funDigitalWrite(I2C_SDA_PIN, 1)
|
|
#define SDA_LOW() funDigitalWrite(I2C_SDA_PIN, 0)
|
|
#define SDA_READ() funDigitalRead(I2C_SDA_PIN)
|
|
|
|
static inline void i2c_delay(void) { Delay_Us(I2C_DELAY_US); }
|
|
|
|
static inline void i2c_init(void) {
|
|
funGpioInitAll();
|
|
|
|
funPinMode(I2C_SDA_PIN, GPIO_CFGLR_OUT_10Mhz_OD);
|
|
funPinMode(I2C_SCL_PIN, GPIO_CFGLR_OUT_10Mhz_OD);
|
|
|
|
// idle bus state
|
|
SDA_HIGH();
|
|
SCL_HIGH();
|
|
}
|
|
|
|
static inline void i2c_start(void) {
|
|
SDA_HIGH();
|
|
SCL_HIGH();
|
|
i2c_delay();
|
|
|
|
SDA_LOW();
|
|
i2c_delay();
|
|
SCL_LOW();
|
|
}
|
|
|
|
static inline void i2c_stop(void) {
|
|
SDA_LOW();
|
|
i2c_delay();
|
|
SCL_HIGH();
|
|
i2c_delay();
|
|
|
|
SDA_HIGH();
|
|
i2c_delay();
|
|
}
|
|
|
|
// returns 0 (I2C_ACK) if acknowledged, 1 (I2C_NACK) if not
|
|
static inline uint8_t i2c_write_byte(uint8_t byte) {
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
if (byte & 0x80) {
|
|
SDA_HIGH();
|
|
} else {
|
|
SDA_LOW();
|
|
}
|
|
|
|
byte <<= 1;
|
|
i2c_delay();
|
|
SCL_HIGH();
|
|
i2c_delay();
|
|
SCL_LOW();
|
|
i2c_delay();
|
|
}
|
|
|
|
// ACK/NACK processing
|
|
SDA_HIGH(); // release SDA line for slave
|
|
i2c_delay();
|
|
SCL_HIGH();
|
|
i2c_delay();
|
|
|
|
uint8_t ack = SDA_READ();
|
|
|
|
SCL_LOW();
|
|
i2c_delay();
|
|
|
|
return ack;
|
|
}
|
|
|
|
// I2C_ACK (0) to request more data, I2C_NACK (1) to end tx
|
|
static inline uint8_t i2c_read_byte(uint8_t ack_control) {
|
|
uint8_t byte = 0;
|
|
|
|
SDA_HIGH();
|
|
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
byte <<= 1;
|
|
i2c_delay();
|
|
SCL_HIGH(); // slave writes data here
|
|
i2c_delay();
|
|
|
|
if (SDA_READ()) {
|
|
byte |= 1;
|
|
}
|
|
|
|
SCL_LOW();
|
|
}
|
|
|
|
// send ACK/NACK to slave
|
|
if (ack_control == I2C_ACK) {
|
|
SDA_LOW();
|
|
} else {
|
|
SDA_HIGH();
|
|
}
|
|
|
|
i2c_delay();
|
|
SCL_HIGH();
|
|
i2c_delay();
|
|
SCL_LOW();
|
|
|
|
SDA_HIGH(); // release bus
|
|
i2c_delay();
|
|
|
|
return byte;
|
|
}
|
|
|
|
static inline void i2c_scan(void) {
|
|
printf("--- I2C Scan Start ---\n");
|
|
uint8_t found = 0;
|
|
|
|
for (uint8_t addr = 0x08; addr < 0x78; addr++) {
|
|
i2c_start();
|
|
|
|
// try to write to the address
|
|
uint8_t ack = i2c_write_byte((addr << 1) | 0);
|
|
|
|
i2c_stop();
|
|
|
|
if (ack == I2C_ACK) {
|
|
printf("Device found at 0x%02X\n", addr);
|
|
found++;
|
|
Delay_Ms(1);
|
|
}
|
|
}
|
|
|
|
if (found == 0) {
|
|
printf("No I2C devices found.\n");
|
|
}
|
|
printf("--- I2C Scan End ---\n");
|
|
}
|
|
|
|
#endif // _I2C_BITBANG_H
|