...

суббота, 6 мая 2017 г.

GraphQL аутентификация, регистрация, личный профиль

Комментарии (0)

    Let's block ads! (Why?)

    Простая модель адаптивного фильтра Калмана средствами Python

    Восстановление данных из поврежденного массива RAID 5 в NAS под управлением Linux

    All-In-One: Proxmox + OpenMediaVault или ещё одна идея для домашнего NAS

    Parallels Mac Management: трудности переходного периода

    Комментарии (0)

      Let's block ads! (Why?)

      Как работать с событиями в Flussonic

      Комментарии (0)

        Let's block ads! (Why?)

        Делаем GraphQL API на PHP и MySQL

        Функциональная безопасность, часть 7 из 7. Методы обеспечения информационной и функциональной безопасности

        Комментарии (0)

          Let's block ads! (Why?)

          [recovery mode] Как я "<" моноидом делал

          Комментарии (0)

            Let's block ads! (Why?)

            Хачим IntegerCache в Java 9

            Комментарии (0)

              Let's block ads! (Why?)

              Повесть о создании классической RTS в домашних условиях с нуля (часть 2: «Воскрешение») Окончание статьи: Сеть

              [Перевод] Узнать и полюбить Xdebug

              пятница, 5 мая 2017 г.

              [Перевод] Развёрнутый комментарий Дэна Абрамова к статье «Вещи, о которых никто вам не расскажет про React»

              Security Week 18: Дыра во всех системах с Intel Core, Apple отобрала сертификат у троянца, рансомварь заполонила планету

              Не пропустите онлайн-трансляцию конференции Build 2017

              Комментарии (0)

                Let's block ads! (Why?)

                Необычный хакатон 20-21 мая: S7 Airlines

                Комментарии (0)

                  Let's block ads! (Why?)

                  Интернет вещей — маркетинг или реальная угроза

                  Комментарии (0)

                    Let's block ads! (Why?)

                    «55% наших пользователей вообще не используют веб-версию» — Tinkoff.ru о мобильной разработке

                    Повесть о создании классической RTS в домашних условиях с нуля (часть 2: «Воскрешение»)

                    Комментарии (0)

                      Let's block ads! (Why?)

                      Функциональное программирование: в Java и C# слишком много церемоний

                      Комментарии (0)

                        Let's block ads! (Why?)

                        [Перевод] Ускоряем восстановление бэкапов в PostgreSQL

                        Комментарии (0)

                          Let's block ads! (Why?)

                          [Перевод] 2038: остался всего 21 год

                          Boxing и unboxing — что быстрее?

                          Комментарии (0)

                            Let's block ads! (Why?)

                            UAC Bypass или история о трех эскалациях

                            Почему мы выбрали новый Angular

                            Комментарии (0)

                              Let's block ads! (Why?)

                              Изменение правил о рекламной рассылке во Франции: согласие на рассылку на электронную почту нужно получать ежегодно

                              Комментарии (0)

                                Let's block ads! (Why?)

                                Обзор Splunk Machine Learning Toolkit

                                Комментарии (0)

                                  Let's block ads! (Why?)

                                  Системы инициализации Unix и Linux после SysV

                                  четверг, 4 мая 2017 г.

                                  Английский для собеседований в IT-компании: что нужно для старта карьеры?

                                  Комментарии (0)

                                    Let's block ads! (Why?)

                                    Волитроника может «продлить» действие закона Мура

                                    Комментарии (0)

                                      Let's block ads! (Why?)

                                      Мобилизация без «головной боли»

                                      Комментарии (0)

                                        Let's block ads! (Why?)

                                        [Перевод] Интерактивная 3D-инсталляция по мотивам «Звёздных войн»

                                        Комментарии (0)

                                          Let's block ads! (Why?)

                                          Российские операционные системы: говорим сейчас, ждём на OS DAY

                                          Комментарии (0)

                                            Let's block ads! (Why?)

                                            Итоги третьего раунда Russian Code Cup 2017

                                            Комментарии (0)

                                              Let's block ads! (Why?)

                                              Redux как сердце архитектуры фронтенда Единой фронтальной системы

                                              Комментарии (0)

                                                Let's block ads! (Why?)

                                                Сегментация текстовых строк документов на символы с помощью сверточных и рекуррентных нейронных сетей

                                                Комментарии (0)

                                                  Let's block ads! (Why?)

                                                  CocoaConf ВС 2016: Swift server side

                                                  Комментарии (0)

                                                    Let's block ads! (Why?)

                                                    Pentestit Security Conference 2017: доклады

                                                    Комментарии (0)

                                                      Let's block ads! (Why?)

                                                      [Из песочницы] Эмулятор БК-0010 на FPGA

                                                      Свободен ото всех оков: Emercoin версии 6.2 стал полностью децентрализованным

                                                      Комментарии (0)

                                                        Let's block ads! (Why?)

                                                        Бесплатные плагины, инструменты и сервисы для разработки игры на юнити

                                                        Комментарии (0)

                                                          Let's block ads! (Why?)

                                                          Прошлое и будущее сотовой связи в зонах, где нет GSM

                                                          Проверяем код динамического анализатора Valgrind с помощью статического анализатора

                                                          Комментарии (0)

                                                            Let's block ads! (Why?)

                                                            Mikrotik на страже температуры

                                                            Транслируем видеопоток с веб-страницы по WebRTC на Facebook и YouTube одновременно

                                                            Комментарии (0)

                                                              Let's block ads! (Why?)

                                                              Рецепт идеального Хабропоста

                                                              Реакция на пользовательские отзывы с целью повышения средней оценки

                                                              Twitter: перехват управления взглядами и мыслями

                                                              Комментарии (0)

                                                                Let's block ads! (Why?)

                                                                Роскомнадзор пытается добить Rutracker. Блокировки серверов-анонсеров и методы обхода

                                                                Как устроено тестирование у разработчиков КОМПАС-3D

                                                                Живем и работаем не в столицах: рынок разработки программного обеспечения в Нижнем Новгороде

                                                                среда, 3 мая 2017 г.

                                                                [Перевод] Проект SeaMonkey официально просит о поддержке

                                                                Комментарии (0)

                                                                  Let's block ads! (Why?)

                                                                  Типизируя техническое интервью

                                                                  Автоматизируем неавтоматизируемое, или про Xamarin в реальных проектах

                                                                  Комментарии (0)

                                                                    Let's block ads! (Why?)

                                                                    RMarkdown, R и ggplot

                                                                    Облако Microsoft Azure в реальных проектах

                                                                    Комментарии (0)

                                                                      Let's block ads! (Why?)

                                                                      [Перевод] Шесть парадигм программирования, которые изменят ваш взгляд на код

                                                                      [Перевод] Bash-скрипты, часть 9: регулярные выражения

                                                                      [Из песочницы] Реализация NetFlow сенсора на FPGA + CPU — гибко и быстро

                                                                      Комментарии (0)

                                                                        Let's block ads! (Why?)

                                                                        Как автоматизировать подтверждение заказа, если ты не Юлмарт (спойлер: точно так же, как Юлмарт)

                                                                        [Из песочницы] «Подводные камни» при проведении совещаний команды проекта

                                                                        Комментарии (0)

                                                                          Let's block ads! (Why?)

                                                                          Ремонт без отвертки, COM-порты и 7 лет доступности запчастей: как обеспечивается надежность железа для магазинов

                                                                          Комментарии (0)

                                                                            Let's block ads! (Why?)

                                                                            Поддержка Visual Studio 2017 и Roslyn 2.0 в PVS-Studio: иногда использовать готовые решения не так просто

                                                                            Комментарии (0)

                                                                              Let's block ads! (Why?)

                                                                              4 крутые штуки про разработку игр

                                                                              Начинаем работать в STM32CubeMX. Часть 3

                                                                              Продолжаем цикл про основы работы STM32MXCube и программированию микроконтроллеров STM32.
                                                                              Часть 1.
                                                                              Часть 2.

                                                                              В прошлых частях мы освоили базовые настройки микроконтроллера, работу с GPIO, таймером, DMA и DAC. В этой части мы познакомимся с ADC и USB.


                                                                              Небольшое вступление к третьей части


                                                                              Вначале я хочу сказать, что с этой части я буду использовать отладочную плату NUCLEO-F767ZI. Эта плата более доступна, чем STM32F746G Discovery, использует микроконтроллер в корпусе LQFP144, а не BGA, и сама плата более удобна для встраивания в разные DIY-проекты. Она имеет Ethernet и USB, а также JTAG-отладчик. Недостатком платы является отсутствие LCD, но он нам пока не нужен.

                                                                              Хотя плата имеет другой микроконтроллер, все проекты из предыдущих частей переносятся на неё почти без изменений (нужно только поменять номера пинов). Также следует учесть, что на этой плате микроконтроллер тактируется источником 8 МГц. Кварц для тактирования микроконтроллера предусмотрен схемой, но не распаян, сигнал 8 МГц снимается с JTAG-отладчика. Если ваш проект использует интерфейс USB, то желательно включать тактирование от HSE, а не от внутреннего RC-осциллятора, так как RC-осциллятор не обладает достаточной точностью и стабильностью частоты. При попытке включить RC-осциллятор при наличии в проекте USB, STM32CubeMX выдаст предупреждение и предложит переключиться на HSE (то есть на внешний высокостабильный источник тактирования). На практике USB-интерфейс всё равно работает, даже от RC, но лучше не рисковать.

                                                                              Я перевёл на эту плату проекты из предыдущих частей и залил их на гитхаб .

                                                                              В комментариях к предыдущим частям были вопросы по поводу IDE. STM32CubeMX позволяет автоматически создавать проекты для различных IDE: IAR (EWARM), MDK ARM v4, MDK ARM v5, Atollic TRUEStudio, SW4STM32 и др. Я пользуюсь Atollic TRUEStudio, который доступен для скачивания с официального сайта бесплатно.

                                                                              Также я проверил материал из предыдущих частей и внёс ряд поправок.
                                                                              Хочу поблагодарить Shamrel за ценные комментарии к предыдущей части.

                                                                              USB VCP


                                                                              Одним из самых простых режимов работы USB является режим VCP — Virtual COM Port. Настройка работы с ним потребует от вас минимальных усилий.

                                                                              В STM32CubeMX находим на вкладке Pinout раздел USB_OTG_FS и устанавливаем Mode=Device_Only:

                                                                              В разделе USB_DEVICE устанавливаем Class For FS IP в режим CDC VCP (Communication Device Class Virtual Com Port):

                                                                              Теперь нужно настроить конфигурацию тактирования так, чтобы частота USB составляла 48 MHz:

                                                                              Идём дальше, на вкладку Configuration, и отключаем параметр VBUS Sensing:

                                                                              Генерируем код и открываем проект в IDE.

                                                                              Находим файл usbd_cdc_if.c и в него вставляем следующее:

                                                                              static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
                                                                              {
                                                                                /* USER CODE BEGIN 6 */
                                                                                USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
                                                                                CDC_Transmit_FS(Buf, *Len);
                                                                                USBD_CDC_ReceivePacket(&hUsbDeviceFS);
                                                                                return (USBD_OK);
                                                                                /* USER CODE END 6 */ 
                                                                              }
                                                                              

                                                                              и
                                                                              uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
                                                                              {
                                                                                uint8_t result = USBD_OK;
                                                                                /* USER CODE BEGIN 7 */ 
                                                                                USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
                                                                                result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
                                                                                /* USER CODE END 7 */ 
                                                                                return result;
                                                                              }
                                                                              

                                                                              Здесь реализован режим эха: всё, что приходит в порт, мы немедленно отправляем обратно.

                                                                              Компилируем и прошиваем микроконтроллер. Затем подключаем разъём User USB платы к компьютеру. Система должна обнаружить новый COM-порт.

                                                                              Для Linux: проверяем ls /dev/tty*, появилось устройство /dev/ttyACM0. Проверяем, и здесь нас ждут ещё сюрприз: отказано в доступе. Нужно добавить себя в группу dialout:

                                                                              sudo adduser user dialout
                                                                              

                                                                              (где user — ваше имя пользователя)

                                                                              Для работы с устройством в Windows вам понадобится скачать и установить драйвер. Для работы в OS X и Linux специальный драйвер не нужен.

                                                                              Запускаем (например) Putty, настраиваем параметры порта. Они должны совпадать с параметрами, указанными в свойствах порта (см. «диспетчер устройств/порты»).

                                                                              Пробуем открыть порт в Putty и что-то послать в порт:

                                                                              Если порт не открывается, можно попробовать выйти из режима отладки в IDE и перезапустить плату. Всё должно заработать.

                                                                              Как мы увидели, работа с USB в режиме виртуального COM-порта очень проста. Единственный недостаток этого режима — очень низкая скорость передачи данных. Интерфейс USB в режиме Full Speed обеспечивает до 12 Мбит/c, в режиме High Speed — до 480 Мбит/c, но VCP ограничивает скорость жалкими 128 кбит/c.
                                                                              Можно сделать высокую скорость передачи данных, но пока отложим это до следующего раза.

                                                                              АЦП

                                                                              Сейчас попробуем запустить АЦП, получить с него значения и отправить на компьютер, реализовав очень простой (и очень медленный) «осциллограф». Чтобы было интереснее, мы подадим на АЦП синусоидальный сигнал, сформированный ЦАП. Так как мы уже делали это в прошлой части, я просто скопирую код в новый проект (с небольшими изменениями, которые большой роли не играют).

                                                                              Сначала немного об АЦП, встроенном в микроконтроллер. Микроконтроллер STM32F767ZI имеет три 12-разрядных АЦП, типа SAR (последовательного приближения), имеющие производительность до 2 MSPS (млн. выборок в секунду). Этот тип АЦП отличается высокой скоростью преобразования, но меньшей точностью, чем сигма-дельта АЦП. Вход опорного напряжения VREF соединён с VDDA, и, через индуктивность, с VDD. Таким образом, опорное напряжение в нашем случае равно 3,3В. Особенностью SAR ADC является использование на входе схемы выборки-хранения, содержащей конденсатор. В момент выборки значения сигнала конденсатор подключается ко входу и заряжается до величины входного сигнала. Если источник сигнала будет иметь слишком большое внутреннее сопротивление, конденсатор не успеет зарядиться полностью, и мы получим заниженное значение. Этот и другие моменты использования АЦП изложены в [1].

                                                                              АЦП данного микроконтроллера имеет множество режимов работы [2], мы рассмотрим только один из них. Попробуем получить одновременно два значения сигнала с двух АЦП, строго синхронно, и записать их в буфер через DMA.

                                                                              Итак, создаём новый проект, добавляем в него уже готовый код для генерации синусоиды на DAC и для USB VCP (через него мы будем отсылать данные на компьютер). Далее (проводами) соединяем выход ЦАП с входами АЦП1 и АЦП2. Для того, чтобы как-то различать сигналы на аналоговых входах, я соединил АЦП1 c ЦАП напрямую, а АЦП2 — через делитель напряжения на переменном резисторе, чтобы можно было менять амплитуду сигнала.

                                                                              Осторожно, аналоговая схемотехника!
                                                                              Если вы будете подавать на вход АЦП сигнал от внешнего источника, следует помнить, что сигнал на любом входе микроконтроллера должен быть ограничен значениями 0 — Vcc, что в большинстве практических случаев приводит к необходимости сдвига и усиления (или ослабления) сигнала.
                                                                              Также следует учесть, что в микроконтроллерах STM32 используются АЦП последовательного приближения (SAR), которые потребляют от источника сигнала довольно большой ток в момент измерения, и требуют источника сигнала с низким импедансом.


                                                                              Рис. 1. Схема выборки-хранения SAR ADC (не из STM32, но совершенно аналогичный)

                                                                              В моменты выборки сигнала конденсаторы (рис. 1) подключаются ко входу АЦП и должны зарядиться до полного уровня сигнала за очень короткое время, потребляя при этом значительный ток. Если источник сигнала будет иметь большое сопротивление, они не успеют зарядиться, и показания АЦП будут неверными. На практике это означает, что мы должны в большинстве случаев использовать внешний буферный усилитель. Так как сегодня мы сосредоточимся на программных аспектах задачи, мы можем обойтись без усилителя, но следует помнить, что без усилителя показания АЦП будут существенно искажены, и в реальных проектах он нужен.


                                                                              Рис. 2. Схема выборки-хранения вызывает провалы уровня сигнала на входе АЦП.

                                                                              К сожалению, в документации STM32 эти вопросы рассмотрены слабо, но я могу порекомендовать руководство [3].
                                                                              Если читателям будет интересно, я могу рассмотреть основы схемотехники аналоговых узлов сопряжения сигналов с АЦП в следующей статье.


                                                                              Нам нужны будут в нашем проекте два таймера. Один из них будет задавать период работы ЦАП, второй — АЦП. Настроим аналого-цифровой преобразователь на работу в двухканальном режиме с одновременной выборкой. Выборка будет происходить по таймеру TIM2. Полученные значения будут складываться в буфер с помощью DMA.

                                                                              Мы будем использовать однократный режим работы DMA (есть также циклический, с ним мы уже познакомились при изучении ЦАП). После того, как буфер заполнится значениями с АЦП, мы копируем его содержимое в другой буфер (с некоторой обработкой), передаём его через USB и запускаем процесс снова. Также для отладки и индикации режима работы мы используем два порта GPIO, к которым подключены светодиоды.

                                                                              Итак, у нас создан проект, в который мы добавили DAC и таймер TIM1. Ещё нам нужно добавить ADC1 (вход IN9), ADC2 (вход IN12) и таймер TIM2. Также нам понадобится USB_OTG_FS.

                                                                              Настраиваем ADC1 на работу в режиме одновременной выборки, с запуском по таймеру 2:

                                                                              ADC2 при этом настраивается автоматически:

                                                                              Настраиваем DMA:

                                                                              Обращаем внимание, что размер передаваемых данных Word, а не Half Word, т.к. за один раз передаются данные с двух АЦП, упакованные в 32-битное слово.
                                                                              Настраиваем таймер TIM2:

                                                                              USB настраиваем так же, как мы это уже делали. Генерируем код.

                                                                              Я не буду здесь расписывать весь исходник проекта, остановлюсь лишь на ключевых моментах. Запуск цепочки таймер-ADC-DMA:

                                                                                //start adc
                                                                                HAL_ADC_Start(&hadc2);
                                                                                HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *)adc_buf, ADC_BUF_SIZE);
                                                                                HAL_TIM_Base_Start_IT(&htim2);
                                                                              

                                                                              Обработчик прерывания:

                                                                              void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
                                                                              {
                                                                                      HAL_TIM_Base_Stop(&htim2);
                                                                                      HAL_ADC_Stop(&hadc2);
                                                                                      HAL_ADCEx_MultiModeStop_DMA(&hadc1);
                                                                                      const int threshold = (1 << 11);
                                                                                      //find a trigger condition
                                                                                      if(state == STARTED)
                                                                                      {
                                                                                              HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, 1);
                                                                                              for(int i = 0; i < (ADC_BUF_SIZE - VCP_BUF_SIZE); i++)
                                                                                              {
                                                                                                      uint32_t sample0_0 = adc_buf[i] & 0x00000FFF;
                                                                                                      uint32_t sample0_1 = adc_buf[i + 1] & 0x00000FFF;
                                                                                                      if(sample0_0 < threshold && sample0_1 >= threshold) //the trigger condition
                                                                                                      {
                                                                                                              memcpy(vcp_buf, adc_buf + i + 1, VCP_BUF_SIZE * sizeof(uint32_t));
                                                                                                              vcp_buf[0] |= 0x80000000;  //mark the first sample in the frame
                                                                                                              CDC_Transmit_FS((uint8_t*)vcp_buf, VCP_BUF_SIZE * sizeof(uint32_t));
                                                                                                      }
                                                                                              }
                                                                                              HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, 0);
                                                                                      }
                                                                                      //restart adc
                                                                                        HAL_ADC_Start(&hadc2);
                                                                                        HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_SIZE);
                                                                                        HAL_TIM_Base_Start_IT(&htim2);
                                                                                        //led flashing
                                                                                        static int cnt = 0;
                                                                                        if((cnt++) % 128 == 0)
                                                                                        {
                                                                                                HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14); //Toggle the state of pin
                                                                                        }
                                                                              }
                                                                              

                                                                              Почему мы не можем передать через USB непосредственно содержимое исходного буфера? Так как скорость VCP слишком мала, мы не сможем передавать весь поток данных с АЦП. Мы захватываем кусок сигнала, передаём его «наверх», потом захватываем следующий кусок и т. д. Если мы не предпримем специальных мер, то в порт будут передаваться случайные фрагменты исходного сигнала. Поэтому нужно сделать программный аналог «триггера», как у цифрового осциллографа. Мы будем передавать в порт не рандомный фрагмент, захваченный АЦП, а кусок сигнала после возникновения некоторого условия. Таким условием может быть пересечение сигналом некоторого уровня в направлении снизу вверх: sample0_0 < threshold && sample0_1 >= threshold, где threshold — порог срабатывания.

                                                                              Именно для этого мы делаем буфер АЦП в два раза больше буфера VCP, и просматриваем его до середины в поисках такого условия. Если условие не наступило, не отправляем в порт ничего, и запускаем следующий цикл АЦП.

                                                                              DMA упаковывает сигналы с двух АЦП в одно 32-битное слово. Не будем менять этот формат, просто добавим единицу в старший разряд первого отчёта в буфере, чтобы ПО верхнего уровня могло распознать начало «кадра»:

                                                                              vcp_buf[0] |= 0x80000000;
                                                                              

                                                                              Для отображения сигнала на компьютере я написал маленькую программу на C#:

                                                                              Она в основном собрана из компонентов в Visual Studio и содержит минимум кода.
                                                                              Её исходники также доступны на Github.

                                                                              Что дальше


                                                                              В следующей части мы рассмотрим интерфейс Ethernet и немного операционную систему реального времени FreeRTOS.

                                                                              Ссылки


                                                                              Исходники проектов к всему циклу статей можно скачать на github. Все проекты сделаны для платы Nucleo F767ZI и используют IDE Atollic TRUEStudio.

                                                                              [1] AN2834 Application note. How to get the best ADC accuracy in STM32 microcontrollers
                                                                              [2] AN3116 Application note. STM32’s ADC modes and their applications
                                                                              [3] Cookbook for SAR ADC Measurements. Freescale Semiconductor. AN4373

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

                                                                              Комментарии (0)

                                                                                Let's block ads! (Why?)