Arduino: FM-радиомодуль на микросхеме RDA5807m

разделы: Arduino , RDA5807M , дата: 2 апреля 2017г.

Данный модуль на Али торгуется по цене около 20р, и представляет собой полноценный сканирующий радиоприемник FM диапазона с управлением по I2C интерфейсу.

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

    На официальном сайте производителя заявлены следующие возможности чипа:
  1. CMOS single-chip fully-integrated FM tuner
  2. Low power consumption
  3. Support worldwide frequency band
  4. Support flexible channel spacing mode
  5. Support RDS/RBDS
  6. Digital low-IF tuner
  7. Fully integrated digital frequency synthesizer
  8. Autonomous search tuning
  9. Support 32.768KHz crystal oscillator
  10. Digital auto gain control (AGC)
  11. Digital adaptive noise cancellation
  12. Programmable de-emphasis (50/75 μs)
  13. Receive signal strength indicator (RSSI) and SNR
  14. Bass boost
  15. Volume control and mute
  16. Line-level analog output voltage
  17. 32.768 KHz 12M,24M,13M,26M,19.2M,38.4MHz Reference clock
  18. Only support 2-wire bus interface
  19. Directly support 32Ω resistance loading
  20. Integrated LDO regulator
  21. MSOP-10pins

Говоря по-русски, здесь нам обещают управление через I2C интерфейс(400KHz). Поддержку приема текстовых сообщений - RDS/RBDS(последний формат используется исключительно в США). Работа от часового кварца. Возможность прямого подключения 32-омных(плеерных) наушников. Индикация уровня сигнала - RSSI. Несколько диапазонов FM: Западная Европа, Восточная Европа, Япония, всемирный диапазон). Частотная коррекция(de-emphasis). Авто-регулировка усиления.

Чип предназначен для использования в сотовых телефонах, автомагнитолах, планшетах, ноутбуках, MP3 и MP4 плеерах.

Однако скачать datasheet с официального сайта не получится. Это видимо особенность всего китайского бизнеса(попробуйте найти datasheet на ESP8266). Неофициальное руководство на английском можно скачать например здесь.

Шина I2C формируется двумя подтягивающими резисторами. Если подключить к модулю питание и воспользоваться мультиметром, то на SDA и SCL можно будет наблюдать высокий потенциал. Это значит, что подтягивающие резисторы для формирования I2C шины не нужны, они уже есть и работают.

Если запустить сканер I2C шины, то обнаружатся три устройства с адресам: 0x20, 0x22, 0xC0. При обращении по адресу 0xC0, устройство работает в режиме совместимости чипа NXP TEA5767.

При обращении по адресу 0x20 устройство работает в режиме блочной записи/чтения. В этом режиме, в начале I2C сессии, указатель адреса при записи автоматически сбрасывается в значения 0x02, при чтении он устанавливается в 0х0А. Если счетчик адреса достигает значения 0x3A, то после он сбрасывается в ноль. Счетчик адреса автоматически увеличивается на единицу при обращении к регистрам.

Регистры 16-битные. Всего функциональных регистров двенадцать: c 0x02 по 0x0F.

При обращении по адресу 0x22 доступен режим произвольного доступа с регистрам. В таком случае протокол работы походит на DS1307, за тем исключением, что регистры двух-байтные, и при операциях записи чтения сначала записывается/читается старший байт регистра, а потом младший. В остальном все тоже самое:

запись произвольного регистра в RDA5897M:

1)начало сессии: формируется START
2)запись байта : посылается адрес 0x22
3)запись байта : посылается адрес записываемого регистра
4)запись байта : записывается старший байт регистра
5)запись байта : записывается младший байт регистра
6)завершение сессии: формируется STOP



чтение произвольного регистра в RDA5897M:

1)начало сессии: формируется START
2)запись байта : посылается адрес 0x22
3)запись байта : посылается адрес считываемого регистра
4)завершение сессии: формируется STOP

5)начало сессии: формируется START
2)запись байта : посылается адрес (0x22 + 0х01) // режим чтения
4)чтение байта : считывается старший байт регистра
5)чтение байта : считывается младший байт регистра
6)завершение сессии: формируется STOP

Замечу, что в "неофициальном руководстве" режим произвольного доступа к регистрам не рассматривается.

Карта регистров устройства:

Если подключить к чипу только лишь питание, то так проверить его работоспособность не получится. Чип будет молчать, даже белого шума не услышите. Включить его можно только через I2C интерфейс.

Если на гитхабе в строке поиска ввести rda5807m, то первым выпадет проект за авторством csdexter:

Это библиотека для Arduino. Скачав ZIP архив и распаковав его в папку Arduino/libraries, следует загрузить единственный пример содержащийся в библиотеке:

Это программа управления радиоприемником через UART. Т.к автор, судя по всему из Северной Америки, нам нужно поменять диапазон частот на RDA5807M_BAND_WORLD, чтобы можно было слушать FM диапазон. Там еще есть диапазон RDA5807M_BAND_EAST, т.е. Восточная Европа, но это УКВ диапазон, на котором сейчас никто не вещает.

В README проекта сказано, что т.к. модуль на 3.3V, то подключать его к Arduino следует через преобразователь логических уровней. Но за насколько дней подключения напрямую, у меня с модулем ничего не случилось. Можно сделать вывод, что I2C порт модуля устойчив к 5V логике. Т.о. подключение модуля к Arduino такое:

    RDA5807M        Arduino
    GND     <===>   GND
    Vcc     <===>   3.3V
    SDA     <===>   Analog Pin 4
    SCL     <===>   Analog Pin 5

    Antenna  ===>    Обычный провод длинной ~20см

    ROUT+LOUT+GND <==> стерео-джек плеерных наушников

После подключения модуля к Arduino и загрузки скетча в микроконтроллер, в наушниках будет такой звук: "Пииииуууу". Это нормально. Радио включилось, теперь нужно найти радиостанцию.

Управляется модуль через последовательный порт. Послав знак вопроса можно получить подсказку по командам:

По команде s должна найтись станция, и наконец-то пойти звук. Командой f можно напечатать частоту станции, а командой q можно посмотреть уровень приема.

Можно немного доработать конструкцию добавив обработку нажатия трех кнопок, для управления радиоприемником без компьютера. Схему подключения кнопки можно найти здесь: Практическое программирование Arduino/CraftDuino - цифровой ввод - кнопка

Модифицированный скетч:

/*
* RDA5807M Example Sketch
*
* This example sketch illustrates how to use some of the basic commands in the
* RDA5807M Library. The sketch will start the RDA5807M in West-FM mode
* (87-108MHz) and then wait for user commands via the serial port.
* More information on the RDA5807M chip can be found in the datasheet.
*
* HARDWARE SETUP:
* This sketch assumes you are using the RRD-102 (V2.0) breakout board.
*
* The board should be connected to a 3.3V Arduino's I2C interface.
* Alternatively, a 5V Arduino can be used if a proper I2C level translator is
* used (see the README for an example).
* You will need an audio amplifier as the RDA5807M is too weak to directly drive
* a pair of headphones. Immediate candidates would be a pair of active
* (multimedia) speakers that you're probably already using with your computer.
* You will also need a proper antenna connected to breakout board. Luckily
* for you, this is a very forgiving chip when it comes to "proper" antennas,
* so for FM only you will be able to get away with just a 2ft (60cm) length of
* wire connected to the FM antenna pad on the shield. Decent results can
* probably be obtained using a 6" breadboard jumper wire too.
*
* USING THE SKETCH:
* Once you've connected the RRD-102 to your Arduino board (and antenna(s), as
* appropriate), connect the Arduino to your computer, select the corresponding
* board and COM port from the Tools menu and upload the sketch. After the sketch
* has been updated, open the serial terminal using a 9600 baud speed. The sketch
* accepts single character commands (just enter the character and press 'send').
* Here is a list of the acceptable commands:
*   v/V     - decrease/increase the volume
*   s/S     - seek down/up with band wrap-around
*   m/M     - mute/unmute audio output
*   f       - display currently tuned frequency
*   q       - display RSSI for currently tuned station
*   t       - display decoded status register
*   ?       - display this list
*
*/

#define BTN_1  12
#define BTN_2  11
#define BTN_3  10

//Due to a bug in Arduino, this needs to be included here too/first
#include <Wire.h>

//Add the RDA5807M Library to the sketch.
#include <RDA5807M.h>

//Create an instance of the RDA5807M named radio
RDA5807M radio;
//Other variables we will use below
char command;
word status, frequency;

void setup()
{
  pinMode(BTN_1, INPUT);
  //Create a serial connection
  Serial.begin(9600);

  //Initialize the radio to the West-FM band. (see RDA5807M_BAND_* constants).
  //The mode will set the proper receiver bandwidth.
  radio.begin(RDA5807M_BAND_WORLD);
}

void loop()
{
  //Wait until a character comes in on the Serial port.
  if(Serial.available()){
    //Decide what to do based on the character received.
    command = Serial.read();
    switch(command){
      case 'v':
        if(radio.volumeDown()) Serial.println(F("Volume decreased"));
        else Serial.println(F("ERROR: already at minimum volume"));
        Serial.flush();
        break;
      case 'V':
        if(radio.volumeUp()) Serial.println(F("Volume increased"));
        else Serial.println(F("ERROR: already at maximum volume"));
        Serial.flush();
        break;
      case 's':
        Serial.println(F("Seeking down with band wrap-around"));
        Serial.flush();
        radio.seekDown();
        break;
      case 'S':
        Serial.println(F("Seeking up with band wrap-around"));
        Serial.flush();
        radio.seekUp();
        break;
      case 'm':
        radio.mute();
        Serial.println(F("Audio muted"));
        Serial.flush();
        break;
      case 'M':
        radio.unMute();
        Serial.println(F("Audio unmuted"));
        Serial.flush();
        break;
      case 'f':
        frequency = radio.getFrequency();
        Serial.print(F("Currently tuned to "));
        Serial.print(frequency / 100);
        Serial.print(".");
        Serial.print(frequency % 100);
        Serial.println(F("MHz FM"));
        Serial.flush();
        break;
      case 'q':
        Serial.print(F("RSSI = "));
        Serial.print(radio.getRSSI());
        Serial.println("dBuV");
        Serial.flush();
        break;
      case 't':
        status = radio.getRegister(RDA5807M_REG_STATUS);
        Serial.println(F("Status register {"));
        if(status & RDA5807M_STATUS_RDSR)
            Serial.println(F("* RDS Group Ready"));
        if(status & RDA5807M_STATUS_STC)
            Serial.println(F("* Seek/Tune Complete"));
        if(status & RDA5807M_STATUS_SF)
            Serial.println(F("* Seek Failed"));
        if(status & RDA5807M_STATUS_RDSS)
            Serial.println(F("* RDS Decoder Synchronized"));
        if(status & RDA5807M_STATUS_BLKE)
            Serial.println(F("* RDS Block E Found"));
        if(status & RDA5807M_STATUS_ST)
            Serial.println(F("* Stereo Reception"));
        Serial.println("}");
        Serial.flush();
        break;
      case '?':
        Serial.println(F("Available commands:"));
        Serial.println(F("* v/V     - decrease/increase the volume"));
        Serial.println(F("* s/S     - seek down/up with band wrap-around"));
        Serial.println(F("* m/M     - mute/unmute audio output"));
        Serial.println(F("* f       - display currently tuned frequency"));
        Serial.println(F("* q       - display RSSI for current station"));
        Serial.println(F("* t       - display decoded status register"));
        Serial.println(F("* ?       - display this list"));
        Serial.flush();
        break;
    }
  }

  // BUTTON HANDLER
  int val = digitalRead(BTN_1);
  if(val==HIGH)   // if button pressed
  {
    Serial.println(F("Seeking down with band wrap-around"));
    Serial.flush();
    radio.seekDown();
  }

  val = digitalRead(BTN_2);
  if(val==HIGH)   // if button pressed
  {
      if(radio.volumeDown())
        Serial.println(F("Volume decreased"));
      else
        Serial.println(F("ERROR: already at minimum volume"));

      Serial.flush();
  }


  val = digitalRead(BTN_3);
  if(val==HIGH)   // if button pressed
  {
      if(radio.volumeUp())
        Serial.println(F("Volume increased"));
      else
        Serial.println(F("ERROR: already at maximum volume"));

      Serial.flush();
  }

  delay(100);

}

Здесь первая кнопка дублирует команду s, вторая - v, третья - V. Если стереовыход подключать к компьютерной аккустике, то вторая и третья кнопки будут не нужны. Уровень громкости можно будет регулировать на самой аккустике.

Выглядит все это как-то так:

Теперь Arduino можно запитать от обычной зарядки от телефона. Минимальный FM приемник готов.

поделиться: