Dionisnation

Dionisnation

TRON: TQ7wgZtMxDnMMUMgdCBwcjwgg9qypRNGET
Пикабушник
поставил 4248 плюсов и 1865 минусов
отредактировал 10 постов
проголосовал за 18 редактирований
Награды:
10 лет на Пикабу За победу в продуктовом сёрфинге За победу над кибермошенниками За подвиги в Мире PlayStation 5более 1000 подписчиков
102К рейтинг 2486 подписчиков 142 подписки 746 постов 207 в горячем

Новая жизнь CD дисковода

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ…

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Статья не моя. Но будет полезная моим подписчикам которые подписались ради DIY. Взята из сообщества Easyelectronics (Не рекламирую, просто указываю чтобы опять тапками не бросались)

Далее от Автора :
Прочитав пару статей других пользователей, захотелось самому начеркать чего-то полезного для остальных. Как все поняли из названия, речь пойдет о создании USB mass storage device класса на програмной реализации V-USB.

Знакомство мое с данной библиотекой произошло случайно и оч. давно. Как и большинство(наверное) на то время любителей я все работал на микрухах типа pl2303 и FT245(232), а они, как известно, не позволяют изменять класс устройства (тока то, что зашито на заводе и все). Купить контроллер с аппаратной частью USB возможности не было, вот, как говорится, и понеслось!) Бодяжил много чего полезного и бесполезного, но как говориться тока для себя зануды любимого. Как-то читал на одном известном форуме, что реализовать то или иное устройство на данной «псевдо» USB нереально, а передавать большие объемы данных и подавно. Так и задался целью замутить чегонить вроде USB флешки или микрофона. И то и другое сделал, но из-за того что я тяжелый на подъем, в массы так и не выкладывал. Вот и моя первая проба познакомить уважаемое сообщество со своим проектом.


Сразу оговорюсь, что все приведенные фотки моего девайса тока для ознакомления, потому как это платка мой программатор AVR по USB со своим бутом и прогой для апдейту. Схему я конечно выложу, но плату разводить, наверное, специально для этого проекта, не буду.

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Проект выполнен на IAR’е, sPlan, SprintLayout, Device Monitoring Studio и утюге под пиво =) Ну, в путь!


Для начала, немного теории. MSD или Mass Storage Class это ничто иное, как один из стандартных классов USB для описания и взаимодействия с утройствами хранения информации. Реализаций и стандартов MSD довольно много и заморачиваться на каждом из них нет смысла. Опишу самый распространенный из них(он же самый простой на мой взгляд): Bulk-only или BBB.


В стандарте USB есть такое понятие, как конечная точка(end-point). Конечная точка — это часть USB-устройства, которая имеет уникальный идентификатор и является получателем или отправителем информации, передаваемой по шине USB. Проще говоря, это буфер, сохраняющий несколько байт. Обычно это блок данных в памяти или регистр микроконтроллера. Данные, хранящиеся в конечной точке, могут быть либо принятыми данными, либо данными, ожидающими передачу. Хост также имеет буфер для приема и передачи данных, но хост не имеет конечных точек.


Конечная точка имеет следующие основные параметры:

1 - Частота доступа к шине

2 - Допустимая величина задержки обслуживания

3 - Требуемая ширина полосы пропускания канала

4 - Номер конечной точки

5 - Способ обработки ошибок

6 - Максимальный размер пакета, который конечная точка может принимать или отправлять;

7 - Используемый конечной точкой тип посылок

8 - Направление передачи данных

Любое USB-устройство имеет конечную точку с нулевым номером (Endpoint Zero). Эта точка позволяет хосту опрашивать устройство с целью определения его типа и параметров, выполнять инициализацию и конфигурирование устройства.


Кроме нулевой точки, устройства, обычно, имеют дополнительные конечные точки, которые используются для обмена данными с хостом. Дополнительные точки могут работать либо только на прием данных от хоста (входные точки, IN), либо только на передачу данных хосту (выходные точки, OUT). Число дополнительных конечных точек устройств определяется режимом передачи.


Для низкоскоростных устройств допускается наличие одной или двух дополнительных конечных точек, а для высокоскоростных — до 15 входных и 15 выходных дополнительных точек.


Но это тока теория, которая выглядит довольно абстрактно. Будем считать, что конечная точка, это ничто иное как фунция в языке C, которая тока принимает параметры, или только возвращает значения.


Так вот, мы строим устьройство, отвечающее спецификации bulk-only. И тут самое приятное: все события делятся на три фазы:

1 - Прием команды от хоста(копьютера)(CBW)

2 - Прием/Передача запрашиваемых данных(DATA)

3 - Передача хосту результата выполнения принятой комманды(STATUS)

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Здесь видно, что мы принимаем данные и отправляем данные, значит мы имеем 2 конечные точки (от хоста к устройству и наоборот), а, исходя из выбранной спецификации, эти точки используют bulk передачу данных.


Следовательно мы должны сконфигурировать библиотеку V-USB соответсвующим образом:

1 - Описываем конечную точку-in

2 - Конечную точку-out

3 - Указываем v-USB, что мы используем 2 конечные точки помимо основной (control-endpoint)

4 - Задаем класс устройсва USB — Mass Storage Class Bulk-only (Не пугайтесь, все это легко видно из файлов прошивки).

На этом весь процесс создания устройства MSD bulk-only закончен и мы приступаем к тому, что принимаем от хоста комманды и соответсвенно реагируем на них!


Теперь вкратце о тех самых коммандах от хоста. Их не так много и большинство из низ поступают только пару раз. Итак хост может попросить от нас следующее:

   ► Inquiry — запрос основных характеристик устройства

   ► Test unit ready — проверка готовности устройства, в т.ч. наличия диска в дисководе.

   ► Request sense — возвращает код ошибки предыдущей команды.

   ► Read capacity — возвращает ёмкость устройства.

   ► Read (4 варианта) — чтение.

   ► Write (4 варианта) — запись.

   ► Mode select — установка параметров устройства.

   ► Mode sense — возвращает текущие параметры устройства

Теперь далее. Пересмотрев массу устройств хранения информации (EEPROM, nand и т.д.) я выбрал, наверное, самое распространненое SD/MMC карту памяти. Подключение ее к AVRке давно известно, а протокол хорошо разжеван. Еще один плюс в том, что эти карты могут читать/писать по 512 байт данных, что очень подходит для данной задачи.


Так, основными коммандами MSD bulk-only устройстве являются чтение и запись блоков информации. Драйвер Windows (да простят меня пользователи Linux) обращается к нашему устройству по принципу LBA, то есть адрес логического блока (или его номер, что одно и тоже) и их количество.


В нашем случае один логический блок это сектор размером в 512 байт. Так если ОС запросит у нас данные из 20-го LBA, то мы просто умножим 20 на 512 и получим линейный адрес на устройстве носителя. Затем прочитем/запишем нужное число блоков и все! Знать что-то о данных на устройстве хранения информации и способе их размещения AVR не должна. Наша задача обеспечить возможность чтения и записи этих самых блоков из/на устроство хранения информации, а остальное сделает ОС.)


Теперь я представлю Вам мою схемку. Сразу оговорюсь, делал на быструю руку, так как печатку делал из головы (схема не сложная):

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Многие заметят, что практически стандартная схема для устройств на V-USB, и что я немного перемудрил с ней, на я повторюсь, что собрал флешку из моего программатора, поэтому здесь немного изврата присутствует. Перемычка JP2 предназначена для прошивки нашего устройства и должна быть установлена только во время обновления прошивки устройства(разъем Х2). Диоды D1 и D2 предназначены для задания рабочего напряжения питания ~3.6V. Можно обойтись и одним(проверено неоднократно), хотя при грамотном подходе лучше сделать не так как я=)


Ну а теперь немного по коду программы. Сначала опишем конфигурацию аппаратной части нашего устройства в файле «usbconfig.h»:

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Здесь мы указали, что порт, к которому подключены дифференциальные сигналы D+ и D-, это порт PORTD, а выводы, к которым они подключены, соответсвенно 3 и 2. Частота кварцевого резонатора равна 16 Мгц. Затем мы описали, что мы сами управляем процессом подключения нашего устройства к шине USB. Для этого мы сделали следующее:

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Это видно из схемы: резистор R7, подключенный к выводу 1 порта PORTD. Далее в программе нам это понадобиться для того, чтобы произвести подключение к хосту в момент времени, который нам более всего подходит. (напомню, что Хост определяет наличие подключения устройства к шине в случае подтягивания линии D- к Vdd. Это я для низкоскоростных устройств).


В рекомендации от V-USB сказано, что линия D+ должна быть подключена к INT0, но я внес некоторые изменения и подключил ее к INT1, что в принципе не запрещено (подключают к IN0 т.к. прерывание INT0 имеет наивысший приоритет в системе прерываний AVR. прим. DH), поэтому я указываю на соответствующие изменения в следующих строках:

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

В принципе, в описании аппаратной части USB это все.


В этом же файле мы указываем, что класс и подкласс устройства определяется классом и подклассом интерфейса (это я про то, что мы используем стандартный интерфейс MSD bulk-only). Это делается следующим образом:

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост
Так же мы помним, что мы имеем 2 конечные точки (т.к. мы принимаем и отправляем данные от хоста), значит мы указываем на это библиотеке V-USB:
USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост
Теперь пару слов о следующих определениях:
USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Поскольку мы использовали стандартный класс USB MSD, то и описать устройство это класса обязаны мы. Позже я вернусь к этим строкам, а пока мы оставим их в покое.


В принципе в этом файле вроде как и все, но я оговорюсь для наиболее дотошных (как я=): я не пират и не пытался нарушить чьета права? использовав VID/PID, которые в моем файле usbconfig.h. Мало того, я даже не знаю чье они, просто первые попавшиеся под руку==)


Пожалуй, распишу немного процесс инициализации устройства на V-USB.


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


usbDeviceConnect();

при вызове которого происходит подтяжка линии D- к напряжению питания устройства. Хост определяет это событие и начинает процедуру конфигурации устройства USB: Сброс девайса, присвоение адреса и т.д.


Во всей этой рутинной суете главное для нас это этап запроса дескриптора устройства, который в свою очередь содержит поддерживаемую версию USB, максимальный размер пакета для control конечной точки, идентификаторы устройства и производителя VID/PID, версию устройсва, строковые номера индексов(если таковые присутсвуют) и количество конфигураций нас родимых.


Поскольку мы проектируем свое собственное ни на что не похожее устройства, то давайте опишем этот дескриптор (Здесь и далее я рассматриваю файлы «MassStorage.h» и «MassStorage.cpp»)

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост
Помните, выше мы описали #define USB_CFG_DESCR_PROPS_DEVICE. Так вот, определив это, мы сообщили библиотеке V-USB, что используется пользовательский «описатель устройства», и при запросе хостом данной информации V-USB передаст то, что мы с вами только что описали. Мы видим, что я описал в usbDescriptorDevice количество конфигураций устройтва равным 1. Что это значит? Это значит что наше устройство может работать только в одном режиме, который мы определим чуть ниже. Так вот наш режим(или конфигурация, если правильнее):
USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост
USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Хочу отметить, что в дескрипторе кофигурации мы встраиваем дескриптор интерфейса и дескрипторы конечных точек. Этот (или эти, если хотите) дескриптор передается V-USB благодаря ранее описанному определению


#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_LENGTH(32)

В этом же десрипторе (usbDescriptorConfiguration) мы указали, пожалуй, самую важную информацию для нашего устройства, а именно:


   ► устройство класса MSD

   ► тип передачи — bulk-only

   ► размеры конецчных точек и их направление


После того, как хост получил дескрипторы устройства, конфигурации, интерфейса и конечных точек, он (хост) начинает «общаться» с нашим устройством как MSD bulk-only. Поскольку мы работаем со стандартным интерфейсом MSD, то никакие control передачи для control конечной точки нас не интересуют. Вместо этого мы определим функцию 

USB_PUBLIC void usbFunctionWriteOut(unsigned char* ucData, unsigned char ucLen)

которая будет принимать все interrupt/bulk передачи данных от хоста к нашему устройству для всех конечных точек, кроме 0 (это control точка). Напомню, что максимальное количество байт, которое может быть принято через usbFunctionWriteOut за один вызов равно 8 байтам (это ограничение V-USB). Ну вот, теперь мы готовы принимать поступающие от хоста байты =))) И на этом этапе мы перейдем к следующему этапу — разделение потока байт от хоста на вменяемые пакеты, которые несут нам полезную информацию. Как мы узнали ранее, хост может направлять в MSD устройство толька комманды и данные. Теперь мы сделаем следующее: 

   ► разделим входной поток данных на комманды и данные

   ► обработаем комманды в соответсвие с их предназначением или примем данные от хоста

   ► ответим хосту на обработанную комманду (предварительно отправив запрошенные данные, если необходимо)

Для того, чтобы воплотить в жизнь написанное чуть выше, давайте разберемся с несколькими положениями, которые касаются Mass Storage Class в целом и bulk-only в частности. Как я уже оговаривал, Mass Storage Class(MSC) не подразумевает того, что устройство, которое работает согласно этой спецификации, занет что-либо о фойловой системе на своем насителе. Оснойвной задачей такого устройсва является предостваление запрашиваемой информации с носителя в нужном объеме и с нужного адреса. Это, с одной стороны, облегчает работу нам с вами, с другой стороны позволяет строить устройства, не привязанные к конкретным накопителям. Все, что мы должны уметь, это выполнить требуемое хостом действие. А действия эти не так уж и сложны(если не вдаваться во все мелочи данного протокола) — выполнять команды из набора SCSI. Я описал все необходимые из них ранее.


Далее. Раскажу немного о том, как согласно MSC bulk-only происходит обмен информацией между нашим устройством и хостом. Опознав нас свами на шине, сбросив, инициализировав и настроив наше устройство, хост посылает нам комманды в так называемом Command Block Wrapper(CBW). Содержимое этого блока разнится от комманды к команде, но самое главное, размер этого CBW остается неизменным. Это положение позволяет нам принять весь CBW при помощи V-USB не смотря на ограничение в 8 байт. Итак, приняв при помощи функции usbFunctionWriteOut CBW, мы можем выделить из него нужные нам данные, а именно — комманды, отсылаемые на исполнение хостом и параметры, которые зависят от принятой комманды. Наверняка у некоторых появится вопрос: А что же будет, если хост будет часто посылать комманды в наш адрес или мы долго будем на них отвечать??? Вот тут проявляется еще один аспект выбранного нами варианта MSD. Хост не будет посылать в наш адрес следующую комманду до тех пор, пока мы не сообщим о результате выполнения предыдущей(есть нюанс с таймаутом, но в программе для нашего устройства мы это обойдем)!!! Также хост присваевает каждому отсылаемому нам CBW уникальный тэг(или номер), так что мы можем обработать одну комманду и ответить на нее даже в случае если хост не дождался нас и отослал еще чтото в наш адрес. Вы скажете, а если мы зависли? Не беда, попытавшись пару раз и не получив никакого КПД с нашей стороны, хост просто будет нас игнарировать. С другой стороны bulk передача согласно спецификации USB не гарантирует доставку данных конечной точки, так что это дает нам дополнительное время на «ногодрыгание».


Но что-то меня опять понесло в теорию=) Давайте все-таки опишем этот самы загадочный CBW:

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Вроде, на первый взгляд, ничего сложного. Теперь давайте пройдемся по его основным элементам (распишу только самые необходимые, если кому интересно, могу лично и подробнее). dCBWSignature — сигнатура блока CBW. Ничего интересного для нас, просто константа(чтото вроде USBD если смотреть в char. dCBWTag — вот это один из камней приткновения в CBW. Значение этого поля и есть тот самы номер пакета. Позже мы будем использовать это занчение для сообщения хосту орезультате выполнения операции с таким тегом. dCBWDataTransferLength — вроде понятно из названия и указывает на размер передаваемых за данную транзакцию, байт. Никогда и никого не интересовало и врядли будет. bCBWFlags — всевозможные флаги. значений много и интерпритаций еще больше. Просто не обращаем внимания. bCBWLUN — номер логического устройства, которому адресован CBW. У нас вроде одно такое устройство, но если кто будет делать картридер, то может и пригодится =) bCBWCBLength — размер переданного CBW. CBWCB[16] — вот она, полезная информация. Этот массив содержит и номер комманды, и параметры для нее, и многое другое. С этим блоком мы познакомимся позже, когда будем знакомиться с коммандами SCSI.


Мы помним, что в MSD bulk-only все транзакции делятся максинум на три этапа. Так вот, приняли мы CBW и выделили из него нужную нам информацию. Это и есть первый этап: так называемый command transport. Из приведенной блок-схемы выше мы видим, что следующим этапом в нашишем диалоге могжут быть передача данных хосту (либо прием их от него) или передача статуса обработки принятого CBW. Так вот, передача того самого статуса являестя обязательным этапом для любой комманды. Этот этап как бы подтвердает тот факт, что мы приняли от хоста CBW с номером dCBWTag и выполнили ее(вне зависимости от результата ее выполненя). Этот этап называется status transport, а данные передаются определенным блоком, имя которому CSW. Давайте опишем и его:

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Эта небольшая структурка как бы является завершением транзакции MSD вида коммандв->данные->статус. Поля этой структуры означают следующее: dCSWSignature — сигнатура блока CSW (это константа, в char это USBS), dCSWTag — номер блока(должен совпадать с номером CBW, для которого высылается статус), dCSWDataResidue — разности между ожидаемым чилом байт от хоста dCBWDataTransferLength в блоке CBW и реально принятыми(при OUT передаче) и наобоот, между запрошенным чилов байт в dCBWDataTransferLength и переданным хосту. Ну и наконец bCSWStatus — результат выполнения комманды с тегом dCSWTag. Нуль — значит все впорядке, другие значения — смотрим в спецификации =))).


Ну и на последок в этапах транзакций осталась стадия передачи данных(data transport). Напомню, что этот этап не всегда присутствует в процессе общения MSD с хостом. Есть энное количество комманд, которые не требуют передачи данных. Но все же этот этап присутствует и мы его сейчас рассмотрим. Мы знаем, что данные могут передаваться как от хоста к MSD, так и наоборот(мы же помним, что мы описали 2 конечные токи in и out). Так вот, в данной реализации MSD от хоста к MSD могут передаваться только данные для записи на носитель информации, а от MSD к хосту как данные прочитанные с носителя, так и запрашиваемые хостом параметры нашего устройства.


В принципе про этапы передачи информации MSD наверное и все. Теперь я коснусь реализации всего написанного выше. Примем исходное сосояние(назовем его RxCBW)=) Хост нам не передал не байта и мы ожидаем от него CBW. Размер этого блока мы занем, а следовательно первые sizeof(CBW) приятых байт и будут CBW. Как только мы приняли CBW мы начинаем его анализировать. Анализ блока CBW начинается с того, что мы распознаем комманду, которая находиться в USB_MSD_CBW.CBWCB[0]. Значение этого байта и есть комманда, которую хост просит нас выполнить. На этом этапе, в зависимости от предложенной нам комманды, устройство может перейти в одно из нескольких состояний: прием данных от хоста(RxData), передача данных хосту(TxData) или передача статуса(TxStatus). При переходе в состояние RxData мы принимаем от хоста n байт информации, записываем ее на носитель и переходим в состояние TxStatus. При переходе в состояние TxData мы передаем хосту запрошенную информацию n байт и переходим в состояние TxStatus. Из состояния TxStatus, передав блок CSW хосту, переходим в состояние RxCBW и ожидаем новые байты от хоста. Сейчас попробую предстваить это во временной диаграмме.

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Ну как-то так (я понимаю, что не все, наверное, понятно, так что готов ответить на вопросы).

Выложу немного скринов, для разнообразия

USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост
USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост
USB ФЛЕШКА НА ATMEGA8 И V-USB. ОТ ИДЕИ К ГОТОВОМУ УСТРОЙСТВУ… Много букв, Easyelectronics, Technobrother, Код, Своими руками, Avr, Atmega, Atmega8, Длиннопост

Я так пологаю, что расписывать работу с картой SD(MMC) не имеет смысла, т.к. про это написано очень много. Пожалуй опишу основные грабли, на которые я наступал в этом процессе (так думаю будет логичнее). Так вот, первое(и наверное основное), я не вседа использую внешнюю подтяжку на линии _CS карты памяти, из-за чего иногда возникают довольно большие неприятности. потому (хотя это и не очень красиво) в таких случаях я всегда первым делом настраиваю должным образом вывод _CS. Второе, не все карты, с которыми я работал(а их было не мало, поверьте), подразумевают размер блока для чтения/записи равным 512 байт. Потому при инициализации карты я страхуюсь и устанавливаю размер этого блока 512. Видел пару карт, которые поддерживали размер блока для чтения/записи в 1 байт, а есть, которые тока 2048 и ни грамом больше(тока 1 раз встречал). В данном проекте я использовал карту kingston на 1гб, хотя можно и другие, думаю проблем не возникнет. Третье, не всегда карта памяти инициализируется на максимальной скорости SPI(возможно это зависит и от разводки, использование проводов и много от чего еще), поэтому можно производить инициализацию на меньших скоростях, хотя у меня на 16Мгц все прекрасно работает на максимуме. Четвертое, линия MISO avr'ки. Я раньше не использовал внешнюю подтяжку на этом выводе, от чего поимел много головной боли. Теперь использую всегда, чего и советую начинающим. Наверное это основное, поэтому поедем дальше.


Мы разобрали процесс(или логики) работы нашего MSD. Научились принимать пакеты CBW, отправлять CSW и данные.

Файлы с исходным кодом.

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


Жду откликов, предложений и т.п. Мот у кого возникнет идея создания устройства на V-USB, то готов поучавствовать в коммандном проекте. Сейчас займусь работой с v-usb и сенсорной панелью вместо мышки=) Всем удачи!


Файлы : mmc_test.zip, MassStorage.Mega8.libusb.zip

Показать полностью 18

ПОДКЛЮЧЕНИЕ ДИСПЛЕЯ NOKIA 1616 НА ПРИМЕРЕ LPC1343

ПОДКЛЮЧЕНИЕ ДИСПЛЕЯ NOKIA 1616 НА ПРИМЕРЕ LPC1343 Много букв, Код, Technobrother, Lcd дисплей, Nokia, Avr, Своими руками, Длиннопост

Дисплей с подсветкой, имеет разрешение 128х160 пикселей и глубину цвета 18 бит. Размеры примерно 28х36мм. шлейф имеет 12 контактных площадок (1-я и 12-я не подключены) с шагом 0.5мм. Логика вся работает от 3.3В и лучше не завышать. От 5В скорее всего сгорит. На подсветку надо около 7В.

UPD: По правильному на питание цифровой схемы надо подать 1.8В и на аналоговую 2.7В, но всё прекрасно работает и от одного источника 3.3В (уже пол года не сгорело ничего), по даташитам это напряжение в пределах допустимого. Так же в комментариях отмечено что появились дисплеи с 3В подсветкой, мне на днях похоже такой же попался, имейте это ввиду.


Работа с дисплеем аналогична работе с Nokia 6100 (статей на эту тему предостаточно) по тому глубоко вдваться не стану, а сконцентрируюсь на различиях.


Отмечу что мне попадалось 2 разновидности дисплеев, но оба работают с данным кодом. Различить их можно по форме шлейфа. Шлейф в форме буквы T — хороший дисплей, верх будет со стороны шлейфа. Если же шлейф просто прямоугольный выходит, то со стороны шлейфа у вас будет низ и ужасно тусклая подстветка. Не знаю, то ли мне бракованный дисплей попался, толи они все такие. На счет подсветки и качества соврал. Промывал от канифоли плату спиртом, в итоге просто слои рассеивателей и поляризаторов разошлись. Не давайте спиртного дисплею, он спивается быстро! :)


Как подключить


В моём варианте работает следующая схема включения:

ПОДКЛЮЧЕНИЕ ДИСПЛЕЯ NOKIA 1616 НА ПРИМЕРЕ LPC1343 Много букв, Код, Technobrother, Lcd дисплей, Nokia, Avr, Своими руками, Длиннопост

Важно! на данной схеме учтены только «подключенные» выводы, крайние в счет не берутся. Таким образом 1-й вывод на схеме соответствует 2-му на дисплее. 10 вывод схемы — 11-му на дисплее.


Взаимодействие


Данный дисплей, как и большенство других цветных Nokia, для взаимодействия использует интерфейс SPI 9 бит. Возможно взаимодействие в режимах 0 и 3 (если память не изменяет). Успешно работает на скоростях 4Мб/с и 9Мб/с, больше проверять не стал. Линия данных на самом деле у дисплея двунаправленная и по ней можно считать такую информацию как ID контроллера в дисплее, но мы её быдем использовать только для записи.


Старший бит является признаком данных: для команды он равен 0, для данных 1. младшие 8 бит содержат либо сами данные, либо код команды.


Ну и естественно перед работой с дисплеем его надо сбросить. делаеся это выбором дисплея и подачей на вывод Reset низкого уровня в моём случае на 100мс. После снятия сброса надо так же выдержать паузу, что бы дисплей успел инициализироваться.


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


И так, получается следующий набор функций (для LPC1343)

void SPI_init() { // Раздел 13.2 UM10375


// Reset SSP (пункт 4)


LPC_SYSCON->PRESETCTRL &= ~(1<<0); // "маска" сброса SSP


LPC_SYSCON->PRESETCTRL |= (1<<0); // 1 в бит RST_SSP_0



// Enable AHB clock to the SSP domain. (пункт 2)


LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11);



// Divide by 1 (SSPCLKDIV also enables to SSP CLK) (пункт 3)


LPC_SSP->CPSR = 0; // отключим тактирование (а то мало ли)



// Set P0.9 to SSP MOSI


LPC_IOCON->PIO0_9 &= ~(7<<0);


LPC_IOCON->PIO0_9 |= (1<<0); // использовать как вывод MOSI


LPC_IOCON->PIO0_9 |= IOCON_COMMON_MODE_PULLUP;



// Set 2.11 to SSP SCK (0.6 and 0.10 can also be used)


LPC_IOCON->SCKLOC = 1; // SCK на вывод 2.11


LPC_IOCON->PIO2_11 &= ~(7<<0); // сброс текущей функции порта ввода-вывода


LPC_IOCON->PIO2_11 |= (1<<0); // использовать как вывод SCK


LPC_IOCON->PIO2_11 |= IOCON_COMMON_MODE_PULLUP;



// Set P0.2/SSEL to GPIO output and high


LPC_IOCON->PIO0_2 &= ~(7<<0); // сброс текущей функции порта ввода-вывода


LPC_IOCON->PIO0_2 |= (1<<0); // использовать как вывод SSEL (можно обычным GPIO как 0)


LPC_IOCON->PIO0_2 |= IOCON_COMMON_MODE_PULLUP;


LPC_GPIO0->DIR |= 1<<2;


LPC_GPIO0->DATA |= 1<<2;



// If SSP0CLKDIV = DIV1 -- (PCLK / (CPSDVSR X [SCR+1])) = (72,000,000 / (2 x [3 + 1])) = 9.0 MHz


LPC_SSP->CR0 = ( (8<<0) // Размер данных 1000 - 9 бит


| (0<<4) // Формат фрейма 00 - SPI


| (0<<6) // Полярность 0 - низкий уровень между фреймами


| (0<<7) // Фаза 0 - по нарастанию


| (3<<8) // Делитель частоты шины на бит


) ;



// Clock prescale register must be even and at least 2 in master mode


LPC_SSP->CPSR = 2; // пердделитель 2-254 (кратно 2)



// Enable device and set it to master mode, no loopback (разрешаем работу)


LPC_SSP->CR1 = ( (0<<0) // 0 - Loop Back Mode Normal


| (1<<1) // Разрешение работы 1 - разрешено


| (0<<2) // Режим ведущий-ведомый 0 - мастер


);


}



void SPI_send(uint16_t value) {


while ((LPC_SSP->SR & ((1<<1) | (1<<4))) != (1<<1)); // если буффер передачи не переполнен и устройство не занято


LPC_SSP->DR = value;


}



// Вспомогательные макросы


#define LCD_send(x) SPI_send(x)


#define LCD_command(cmd) LCD_send(cmd)


#define LCD_data(data) LCD_send(0x0100|(uint8_t)(data))



void LCD_reset(void) {


// Настройка для вывода Reset дисплея


LPC_IOCON->PIO0_8 &= ~(7<<0); // сброс текущей функции порта ввода-вывода


LPC_IOCON->PIO0_8 |= IOCON_COMMON_MODE_PULLUP;


LPC_GPIO0->DIR |= 1<<8;


LPC_GPIO0->DATA |= 1<<8;


// Настройка для вывода Select


LPC_IOCON->PIO0_2 &= ~(7<<0); // Временно отключаем спецфункцию вывода выбора SPI


delayms(100);


// Сброс дисплея


LPC_GPIO0->DATA &= ~(1<<2); // ncs = 0


LPC_GPIO0->DATA &= ~(1<<8); // nrst = 0


delayms(100);


LPC_GPIO0->DATA |= 1<<8; // nrst = 1


LPC_GPIO0->DATA |= 1<<2; // ncs = 1


delayms(100);


// Возврат спецфункции


LPC_IOCON->PIO0_2 |= (1<<0); // использовать как вывод SSEL


}

В этих функциях по сути собран весь аппаратно-зависимый код. именно по этой причине функция LCD_reset включена сюда, хотя правильнее её описать в следующем разделе. Я использовал «фоновый вывод данных», так функция SPI_send сначала ожидает окончания вывода предидущего байта (9 бит), затем помещает очередной байт (9 бит) на вывод и возвращается не ожидая завершения операции вывода.


Важно: Линию выбора дисплея CS обязательно надо периодически освобождать, иначе вывода никакого не будет, получите просто белый экран. У меня используется полностью аппаратный контроль.


Инициализация дисплея


Идем по пути найменьшего сопротивления, и одалживаем у тов. Rossum’а код для работы с дисплеями Nokia из проекта NokiaSuperBreakout. Не беда что нашего дисплея нет в перечислении, берём тот что соответствует диспею 132х160 контроллер SPFD54124B.


Данный код настраивает дисплей на 16-битный индексный режим вывода, в итоге получаем формат BGR 5-6-5. по биту глубины на R и B мы теряем, но зато получаем возможность передавать только 2 бата на один пиксель, взамен 3-х в 18битном режиме.


Перед инициализацией надо не забыть сбросить дисплей (иногда критично).

const uint16_t init_lcd1616ph[] = {


0xBA, 0x107, 0x115, // Data Order


0x25, 0x13F, // Contrast


0x11, // Sleep Out


0x13, // Display Normal mode



0x37,0x100, // VSCROLL ADDR


0x3A,0x105, // COLMOD pixel format 4=12,5=16,6=18


0x29, // DISPON


0x20, // INVOFF


0x13 // NORON


};



void LCD_init()


{


const uint16_t *data = &init_lcd1616ph[0];


uint16_t size = sizeof(init_lcd1616ph)/sizeof(init_lcd1616ph[0]);


while(size--) {


LCD_send(*data++);


}


LCD_command(0x2D);


int i;


for (i = 0; i < 32; i++)


LCD_data(i<<1);


for (i = 0; i < 64; i++)


LCD_data(i);


for (i = 0; i < 32; i++)


LCD_data(i<<1);


delay(100);


m_lcdResetClip();


EndDraw();


SetFont(0);


}

Про m_lcdResetClip, EndDraw и SetFont потом.


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



Вывод графики



Принцип вывода у всех встреченных мной дисплеев один. Вначале передается команда выбора диапазона строк, затем диапазона столбцов, после чего попиксельно выводятся пиксели в получившееся окно. Таким образом для вывода изображения в области [ x1:y1, x2:y2 ] надо передать следующую последовательность:


[PASET] [y1] [y2] [CASET] [x1] [x2] [RAMWR] [pixel_1] [pixel_2]… [pixel_N]


Однако, в отличии от 6100 дисплей для 1616 каждая из величин координат (x1, x1, y1, y2) имеет 2-хбайтовый размер, не смотря на то, что старший байт всегда нулевой. Контроллер дисплея сам будет переносить «курсор» вывода в окне на следующую строку вывода, при достижении правой границ окна. Направление заполнения слева-направо, сверху вниз. Удобно. Ну и немаловажный фактор: левый верхний угол имеет координату x:y = 2:1.


Таким образом получаем что на операцию вывода требуется передать 11 служебных байт плюс 2хN байт данных. Естественно получаем что выгоднее выводить прямогольными областями по несколько пикселей за раз.


Ну а теперь к ложке дегтя. К сожалению при передаче координат «вне экрана» предсказать поведение дисплея нельзя. Он вроде как и «закольцован» на размер в 256 байт, но артефакты попадаются порой очень странные. По этому у вас есть выбор: либо не передавать координаты вне экрана, либо делать програмное отсечение. Я выбрал второй вариант и вот что из этого получилось:

// Nokia1616


#define displayOffsetX 2


#define displayOffsetY 1


#define displayWidth 128


#define displayHeight 160



#define RGB(r, g, b) (((uint32_t)(R))|((uint32_t)(g)<<8)|((uint32_t)(b)<<16))


#define RECT_set(rect, l, t, r, b) { (rect).left = (l); (rect).top = (t); (rect).right = (R); (rect).bottom = (b); }



// Описание переменных


RECT m_lcdBound; // Установленная для вывода область


POINT m_lcdOutput; // Очередная позиция для вывода


RECT m_lcdClip; // Размеры области отсечения


uint8_t m_lcdClipOutput; // Активны ли отсечения в текущей итерации вывода



uint32_t BeginDraw(int16_t left, int16_t top, uint16_t width, uint16_t height)


{


int16_t right = left + width - 1;


int16_t bottom = top + height - 1;


if( left >= m_lcdClip.left && top >= m_lcdClip.top && right <= m_lcdClip.right && bottom <= m_lcdClip.bottom ) { // RectInRect


// область вывода полностью видима, используем "быстрый" вывод без проверок отсечения


m_lcdClipOutput = 0;


} else {


// область вывода частично либо полностью невидима на дисплее, используем вывод с проверкой отсечений


m_lcdClipOutput = 1;


m_lcdOutput.x = left;


m_lcdOutput.y = top;


RECT_set(m_lcdBound, left, top, right, bottom);


if(left < m_lcdClip.left) left = m_lcdClip.left; // ClipRect


if(top < m_lcdClip.top) top = m_lcdClip.top;


if(right > m_lcdClip.right) right = m_lcdClip.right;


if(bottom > m_lcdClip.bottom) bottom = m_lcdClip.bottom;


}


if( left > right || top > bottom ) { // IsRectValid


// область не видна на дисплее, завершаем вывод


EndDraw();


return 0;


}


uint32_t count;


// Устанавливаем "виртуальные" границы вывода


LCD_command(0x2A); //LCD_command(CASETP);


count = right - left + 1;


left += displayOffsetX;


right += displayOffsetX;


LCD_data(left>>8);


LCD_data(left);


LCD_data(right>>8);


LCD_data(right);


// Диапозон строк


LCD_command(0x2B); //LCD_command(PASETP);


count *= (bottom - top + 1);


top += displayOffsetY;


bottom += displayOffsetY;


LCD_data(top>>8);


LCD_data(top);


LCD_data(bottom>>8);


LCD_data(bottom);


LCD_command(0x2C); //LCD_command(RAMWR);


// Возвращаем количество видимых пикселей


return count;


}



void EndDraw()


{


m_lcdClipOutput = 1;


m_lcdBound.right = m_lcdBound.left - 1; // SetRect


}



void NextPoint(uint32_t color)


{


// Надо ли проверять отсечения при выводе


if( m_lcdClipOutput ) {


int16_t x = m_lcdOutput.x;


int16_t y = m_lcdOutput.y;


// учит.отсеч.


//if(!m_lcdClip.width /* || !m_lcdClip.height */) return;


if(m_lcdBound.right < m_lcdBound.left) { // IsRectValid вывод недоступен


return;


}


// Смещение на следующую позицию вывода


if( m_lcdOutput.x >= m_lcdBound.right ) {


// Если в конце строки - переходим на следующую


m_lcdOutput.x = m_lcdBound.left;


if( m_lcdOutput.y >= m_lcdBound.bottom ) {


// Если последняя точка, переходим в начало (или можно завершить вывод вызовом EndDraw)


m_lcdOutput.y = m_lcdBound.top;


} else {


m_lcdOutput.y++;


}


} else {


m_lcdOutput.x++;


}


if(!(x >= m_lcdClip.left && x <= m_lcdClip.right && y >= m_lcdClip.top && y <= m_lcdClip.bottom) ) { // PtInRect


return;


}


}


// точка будет видимой


uint8_t r = color;


uint8_t g = color>>8;


uint8_t b = color>>16;


LCD_data((r&0xF8)|(g>>5));


LCD_data(((g<<3)&0xE0)|(b>>3));


}

Данные функции являются «дисплей ориентированными» и могут быть изменены для работы с другим дисплеем (естественно не забыв и про функцию инифиализации).


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


В функции настройки отображения я прибавляю смещение начала координат, что позволяет мне не запоминать с каким именно дисплеем я работаю. С той же целью для цвета используется 32-битное значение, по 8 бит на компоненту, и 8 бит прозапас и для выравнивания.


Функция вывода очередной точки NextPoint должна выполнить некоторые проверки и расчеты, тут нам позволит хорошо ускорить процесс использование фонового вывода на дисплей: пока по SPI передаются данные, мы проводим свои проверки для следующей точки.


Ну а функция завершения вывода просто задает недействительную область. При желании и этого можно было не делать, но вдруг появится дисплей, которому требуется что-либо сказать по окончании? Не переписывать же потом весь код.


Ну и для завершения картины средства для работы с отсечениями:

typedef struct _tagPOINT {


int16_t x;


int16_t y;


} POINT, *PPOINT;



typedef struct _tagRECT {


int16_t left;


int16_t top;


int16_t right;


int16_t bottom;


} RECT, *PRECT;



void m_lcdSetClip(const RECT *r)


{


// Проверяем на видимость отсечения


RECT_set(m_lcdClip, r->left, r->top, r->right, r->bottom);


// Устанавливаем "абсолютное" ограничение для вывода c усечением до границ дисплея


if(m_lcdClip.left < 0) m_lcdClip.left = 0; // ClipRect


if(m_lcdClip.top < 0) m_lcdClip.top = 0;


if(m_lcdClip.right >= displayWidth) m_lcdClip.right = displayWidth - 1;


if(m_lcdClip.bottom >= displayHeight) m_lcdClip.bottom = displayHeight - 1;


// Is clip valid


if(m_lcdClip.bottom < m_lcdClip.top || m_lcdClip.right < m_lcdClip.left) { // IsRectValid


// invalid clip region


RECT_set(m_lcdClip, 0, 0, -1, -1);


}


}



void m_lcdResetClip()


{


RECT_set(m_lcdClip, 0, 0, displayWidth - 1, displayHeight - 1);


}

Примитивы


Самое простое пожалуй это закрасить область одним цветом.

void Fill(int16_t left, int16_t top, uint16_t width, uint16_t height, uint32_t color)


{


uint32_t count;


count = BeginDraw(left, top, width, height); // Функция возвращает количество видивых пикселей в установленной области вывода.


m_lcdClipOutput = 0; // Принудительно меняем функцию вывода, выводим только необходимое количество пикселей


while(count--) {


NextPoint(color);


}


EndDraw();


}



void Clear(uint32_t color)


{


Fill(0, 0, displayWidth, displayHeight, color);


}



void Pixel(int16_t x, int16_t y, uint32_t color)


{


Fill(x, y, 1, 1, color);


}

А проверяется всё это дело так:

SPI_init();


LCD_reset();


LCD_init();


Clear(0x00000000);


Fill(10, 20, 30, 40, 0x00FF00FF);

Показать полностью 2

ДИСПЛЕЙ 3.7 дюйма ОТ ТЕЛ. HTC A8181 для DIY электроники

Всем привет) И так, я вернулся после 2-х недельного бана и принес немного полезной инфы.

ДИСПЛЕЙ 3.7 дюйма  ОТ ТЕЛ. HTC A8181 для DIY электроники Technobrother, Avr, Arduino, Микроконтроллеры, Дисплей, Своими руками, Длиннопост
Тем ребяткам которые очень хотят использовать нормальные дисплеи, предлагаю вам побаловать своего внутреннего перфекциониста: Дисплей от тел. HTC A8181 диагональ 3.7 » разрешение 480х800, есть два вида такого дисплея, как TFT так и AMOLED, отличаются глубиной цвета и немного питанием по тому пин то пин не совместимы. Намного дешевле чем брать какие то заводские по причине того что массовость играет серьезную роль в цене.

Купить TFT можно за $9.25
Предлагаю сопутствующие фото и .PDF

ДИСПЛЕЙ 3.7 дюйма  ОТ ТЕЛ. HTC A8181 для DIY электроники Technobrother, Avr, Arduino, Микроконтроллеры, Дисплей, Своими руками, Длиннопост
ДИСПЛЕЙ 3.7 дюйма  ОТ ТЕЛ. HTC A8181 для DIY электроники Technobrother, Avr, Arduino, Микроконтроллеры, Дисплей, Своими руками, Длиннопост
п.с. На фото два примера, отличаются TFT от AMOLED наличием дополнительного маленького шлейфа для питания светодиодной подсветки. Лично я себе купил TFT но у меня пока есть и рабочая лошадка с AMOLED, вскоре будет с чем поиграться.

AMS369FG03-002_Rev2_0_20090603_201210156706.pdf - https://vk.com/doc-50664262_437108999
ACX425AKM_Ver0_4_20100624_201306185709.pdf - https://vk.com/doc-50664262_437108998
Показать полностью 3

Модуль сенсорных кнопок для ардуино на чипе MPR121

Модуль сенсорных кнопок для ардуино на чипе MPR121 Arduino, Technobrother, Mpr121, Своими руками, Интересное, Микроконтроллеры, Железо, Радиолюбители, Видео, Длиннопост
Данный контроллер может использоваться в различных пультах дистанционного управления, MP3 плейерах, мобильных телефонах, домофонах, кодовых электронных замках, при замене кнопочных устройств ввода в разного рода устройствах.
Модуль сенсорных кнопок для ардуино на чипе MPR121 Arduino, Technobrother, Mpr121, Своими руками, Интересное, Микроконтроллеры, Железо, Радиолюбители, Видео, Длиннопост

Особенности:

напряжение питания 1,7В – 3,6В;

29 мкА при периоде опроса 16мс;

3 мкА в режиме малого потребления;

12 электродов

автоматическая калибровка входов;

возможность настройки пороговых значений срабатывания для каждого электрода;

I²C интерфейс, и выход прерывания IRQ, срабатывает при изменения состояния электродов;

встроенный драйвер светодиодов, до 8 выходов. Мультиплексируются с входами электродов;

рабочая температура -40°C — +85°C;

корпус QFN20, 3 x 3 мм.

Готовый модуль с кнопками.

Модуль сенсорных кнопок для ардуино на чипе MPR121 Arduino, Technobrother, Mpr121, Своими руками, Интересное, Микроконтроллеры, Железо, Радиолюбители, Видео, Длиннопост

Что из этого можно сделать?
Например:
Фруктовая клавиатура потехи ради)

Модуль сенсорных кнопок для ардуино на чипе MPR121 Arduino, Technobrother, Mpr121, Своими руками, Интересное, Микроконтроллеры, Железо, Радиолюбители, Видео, Длиннопост

Или такие сенсорные кнопки

Модуль сенсорных кнопок для ардуино на чипе MPR121 Arduino, Technobrother, Mpr121, Своими руками, Интересное, Микроконтроллеры, Железо, Радиолюбители, Видео, Длиннопост

немного больше инфы здесь - https://exclusive4ubro.wordpress.com/2015/12/10/arduino-%D0%...

Показать полностью 4 1

Парень замутил себе световой меч на ардуинке со спецэфектами

Парень замутил себе световой меч на ардуинке со спецэфектами Star Wars, Своими руками, Lightsaber, Световой меч, Arduino, Видео, Дайте две
JakeSoft — мастер по созданию кастомных световых мечей, за его плечами уже не один десяток собственноручно собранных экземпляров знаменитого оружия джедаев из серии Start Wars, самых разных модификаций и цветов. Для управления датчиками и подсветкой в своих мечах JakeSoft использует Arduino.

кому интересно почитать перевод описания самого автора прошу сюда - https://exclusive4ubro.wordpress.com/2015/12/10/%D1%81%D0%B2...

Показать полностью 1 2

Ищу СоАдминистратора в Паблик и на Сайт

Паблик тематический по теме большинства моих постов. а именно о технике и гаджетах и электронике.

Ищу СоАдминистратора в Паблик и на Сайт Поиск, Подписчики, Канифоль, Техника, Technobrother, Гаджеты, Электроника, Сообщество

Так вот нужна помощь, ищу человека который(-ая) готов(-а) помогать мне в развитии сообщества и сайта на тематику электроники.

Ищу СоАдминистратора в Паблик и на Сайт Поиск, Подписчики, Канифоль, Техника, Technobrother, Гаджеты, Электроника, Сообщество

На сайте я вам дам доступ для размещения постов и модерации. Грубо говоря вы будете публикатор+модер. 

Ребята и девушки гики, электронщики и вообще кто в теме пишите в Коментарии кто готов присоеденится думаю из 2000 подписчиков кто то да и найдётся)

Показать полностью 2

Переходник из VGA на тюльпаны (RGB)

Переходник из VGA на тюльпаны (RGB)
Отличная работа, все прочитано!