класс I2S – протокол шины Inter-IC Sound

Класс I2S управляет шиной Inter-IC Sound (I2S) в режиме контроллера – MCU генерирует тактовый сигнал битов (SCK) и тактовый сигнал выбора слова (WS) и обменивается данными сэмплов по линии SD. Драйвер поддерживает непрерывный DMA в фоновом режиме, поэтому со стороны Python требуется лишь поддерживать заполнение внутреннего буфера сэмплов. Режимы периферийного устройства / только приёма не поддерживаются.

Доступно на STM32 OpenMV cam, у которых разведена периферия I2S, и на OpenMV Cam RT1062. Не предоставляется на OpenMV Cam AE3 (порт alif).

I2S(2) на STM32 OpenMV cam использует те же выводы, что и SPI(2) – тактовый сигнал битов на P2 (SCK), выбор слова на P3 (NSS), а линия последовательных данных следует соглашению о направлении данных SPI: TX использует P0 (MOSI), RX использует P1 (MISO).

Пример – вывод (TX). Создание шины TX для управления внешним аудио-DAC на частоте 44.1 кГц, 16-битные моно-сэмплы, с резервным DMA-буфером размером 16384 байта (16 КиБ):

from machine import I2S, Pin

audio_out = I2S(
    2,
    sck=Pin("P2"), ws=Pin("P3"), sd=Pin("P0"),
    mode=I2S.TX,
    bits=16,
    format=I2S.MONO,
    rate=44100,
    ibuf=16384,
)

Пример – ввод (RX). Создание шины RX, захватывающей данные с микрофона на частоте 22.05 кГц, 32-битное стерео (левый + правый, чередующиеся), с резервным DMA-буфером размером 16384 байта (16 КиБ):

from machine import I2S, Pin

audio_in = I2S(
    2,
    sck=Pin("P2"), ws=Pin("P3"), sd=Pin("P1"),
    mode=I2S.RX,
    bits=32,
    format=I2S.STEREO,
    rate=22050,
    ibuf=16384,
)

Методы передачи можно использовать тремя способами:

Блокирующийwrite() и readinto() возвращают управление только после завершения операции:

num_written = audio_out.write(buf)   # blocks until buf is drained
num_read = audio_in.readinto(buf)    # blocks until buf is filled

Неблокирующий – установите функцию обратного вызова с помощью irq(), и методы передачи вернут управление немедленно. Функция обратного вызова вызывается из планировщика MicroPython, когда DMA опустошает буфер TX или заполняет буфер RX:

audio_out.irq(i2s_callback)
num_written = audio_out.write(buf)   # returns immediately

audio_in.irq(i2s_callback)
num_read = audio_in.readinto(buf)    # returns immediately

asyncioI2S является потоком и может быть обёрнут в asyncio.StreamReader / asyncio.StreamWriter:

swriter = asyncio.StreamWriter(audio_out)
swriter.write(buf)
await swriter.drain()

sreader = asyncio.StreamReader(audio_in)
num_read = await sreader.readinto(buf)

Конструктор

class machine.I2S(id: int, *, sck: Pin, ws: Pin, sd: Pin, mck: Pin | None = None, mode: int, bits: int, format: int, rate: int, ibuf: int)

Создаёт объект I2S с заданным id:

  • id идентифицирует конкретную шину I2S; зависит от платы и порта

Параметры, передаваемые только по ключевому слову, которые поддерживаются на всех портах:

  • sck – объект вывода для линии последовательного тактового сигнала

  • ws – объект вывода для линии выбора слова

  • sd – объект вывода для линии последовательных данных

  • mck – объект вывода для линии основного тактового сигнала; частота основного тактового сигнала равна частоте дискретизации * 256

  • mode задаёт приём или передачу

  • bits задаёт размер сэмпла (биты), 16 или 32

  • format задаёт формат каналов, STEREO или MONO

  • rate задаёт частоту дискретизации аудио (Гц); это частота сигнала ws

  • ibuf задаёт длину внутреннего буфера (байты)

Для всех портов DMA работает непрерывно в фоновом режиме и позволяет пользовательским приложениям выполнять другие операции, пока данные сэмплов передаются между внутренним буфером и периферийным блоком I2S. Увеличение размера внутреннего буфера потенциально увеличивает время, в течение которого пользовательские приложения могут выполнять операции, не связанные с I2S, до возникновения недополнения (например, метод write) или переполнения (например, метод readinto).

Методы

init(*, sck: Pin, ws: Pin, sd: Pin, mck: Pin | None = None, mode: int, bits: int, format: int, rate: int, ibuf: int) None

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

deinit() None

Деинициализирует шину I2S

readinto(buf: bytearray) int

Считывает аудио-сэмплы в буфер, заданный параметром buf. buf должен поддерживать протокол буфера, например bytearray или array. Порядок байтов «buf» – little-endian. Для формата Stereo сэмпл левого канала предшествует сэмплу правого канала. Для формата Mono используются данные сэмпла левого канала. Возвращает количество прочитанных байтов

write(buf: bytes) int

Записывает аудио-сэмплы, содержащиеся в buf. buf должен поддерживать протокол буфера, например bytearray или array. Порядок байтов «buf» – little-endian. Для формата Stereo сэмпл левого канала предшествует сэмплу правого канала. Для формата Mono данные сэмпла записываются как в правый, так и в левый канал. Возвращает количество записанных байтов

irq(handler: Callable[[I2S], None]) None

Устанавливает функцию обратного вызова. handler вызывается, когда buf опустошается (метод write) или становится заполненным (метод readinto). Установка функции обратного вызова переводит методы write и readinto в неблокирующий режим работы. handler вызывается в контексте планировщика MicroPython.

static shift(*, buf: bytearray, bits: int, shift: int) None

побитовый сдвиг всех сэмплов, содержащихся в buf. bits задаёт размер сэмпла в битах. shift задаёт количество битов для сдвига каждого сэмпла. Положительное значение – для сдвига влево, отрицательное – для сдвига вправо. Обычно используется для управления громкостью. Каждый сдвиг на один бит изменяет громкость сэмпла на 6 дБ.

Константы

RX: int

для инициализации mode шины I2S на приём

TX: int

для инициализации mode шины I2S на передачу

STEREO: int

для инициализации format шины I2S как стерео

MONO: int

для инициализации format шины I2S как моно