classe I2S – protocolo de barramento Inter-IC Sound

A classe I2S controla um barramento Inter-IC Sound (I2S) no modo controlador – o MCU gera o clock de bits (SCK) e o clock de seleção de palavra (WS) e troca dados de amostras na linha SD. O driver suporta DMA contínuo em segundo plano, de modo que o lado Python só precisa manter o buffer interno de amostras abastecido. Os modos periférico / somente recepção não são suportados.

Disponível em câmeras OpenMV STM32 que conectam um periférico I2S e na OpenMV Cam RT1062. Não exposto na OpenMV Cam AE3 (porta alif).

I2S(2) em câmeras OpenMV STM32 compartilha seus pinos com SPI(2) – clock de bits em P2 (SCK), seleção de palavra em P3 (NSS), e a linha de dados serial segue a convenção de direção de dados do SPI: TX usa P0 (MOSI), RX usa P1 (MISO).

Exemplo – saída (TX). Construa um barramento TX para controlar um DAC de áudio externo a 44,1 kHz, amostras mono de 16 bits, com um buffer de DMA de 16384 bytes (16 KiB):

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,
)

Exemplo – entrada (RX). Construa um barramento RX que captura de um microfone a 22,05 kHz, estéreo de 32 bits (esquerdo + direito intercalados), com um buffer de DMA de 16384 bytes (16 KiB):

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,
)

Os métodos de transferência podem ser usados em três estilos:

Bloqueantewrite() e readinto() retornam somente após a conclusão da operação:

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

Não bloqueante – instale um callback com irq() e os métodos de transferência retornam imediatamente. O callback é executado pelo escalonador do MicroPython quando o DMA esvazia o buffer TX ou enche o buffer 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 é um stream e pode ser encapsulado por 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)

Construtor

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)

Constrói um objeto I2S com o id fornecido:

  • id identifica um barramento I2S específico; é dependente da placa e da porta

Parâmetros somente por palavra-chave que são suportados em todas as portas:

  • sck é um objeto pino para a linha de clock serial

  • ws é um objeto pino para a linha de seleção de palavra

  • sd é um objeto pino para a linha de dados serial

  • mck é um objeto pino para a linha de clock mestre; a frequência do clock mestre é a taxa de amostragem * 256

  • mode especifica recepção ou transmissão

  • bits especifica o tamanho da amostra (bits), 16 ou 32

  • format especifica o formato do canal, STEREO ou MONO

  • rate especifica a taxa de amostragem de áudio (Hz); esta é a frequência do sinal ws

  • ibuf especifica o comprimento do buffer interno (bytes)

Em todas as portas, o DMA é executado continuamente em segundo plano e permite que as aplicações do usuário realizem outras operações enquanto os dados de amostra são transferidos entre o buffer interno e a unidade do periférico I2S. Aumentar o tamanho do buffer interno tem o potencial de aumentar o tempo que as aplicações do usuário podem realizar operações não relacionadas a I2S antes de um underflow (ex.: método write) ou overflow (ex.: método readinto).

Métodos

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

veja o Construtor para as descrições dos argumentos

deinit() None

Desinicializa o barramento I2S

readinto(buf: bytearray) int

Lê amostras de áudio para o buffer especificado por buf. buf deve suportar o protocolo de buffer, como bytearray ou array. A ordenação de bytes de “buf” é little-endian. Para o formato Estéreo, a amostra do canal esquerdo precede a amostra do canal direito. Para o formato Mono, os dados da amostra do canal esquerdo são usados. Retorna o número de bytes lidos

write(buf: bytes) int

Escreve as amostras de áudio contidas em buf. buf deve suportar o protocolo de buffer, como bytearray ou array. A ordenação de bytes de “buf” é little-endian. Para o formato Estéreo, a amostra do canal esquerdo precede a amostra do canal direito. Para o formato Mono, os dados da amostra são escritos em ambos os canais, direito e esquerdo. Retorna o número de bytes escritos

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

Define um callback. handler é chamado quando buf é esvaziado (método write) ou fica cheio (método readinto). Definir um callback altera os métodos write e readinto para operação não bloqueante. handler é chamado no contexto do escalonador do MicroPython.

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

deslocamento bit a bit de todas as amostras contidas em buf. bits especifica o tamanho da amostra em bits. shift especifica o número de bits a deslocar cada amostra. Positivo para deslocamento à esquerda, negativo para deslocamento à direita. Tipicamente usado para controle de volume. Cada deslocamento de bit altera o volume da amostra em 6dB.

Constantes

RX: int

para inicializar o mode do barramento I2S como recepção

TX: int

para inicializar o mode do barramento I2S como transmissão

STEREO: int

para inicializar o format do barramento I2S como estéreo

MONO: int

para inicializar o format do barramento I2S como mono