Рубрики
*NIX информация

FT4232H / ftdi_eeprom / python env / napic

FT4232H

FT4232H переключить в режим MODBUS 485
https://manpages.debian.org/testing/ftdi-eeprom/ftdi_eeprom.1.en.html
https://netcup-03.armbian.com/dl/rockpi-s/archive/Armbian_26.2.1_Rockpi-s_trixie_current_6.18.9_minimal.img.xz


PID 6011 = FT4232H в режиме Quad UART (4 последовательных порта)
PID 6014 = FT4232H в режиме Quad UART/FIFO (с поддержкой дополнительных режимов)

napic arbian

0. Дистрибутив:
Armbian_26.2.1_Rockpi-s_trixie_current_6.18.9_minimal

1. Оверлеи:
/boot/armbianEnv.txt
overlays=otg-host


2. Костюмные оверлеи от напи:
команда для добавления:
armbian-add-overlay <файл.dts>
инструкция:
https://napiworld.ru/recipes/armbian-tuning/
где брать файлы:
https://gitlab.nnz-ipc.net/pub/napilinux/kernel/-/tree/linux6.6/arch/arm64/boot/dts/rockchip/overlay

3. Необходимый софт установка:
apt update
apt install libftdi1-2 libftdi-dev ftdi-eeprom gcc libftdi1-dev libftdi1 libudev-dev

4. Проверка usb:
lsusb
lsusb -v -d 0403:6011 | grep -i "serial\|product"

Выгрузка модулей если требуется:
rmmod ftdi_sio
rmmod usbserial

5. ДОКИ
/usr/share/doc/ftdi-eeprom/examples/
zcat /usr/share/doc/ftdi-eeprom/example.conf.gz

6. Пример конфигурационный файл для прошивки FT4232 в режиме MODBUS 485:
cat > ft4232h.conf << EOF
# Имя файла, содержащий образ EEPROM, который будет создан
filename=test.bin

# Идентификатор производителя. Для FT4232H значение по умолчанию: 0x0403
vendor_id=0x0403

# Идентификатор продукта. Для FT4232H значение по умолчанию: 0x6011
product_id=0x6011

# Тип EEPROM микросхемы. 0x46 для 93xx46, 0x56 для 93xx56 и 0x66 для 93xx66
#eeprom_type=0x46
eeprom_type=0x56

manufacturer="lablab2"
product="Quad RS485"
serial="1234"

# Разрешить использование серийного номера
use_serial=true

# Ограничение по потреблению микросхемы: (значение параметра) * 2 мА. Значение параметра
# должно быть равно 0, когда self_powered=true
#max_power=0
#max_power=500


# Микросхема питается не от USB, а от собственного источника питания
#self_powered=true
#self_powered=false

# Если на линии RI логический 0 и значение параметра равно true, то хост контроллер USB
# выйдет из режима ожидания примерно через 20 мс.
# remote_wakeup=false
#remote_wakeup=true

# Задать режим работы порта
# # "UART", "FIFO", "OPTO", "CPU", "FT1284"
#cha_type=UART
#chb_type=FIFO
#chc_type=OPTO
#chd_type=CPU

# Использовать драйвер виртуального com-порта
#cha_vcp=true
#chb_vcp=true
#chc_vcp=true
#chd_vcp=true

# Разрешить режим RS-485
#cha_rs485=true
#chb_rs485=true
#chc_rs485=true
#chd_rs485=true

# Channel A
cha_type=UART
cha_vcp=true
cha_rs485=true
#cbush0 = TXDEN

# Channel B
chb_type=UART
chb_vcp=true
chb_rs485=true

# Channel C
#chc_type=UART
chc_vcp=true
chc_rs485=true
#CDBUS7=TXDEN

# Channel D
#chd_type=UART
chd_vcp=true
chd_rs485=true
#DDBUS7=TXDEN

# Управление направлением (TXDEN)
# invert_txd = true
EOF

7. Работа с прошивкой ft4232
Зашить:
ftdi_eeprom --flash-eeprom ft4232h.conf
прочитать:
ftdi_eeprom --read-eeprom ft4232h.conf

Сборка libftdi

Собирем сам соберется, но тут 0.17 :(
cd /opt
git clone https://github.com/lipro/libftdi
cd libftdi
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="/usr" ../
make
make install

Собираем с сайта libftdi

###https://www.intra2net.com/en/developer/libftdi/download.php
###Requirements and dependencies
###libusb 1.0 - Library for talking to USB devices from user-space. Needed by libftdi.
###libconfuse - Library for parsing configuration files. Needed by ftdi_eeprom.
###
wget https://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.5.tar.bz2
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="/usr" ../
make
make install

Питон скрипт для тестов:



Python env:

0. Установите пакеты:
apt update && apt install python3-venv python3-full -y

1. Создайте виртуальное окружение (например, в папке myenv):
python3 -m venv myenv

2. Активируйте его:
source myenv/bin/activate

3. Установите библиотеку:
pip install minimalmodbus


4. Пере использование окружения:
cd /root/myenv
source /root/myenv/bin/activate
Запуск
python read_modbus.py

Python скрипты для тестов:

cat > 1.txt << "EOF"
import minimalmodbus
import serial

# Настройка порта
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', slaveaddress=1)
instrument.serial.baudrate = 9600
instrument.serial.bytesize = 8
instrument.serial.parity = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 1.0

# Самая важная строчка для FTDI под Linux:
# Драйвер очистит входной буфер от эха сразу после отправки запроса
instrument.serial.flushInput()

try:
    # Читаем 1 регистр (holding) с адреса 769 (в mbpoll это -r 769 -t 4)
    # minimalmodbus использует адресацию от 0, поэтому проверяем 769 или 768 в зависимости от карты регистров устройства
    value = instrument.read_register(769, functioncode=3)
    print(f"Значение регистра: {value}")
except Exception as e:
    print(f"Ошибка чтения: {e}")
EOF

python 1.txt

cat > 2.txt << "EOF"
import serial
import time

# Настройки порта
ser = serial.Serial(
    port='/dev/ttyUSB0',
    baudrate=9600,
    bytesize=8,
    parity='N',
    stopbits=1,
    timeout=1.0
)

# Формируем запрос Modbus RTU (тот самый, что слал mbpoll)
# Чтение 1 регистра с адреса 769 (0x0301) для устройства 1
request = b'\x01\x03\x03\x00\x00\x01\x84\x4E'

# Очищаем буферы
ser.reset_input_buffer()
ser.reset_output_buffer()

# Отправляем запрос
ser.write(request)
ser.flush()

# Ждем ответа и вычитываем порцию (запрос занял время, плюс ответ)
time.sleep(0.1)

# Читаем сырые данные
raw_response = ser.read(ser.in_waiting)

print(f"Сырой ответ из порта: {raw_response}")

# Отсекаем эхо, если оно есть (ищем начало нашего ответа с адреса \x01)
# Если устройство вернуло 7 байт, как в ошибке:
if len(raw_response) >= 7:
    # Если в начале висит эхо запроса (8 байт), отрезаем его
    if raw_response.startswith(request):
        response = raw_response[len(request):]
    else:
        response = raw_response

    print(f"Пакет после отсечения эха: {response}")

    if len(response) >= 7:
        # Извлекаем данные из 4-го и 5-го байта (индексы 3 и 4)
        high_byte = response[3]
        low_byte = response[4]
        value = (high_byte << 8) + low_byte
        print(f"🎉 Успешно! Значение регистра: {value}")
else:
    print("Не удалось получить полный ответ от устройства.")

ser.close()
EOF

python 2.txt

cat > rs485.py << "EOF"
import os
import fcntl
import struct
import sys

TIOCGRS485 = 0x542E
TIOCSRS485 = 0x542F
SER_RS485_ENABLED = 0x01
SER_RS485_RX_DURING_TX = 0x08

def set_rs485(port, enable=True):
    fd = os.open(port, os.O_RDWR | os.O_NOCTTY)
    try:
        # Читаем текущие настройки
        buf = fcntl.ioctl(fd, TIOCGRS485, struct.pack('8I', 0,0,0,0,0,0,0,0))
        flags = struct.unpack('8I', buf)[0]
        if enable:
            flags |= SER_RS485_ENABLED
            flags &= ~SER_RS485_RX_DURING_TX
        else:
            flags &= ~SER_RS485_ENABLED
        fcntl.ioctl(fd, TIOCSRS485, struct.pack('8I', flags, 0,0,0,0,0,0,0))
    finally:
        os.close(fd)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python rs485.py /dev/ttyUSB0")
        sys.exit(1)
    set_rs485(sys.argv[1], True)
EOF

python3 rs485.py /dev/ttyUSB0
python3 rs485.py /dev/ttyUSB1
python3 rs485.py /dev/ttyUSB2
python3 rs485.py /dev/ttyUSB3

mbpoll и modpoll:


0. датчик:
holding (output) регистры:
768 температура * 10
796 влажность *10
ID, по умолчанию 1. Как изменить пока не ясно.
13 скорость, по умолчанию 3 - 9600
14 чётность, по умолчанию 0 - NONE
1279 коррекция температуры
1280 коррекция влажности
В некоторых сниферах и OPC серверах надо указывать адрес на 1 больше.

1. Пример команд:
mbpoll -m rtu -a 1 -r 769 -c 1 -t 4 -b 9600 -P none -v /dev/ttyUSB0
modpoll -b 9600 -p none -m rtu -a 1 -r 769 -c 1 -t 4 -1 /dev/ttyUSB1

for i in 0 1 2 3 ; do
modpoll -b 9600 -p none -m rtu -a 1 -r 769 -c 1 -t 4 -1 /dev/ttyUSB$i
sleep 2
done


for port in 0 1 2 3 ; do
    for reg in 768 796 1279 1280 ; do
    modpoll -b 9600 -p none -m rtu -a 1 -r $reg -t 4 -c 1 -1 /dev/ttyUSB$port
    sleep 1
  done
done



screen /dev/ttyUSB0 9600 cs8 -parenb -cstopb
stty -F /dev/ttyUSB0 9600 raw -echo; cat /dev/ttyUSB0
socat -d -d OPEN:/dev/ttyUSB0,b9600,rawer,echo=0 SYSTEM:'tee /tmp/tty.log | socat - "OPEN:/dev/ttyUSB0,b9600,rawer,echo=0"'


2. Тесты:
while true; do echo "x" > /dev/ttyUSB0; sleep 0.1; done

3. Снять блокировку если нужно
rm -f /var/lock/LCK..ttyUSB0