3.22. 코드로 보는 SPI¶
machine.SPI는 하드웨어 SPI 컨트롤러를 감쌉니다. CS 선은 스크립트가 관리하는 일반적인 Pin 출력입니다. 버스 id, 원하는 클럭 속도, 그리고 (필요하다면) 모드를 지정하여 SPI 인스턴스를 생성하십시오:
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
id는 어느 하드웨어 SPI 블록을 사용할지 선택합니다. 사용 가능한 번호와 그것이 매핑되는 SCK/MOSI/MISO 핀은 보드에 따라 다릅니다(OpenMV 보드 참조). baudrate는 SCK 주파수를 헤르츠 단위로 나타냅니다. 하드웨어가 실제로 달성하는 속도는 클럭 분주로 인해 약간 더 낮을 수 있으며, SPI 객체의 출력된 값에서 이를 확인할 수 있습니다.
CS 핀은 유휴 시 비활성화 상태가 되도록 value=1로 생성됩니다. 모든 트랜잭션은 CS를 활성화하고(로우로 구동), 바이트를 이동시킨 다음, 다시 CS를 비활성화합니다(하이로 구동).
3.22.1. 읽기, 쓰기, 교환¶
세 가지 메서드가 일반적인 경우를 처리합니다:
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()는 쓰기 전용 고속 경로입니다. 컨트롤러는 바이트를 밀어 넣고 주변장치가 MISO로 되돌려 보낸 것은 무엇이든 폐기합니다. read()는 그 거울상으로, MOSI에 고정된 더미 바이트(기본값 0)를 보내면서 N개의 SCK 펄스를 클럭으로 내보내고 MISO 바이트를 저장합니다. write_readinto()는 전이중 형태입니다. 한 버퍼의 바이트를 보내면서 동시에 들어오는 MISO 바이트를 다른 버퍼에 저장합니다. 많은 주변장치가 이 패턴을 사용하며 – “명령 바이트를 보낸 다음, 이어지는 전송에서 응답을 읽는다” – 따라서 이 두 작업은 자연스럽게 하나의 write_readinto 호출에 들어맞습니다.
대부분의 주변장치는 CS 선이 트랜잭션 전체(명령 바이트부터 응답 바이트까지) 동안 활성화 상태로 유지되기를 기대합니다. 따라서 cs.value(0) / cs.value(1) 괄호를 각 메서드 호출이 아니라 전체 시퀀스 둘레에 두십시오.
3.22.2. 전형적인 센서 읽기¶
많은 SPI 센서는 자신의 상태를 일련의 내부 레지스터 집합으로 구성하며 동일한 교환 형태를 따릅니다: 레지스터 주소(최상위 비트에 읽기/쓰기 플래그를 포함)를 보낸 다음, 레지스터의 바이트를 읽거나 씁니다. 이러한 장치에서 레지스터 0x0F를 읽는 예:
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]
첫 번째 MISO 바이트는 쓰레기 값입니다(그 시점에 장치는 아직 명령을 수신하고 있었습니다). 두 번째 MISO 바이트가 레지스터 내용을 담고 있습니다. 정확한 명령 바이트 형식 – 어느 비트가 읽기/쓰기 플래그인지, 다중 바이트 읽기에서 주소가 자동 증가하는지 – 은 장치의 데이터시트에 나와 있습니다.
3.22.3. 비트뱅잉(bit-banging)¶
위의 SPI 인스턴스는 하드웨어 SPI 블록을 사용합니다. 이는 MCU 내부의 전용 주변장치로, 자체 시프트 레지스터와 클럭 생성기를 갖고 SCK / MOSI / MISO 파형을 실리콘에서 생성합니다. 소프트웨어는 그저 바이트를 건네줄 뿐이며, 비트는 CPU의 추가 도움 없이 선 위에서 이동하므로 CPU는 병렬로 다른 작업을 자유롭게 처리할 수 있습니다.
대안은 비트뱅잉입니다. 소프트웨어가 각 비트를 루프로 돌면서 GPIO 핀을 직접 토글하여 동일한 파형을 생성합니다. 관여하는 하드웨어 주변장치가 없습니다. CPU가 SCK를 로우로 구동하고, MOSI를 설정하고, SCK를 하이로 구동하고, MISO를 샘플링하는 식으로 모든 바이트의 모든 비트에 대해 이를 수행합니다. 이는 트랜잭션 전체 동안 CPU를 묶어두고 하드웨어 블록보다 느리게 동작하지만, 어떤 핀에서도 동작하며 하드웨어 블록이 비어 있을 필요가 없습니다.
machine.SoftSPI는 동일한 SPI API의 비트뱅잉 구현입니다:
from machine import SoftSPI, Pin
spi = SoftSPI(baudrate=500_000, polarity=0, phase=0,
sck=Pin("P2"), mosi=Pin("P0"), miso=Pin("P1"))
장치가 하드웨어 SPI 블록에 배선되지 않은 핀에 연결되어야 할 때, 또는 하드웨어 블록이 모두 사용 중일 때 이를 사용하십시오. 500 kHz는 대부분의 캠에서 무난한 상한이며, CPU는 트랜잭션 전체 동안 바쁘게 유지됩니다.