Skip to content

Sysctl SPI rework

what's happening

  • we can bump the clock to 4MHz, 10x faster than before. this also makes transmission more reliable
  • the response time to SPI commands needs to be pretty tight in the firmware, and then we can get rid of massive delays in the driver
  • to negotiate this support, i introduce API version 2 which is derived from the firmware build date
  • when API >= 2 is detected, the delays are strongly reduced
  • to make pocket reform LPC fw SPI responsive enough, i put it on a 5ms timer interval that checks the SPI inbox, returns if empty, otherwise reads 4 bytes
  • got rid of the unnecessary "parser"
  • also updating the battery info for SPI more often now so we can do higher fidelity monitoring over sysfs
  • matching LPC driver MR: reform-tools!127 (merged)

some SPI theory

  • in SPI, write/read is always one simultaneous transaction, which means that, for example, 8 bytes can be written and read at the same time. but:
    • there are FIFOs that buffer reading and writing in the ARM PrimeCell SPI block
    • this isn't always practical for request/response patterns
    • the pico-sdk read/write API is designed so that you do half-duplex:
      • when you write() from the pico side, it'll read and discard the same number of bytes from the host
      • when you read() from the pico side, it'll send the same number of dummy bytes (i.e. 0xff, you can specify)
    • the linux spi_read()/spi_write() are meant for full duplex, but use the FIFO buffers.
      • linux spi_write() sends what you pass in to the client, but doesn't discard the (dummy) response
      • so if you use the normal read() from the pico, you have to do a useless spi_read() on the linux side to consume those bytes that are now in the read buffer from the previous write()
    • if you write from linux using spi_write(), and then read that on the rp2040 using spi_read_blocking(), you don't need to explicitly write something back, because that's already part of the read in the pico API
      • and you need to consume this dummy response on the linux side, it doesn't get automatically discarded
  • in the original classic lpc11u24 firmware, to read the command from the host, i just manually did: uint8_t rx = LPC_SSP0->DR; (not filling the write buffer at the same time!)
  • to stay compatible i need to do the same on the rp2040/rp2350 and can't use spi_read_blocking, so i'll do rx = (uint8_t)spi_get_hw(spi)->dr; (equivalent). this also avoids an extra spi_read(with len=4) call on the linux side before reading the actual response (with len=8).
Edited by minute

Merge request reports

Loading