Итоги года: Кому-то приходится яростно сводить баланс, кто-то сваливает погреться поюжнее, а коллеги по теме жгут очередную пачку разноцветных светодиодов на платах естественного цвета ёлочки. Идиллия, вроде.

Так получилось, что в моей домашней лаборатории к концу прошлого года померло двое. Ясно. Нужно вскрытие. Точнее, они не совсем померли, а только начали подавать признаки разложения. Но это - моя опора, так что вскрытие не помешает. Хоть это и не сильно сложная задача, но многим интересно, как там устроены внутренности, и что сними ещё можно сделать. Кто не любит вскрытие? - Только те, которых вскрывают. А их кто-то спрашивал? Скальпель, паяльник, спирт, спирт, спирт, огурец, поехали!

Он сопротивлялся

Первый подопытный - это с виду простой китайский труженик, мультиметр UNI-T UT33B+. По отзывам моих заказчиков весьма надёжная серия. В питерском климате переключатель режимов уже почти 2 года чувствует себя превосходно.

Размер - карманный. И ещё автоматику я очень не люблю.
Размер - карманный. И ещё автоматику я очень не люблю.

По эргономике я, правда, понял, что отсутствие кнопки "ВКЛ" мне не удобно. Не спеша присматриваю замену, ибо приятная работа, как оказалось, на первом месте. Но на нулевом месте всё-таки надёжность - предыдущий пациент как-то раз внезапно отказался измерять ~230 V, и следующим пациентом мог стать я сам.

Заболел пациент, можно сказать, по естественной причине - отказался пропускать через себя больше 2 ампер вместо положенных 200 mА. Поломка понятна. Но на вскрытии пациент показал наличие тестовых точек на плате с маркировкой TXD и RXD. Я быстро это соотнёс с опытами товарища @tataranovich, и ссылкой оттуда на не менее знаменитый сайт sigrok. Там заинтересовался новым для меня решением для UART-USB в виде чуть более нового чипа CH9329, которым оказался завален китайско-российский импорт. И меня уже было не остановить.

Маленький оффтоп. Как поймать кота

‒ Как проще всего поймать кота?
‒ Положить на землю картонную коробку, открыть её, сидеть ждать.
‒ А как поймать инженера-электронщика?
‒ Нарисовать контактные площадки, подписать их TX и RX, сидеть ждать.

Всё максимально просто, но держался он неплохо. И сейчас держится.
Всё максимально просто, но держался он неплохо. И сейчас держится.

Надпись TXD меня действительно не обманула. Да и sigrok говорит, что большинство спец.микросхем для мультиметров сами по себе передают измеренные данные по UART. Очень похоже, что все эти чипы сейчас - просто более-менее универсальный микроконтроллер с хорошим АЦП, масочной или одноразовой прошивкой, и часто со встроенной EEPROM для калибровки.

Один из популярных не так давно СнК DTM0660.
Один из популярных не так давно СнК DTM0660.

Я понадеялся, что UNI-T в другую свою продукцию тоже ставит чипы Cyrustek, но тут я ошибся. Просмотрел всё, что у церроз-этого-тека есть, а также выборочно других кандидатов. Нашёл несколько разных протоколов передачи: кто-то передаёт отдельные цифры прямо в ASCII-тексте, кто-то вообще побитно передаёт состояние сегментов ЖК-индикатора. Но точно 10 байт - ни у кого не нашёл. Есть вероятность, что просто прошивка написана специально для UNI-T.

Ну да ладно, протокол на ноге TXD оказался в итоге максимально простым, и даже выудить оттуда получилось почти всё. А при засылании в RXD долгого BREAK мультиметр перезагружался. Может быть тоже полезно. Но вот засылать что-нибудь осмысленное в RXD я не стал - калибровку можно убить, а переключать режимы я всё равно удалённо не смогу. Пришлось пока отказаться от этой затеи.

Период измерений где-то 0,5 секунды
Период измерений где-то 0,5 секунды
Скорость 2400 бит/с 8N1. С паузами, иногда приличными.
Скорость 2400 бит/с 8N1. С паузами, иногда приличными.

В общем, я не буду супер-новатором в соединении мультиметра с компом через USB-UART. Однако расскажу о паре важных моментов, которые приходится учитывать. Во-первых, конечно, гальваническая развязка. Велосипедов нам лишних изобретать не надо, и рекомендованная схема с развязкой есть во всех описаниях чи��ов, что я прочитал.

Рекомендованный одним из производителей принцип развязки. Не пытайтесь повторить это дома.
Рекомендованный одним из производителей принцип развязки. Не пытайтесь повторить это дома.

"Общий" (COM) контакт мультиметра - это не VDD или GND микросхемы, а классическая виртуальная средняя точка. Можете заглянуть в описания по ссылкам. У кого-то это половина питания, у кого-то опорное напряжение. В общем, то, что удобно конкретно этой (ещё понятно, какой!) SoC для измерения биполярного сигнала. И это точно не земля UART. Так что без развязки даже измерить напряжение на какой-нибудь отладочной плате, питаемой от USB - уже не получится.

Не получится без костылей. Мультиметром, оказывается, можно точно измерить напряжение собственной батарейки. Но я не скажу, как - догадайтесь сами, пишите в комментах. Моё решение: батарейный отсек вскрывать нужно, но корпус мультиметра - нет.

Второй ахтунг разработчика я только предполагал, но по расчётам в итоге он не внёс существенного ухудшения в работу мультиметра. Суть в том, что прибор пока всё-таки питается от батареек, а их менять чаще, чем в оригинале, мне бы не хотелось. Хитрое включение, которое я приводил в предыдущей статье, бережёт энергию приёмника, а не передатчика. Я боялся, что опторазвязка по стандартной схеме сожрёт немало энергии. Но холодный рас��ёт сказал, что передачи редкие, 2 раза в секунду, и беспокоиться не стоит. В итоге даже по измеренным данным к обычному потреблению тока в 1,4 mA добавилось не больше 0,1 mA.

Незатейливо. Без плодово-ягодных плат и ардуинов.
Незатейливо. Без плодово-ягодных плат и ардуинов.

Третий момент связан с ограничением допустимой скорости нарастания синфазного напряжения у оптронов (dV/dt в описаниях оптронов, если оно вообще указано). В момент подключения щупов к сети, например, иногда действительно приходит битый пакет. Я даже специально это подловил - под следующим спойлером. На то и контрольная сумма. А для измерений в "летающих" цепях вся эта масса прибора с проводами сама внесёт немалую ёмкость с схему. Только синфазный фильтр, только хардкор.

Оптрон залит клеевым пистолетом во избежании пробоя на плату. Обломок отладочной платы с CH9329 прихвачен мелким винтом к корпусу
Оптрон залит клеевым пистолетом во избежании пробоя на плату. Обломок отладочной платы с CH9329 прихвачен мелким винтом к корпусу
Предварительный тест на пробой и финальная компоновка. Клея и изоляции не жалеем, да
Предварительный тест на пробой и финальная компоновка. Клея и изоляции не жалеем, да

Отдельная история произошла с разъёмами Type-C, которые я пытался встроить в корпус мультиметра. Ни разу они не маленькие, я вам скажу. А ведь ещё зазор между разъёмом и оригинальными потрохами прибора хотелось бы иметь. Чтобы оно меня потом внезапно не шарахнуло. Я просмотрел много вариантов, и часть из них заказал на пробу. Попадаются разные решения, в том числе без резисторов на контактах CC1 и CC2 - а значит могут не работать с хостом Type-C. Самый мелкий (третий слева на картинке) подошёл по размерам, но из партии 10 шт. по крайней мере 8 шт. оказались бракованными - их забыли пропаять. И я это выяснил, когда после монтажа залил всё клеевым пистолетом. Словарь литературного русского языка пришлось оставить на какое-то время в стороне.

В общем, не мытьём, так катанием получилось собрать связку мультиметр-развязка-UART-USB. Нужный режим микросхемы CH9329 получилось зашить через USB с помощью информации и софта, любезно слитого вот сюда (сработало через VirtualBox+Win7). Вроде ещё есть прошивальщик, работающий через зад, то есть со стороны UART. Выставил скорость 2400 bps, признак окончания пакета 100 ms. А также произвольный код PID и VID (из списка типа устаревших), чтобы потом USB-устройство найти программно.

Засекаю в списке новое устройство, и запускаю заветный sudo cat /dev/hidraw1 . При чтении устройство возвращает пакет, фактически HID-дескриптор. У микросхемы CH9329 он 64-байтный, начинается с указания длины полезных данных (10). Содержит нужные мне 10 байт сообщения от мультиметра, а остальное - мусор из буфера. Запись в порт я тоже проверил - работает.

Значит, пора включить доступ к VID/PID в /etc/udev/rules.d/ , и писать код.

Для начала - поиск нужного устройства.
#!/usr/bin/python3

import os

class ch9329:
    '''
Работа с функцией USB-UART микросхемы CH9329 в Linux
    '''
    
    default_vid = 0x1A86
    default_pid = 0xE429
    
    @classmethod
    def find( cls, vid=None, pid=None, single=True ):
        '''
Ищет похожее USB-устройство по идентификатору.
Возвращает его имя для open(), или список имён при single=False
        '''

        if vid is None:
            vid=cls.default_vid
        if pid is None:
            pid=cls.default_pid
        searchstr = 'v{0:08X}p{1:08X}'.format( vid, pid )
        #print(searchstr)
        prefix='/sys/class/hidraw'
        suffix='device/modalias'
        devlist = []
        for hidraw in os.listdir(prefix):
            #print(hidraw)
            with open( prefix + '/' + hidraw + '/' + suffix, 'rt' ) as modalias:
                devlisttr = modalias.readline()
                #print(devlisttr)
                if devlisttr.find( searchstr ) >= 0:
                    devlist.append( '/dev/' + hidraw )
        #print( devlist )
        if single:
            if len(devlist)==0:
                return None
            if len(devlist)==1:
                return devlist[0]
            raise OverflowError('Много штук {0:04X}:{1:04X} !!!'.format(vid,pid))
        else:
            return devlist
            
    def __init__( self, name=None, vid=None, pid=None ):
        self.name=name
        self.vid=vid
        self.pid=pid
        self.dev=None
    
    def __enter__( self ):
        if self.name is None:
            self.name = ch9329.find( vid=self.vid, pid=self.pid, single=True )
        if self.name is None:
            raise FileNotFoundError('Нет устройства /dev/hidrawX')
        #print('Opening',self.name)
        self.dev=open( self.name, 'rb+' )
        return self
        
    def close( self ):
        #print('Closing')
        self.dev.close()
            
    def __exit__( self, exc_type, exc_value, traceback ):
        self.close()
        self.dev=None
        return False

    @classmethod
    def open( cls, name=None, vid=None, pid=None ):
        me = ch9329( name, vid, pid )
        me.__enter__()
        return me
        
    def read( self ):
        '''
Читает посылку до 63 байт.
        '''
        raw = self.dev.read(64)
        if len(raw)==64:
            pktsize=raw[0]
            #print('Read',pktsize,'bytes')
            if pktsize>=0 and pktsize<=63:
                return raw[1:1+pktsize]
        raise IOError('Получен непонятный пакет')
        
    def write( self, bts: bytes ):
        '''
Отправляет байты bts.
Если размер bts больше 63 байт, разбивает посылку на несколько
        '''
        written=0
        todo=len(bts)
        raw = bytearray(64)
        while todo>0:
            pktsize=min(todo,63)
            raw[0]=pktsize
            raw[1:1+pktsize]=bts[written:written+pktsize]
            todo=todo-pktsize
            #print('Write next',pktsize,'bytes,',todo,'remains')
            if self.dev.write(raw)!=64:
                raise IOError('Пакет не передан')
                #break
            written=written+pktsize
        #print('Write total',written,'bytes')
        return written


if __name__=='__main__':
    print( 'default:', ch9329.find() )
    print( '  ut33b:', ch9329.find( 0x0CC1, 0x2511 ) )
    print( '  mouse:', ch9329.find( 0x09da, 0x8736 ) )
    print( '    hub:', ch9329.find( 0x1d6b, 0x0003 ) )
    
    with ch9329() as dev:
        #dev.write( bytes(range(91)) )
        dev.write( bytes(b'1145\n') )
        print( dev.read() )
        #print( dev.read() )
А потом и декодирование сообщений с мультиметра.
#!/usr/bin/python3

from ch9329 import ch9329
from math import inf

class ut33( ch9329 ):

    max_value = 8971
    max_disp = 1999

    modes = [
        [ 0x0116, '=200mV',  1, 'mV=',  4, 'V'],
        [ 0x0114, '=2000mV', 0, 'mV=',  3, 'V'],
        [ 0x0115, '=20V',    2, 'V=',   2, 'V'],
        [ 0x0111, '=200V',   1, 'V=',   1, 'V'],
        [ 0x0113, '=600V',   0, 'V=',   0, 'V'],
        [ 0x0112, '~600V',   0, 'V~',   0, 'V'],
        [ 0x011a, '~200V',   1, 'V~',   1, 'V'],
        [ 0x011b, '=1.5V',   3, 'V=',   3, 'V'],
        [ 0x0119, '=9V',     2, 'V=',   2, 'V'],
        [ 0x0117, '=12V',    2, 'V=',   3, 'V'],
        [ 0x011c, '=10A',    2, 'A=',   2, 'A'],
        [ 0x011e, '=200mA',  1, 'mA=',  4, 'A'],
        [ 0x011f, '=200μA',  1, 'μA=',  7, 'A'],
        [ 0x011d, 'diode',   3, 'V=',   3, 'V'],
        [ 0x010d, '200Ω',    1, 'Ω',    1, 'Ω'],
        [ 0x010f, '2kΩ',     0, 'Ω',    0, 'Ω'],
        [ 0x010e, '20kΩ',    2, 'kΩ',  -1, 'Ω'],
        [ 0x010b, '200kΩ',   1, 'kΩ',  -2, 'Ω'],
        [ 0x0107, '20MΩ',    2, 'MΩ',  -4, 'Ω'],
    ]

    def __init__( self, name=None, vid=0x0CC1, pid=0x2511 ):
        super().__init__( name, vid, pid )

    def read( self, debug=False ):
        '''
Читает данные из мультиметра UT33B+.
В режиме debug=True возвращает аннотацию каждого принятого пакета данных.
В режиме debug=False ждёт и возвращает прочитанное значение и единицу измерения.
        '''
        while True:
            pkt = super().read()
            if len(pkt)==10:
            
                #print(pkt.hex(' '))
                
                # Формат: ab cd MM MM NN NN NN NN SS SS
                # ab cd - постоянная сигнатура
                # MM MM - режим работы
                # NN NN NN NN - показания АЦП (со знаком в доп.коде)
                # SS SS - контрольная сумма 6 байт MM и NN
                # все числа начинаются со старшего байта
                
                sig = int.from_bytes( pkt[0:2], byteorder='big', signed=False)
                mode = int.from_bytes( pkt[2:4], byteorder='big', signed=False)
                adc = int.from_bytes( pkt[4:8], byteorder='big', signed=True)
                check = int.from_bytes( pkt[8:10], byteorder='big', signed=False)
                #print( 'sig={0} check={3} mode={1:04x} adc={2:d}'.format( sig==0xabcd, mode, adc, check==sum(pkt[2:8]) ) )

                if sig==0xabcd and check==sum(pkt[2:8]):
                    strout = 'Неизвестный режим: {0:04x} adc={1:d} '.format(mode, adc)
                    for sw in self.modes:
                        if sw[0]==mode:
                            fmt = '{0:.' + '{0:d}'.format(sw[2]) + 'f} {1}'
                            #print(fmt)
                            val = adc/pow(10,sw[4])
                            if abs(adc)>self.max_value:
                                fmt = fmt + ' (совсем переполнение)'
                                if adc>0:
                                    val = inf
                                else:
                                    val = -inf
                            elif abs(adc)>self.max_disp:
                                fmt = fmt + ' (переполнение)'
                            strout = fmt.format( adc/pow(10,sw[2]), sw[3] )
                            #print(strout)
                            if not debug:
                                return ( val, sw[5] )
                else:
                    strout = 'Неверные значения: sig={0:04x} check={3} mode={1:04x} adc={2:d}'.format(sig, mode, adc, check)
            else:
                strout = 'Неправильный пакет: ' + pkt.hex(' ')
            if debug:
                return strout


if __name__=='__main__':
    with ut33() as dev:
        print('Девайс',dev.name,'открыт')
        while True:
            print( dev.read() )
            #print( dev.read( True ) )
            

В выводе как раз приведу редкий случай влияния dV/dt - битого пакета при тыкании щупами, куда попало.

1 V~
1 V~
41 V~
197 V~
227 V~
226 V~
Неверные значения: sig=abcd check=245 mode=01e2 adc=226
71 V~
215 V~
227 V~
227 V~
227 V~
227 V~

Почему в коде два лимита показаний мультиметра? По ходу тестирования всего этого хозяйства выяснилось: у АЦП микросхемы мультиметра вовсе не 2000 дискретных уровней каждой полярности, а целых 8972. Хоть сам прибор на штатном дисплее и показывает перегрузку выше цифры 1999, но по крайней мере ещё 5000 дополнительных отсчётов сверху и снизу, получаемых через UART, похожи на линейный диапазон. Пока только грубо проверял, сравнивая с показаниями лабораторного БП. Наверное, можно придумать более точные способы измерить линейность, и в ближайшее время я попробую.

Почему производителем установлен такой лимит? Не могу сказать, но могу предположить. Например, у подопытного специфицируется погрешность не лучше 0,5%. На дисплей-то влезают показания до -9999, но столько цифр не имеют смысла. Хотя относительные измерения, где роль играет именно разрешение, тоже бывают нужны. И мультиметры на 6000 дискретов с такой же погрешностью - не редкость. В общем, пока не идентифицирован чип внутри, это загадка.

Готов к трудной работе
Готов к трудной работе

После проверки работы при питании от 2,2 до 3,4 В, и теста изоляции прибор в строю. В начале года мне уже попалась работа, где я задействовал автоматизированный сбор данных с этого мультиметра. На очереди был бы ещё один апгрейд схемы - счастливое избавление от батарейки при USB-подключении. Но это уже не так просто. И, похоже, я дозрел до покупки готового решения с большей точностью.

Он меня игнорил

Товарищ осциллограф Hantek DSO4104C. Рабочая лошадка, а точнее, рабочий ослик. До сих пор, правда, не привык к сокращению "ослик". Вот "осцилл" - да, вполне. Ну да ладно, живой язык - это по-любому лучше, чем мёртвый.

Портрет на рабочем месте. Съёмка немного постановочная, но совсем чуть-чуть
Портрет на рабочем месте. Съёмка немного постановочная, но совсем чуть-чуть
Говорят, проще собрать комп внутри осциллографа, чем осцилл подключить к компу.
Говорят, проще собрать комп внутри осциллографа, чем осцилл подключить к компу.

Анамнез: тело работает, но по USB перестало подключаться к ПК.

Во имя славы китайских богов (тут должна быть ещё картинка, но я и так перегрузил статью картинками) китайские товарищи много чего предусмотрели. В качестве защиты от непотребств извне товарищи не мелочились на какие-то там защитные диоды, супрессоры то бишь. А просто поставили USB-хаб на отдельной плате. Соединяется это всё с основной платой кабелем SATA - вот это неплохое решение. А супрессоры - это ж прошлый век!

Фотографировал уже после того, как попытался восстановить.
Фотографировал уже после того, как попытался восстановить.

Может эта защита наконец сработала, а может ещё что-то случилось. Свежепочиненный напряжёметр, например, показал на выходе регулятора 3,8 В вместо 3,3 В. Короче, плата эта сдохла полностью.

Проц внутри - S3C2416. Вот так он подключён к внешним цифровым интерфейсам.
Проц внутри - S3C2416. Вот так он подключён к внешним цифровым интерфейсам.

Ясен палец, в первом приближении я убрал хаб, и на свой страх и риск просто замкнул USB между разъёмом и процессором. Ну, как обычно, соплёй закорачивают предохранители. Только это чуть более высокотехнологичная сопля. И да, оно заработало. Но с особенностями.

Ещё раз воспою славу китайским богам (про картинку я уже писал, не буду повторять) - этот прибор, в отличии от многих других проприетарных поделий поддерживает общепринятый протокол управления SCPI. Через транспорт USB TMC, который аж в далёком 2003 году стандартизировали. Для тех, кто не в курсе - это как флешка и мышка, не надо никаких "спец. драйверов", чтобы ОСь увидела устройство. Управлять прибором можно как угодно, хоть через echo && cat в терминале, команды для любого осцилла будут примерно одинаковыми, а особенности документированы.

И вот, ОСь таки его увидела. Отпрыска она назвала уникальным именем /dev/usbtmc0, и в общем ничего не предвещало беды. Я запустил скрипты, которыми с этого-же осцилла снимал данные раньше, и... Нет. (тут должен быть запрещённый площадкой непереводимый русский фолклор). Не совсем.

Код максимально тупой благодаря USB TMC
#!/usr/bin/python3

class usbtmc:

	def __init__(self, name: str):
		self.dev = open( name, 'r+b', buffering=0 )
		
	def __del__(self):
		try:
			self.dev.close()
		except:
			pass
		
	def send(self, cmd: str):
		print('>',cmd)
		self.dev.write(bytes(cmd,'ascii'))
		
	def recv(self, cmd: str) -> bytes:
		print('>',cmd+'?')
		self.dev.write(bytes(cmd+'?','ascii'))
		ans = self.dev.read(200)
		bens = ans.decode( encoding='ascii', errors='replace' )
		print('<',bens)
		return bens
		
try:
	osc = usbtmc('/dev/usbtmc0')
except:
	osc = usbtmc('/dev/usbtmc1')

Первый - это логика подключения и общения с прибором. Второй - установка режима всех каналов. Есть ещё захват данных и загрузка паттерна в генератор. Но выглядят они уж сильно костыльно, и я их пока стесняюсь показывать. Хотя работают.

#!/usr/bin/python3

from usbtmc import *

vertical = 1.0
horizontal = 1e-3

osc.recv('*IDN') # Вот он где, источник проблем
osc.send('*RST')
osc.recv('*OPC')

for c in range(1,3):
	prefix = ':CHANNEL{}'.format(c)
	osc.send(prefix+':DISP ON')
	osc.send(prefix+':BWL ON')
	osc.send(prefix+':COUP DC')
	osc.send(prefix+':PROB 10')
	osc.send(prefix+':SCAL {}'.format(vertical))
	osc.recv('*OPC')
	
osc.send(':CHANNEL3:OFFSET -3.5')
osc.send(':CHANNEL4:PROB 100')
osc.recv('*OPC')

osc.send(':ACQ:TYPE HRES')
osc.send(':TIM:SCAL {}'.format(horizontal))
osc.send(':TRIG:MODE EDGE')
osc.send(':TRIG:EDGE:SOURCE CHANNEL1')
osc.send(':TRIG:EDGE:LEVEL {}'.format(vertical))
osc.recv('*OPC')

Для тех, кто не в курсе: SCPI - это текстовый протокол управления измерительными приборами, грубо говоря аналогичен HTTP. Из тех же 1980х годов. Просто вместо GET /trig/mode?=xyz там передают :TRIG:MODE xyz . Логика примерно та же. Работает поверх чего угодно - TCP, USB, RS232, ну, и через свой собственный, но уже сильно устаревший интерфейс GPIB.

SCPI-команды прибор воспринимает, да. Устанавливает режимы, захватывает сигнал, передаёт его мне, всё как надо. Но не реагирует на единственную команду - идентификация *IDN. По стандарту прибор должен отвечать на неё своими именем, фамилией и серийным номером. Но он молчит. Самое странное, что (чисто случайно) поставив между ПК и осциллографом внешний USB-хаб я таки увидел ответ. С хабом - работает, без хаба - нет.

Так вот зачем внутри осцилла нужен был USB-хаб! Кстати, действительно, а зачем? Этот момент я до конца не понял. Возможно, дело в задержке между USB-запросом и ответом, которую хаб проглатывает, а ПК - нет. Проверить у меня тогда не получилось, поскольку сам осцилл в отключке на операционном столе, а его переносной земляк и собрат от FNIRSI не так быстр для USB 2.0.

Я уж было понадеялся просто поставить обычную защиту на USB, и закрыть эту тему. Лёгкого пути не предвиделось, и я решил: Раз уж всё менять, так не поставить ли мне сразу вместе с хабом и гальваническую развязку? Дополнительные возможности, защита, и места внутри прибора столько, что ещё один такой же влезет. А что? Да начнётся настоящий танец с граблями!

Не моя фотка, но похож, как две капли.
Не моя фотка, но похож, как две капли.

Для начала я взял обычный аудиофильский USB-изолятор на основе старого доброго ADUM3160. В моём случае он не отменяет наличие хаба, но какой-то простой хаб откопать в запасниках было не сложно, да и надо с чего-то начинать. Это - цифровой изолятор, заточенный под сигналы USB 1.1 LS и FS, конкретный режим выбирается джампером. А вы чего хотели?

Для начала собрал цепочку ПК-хаб-изолятор-осцилл. Хаб и осцилл в этой цепочке стандартно начинают работать в режиме USB 1.1, и рапортуют ОСи, что они оба вообще-то 2.0. ОСь переключает их из 1.1 в 2.0, но не тут то было - изолятор не пропускает траффик 2.0 480 Мбит/с. ОСь трижды ругается в логах, что, дескать, кабель у вас - ну, не очень, но в конце догадывается оставить осцилл в режиме 1.1.

И тут в софте у осцилла обнаруживается ещё один косячок - в режиме 1.1 он рапортует ОСи, что умеет слать длинные USB-пакеты по 512 байт. Что разрешено для 2.0, но запрещено в 1.1. ОСь и хаб понимают, что эта лажа совсем не по фен-шуям, но даже как-то работают.

Переставил хаб, и цепочка стала ПК-изолятор-хаб-осцилл. Тут уже хаб возмутился: Не могу, говорит, я оставить соединение сверху 1.1, а снизу включить 2.0. Какая боль! Может быть есть другие хабы и драйвера, которые так могут, но моя связка не заработала совсем. Ясно. Нахожу изолятор 2.0 на ADUM3166. Вдруг нахожу ещё более крутую штуку на основе CH318 сразу вместе со всем фаршем!

Вот так, дёшево и сердито.
Вот так, дёшево и сердито.

Товарищи из WCH пока не умеют делать цифровые изоляторы в больших количествах. Но поняли, что это не единственный способ развязки. Для изоляции можно поставить и обычные сигнальные трансформаторы. А если перекодировать данные, и сразу обвешать всё это хабами, разрешив задержку - то трансформатора достаточно одного!

Возможностей много, а изолятор - один
Возможностей много, а изолятор - один

Дождался я заказа, запихал это всё в осциллограф, дополнительно заизолировал разъём от корпуса знаменитой синей изолентой. Проверил изоляцию тем же методом, что и у мультиметра. И в таком виде оно всё заработало без вопросов.

Крепёж готов. А что ещё надо для счастья?
Крепёж готов. А что ещё надо для счастья?
Изоляция, изоляция, и ещё раз изоляция. В том числе по радио.
Изоляция, изоляция, и ещё раз изоляция. В том числе по радио.
Внутри корпуса железный экран. Да и без синей изоленты работать не будет.
Внутри корпуса железный экран. Да и без синей изоленты работать не будет.

А, самое-то главное: я ж ещё в мультиметре убавил звук перепайкой резистора. А в осциллографе - забыл. Этот осцилл при получении команды *RST сбрасывает настройки, и при этом вспоминает про подзвучку кнопок, чтоб его. Напрашивается на повторное вскрытие.

Эпилог

Если копнуть поглубже, можно найти как мусор, так и сокровища. В общем, изучаю возможности, нахожу как откровенно плохие, так и очень интересные решения, пробую делать лучше.

Статья получилось на мой взгляд длинноватой. Может, отзывов комментариях посоветуйте, имеет ли смысл убрать что-то, хотя-бы под спойлер, или (не дай Бог!) добавить.