Friday, December 28, 2012

Portable console on STM32F407. Prat 3. Coordinate reeding, temperature and battery level from ADS7846.

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

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

Я уже частично начал рассказ о работе с сенсорным экраном в прошлой части статьи (все конкретно по режимам работы).

STM32 общается с контроллером сенсорного экрана по SPI. Полный запрос вмещается в один байт. Процесс получения данных выглядит: "Открытие диалога", "Последовательная отправка байта запроса", "Получение ответного байта (12/8 бит)", "Завершение диалога".

Содержание "байта запроса"







Описание битов "байта запроса"





















Из описания следует, что седьмой бит (START) должен быть всегда выставлен в 1.

Биты 6-4 (A2-A0) - выбор канала чтения.

Описание битов "байта запроса"












Бит 3 (MODE) управляет длиной ответного пакета данный (0 - 12 бит, 1 - 8 бит).

Бит 2 (SER/DFR) выбор режима (0 - дифференциальный режим, 1 - несимметричность режим).
Говоря практическим языком, если требуется читать координаты - выбирается дифференциальный режим (выставить в 0), а если получить значение батареи или датчика температуры - несимметричный (выставить в 1).


Несимметричный режим.

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


Дифференциальный режим.

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

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

(Ссылка на источник)

Биты 1 и 0 (PD1-PD0) отвечают за введение контроллера сенсорного экрана в различные режимы, в которых у контроллера сенсорного экрана будет разное энергопотребление.

Описание битов выбора режима контроллера


















Процедура записи данных:

static void WR_CMD (uint8_t cmd)
{
   /* Wait for SPI2 Tx buffer empty */
   while (SPI_I2S_GetFlagStatus(Open_SPI, SPI_I2S_FLAG_TXE) == RESET);
   /* Send SPI2 data */
   SPI_I2S_SendData(Open_SPI,cmd);
   /* Wait for SPI2 data reception */
   while (SPI_I2S_GetFlagStatus(Open_SPI, SPI_I2S_FLAG_RXNE) == RESET);
   /* Read Open_SPI received data */
   SPI_I2S_ReceiveData(Open_SPI);
}


Процедура чтения данных:

static int RD_AD(void)

{ 

   unsigned short buf,temp;

   /* Wait for Open_SPI Tx buffer empty */

   while (SPI_I2S_GetFlagStatus(Open_SPI, SPI_I2S_FLAG_TXE) == RESET);

   /* Send Open_SPI data */

   SPI_I2S_SendData(Open_SPI,0x0000);

   /* Wait for SPI2 data reception */

   while (SPI_I2S_GetFlagStatus(Open_SPI, SPI_I2S_FLAG_RXNE) == RESET);

   /* Read Open_SPI received data */

   temp=SPI_I2S_ReceiveData(Open_SPI);

   buf=temp<<8;

   DelayUS(1);

   while (SPI_I2S_GetFlagStatus(Open_SPI, SPI_I2S_FLAG_TXE) == RESET);

   /* Send Open_SPI data */

   SPI_I2S_SendData(Open_SPI,0x0000);

   /* Wait for Open_SPI data reception */

   while (SPI_I2S_GetFlagStatus(Open_SPI, SPI_I2S_FLAG_RXNE) == RESET);

   /* Read Open_SPI received data */

   temp=SPI_I2S_ReceiveData(Open_SPI);

   buf |= temp;

   buf>>=3;

   buf&=0xfff;

   return buf;

} 



Процедура получения координаты X:

int Read_X(void)

{  

   int i;

   TP_CS(0);

   DelayUS(1);

   WR_CMD(0x90);

   DelayUS(1);

   i=RD_AD();

   TP_CS(1);

   return i;

}



Процедура получения координаты Y:

int Read_Y(void)

{

   int i;

   TP_CS(0);

   DelayUS(1);

   WR_CMD(0xD0);

   DelayUS(1);

   i=RD_AD();

   TP_CS(1);

   return i;

} 



Процедура получения текущего уровня заряда:

int Read_Bat(void)

{

   int i;

   TP_CS(0);

   DelayUS(1);

   WR_CMD(0xa4);

   DelayUS(1);

    i=RD_AD();

   TP_CS(1);

   return i;

}



Ссылки на части статьи проекта:

Портативная консоль на STM32F407. Часть 1
Портативная консоль на STM32F407. Часть 2. Питание от батареи.

Portable console on STM32F407. Part 2. Battery.

На столе система работает замечательно. Но когда дело заходит о портативном устройстве, которое должно питаться от батареи, приходиться задумываться о том, что бы батареи хватало на длительный промежуток времени. Для этого нужно организовать режим сна, в котором контроллер будет как можно более экономичным. Эта статья будет посвящена тому, как я работал над переходом моей консоли в режим низкого энергопотребления, а так же расскажу про режим низкого энергопотребления в STM32. В моем проекте эту часть можно было реализовать аппаратно, поставив банальный выключатель или сделать систему на трех транзисторах, которая задействует две ножки контроллера и к тому же не очень надежна. Но что бы не вносить изменения в схему устройства, пришлось реализовывать все это программно. К счастью в STM32 есть 3 режима низкого энергопотребления, у каждого есть свои плюсы и минусы.
  • Sleep. Первая ступень экономичной работы.
    По умолчанию, после выполнения процессором Cortex инструкции WFE или WFI, отключается внутренняя синхронизация и прекращается выполнение кода программы. В режиме SLEEP, остальная часть STM32 продолжает работу. Выход из режима SLEEP происходит, когда УВВ (Устройство ввода-вывода) генерирует прерывание. Если STM32 синхр
    онизируется блоком ФАПЧ (Фазовая автоподстройка частоты) и HSE-генератором частотой 72 МГц и использует все УВВ, то при переходе в режим SLEEP потребляемый ток снизится до приблизительно 14.4мА. Тем не менее, если выполнить специальную подготовку STM32 к переходу в экономичный режим, отключив синхронизацию всех УВВ, кроме тех, что используются для возобновления работы процессора Cortex, и переключившись на синхронизацию от HSI-генератора (частоту которого можно снизить до 1 МГц и даже менее), можно добиться снижения потребляемого тока до приблизительно 0.5 мА.
    Потребляемый ток можно так же снизить до 0.14 мА
  • Stop. Вторая ступень экономичной работы. 
    Для этого необходимо установить бит SLEEPDEEP в регистре управления энергопотреблением ядра Cortex и сбросить бит Power Down Deep Sleep (PDDS) в регистре управления энергопотреблением STM32.
    После завершения конфигурации режима STOP, выполнение инструкции WFI или WFE приведет к остановке процессора Cortex и отключению HSI- и HSE-генераторов. Флэш-память, статическое ОЗУ и УВВ остаются запитанными, поэтому, состояние STM32 сберегается. Также как и в случае с режимом SLEEP, выход из режима STOP возможен путем генерации прерывания УВВ. Однако в режиме STOP синхронизация всех УВВ отключена, за исключением контроллера внешних прерываний. Таким образом, выход из режима STOP возможен при изменении состояния любой из линии ввода-вывода. Кроме того, у контроллера внешних прерываний имеется одна линия, которая может, как запрашивать, так и генерировать прерывание по достижении заданного времени часами реального времени. Поскольку у часов реального времени имеется отдельный генератор (LSI или LSE), то они могут использоваться для генерации периодических прерываний для вывода STM32 из режима STOP.
    После перехода STM32 в режим STOP его потребляемый ток снижается с миллиампер, потребляемых в режиме RUN, до приблизительно 24 мкА. Дальнейшего снижения энергопотребления можно добиться переводом внутреннего генератора в специальный экономичный режим работы. Для этого необходимо установить бит LPDS в регистре управления энергопотреблением STM32. Если при переходе в режим STOP данный бит был установлен, то потребляемый ток снизится до 14 мкА. Если используются часы реального времени, то потребляемый ток увеличится на 1.4 мкА.
  • StandBy. Третья ступень экономичной работы. STM32 можно настроить на работу в режиме STANDBY, если установить бит SLEEPDEEP в регистре управления энергопотреблением ядра Cortex и установить бит Power Down Deep Sleep в одноименном регистре STM32. После этого, выполнение инструкции WFI или WFE приведет к переводу STM32 в режим с наименьшим энергопотреблением. В режиме STANDBY STM32 абсолютно полностью бездействует. Отключены внутренний стабилизатор напряжения и HSE- и HSI-генераторы. В этом режиме STM32 потребляет ток всего лишь 2 мкА.
    В режиме STANDBY потребляемый ток равен 2 мкА, а задержка возобновления составляет 50 мкс. Выход из режима STANDBY возможен по прерыванию часов реального времени (достижение заданного времени) точно также как и при выходе из режима STOP. Кроме того, возобновление возможно через внешний вывод сброса STM32 или с помощью независимого сторожевого таймера. Выход из режима STANDBY также возможен по нарастающему фронту на линии 0 порта А. Данный вывод можно настроить, как вывод возобновления WKUP путем установки бита EWUP в регистре управления энергопотреблением и статуса. Поскольку режим STANDBY самый маломощный, то и выход из него осуществляется дольше всего: задержка возобновления исполнения инструкций составляет около 50 мкс.
    После перехода в режим STANDBY содержимое статического ОЗУ, регистров ядра Cortex и STM32 теряется. Выход из режима STANDBY практически идентичен программному сбросу.
Так как значения SRAM хранить было не обязательно, а все параметры из настроек хранятся на карте памяти, в проекте консоли было решено использовать режим StandBy. Что бы достичь как можно более низкого энергопотребления без внесения и нагромождения аппаратной части проекта, требовалось программно отключать (переводить в режим низкого энергопотребления) всю периферию. Сперва взялся за дисплей. Подсветка была на одной из ножки GPIO контроллера, поэтому это можно было оставить, так как при переходе в экономичный режим, все значения на портах вывода сбрасывались в ноль. Контроллер дисплея (ILI9481) потреблял около 14 мА, что достаточно много. Для решения данной проблемы необходимо ввести контроллер дисплея в режим Sleep. Для того что бы реализовать это с ILI9481, достаточно отправить контроллеру команду выбора регистра 0x10. Номер регистра для перехода в режим Sleep можно найти в документации на ваш дисплей. Вторым этапом понижения энергопотребления была сенсорная панель. В моем проекте использовался контроллер ADS7846, который кроме того, что может выдавать текущее состояние о нажатии, может отправлять текущее значение уровня заряда батареи, и значение с двух датчиков температуры (о получении координат, уровня заряда и температуры в следующей части статьи).
STM32 общается с контроллером сенсорного экрана по SPI. Полный запрос вмещается в один байт. Процесс получения данных выглядит: "Открытие диалога", "Последовательная отправка байта запроса", "Получение ответного байта (12/8 бит)", "Завершение диалога".   

Содержание "байта запроса"

Описание битов "байта запроса"

Из описания следует, что седьмой бит (START) должен быть всегда выставлен в 1.
(Полное описание в следующей части статьи)
Биты 1 и 0 (PD1-PD0) отвечают за введение контроллера сенсорного экрана в различные режимы, в которых у контроллера сенсорного экрана будет разное энергопотребление.

Описание битов выбора режима контроллера
В итоге, для того что бы перевести сенсорный экран в режим низкого энергопотребления, необходимо отправиться на контроллер 10000000 в бинарном виде или 0x80 в шестнадцатеричном.

На текущий момент удалось добиться потребления в режиме StandBy - 0.4 мА


(Функции работы с контроллером сенсорного экрана описаны в следующей части статьи)

Ссылки на части статьи проекта:

Портативная консоль на STM32F407. Часть 1

RGB and Alpha

Сегодня, работая с проектом консоли, реализованной на STM32F407, столкнулся с проблемой рисования графических элементов с процентным соотношением смешивания самого элемента и фонового графического изображения под ним (фона).

Рис. 7.1. Непрозрачный чайник
Непрозрачный чайник
Рис. 7.2. Прозрачный чайник
Прозрачный чайник
  


Для реализации данной задачи, достаточно одной очень простой формулы.




В проекте консоли, цвета представляются в формате RGB. Будем брать в процентном соотношении коэффициент прозрачности (от 0.0 до 1.0) и разность 1 и коэффициента прозрачности фона. Формулу применяем и для R, и для G, и для B. Вот что получилось в итоге:
NEW.R = FIGURE.R * ALPHA + BACKGROUND.R * (1 - ALPHA)
NEW.G = FIGURE.G * ALPHA + BACKGROUND.G * (1 - ALPHA)
NEW.B = FIGURE.B * ALPHA + BACKGROUND.B * (1 - ALPHA)
где NEW - это результирующий цвет смешивания, FIGURE - цвет фигуры (которая накладывается), BACKGROUND - цвет фона, на который накладывается фигура (изображение).
Вот собственно и всё.

Tuesday, December 25, 2012

Johny - A smart friendly robot


v.3.0.0
Началось все ещё года 2 назад. Этот робот постоянно модернизировался и вот так он выглядит на сегодняшний день. В этой версии была полностью переделана главная плата (но распиновка периферии почти не изменилась). Так же были добавлены боковые оптические датчики, в следствии чего робот перестал натыкаться на стены и объекты, к которым подъезжал под углом (ультразвук отражался от стен). Ориентация робота в пространстве улучшилась в разы. Был снят ИК приемопередатчик, поэтому теперь роботом нельзя управлять с пульта от телевизора  На замену ему появился Bluetooth. Скорость общения 9600. На компьютере организован виртуальный COM-порт. Имея такую беспроводную связь, можно в последствии развить проект, что робот будет отправлять данные на компьютер, и компьютер основываясь на полученных данных  (а так же видео с камеры, полученные из ресивера) может строить карту помещения, распознавать объекты, двигаться по проложенным маршрутам (когда сформирует полную карту помещения).
 Новые мозги
                              
Боковые оптические датчики

 
                                   
Предыдущих версии:

v.2.0.0 (вид сбоку)

v.2.0.0 (вид спереди)

v.2.0.0 (вид сзади)

В версии v.2.0.0 главным изменением было то, что у робота теперь вместо "светодиодной" головы были установлены ультразвуковые датчики и аналоговая видео камера, которая работает независимо от робота (передает видео на ресивер по беспроводному соединению). Вместо двух "мозгов" (главный контроллер и "светодиодная голова") теперь один. Раньше, за звуки отвечала "светодиодная голова", теперь робот вынужден молчать (но к счастью вскоре на роботе появился звуковой модуль, который способен воспроизводить аудио-файлы в формате .wav).

Самая первая версия робота (v.1.0.0):

Управляется с помощью пульта. Нет никакой ориентации, никаких датчиков. Только весёлый робот и потешные рожицы на RGB матрице 8х8. 







Portable console on STM32F407. Part 1. Introduction









Началось все с того, что приобрел ЖК дисплей разрешением 320x480 (ILI9481) и резистивный сенсорный экран с контроллером ADS7846. Дисплей подключал по FSMC. Контроллер сенсорного экрана по SPI.
В начале работы выполняется инициализация RTC (Read Time Clock), а так же параметры для перехода в режим сна (STANDBY Mode, потребление около 2мкА).

Были разработаны следующие драйвера:
  • Драйвер управления дисплеем:
    • Инициализация и настройка FSMC
    • Инициализация и настройка контроллера дисплея
    • Заливка экрана
    • Заливка пикселя
    • Рисования текста (используя таблицу шрифтов, в данном проекте это шрифт размерами 5x8)
    • Рисование основных геометрических примитивов (линии, эллипсы, прямоугольники)
    • Рисование изображений с внутренней (flash) памяти
    • Рисование изображений с карты памяти
    • Аппаратная прокрутка содержимого дисплея
  • Драйвер управления сенсорным экраном:
    • Инициализация и настройка SPI
    • Инициализация и настройка контроллера сенсорного экрана
    • Сохранение калибровочных данных на карту памяти
    • Загрузка калибровочных данных с карты памяти
    • Считывание значения текущего напряжения батареи (в ADS7843 такой функции нет)
  • Драйвер управления картой памяти:
    • Настройка транспорта SDIO
    • Реализация технологии файловой системы (FatFs)
Драйвер для управления дисплеем разделяется на два файла. В первом по шаблону записаны основные функции, такие как: настройка транспорта, инициализация, вывод пикселя, и получение разрешения дисплея. (эти файлы носят названия с конкретным названием дисплея, по сути они являются низкоуровневыми драйверами, имея множество таких файлов заполненных по одному шаблону, можно менять устройство вывода без каких либо затруднений). А так же файлы низкоуровневого управления (текст, фигуры, графика). 
Разобравшись с работой USART в STM32, я реализовал систему общения, буферизации принятых данных, и вывода принятых данных на дисплей. При полном заполнении экрана текстом, выполняется аппаратная прокрутка со смещением содержимого рабочей области терминала на одну строку.
Размер буфера можно изменять по мере необходимости (изначально был установлен в 50 000 символов, чего вполне хватало для умеренной работы). Для моргания курсора специально завел таймер, при срабатывании которого изменяется состояние курсора, и на каждое 100 срабатывание выполняется обновление значений и прорисовка часов и батареи. 
Также ввел поддержку esc-последовательностей (которые начинаются с \e и зависят от двух параметров), которые часто используются в терминалах для выделения участков теста цветом. Функции перевода строки, перевода каретки и табуляция так же поддерживаются. 
В процессе работы, вся полученная информацию из USART записывается на карту памяти в файле LOG.txt. Все настройки сохраняются в SETTINGS.txt
Реализована система обработки пользовательских элементов (кнопки, формы) при срабатывании сенсорного экрана. 
Встроенная пользовательская клавиатура для набора текста. Имеет русскую и английскую раскладку, а так же почти все символьные знаки что и на классической клавиатуре. При открытии и закрытии изменятся высота рабочей зоны терминала и зоны аппаратной прокрутки содержимого.
На панели задач отображается текущий номер страницы и клавиши переключения страниц (неактивны при развёрнутой клавиатуре). Индикатор батареи, который может быть раскрашен 3 цветами в зависимости от уровня заряда (зелёный, жёлтый, красный). Внутри индикатора отображается текущее время в формате часы : минуты. А так же кнопки открытия меню и изменения состояния клавиатуры.
В меню выполняется настройка скорости порта (BaudRate), и текущего времени. Там же можно перейти в режим сна (для выхода из режима сна необходимо нажать боковую кнопку на устройстве, при нажатии которой происходит перелистывание страниц вверх).
Ведется обслуживание USB Host для HID устройств. Мышку обслуживает здорово, правда иногда не с первого раза подхватывает. Клавиатуру классическую (больших размеров) тоже нормально обслуживает, но тоже порой не с первого раза подхватывает, и при нажатии на Caps Lock/Num Lock/Scroll Lock не зажигаются светодиоды на клавиатуре. А вот с клавиатурой небольших размеров (так же беспроводными) ничего не выходит - при нажатии клавиш ничего не приходит. (Может кто имел дело с этим?)
Так же на данном устройстве в последствии будет установлен Bluetooth модуль, с помощью которого можно будет общаться с устройствами без проводов.