Декодер медленного телевидения (SSTV), часть 2


Jоn Dаwsоn
https://101-things.readthedocs.io/en/latest/sstv_decoder_part2.html

       В первой части этого проекта продемонстрирован очень простой декодер SSTV, использующий Raspberry Pi Pico (RP2040) и недорогой TFT-дисплей ILI9341. Проект вызвал большой интерес, и я получил множество запросов и предложений, включая добавление новых режимов и функций. В этом обновлении я улучшил декодер SSTV, добавив более продвинутые функции, такие как кодировщик, поддержка SD-карт и меню-ориентированный пользовательский интерфейс. Проект вырос из простого скетча для Arduino в библиотеку функций SSTV, которую можно использовать в других проектах, с набором примеров схем для начала работы.

Новые режимы

Наиболее востребованными режимами являются PD120 и PD180. Именно эти режимы используются МКС для периодических передач из космоса. Это были первые новые режимы, которые были реализованы. Разрешение этих режимов значительно выше, чем у существующих режимов Мартина/Скотти, поэтому их пришлось уменьшить, чтобы они поместились на дисплее ILI9341.

На сайте Spacecomms можно скачать ряд аудиофайлов , которые были должным образом протестированы с помощью декодера Pico SSTV.

space_comms.jpg

Некоторые режимы было довольно просто реализовать, внеся изменения в существующие режимы. Режимы SC2 и ScottieDX можно было реализовать, изменив временные параметры существующих режимов. Режимы Robot24, Robot36 и Robot72 сложнее. В этих режимах используется кодирование yCrCb. Режим Robot 36 особенно сложно декодировать с использованием текущей архитектуры, поскольку компоненты Cr и Cb передаются попеременно в строках развертки. Дополнительная синхронизация (вроде бы) в 1500 Гц указывает на то, что строка развертки содержит информацию Cr, а 2300 Гц — на то, что строка развертки содержит информацию Cb. Благодарность Франциску Капуцци (IS0JSV) за его остроумный метод обнаружения и правильного декодирования цветности в этих режимах. В дополнение к цветным режимам Robot, декодер теперь также поддерживает черно-белые режимы Robot.

Библиотека

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

Я решил, что наилучшим подходом будет переход от скетча Arduino к созданию библиотеки Arduino. Одно из преимуществ библиотек Arduino — возможность включать множество примеров кода. Я решил использовать эту функцию, чтобы предоставить несколько различных примеров проектов, от самых простых до более полных.

  • sstv_receive_tft — Аналогично оригинальной конструкции, поддерживает оригинальное оборудование, но с новыми режимами.

  • sstv_recieve_sd — добавляет в базовую конструкцию простую функцию автоматической записи данных на SD-карту.

  • sstv_transmit_basic — минимальный пример только для передачи. Передает изображение с SD-карты.

  • sstv_full — Функции приема и передачи, хранение данных на SD-карте и полнофункциональный пользовательский интерфейс с меню.

Я надеялся, что преобразование проекта SSTV в библиотеку позволит повторно использовать код в других проектах и ??на различных аппаратных платформах. Проект Wio Terminal SSTV Франциску Капуцци (IS0JSV) представляет собой действительно замечательное устройство SSTV и является отличным примером того, как можно использовать библиотеку.

sstv.jpg

Если вы следили за развитием проекта Pi Pico Rx , вам может быть интересно узнать, что теперь приемник включает в себя встроенный декодер, основанный на этой библиотеке.

sstv_off_air1.png pico-rx-sstv.jpg
Пример встроенного SSTV-декодера в приемник Pi-Pico RX

Хранение изображений на SD-карте

sd_card_circuit.png
Схема подключения SD-карты

SDCARD_MISO 4 
SDCARD_MOSI 7
SDCARD_CS   5
SDCARD_SCK  6 

Одна из самых востребованных функций — хранение данных на SD-карте. Это значительно повышает удобство использования устройства, поскольку позволяет автоматически сохранять полученные изображения, а значит, декодер можно оставлять без присмотра. Я оставлял свой декодер работать на несколько дней подряд и периодически проверяю, что пришло.

poster

Хотя можно приобрести держатели для SD-карт, я решил использовать держатель, встроенный в большинство дисплеев ILI9341. Для подключения шины SPI к SD-карте требуется всего несколько дополнительных проводов. Я выбрал библиотеку SDFS, входящую в состав ядра Arduino Pico. Кроме того, библиотека VFS позволяет получать доступ к SD-карте с помощью стандартных функций библиотеки C.

Для хранения изображений я написал очень простую библиотеку, которая позволяет загружать и сохранять изображения в формате .bmp. Преимущество хранения на SD-картах заключается в том, что они позволяют сохранять изображения в полном разрешении, даже если их приходится уменьшать для отображения на TFT-дисплее.

SSTV-кодер (передатчик)

transmit_circuit.png
Схема подключения для передачи данных

По сравнению с декодером, кодер относительно прост в реализации. Аудиосигнал генерируется с помощью ШИМ, после чего используется фильтр и конденсатор, блокирующий постоянный ток. Код для обработки ШИМ-сигнала был заимствован из других проектов.

Процесс кодирования всегда начинается с фиксированной последовательности, состоящей из двух 300-миллисекундных импульсов с частотой 1900 Гц. Функция generate_tone принимает два параметра: частоту и длительность. Я использую 16 бит дробной части для представления длительности в миллисекундах. Высокое разрешение необходимо для поддержания точных временных параметров на протяжении всего времени передачи изображения. После этого кодирование изображения зависит от режима передачи.

void c_sstv_encoder :: generate_sstv(e_sstv_tx_mode mode)
{
  generate_tone(1900, 300 << 16);
  generate_tone(1200, 10 << 16);
  generate_tone(1900, 300 << 16);
  generate_vis_code(mode);

  //...

  generate_martin(mode);

}

Процесс кодирования обрабатывает изображение построчно. Каждая строка состоит из импульса для каждого цвета (RGB в случае Мартина). Каждый пиксель состоит из короткого импульса с частотой от 1500 Гц до 2300 Гц, с интервалом в 1500 Гц между цветами. В конце каждой строки отправляется горизонтальный синхронизирующий импульс с частотой 1200 Гц.

void c_sstv_encoder :: generate_martin(e_sstv_tx_mode mode)
{

  uint16_t width, height;
  float colour_time_ms;

  switch(mode)
  {
    case tx_martin_m1:
      width = 320;
      height = 240;
      colour_time_ms = 146.320;
      break;

    case tx_martin_m2:
      width = 320;
      height = 240;
      colour_time_ms = 73.216;
      break;

    default: return;
  }

  uint32_t hsync_pulse_ms_f16 = 4.862 * (1<<16);
  uint32_t colour_gap_ms_f16 = 0.572 * (1<<16);
  uint32_t pixel_time_ms_f16 = (colour_time_ms*(1<<16))/width;

  //send rows
  for(uint16_t row=0u; row < height; ++row)
  {
    generate_tone(1500, colour_gap_ms_f16);
    for(uint16_t col=0u; col < width; ++col)
      generate_tone(get_pixel(width, height, row, col, 1), pixel_time_ms_f16);

    generate_tone(1500, colour_gap_ms_f16);
    for(uint16_t col=0u; col < width; ++col)
      generate_tone(get_pixel(width, height, row, col, 2), pixel_time_ms_f16);

    generate_tone(1500, colour_gap_ms_f16);
    for(uint16_t col=0u; col < width; ++col)
      generate_tone(get_pixel(width, height, row, col, 0), pixel_time_ms_f16);

    generate_tone(1500, colour_gap_ms_f16);
    generate_tone(1200, hsync_pulse_ms_f16);
  }
}

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

void c_sstv_encoder :: generate_tone(uint16_t frequency, uint32_t time_ms_f16)
{
    uint32_t samples_exact_f16 = (m_Fs_Hz*time_ms_f16/1000) + m_residue_f16;
    uint32_t samples = samples_exact_f16 >> 16u;
    m_residue_f16 = samples_exact_f16-(samples << 16u);
    output_samples(frequency, samples);
}

Сами тоны генерируются с помощью простого фазового аккумулятора. Фазовый аккумулятор имеет высокое разрешение. 10 старших битов фазового аккумулятора управляют таблицей поиска, предварительно запрограммированной 16-битной синусоидальной волной. Сгенерированный сэмпл затем отправляется на ШИМ-аудиомодуль для вывода.

void c_sstv_encoder :: output_samples(uint32_t frequency, uint16_t samples)
{
    uint32_t step = (static_cast<uint64_t>(frequency)<<32)/m_Fs_Hz;
    for(uint16_t idx = 0; idx < samples; ++idx)
    {
      output_sample(m_sin_table[m_phase >> 22]);
      m_phase += step;
    }
}

Полный пример - Кодировщик/декодировщик с меню

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

full_circuit.png


Схема подключения для передачи данных

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

В состав ядра Arduino Pico входит библиотека для эмуляции EEPROM с использованием встроенной флэш-памяти Pi Pico. Эта функция используется для хранения пользовательских настроек и их восстановления после каждого выключения и включения питания.

Элемент

Количество

Пример URL

Примечания

Дисплей ILI9341 или ILI9342 с разрешением 320x240 (SPI)

1

https://shorturl.at/Kwjb0

Для получения изображений

Raspberry Pi Pico

1

https://shorturl.at/bKibr

Микроконтроллер

Резистор 10 кОм

2

https://shorturl.at/aSetc

Для получения изображений

Керамический конденсатор 100 нФ

2

https://shorturl.at/smvFK

1 для передачи, 1 для приема

Резистор 100 Ом

2

https://shorturl.at/QXFMh

Для передачи изображений

Керамический конденсатор 470 нФ

1

https://shorturl.at/hRgnC

Для передачи изображений

Стереоразъем 3,5 мм

1

https://shorturl.at/KUiZ2

1 для передачи, 1 для приема

Тактильные кнопки 6 мм

4

https://shorturl.at/IHNVn

Для интерфейса с меню

SD-карта

1

https://shorturl.at/C5DyY

Примеры использования SD-карт

Корпус, напечатанный на 3D-принтере

1

https://shorturl.at/M5z12

(Примечание: ссылки приведены в иллюстративных целях и не обязательно являются рекомендациями.)

Подключение дисплея (распиновка) показана ниже:

Сигнал

Номер пина
Дисплея

Номер пина Пико

Номер Pico
GPIO

Vcc

1

36 (3v3 out)

NA

GND

2

18 (GND)

NA

CS

3

17

13

RESET

4

36 (3v3 out)

NA

DC

5

15

11

MOSI

6

20

15

SCK

7

19

14

LED

8

36 (3v3 out)

NA

Четыре кнопки, используемые для навигации по меню, подключаются между контактом GND и свободным контактом GPIO:

Сигнал

Номер пина Пико

Номер Pico GPIO

Gnd

23 (GND)

NA

UP_BTN

22

26 (17)

DOWN_BTN

26

20

RIGHT_BTN

27

21

LEFT_BTN

29

22

Режим слайд-шоу

slideshow.jpg

Файловый браузер изображений просматривает все изображения в корневой папке SD-карты. Навигация по изображениям осуществляется с помощью кнопок «Далее» и «Назад». Файловый браузер также работает в режиме слайд-шоу, переходя к следующему изображению по истечении заданного времени ожидания. Если во время работы слайд-шоу получено изображение, декодер автоматически переключается в режим приема.

Текстовое наложение

text_overlay.jpg

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

Наложение текста реализовано с использованием буфера кадров, который позволяет отображать текст и графические примитивы в определенной области памяти. Код буфера кадров был повторно использован из проекта pico planetarium .

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

Корпус, напечатанный на 3D-принтере

enclosure_complete1.jpg

Конструкция корпуса, напечатанного на 3D-принтере, была переработана для обеспечения расширенной функциональности. В качестве отправной точки я использовал дизайн планетария , который уже предусматривает размещение 4 кнопок и TFT-дисплея.

Корпус обеспечивает легкий доступ к USB-порту Pico, а также позволяет использовать кнопку загрузки, не снимая ее с места, что упрощает процесс программирования через USB.

Я постарался спроектировать корпус максимально гибким, предусмотрев несколько различных передних панелей для размещения TFT-дисплеев разных размеров, от 2,4 до 3,2 дюймов. Доступ к разъему для SD-карты TFT-дисплея осуществляется через прорезь в верхней части корпуса. Стенки корпуса в этой области истончены, чтобы слот для SD-карты можно было обрезать под конкретный дисплей.

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

Для портативной работы корпус включает в себя вместительный батарейный отсек. Если вы хотите изучить возможность работы Pi Pico от батарей, в разделе 3.1 в техническом описании представлены несколько вариантов. Pico оснащен эффективным импульсным стабилизатором напряжения и может работать от 1,8 В до 5,5 В. Pico может работать от 2 или 3 батареек типа AA или AAA, или от одной литиевой батареи 3,7 В.

enclosure_parts.jpg

Корпус позволяет установить 4 тактильных переключателя размером 6 мм. Они припаиваются к предварительно нарезанной и просверленной макетной плате. Макетная плата крепится к панели с помощью плавких крепежных элементов, встроенных в переднюю панель. Те же плавкие крепежные элементы используются для крепления TFT-дисплея.

enclosure_construction_11.jpg enclosure_construction_21.jpg

enclosure_construction_41.jpg enclosure_construction_5.jpg

Передняя панель и крышка батарейного отсека крепятся саморезами M3x6 с потайной головкой.

Заключение

В этой версии декодер Pi Pico SSTV был расширен и превращен в более функциональное портативное устройство с поддержкой самых популярных режимов. Мы добавили интерфейс с меню, хранилище на SD-карте и браузер файлов образов.

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

В будущем я хотел бы достичь еще многого. В частности, я хотел бы расширить код, добавив поддержку небольшой камеры. Также я хотел бы расширить декодер, включив в него другие цифровые режимы, такие как FT8, PSK31 и RTTY. Кроме того, я хотел бы заняться разработкой функциональности CW. Следите за обновлениями!


Примечание от RA3TOX.

Собрал вариант полнофункционального декодера, скомпилировав файл sstv_full_web.ino из архива с примерами.

Монтаж выполнил на макетной плате 70х50 мм. С одной стороны платы находится микроконтроллер, с другой - дисплей и кнопки управления. Дисплей и МК установлены на разъёмных планках.

Конструкция RA3TOX Конструкция RA3TOX Конструкция RA3TOX Конструкция RA3TOX

Конструкция RA3TOX Конструкция RA3TOX

Для желающих я сделал разводку платы в программе Sprint Layot 5.0.
Файл разводки sstv-dek1.lay

Конструкция RA3TOX
Вид со стороны микроконтроллера (кликабельно)


[ На главную ] [ В раздел ] [ Декодер SSTV - часть 1 ]