Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

Компоненты и материалы

Goldilocks Analogue (прототип) — или Arduino Uno + MCP4822 DAC + микрофонный усилитель + усилитель наушников 1
MAX9744 (усилитель наушников) 1
MAX9814 (микрофонный усилитель) 1
MCP4921 DAC 1
Arduino UNO 1
Arduino Wireless Shield (XBee) 1

О проекте

Строю продвинутый клон Arduino на базе AVR ATmega1284p с особыми фичами: 12-битный ЦАП MCP4822, усилитель наушников, 2x SPI память (SRAM, EEPROM), SD-карта. Реальных применений для аналоговых выходов много, но у Arduino нет встроенного ЦАП, поэтому мало опубликованных проектов с аналоговыми сигналами. Walkie-Talkie — пример использования цифрового и аналогового вместе для простого, но полезного проекта.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

Сама функциональность Walkie-Talkie — всего несколько строк кода, но она построена на фундаменте: аналоговый ввод (сэмплирование), аналоговый вывод на SPI шине к MCP4822, рутины тайминга сэмплов, и цифровая радиоплатформа XBee. Давайте начнем сверху и углубимся по слоям.

XBee Radio

Использую XBee Pro S2B, настроенные на точечную связь. Нужен один Coordinator, другой Router. Конфигурационные гайды в интернете.

Радиомодули настроены на максимальное межсимвольное время перед отправкой пакета — пакеты уходят только когда полные (84 байта). Это максимизирует пропускную способность. Сырая пропускная способность 250 кбит/с, но реальная пользовательская скорость ~32 кбит/с. Это влияет на частоту сэмплирования и качество речи.

С 8-битными сэмплами ~3 кГц сэмплирования генерирует столько данных, сколько можно передать без сжатия. Сжатие — для другого проекта.

XBee в AT-режиме — прозрачный последовательный канал между двумя концами. Простейший способ связать два устройства по цифровому радио. Позволил простое тестирование проводами перед проверкой радио.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

На трассировке логического анализатора видно приход пакетов XBee на (фиолетовую) линию Rx. Принятые данные складываются в кольцевой буфер и воспроизводятся с постоянной скоростью. Буфер приема до 255 байт — достаточно, так как пакет XBee 84 байта.

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

Частота сэмплирования

Рассчитываем битовый бюджет: 8 бит × 3000 Гц = 24 кбит/с для передачи. Это работает хорошо. 4 кГц слишком близко к теоретическому максимуму и работает плохо.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

На логическом анализаторе видно приход пакета, начинающегося с 0x7E 0x7C на Rx. И микрофонный усилитель, и выход ЦАП смещены вокруг 0x7F(FF), так что уровни сигнала здесь очень низки. Частота сэмплирования 3000 Гц.

Обработка сэмплов

Поставил "пинг" на выход для захвата момента обработки прерывания сэмплирования (желтый след). Видно, что время в прерывании очень мало относительно доступного. Возможно, можно реализовать сжатие данных.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

В прерывании сэмплирования две главные активности: генерация аудио выхода — запись сэмпла в ЦАП, и чтение АЦП для захвата аудио сэмпла и передачи в USART буфер.

Это делает функция audioCodec_dsp, вызываемая из таймерного прерывания.

Использую 8-битный Timer0 AVR для генерации регулярных интервалов сэмплирования через прерывание. Используя частоту MCU, являющуюся двоичным кратным стандартным аудио частотам, можно генерировать точные частоты сэмплирования только 8-битным таймером с предделителем 64. Для нестандартных частот (44100 Гц) нужен 16-битный Timer1 для достаточной точности без предделителя.

АЦП ATmega1284p в свободном режиме, масштабирован до 192 кГц. Близко к максимальной скорости захвата для 8-битных сэмплов, но в спецификации.

Прерывание занимает 14 мкс, очень мало относительно 333 мкс на период сэмпла. Остается время на UI или доп. аудиообработку.

SPI транзакция

На детальном уровне видим реальную SPI транзакцию вывода входящего сэмпла в MCP4822 ЦАП.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

Приложение построено на Goldilocks Analogue Prototype 2 со стандартной SPI шиной. Поздние прототипы используют Master SPI Mode на USART 1 ATmega1284p — немного ускоряет SPI через двойную буферизацию и освобождает обычную SPI для одновременной работы с SD-картой или SPI памятью для аудиостриминга. В Walkie-Talkie аудиозахват не нужен, поэтому старый прототип и обычная SPI подходят.

Заключение

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

Это тест добавления микрофонного входа на базе MAX9814 к Goldilocks Analogue. Буду перерабатывать Прототип 3 и добавлю схему усиления микрофона для приложений, нуждающихся в аудиовходе: walkie-talkie, войс чейнджеры, вокальные музыкальные синтезаторы.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

Также запускаю ATmega1284p на повышенной частоте 24.576 МГц (стандарт 20 МГц). Эта частота позволяет точную генерацию аудио сэмплов от 48 кГц до 4 кГц (даже до 1500 Гц). Дополнительные такты MCU на период сэмпла очень полезны для синтеза музыки.

Код на Sourceforge AVR freeRTOS. Привет Шуяну из SeeedStudio — их OPL крутой, источник многих компонентов и PCB.

Код

audioCodec_dsp (C/C++)

void audioCodec_dsp(uint16_t *ch_A, uint16_t *ch_B) {
  int16_t xn;
  uint8_t cn;
  
  /*----- Audio Rx -----*/
  if(ringBuffer_IsEmpty((ringBuffer_t*)&(xSerialPort.xRxedChars))) {
    cn = 0x80 ^ 0x55; // A-Law нулевой сигнал на выход
  } else if (ringBuffer_GetCount(&(xSerialPort.xRxedChars)) > (portSERIAL_BUFFER_RX>>1)) {
    cn = ringBuffer_Pop((ringBuffer_t*)&(xSerialPort.xRxedChars)); // поп два сэмпла, первый отбрасываем
    cn = ringBuffer_Pop((ringBuffer_t*)&(xSerialPort.xRxedChars));
  } else {
    cn = ringBuffer_Pop((ringBuffer_t*)&(xSerialPort.xRxedChars));
  }
  alaw_expand1(&cn, &xn); // расширение A-Law компрессии
  *ch_A = *ch_B = (uint16_t)(xn + 0x7fff); // сдвиг в положительную область, вывод на A и B каналы
  
  /*----- Audio Tx -----*/
  AudioCodec_ADC(&mod7_value.u16); // сэмпл 10 бит left justified
  xn = mod7_value.u16 - 0x7fe0; // центрирование сэмпла к 0
  IIRFilter(&tx_filter, &xn); // фильтрация передаваемого сэмпла
  alaw_compress1(&xn, &cn); // компрессия A-Law
  xSerialPutChar(&xSerialPort, cn); // передача сэмпла
}

Прерывание таймера (C/C++)

ISR(TIMER0_COMPA_vect) __attribute__ ((hot, flatten));
ISR(TIMER0_COMPA_vect) {
#if defined(DEBUG_PING)
  PORTD |= _BV(PORTD7); // Ping IO line (желтый след)
#endif
  
  DAC_out(ch_A_ptr, ch_B_ptr); // передача данных в MCP4822 — первая для регулярности (меньше джиттер)
  
  if (audioHandler != NULL)
    audioHandler(ch_A_ptr, ch_B_ptr); // глобальный аудио обработчик (callback)
    
#if defined(DEBUG_PING)
  PORTD &= ~_BV(PORTD7);
#endif
}

Вывод в ЦАП (C/C++)

void DAC_out(const uint16_t *ch_A, const uint16_t *ch_B) {
  DAC_command_t write;
  if (ch_A != NULL) {
    write.value.u16 = (*ch_A) >> 4;
    write.value.u8[1] |= CH_A_OUT;
  } else {
    write.value.u8[1] = CH_A_OFF;
  }
  SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC; // SS low
  SPDR = write.value.u8[1];
  while (!(SPSR & _BV(SPIF)));
  SPDR = write.value.u8[0];
  
  if (ch_B != NULL) {
    write.value.u16 = (*ch_B) >> 4;
    write.value.u8[1] |= CH_B_OUT;
  } else {
    write.value.u8[1] = CH_B_OFF;
  }
  while (!(SPSR & _BV(SPIF)));
  SPI_PORT_SS_DAC |= SPI_BIT_SS_DAC; // SS high, защелкиваем значение
  
  SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC; // SS low для канала B
  SPDR = write.value.u8[1];
  while (!(SPSR & _BV(SPIF)));
  SPDR = write.value.u8[0];
  while (!(SPSR & _BV(SPIF)));
  SPI_PORT_SS_DAC |= SPI_BIT_SS_DAC; // SS high
}

AVRfreeRTOS на Sourceforge — репозиторий порта freeRTOS для AVR, включая DAC.h и файлы аналогового тестирования. Не используйте связанный GitHub, идите на Sourceforge для актуального кода.

Схемы

Схема не абсолютно точна: использует MCP4725 (I2C), а не MCP4822 (SPI), в Fritzing не было нужной платы Adafruit. Нарисована в одном направлении (кроме перекрещенных Rx/Tx). XBee платы просто заменяют два провода Rx/Tx. Любой радиокомплект с достаточной пропускной способностью подойдет.

Продвинутый XBee Walkie-Talkie на Arduino с ЦАП и аудиоусилителями

Схема выхода ЦАП и усилителя наушников. Микрофонный усилитель будет добавлен в прототип 4.

Производственный процесс

  1. Ключевые соображения для высокообъемной швейцарской обработки
  2. Руководство по ЧПУ-прототипированию: точность, скорость и экономичное производство
  3. Экспертное производство валов: точные процессы и индивидуальные решения
  4. Пассивация нержавеющей стали: усиление коррозионной стойкости и производительности
  5. Измерение аналоговых датчиков на Raspberry Pi с одним GPIO-пином
  6. Использование АЦП MCP3008 для чтения аналоговых датчиков с Raspberry Pi
  7. Высокоточная генерация волновых форм на базе ЦАП с пользовательской печатной платой
  8. Умный контроллер полива на Windows 10 IoT, Raspberry Pi и XBee-датчиках влажности
  9. Почему аналоговые измерения драйвят производительность завода
  10. Продвинутые экранированные кабели для сигнальных цепей: практические методы подключения (Часть 2)