Если вы вдруг оказались на необитаемом острове… или Evolution board с USB

в 17:16, , рубрики: avr, diy или сделай сам, usb, Песочница, метки: , ,

Потребовалось мне как то прошить на необитаемом острове контроллер. Благо был под рукою ноутбук и я подумал, что просто кнопками щелкать — это не метод настоящего джедая. Но это шутка. Девайс можно использовать и для описанных выше целей, но создавался он по другой причине. Иногда в обеденный перерыв очень хотелось что-либо поделать с исследуемыми устройствами (например LCD-дисплеем). Проблема состояла в том, что на компьютер невозможно установить какие-либо драйвера — нужно звать администратора и объяснять цель всех этих установок.

Но USB это не только поточные устройства (так называемые CDC), но еще и HID и Mass Storage. А HID-драйвер установлен уже по умолчанию. Поэтому решено было сделать HID-устройство, с возможностью вывода и ввода через порты контроллера.

Вечер потратил, что бы составить схему.

Развязка именно такая. Пара диодов D1 и D4 понижают напряжение питания примерно 3.8 — 4 вольт. Это предусмотрено для конструкций, имеющих напряжение питания ниже 5ти вольт. Стабилитрончики D2 и D3 занимаются тем же, ограничивая агрессивное напряжение пятивольтовой шины. Больше в конструкции нет ничего интересного, на что следовало бы обратить внимание.

Я делаю это не для продажи, поэтому заморачиваться с травлением плат вообще не стал. Просто купил так называемую растровую плату с дырками и собрал не ней. Снизу сделал гребенку для возможности использования конструкции на breadboard. Их получил, раскурочив панельку для установки микросхемы. Все это заняло еще один вечер. Обратную сторону я прикрыл пластиковым мягким материалом, что бы исключить случайного касания с другими элементами на breadboard.

image Если вы вдруг оказались на необитаемом острове… или Evolution board с USB Если вы вдруг оказались на необитаемом острове… или Evolution board с USB Если вы вдруг оказались на необитаемом острове… или Evolution board с USB

А вот написание кода уже заняло время… Изобретать велосипед я не стал, просто взяв за основу готовый проект реализации v-usb. Но не каждый дескриптор будет работать, как задумывалось и тем более с ходу. Помучав пару программ для автоматического составления дескриптора и не получив нужного результата, пришлось изучать рекомендации форума исполнителей USB.

Через две недели я уже мигал светодиодами на доске и возил все это железо на работу.

А еще через пару дней уперся в неприятный момент: на компьютере не оказалось ни одной среды разработки. Зато имелась установленная Java (JRE). И перерыв в тот день потратил на то, чтобы найти описание как правильно писать нативную dll к Java для управления HID. И тут случайно я нашел один просто обалденный продукт. Точнее статью. Но описание меня очень заинтересовало.

Вечером я уже экспериментировал с Java-классами, пытаясь мигать лампочками. Увы, библиотека позволяла работать только с фьючерами. А просто репорты выбрасывали исключения. Связался с разработчиком. Парень пообещал помочь. Но все те, кто говорит на русском, имеют плохую память. Поэтому подождав пару дней до наступления выходных, переписал firmware микроконтроллера на работу с фьючерами и приступил к конвертации с С++ кода для моего дисплейчика. Конечно, скорость оставляет желать лучшего, но это тоже интересный вариант. Ведь мне нужно только подобрать управляющие коды к дисплею, помигать лампочками, переключить пару релюшек или (если совсем плохо на необитаемом острове) зашить случайно микроконтроллер. Тем более у меня не стоит задача управлять реактором, где за доли секунды можно проморгать цепную реакцию.

И так, что конкретно можно программно менять в контроллере:

  • DS_CMD_PORTC = 0 — чтение/запись порта C;
  • DS_CMD_DDRC = 1 — чтение/запись регистра управления DDRC;
  • DS_CMD_PORTB = 2 — чтение/запись порта B;
  • DS_CMD_DDRB = 3 — чтение/запись регистра DDRB;
  • DS_CMD_UDR = 4 — чтение/запись регистра UDR;
  • DS_CMD_BRRL = 5 — чтение/запись регистра BRRL;
  • DS_CMD_BRRH = 6 — чтение/запись регистра BRRH;
  • DS_CMD_UCSRA = 7 — чтение/запись регистра USCRA;

Есть, правда, еще одна команда, но для единичного устройства она не потребуется.

Ну и далее представлен класс, который должен выполнять работу обмена.

public class DSHIDBr extends HIDCommunication {
    private final Object finalizerGuardian = new Object() {
       protected void finalize() throws Throwable {
           System.out.println("finalize");
           if (isOpened())
               CloseHIDDevice();
       }
    };
  

       public static final String DATE_FORMAT_NOW = "HH:mm:ss.nnn";
       public Calendar cal;
       protected SimpleDateFormat sdf;
       public DSHIDBr(){
           cal = Calendar.getInstance();
           sdf = new SimpleDateFormat("HH:mm:ss.SSS");
       }       

       public final static byte DS_CMD_DEV_VERSION = (byte) 254;

       public final static byte DS_CMD_PORTC = 0;
       public final static byte DS_CMD_DDRC  = 1;
       public final static byte DS_CMD_PORTB = 2;
       public final static byte DS_CMD_DDRB  = 3;
       public final static byte DS_CMD_UDR   = 4;
       public final static byte DS_CMD_BRRL  = 5;
       public final static byte DS_CMD_BRRH  = 6;
       public final static byte DS_CMD_UCSRA = 7;

       public final static byte FOOT28C = 32;
       public final static byte FOOT27C = 16;
       public final static byte FOOT26C = 8;
       public final static byte FOOT25C = 4;
       public final static byte FOOT24C = 2;
       public final static byte FOOT23C = 1;
       

       public final static byte FOOT19B = 32;
       public final static byte FOOT18B = 16;
       public final static byte FOOT17B = 8;
       public final static byte FOOT16B = 4;
       public final static byte FOOT15B = 2;
       public final static byte FOOT14B = 1;       

       public byte SendCommand(byte Command, byte Value) {
            short /*MaxWriteLength,*/ FeatureReportLength;           

            /* Check if HID device opened */
            if (isOpened() == false) {
                return  HID_DEVICE_NOT_OPENED;
            }

            /* Read the Feature Report Length this must be as mentioned in Hid Report descriptor + 1 (Report ID) */
            FeatureReportLength = GetFeatureReportLength();           

            byte[] Outpacket = new byte[FeatureReportLength];
            /* We don't use ReportID set it to '0' */

            Outpacket[0] = 0;              

            /* Load the useful command number */
            Outpacket[1] = Command;
            Outpacket[2] = Value;
            /* Write TX buffer via SetReport(Feature) requst */
            byte Status = SetFeatureReport(Outpacket, FeatureReportLength);
            return Status;
           }    

       public byte readValue;

       public byte ReadCommand(){
            short /*MaxWriteLength,*/ FeatureReportLength;          

            /* Check if HID device opened */
            if (isOpened() == false) {
                return  HID_DEVICE_NOT_OPENED;
            }

            /* Read the Feature Report Length this must be as mentioned in Hid Report descriptor + 1 (Report ID) */

            FeatureReportLength = GetFeatureReportLength();           

            byte[] buffer = new byte[FeatureReportLength];
            buffer[0] = 0;  
            byte Status = GetFeatureReport(buffer);

            if (buffer.length > 0)
                readValue = buffer[1];
            return Status;
       }

       

       public String now() {       
           return sdf.format(cal.getTime());
       } 
}

Основных функций не много. Инизиализация, финализация, посылка байта и прием байта. Есть еще одна, вспомогательная. Возвращающая текущее время с точностью до миллисекунд. Зачем она? Для протоколирования. Самое главное в работе — это логи. А логи без точного времени могут помочь мало.

Ну и для самых терпеливых, кто умудрился добраться до конца, публикую ссылочку на фирмваре. Она, правда, на рапиде. A в добавок сами проектики на Java.

Автор: svd71

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js