3.22. SPI em código¶
machine.SPI encapsula um controlador SPI por hardware; as linhas CS são saídas Pin normais geridas pelo script. Construa uma instância SPI com o id do barramento, a frequência de relógio desejada e (se necessário) o modo:
from machine import SPI, Pin
spi = SPI(0, baudrate=1_000_000, polarity=0, phase=0)
cs = Pin("P3", Pin.OUT, value=1) # CS idle high
O id seleciona qual o bloco SPI por hardware a utilizar; os números disponíveis e os pinos SCK/MOSI/MISO a que mapeiam dependem da placa (consulte o Placas OpenMV). baudrate é a frequência SCK em hertz – a taxa efetiva que o hardware atinge pode ser ligeiramente inferior devido à divisão do relógio, o que o valor impresso do objeto SPI mostrará.
O pino CS é construído com value=1 para que fique inativo no estado desativado. Cada transação ativa o CS (coloca-o a baixo), transfere os bytes e desativa o CS (coloca-o a alto) novamente.
3.22.1. Leitura, escrita e troca¶
Três métodos cobrem os casos mais comuns:
cs.value(0)
spi.write(b"\x10\x20\x30") # send 3 bytes, ignore what comes back
cs.value(1)
cs.value(0)
data = spi.read(4) # read 4 bytes; sends 0x00 while reading
cs.value(1)
rx = bytearray(2)
cs.value(0)
spi.write_readinto(b"\x9F\x00", rx) # send 0x9F, 0x00; receive 2 bytes
cs.value(1)
write() é o caminho rápido apenas de escrita; o controlador envia os bytes e descarta o que o periférico tiver enviado de volta em MISO. read() é a imagem espelho – debita N pulsos SCK enquanto envia um byte fictício fixo (0 por omissão) em MOSI e armazena os bytes MISO. write_readinto() é a forma full-duplex: envia os bytes de um buffer e armazena os bytes MISO simultâneos noutro. Muitos periféricos utilizam este padrão – «enviar um byte de comando e depois ler a resposta na transferência seguinte» – pelo que as duas operações se encaixam naturalmente numa única chamada write_readinto.
A maioria dos periféricos exige que a linha CS permaneça ativa durante toda a transação (dos bytes de comando aos bytes de resposta), por isso mantenha os parênteses cs.value(0) / cs.value(1) em torno de toda a sequência e não em torno de cada chamada de método.
3.22.2. Uma leitura típica de sensor¶
Muitos sensores SPI organizam o seu estado como um conjunto de registos internos e seguem o mesmo padrão de troca: enviar o endereço do registo (com um indicador de leitura/escrita no bit mais significativo), depois ler ou escrever os bytes do registo. Uma leitura do registo 0x0F num tal dispositivo:
rx = bytearray(2)
cs.value(0)
spi.write_readinto(b"\x8F\x00", rx) # 0x80 = "read" flag, then reg 0x0F
cs.value(1)
register_value = rx[1]
O primeiro byte MISO é inválido (o dispositivo ainda estava a receber o comando nesse momento); o segundo byte MISO contém o conteúdo do registo. O formato exato do byte de comando – qual o bit do indicador de leitura/escrita, se o endereço incrementa automaticamente em leituras de múltiplos bytes – está na folha de dados do dispositivo.
3.22.3. Bit-banging¶
A instância SPI acima utiliza um bloco SPI por hardware: um periférico dedicado dentro do MCU com o seu próprio registo de deslocamento e gerador de relógio que produz as formas de onda SCK / MOSI / MISO em silício. O software limita-se a entregar-lhe um byte; os bits movem-se no fio sem mais intervenção da CPU, deixando-a livre para realizar outro trabalho em paralelo.
A alternativa é o bit-banging: o software percorre cada bit e comuta diretamente os pinos GPIO para produzir a mesma forma de onda. Não há nenhum periférico de hardware envolvido – a CPU coloca SCK a baixo, define MOSI, coloca SCK a alto, amostra MISO, e assim sucessivamente para cada bit de cada byte. Isto ocupa a CPU durante toda a transação e é mais lento do que o bloco de hardware consegue, mas funciona em qualquer pino e não necessita de um bloco de hardware disponível.
machine.SoftSPI é a implementação por bit-banging da mesma API SPI:
from machine import SoftSPI, Pin
spi = SoftSPI(baudrate=500_000, polarity=0, phase=0,
sck=Pin("P2"), mosi=Pin("P0"), miso=Pin("P1"))
Utilize-o quando o dispositivo precisar de estar em pinos que não estão ligados a um bloco SPI por hardware, ou quando os blocos de hardware estiverem todos em utilização. 500 kHz é um limite confortável na maioria das câmaras; a CPU fica ocupada durante toda a transação.