Отладка интерфейса I2S

В этом тексте я написал про то как можно отлаживать интерфейс I2S.

I2S-это по сути труба для чисел в аудиоустройствах. Это проводной последовательный синхронный полнодуплексный интерфейс физического уровня для аудио ЦАП (ов) и АЦП. Интерфейс для связи в пределах одной печатной платы. Битовые частоты под 3MHz поэтому эту технологию можно причислить к Hi Load. Топология Master-Slave. Мастер выдает частоту синхронизации SCL и частоту дискретизации WS. Стандарт определяет битовую частоту до 2,7 MHz. Вся спека I2S насчитывает всего-навсего 7 страничек.

Что нам понадобится из железа?

Оборудование

Назначение

осциллограф Tektronix TDS 2014C

для измерения сигнала

логический анализатор Saleae и полный комплект цепляш для него.

для измерения сигнала

Android смартфон

для скриншотов и диагностический приложений

USB-Flash (ка)

для скриншотов c осциллографа

устройство с микроконтроллером, который поддерживает I2S

исследуемый прибор

4 щупа для осциллографа

для измерения сигнала

Что нужно из софтвера?

Программа

Назначение

Inkscape

Векторный графический редактор для анализа осциллограмм

Snipping Tool

Win (довая) утилита для селективных скриншотов

Audizr

Android приложение, которое показывает спектр аудиосигнала по данным с микрофона

Logic 2

Утилита от вендора для управления логическим анализатором

В теории правила обмена по I2S весьма простые:

1--Нужно минимум 3 провода: SCL, SW, SD

2--Формат передачи это two«s complement. То есть I2S передает знаковые целые числа и разрядность может быть абсолютно любой. Зависит от производителя микросхемы DAC. Для отладки придется научиться читать и интерпретировать бинарные представления типов данных int7_t, int13_t, int24_t и прочее.

3--Положительный перепад защелкивает данные.

4--Семпл передается старшим битом вперед BigEndiag.

5--Первый бит от предыдущего фрейма

6--WS 0V — левый канал WS 3.3V правый канал.

cef7b970e8fa9caa46305c7d5186b1f2.png

Как отлаживать I2S на очередном устройстве?
Можно постоянно отправлять в шину тестовый семпл 0×87654321. Этот семпл 0×87654321 очень удобно так как позволяет определить порядок байт и даже порядок бит в кадре. Можно добавить к модульным тестам I2S вот такой модульный тест.

static uint32_t array_tx[I2S_BLOCK_SIZE];

static bool test_i2s_write_one(uint8_t i2s_num) {
    LOG_INF(I2S, "%s() I2sNum %u", __FUNCTION__, i2s_num);
    uint32_t s = 0;
    for(s=0; s < ARRAY_SIZE(array_tx); s++){
    	array_tx[s]=0x87654321;
    }

    ASSERT_TRUE(i2s_api_write(i2s_num, array_tx, I2S_BLOCK_SIZE));
    return true;
}

Так как микроконтроллер LittleEndian, то в RAM памяти семпл 0x87654321 будет лежать так 0×21436587. Запустить тест можно по команде из UART-CLI.

e77cedf9287240ad2348ba404b06da1c.png

Теперь нужен логический анализатор. Вот что я получил на экране логического анализатора

ff79dd6297acb3471d932c3c7b943fc2.png

Тут SCL=3,125 MGz WS=45,9kHz. Отношение частот получается 69.7 раз. Что-то нет то. Сделаем скриншот в векторном редакторе проанализируем осциллограмму в бесплатной программе Inkscape.

2df0617630a502828dbff2ad8d47953f.png

Что то не сходится с ожидаемым 0×87654321. Непорядок. Несоответствие. Я ожидал на экране логического анализатора увидеть это 0b1000_0111_0110_0101_0100_0011_0010_0001 аполучилось какое-то 0×7AF5EBDx. В чем же дело?

Первое, что бросается в глаза это битовая скорость SCK, которая не поспевает за частотой дискретизации WS. При этом частота SCK не является непрерывной, а пуляет пачками по 7 тактов. Это очень-очень странно. Это как если бы такси-автомобиль по свободной автомагистрали бы ездил рывками.

Вернулся в код и увеличил на всякий случай частоту тактирования провода SCK. Выяснилось, что картинка слегка улучшилась. Теперь хотя бы данные стали чуть более похожи на правду. Но тем не менее появляются какие-то фантомные клоки, которые не отображаются на осциллограмме. Но если бы они были, то тестовый паттерн был бы похож на правду.

2fdba17083453a25d490b8995d359b7d.png

У меня появилось подозрение, что логический анализатор не работает. Я решил измерить частоту на проводе SCK обыкновенным осциллографом и увидел, что осцилл как раз показывает, что частота SCK вполне себе непрерывная. Отличная частота.

c7a7498e05acb8a0ec44b915c8df0b8f.png

Это значит, что логический анализатор Saleae (сало) как-то некорректно настроен. Заходим заново в программу логического анализатора (не перепутайте со Slack (ом))

6dbae0a90fa0dacdee2fe91ae3960a8d.png

Заходим в настройки каналов

e499b20e3bef8ab67e0c9c915e49f668.png

выставляем настройки как показано на скриншоте. Крайне важно поставить максимальную частоту дискретизации. Для данное модели это 500 000 000 семплов в секунду. Надеюсь, это даст нам четкую картинку трафика на шине I2S

c43caee27fb5195d07815b5e7afb5612.png

вот теперь с корректными настройками картинка добротная, четкая

f4466bf4e32daa6a232927d2d9ce465a.png

эта картинка отлично анализируется

77cba585ee5820b636b7222f0d1c4291.png

Битовая частота 2941000 Hz, частота дискретизации на проводе WS 45821 Hz. Как и положено битовая частота в 64 раза превышает частоту дискретизации.

Данные в I2S должны передаваться в формате BigEndian (старший байт вперед). То есть в привычной для человека форме. Сам же микроконтроллер хранит qword (ы) в Little Endian (младший байт вперед).

Проведем еще один тест. Сделаем явно чтобы в RAM памяти данные шли в порядке 0×87654321.

static uint8_t array_tx[I2S_BLOCK_SIZE];

static bool test_i2s_write_one(uint8_t i2s_num) {
    LOG_INFO(TEST, "%s() I2sNum %u", __FUNCTION__,i2s_num);
    uint32_t s=0;
    for(s=0; s

Запускаем тест. В RAM памяти семпл лежит в формате 0×87654321. Сначала старшие байты потом младшие. Так как действия происходят на LittleEndian процессоре, то uint32_t переменная на этой памяти примет значение 0×21436587.

163326009e76f80edd51d5e0d580069e.png

А на осциллограмме видно, что байты идут в инвертированном порядке по отношению к тому как байты следуют в RAM памяти микроконтроллера. Это значит что сначала посылаются младший байт затем старший. Вот и теперь еще раз получается, что контроллер I2C делает инверсию байт, что поданы как аргумент для I2S трансивера.

b205fb204925e15b4c3362f1cb89548c.png

То есть микроконтроллер nrf5340 посылает qword слова не так как они на самом деле лежать в RAM памяти, а в инверсном порядке байт! Одновременно с этим по стандарту I2S надо посылать в формате BigEndian. Порядок байт не совпадает. Порядок же бит в пределах байта корректный.

Что из этого следует?

Получается что перед отправкой семплы не надо разворачивать побайтово. Есть DAC у которых разрядность меньше 32 бит. Например 24 бита. Допустим я хочу воспроизвести синусоиду 800 Hz по предварительно расчитанной LUT таблице. Расcчитал пару периодов. Сохранил семплы в LUT. В столбце Tx значение, которое надо отправить. В столбце sample RAM подготовленное к отправке число в RAM памяти. Поэтому например -38=0xFFFFFFDA будет в массиве RAM cохранено как 0×00DAFFFF. Тогда оно будет отправлено I2S модулем как 0xFFFFDA и I2S DAC корректно распознает такой семпл.

LookUpTable (LUT) for 24-bit DAC
+-----+------------+------------+------------+
| No  | sample RAM |     sample | sample hex |
+-----+------------+------------+------------+
|   1 | 0x00000000 |          0 | 0x00000000 |
|   2 | 0x000d0000 |         13 | 0x0000000d |
|   3 | 0x001a0000 |         26 | 0x0000001a |
|   4 | 0x00250000 |         37 | 0x00000025 |
|   5 | 0x002d0000 |         45 | 0x0000002d |
|   6 | 0x00310000 |         49 | 0x00000031 |
|   7 | 0x00310000 |         49 | 0x00000031 |
|   8 | 0x002d0000 |         45 | 0x0000002d |
|   9 | 0x00260000 |         38 | 0x00000026 |
|  10 | 0x001b0000 |         27 | 0x0000001b |
|  11 | 0x000e0000 |         14 | 0x0000000e |
|  12 | 0x00000000 |          0 | 0x00000000 |
|  13 | 0x00f3ffff |        -13 | 0xfffffff3 |
|  14 | 0x00e6ffff |        -26 | 0xffffffe6 |
|  15 | 0x00dbffff |        -37 | 0xffffffdb |
|  16 | 0x00d3ffff |        -45 | 0xffffffd3 |
|  17 | 0x00cfffff |        -49 | 0xffffffcf |
|  18 | 0x00cfffff |        -49 | 0xffffffcf |
|  19 | 0x00d3ffff |        -45 | 0xffffffd3 |
|  20 | 0x00daffff |        -38 | 0xffffffda |
|  21 | 0x00e5ffff |        -27 | 0xffffffe5 |
|  22 | 0x00f2ffff |        -14 | 0xfffffff2 |
|  23 | 0x00ffffff |         -1 | 0xffffffff |
|  24 | 0x000d0000 |         13 | 0x0000000d |
|  25 | 0x001a0000 |         26 | 0x0000001a |
|  26 | 0x00240000 |         36 | 0x00000024 |
|  27 | 0x002c0000 |         44 | 0x0000002c |
|  28 | 0x00310000 |         49 | 0x00000031 |
|  29 | 0x00310000 |         49 | 0x00000031 |
|  30 | 0x002e0000 |         46 | 0x0000002e |
|  31 | 0x00260000 |         38 | 0x00000026 |
|  32 | 0x001c0000 |         28 | 0x0000001c |
|  33 | 0x000f0000 |         15 | 0x0000000f |
|  34 | 0x00010000 |          1 | 0x00000001 |
|  35 | 0x00f4ffff |        -12 | 0xfffffff4 |
|  36 | 0x00e7ffff |        -25 | 0xffffffe7 |
|  37 | 0x00dcffff |        -36 | 0xffffffdc |
|  38 | 0x00d4ffff |        -44 | 0xffffffd4 |
|  39 | 0x00cfffff |        -49 | 0xffffffcf |
|  40 | 0x00cfffff |        -49 | 0xffffffcf |
|  41 | 0x00d2ffff |        -46 | 0xffffffd2 |
|  42 | 0x00daffff |        -38 | 0xffffffda |
|  43 | 0x00e4ffff |        -28 | 0xffffffe4 |
|  44 | 0x00f1ffff |        -15 | 0xfffffff1 |
+-----+------------+------------+------------+
                ^
                |
               first byte in I2S

Что на входе DAC? При отладке I2S важно убедиться, что на осциллограмме есть переход от отрицательных PCM семплов в положительные PCM семплы

переход через O на I2S осцилограммепереход через O на I2S осцилограмме

Что на выходе DAC? Тут все просто. Надо увидеть синус.

51bab6147581826f3500f17ed998a3e5.png

Теперь и вы умеете отлаживать интерфейс I2S и можете учить других.

Вывод

В инженерном деле и в разработке Hi-Tech электроники в частности очень важно уметь проверить одно и то же как минимум 2 мя способами. Так можно найти и исключить баг в самих средствах измерения.

Может показаться странно, но программистам микроконтроллеров также важно уметь рисовать причем в векторных рисовалках типа программы inkscape.

© Habrahabr.ru