134 lines
5.0 KiB
C#
134 lines
5.0 KiB
C#
using LibUsbDotNet.LibUsb;
|
|
using LibUsbDotNet.Main;
|
|
|
|
namespace RTCSync.Utils;
|
|
|
|
public static class I2CUtils
|
|
{
|
|
private const int VID = 0x1A86;
|
|
private const int PID = 0x5512; // CH341T
|
|
|
|
// Команды CH341 для I2C
|
|
private const byte CH341_CMD_I2C_STREAM = 0xAA;
|
|
private const byte CH341_CMD_I2C_STM_STA = 0x74; // START
|
|
private const byte CH341_CMD_I2C_STM_STO = 0x75; // STOP
|
|
private const byte CH341_CMD_I2C_STM_OUT = 0x80; // write byte (len в младших битах)
|
|
private const byte CH341_CMD_I2C_STM_IN = 0xC0; // read byte
|
|
private const byte CH341_CMD_I2C_STM_END = 0x00; // конец стрима
|
|
|
|
public static void ScanDevice(IUsbDevice device)
|
|
{
|
|
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
|
|
var reader = device.OpenEndpointReader(ReadEndpointID.Ep02);
|
|
|
|
Console.WriteLine("Сканирование I2C шины (0x03 - 0x77)...");
|
|
|
|
for (byte addr = 0x03; addr < 0x78; addr++)
|
|
{
|
|
// Пробуем послать START + адрес + STOP
|
|
// Если устройство есть — придёт ACK, если нет — NACK
|
|
var cmd = new byte[]
|
|
{
|
|
CH341_CMD_I2C_STREAM, // CH341_CMD_I2C_STREAM
|
|
CH341_CMD_I2C_STM_STA, // START
|
|
CH341_CMD_I2C_STM_OUT | 1, // OUT, 1 байт
|
|
(byte)(addr << 1), // адрес + write bit
|
|
CH341_CMD_I2C_STM_STO, // STOP
|
|
CH341_CMD_I2C_STM_END // END
|
|
};
|
|
|
|
writer.Write(cmd, 500, out int written);
|
|
|
|
var buf = new byte[4];
|
|
reader.Read(buf, 200, out int read);
|
|
|
|
// CH341 возвращает статус: 0x00 = ACK получен (устройство есть)
|
|
// Первый байт ответа — статус последней I2C операции
|
|
if (read > 0 && buf[0] == 0x00)
|
|
{
|
|
Console.WriteLine($" Найдено устройство: 0x{addr:X2}");
|
|
}
|
|
}
|
|
|
|
Console.WriteLine("Сканирование завершено.");
|
|
}
|
|
|
|
public static void CH341Init(IUsbDevice device)
|
|
{
|
|
Console.WriteLine("Пытаемся инициализировать устройство");
|
|
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
|
|
|
|
// Установка скорости I2C: 0x00=20kHz, 0x01=100kHz, 0x02=400kHz, 0x03=750kHz
|
|
var cmd = new byte[]
|
|
{
|
|
CH341_CMD_I2C_STREAM,
|
|
0x60 | 0x01, // CH341_CMD_I2C_STM_SET | 100kHz
|
|
CH341_CMD_I2C_STM_END
|
|
};
|
|
writer.Write(cmd, 1000, out _);
|
|
}
|
|
|
|
public static byte[] Read(IUsbDevice device, byte address, byte reg, int length)
|
|
{
|
|
// Формируем пакет: START → write addr+reg → RESTART → read → STOP
|
|
var cmd = new byte[]
|
|
{
|
|
CH341_CMD_I2C_STREAM,
|
|
CH341_CMD_I2C_STM_STA,
|
|
CH341_CMD_I2C_STM_OUT | 2, // 2 байта: адрес + регистр
|
|
(byte)(address << 1), // write
|
|
reg,
|
|
CH341_CMD_I2C_STM_STA, // repeated START
|
|
CH341_CMD_I2C_STM_OUT | 1,
|
|
(byte)((address << 1) | 1), // read
|
|
(byte)(CH341_CMD_I2C_STM_IN | (length - 1)),
|
|
CH341_CMD_I2C_STM_STO,
|
|
CH341_CMD_I2C_STM_END
|
|
};
|
|
|
|
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
|
|
var reader = device.OpenEndpointReader(ReadEndpointID.Ep02);
|
|
|
|
writer.Write(cmd, 1000, out _);
|
|
var buf = new byte[length];
|
|
reader.Read(buf, 1000, out var transferred);
|
|
return buf;
|
|
}
|
|
|
|
public static byte[] ReadWithRetry(IUsbDevice device, byte address, byte reg, int length)
|
|
{
|
|
for (var attempt = 0; attempt < 100; attempt++)
|
|
{
|
|
var result = Read(device, address, reg, length);
|
|
|
|
if (result[0] != 0x03)
|
|
return result;
|
|
|
|
Thread.Sleep(10);
|
|
}
|
|
|
|
throw new Exception("Ошибка чтения CH431 после 100 попыток");
|
|
}
|
|
|
|
public static void Write(IUsbDevice device, byte address, byte reg, byte[] data)
|
|
{
|
|
// START → write addr → write reg → write data[0..n] → STOP
|
|
// CH341_CMD_I2C_STM_OUT | N означает "записать N байт"
|
|
// N = 1 (адрес) + 1 (регистр) + data.Length
|
|
var cmd = new byte[5 + data.Length + 2];
|
|
int i = 0;
|
|
|
|
cmd[i++] = CH341_CMD_I2C_STREAM;
|
|
cmd[i++] = CH341_CMD_I2C_STM_STA;
|
|
cmd[i++] = (byte)(CH341_CMD_I2C_STM_OUT | (2 + data.Length)); // адрес + регистр + данные
|
|
cmd[i++] = (byte)(address << 1); // write bit = 0
|
|
cmd[i++] = reg;
|
|
foreach (var b in data)
|
|
cmd[i++] = b;
|
|
cmd[i++] = CH341_CMD_I2C_STM_STO;
|
|
cmd[i] = CH341_CMD_I2C_STM_END;
|
|
|
|
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
|
|
writer.Write(cmd, 1000, out _);
|
|
}
|
|
} |