embedded-hal
embedded-hal copied to clipboard
Reuse pins given to driver (e.g. SPI or I2C)
I would like to write a driver for the (not so popular) TLC5957 LED driver chip, which has a rather convoluted serial protocol.
Like many devices with an internal shift register, this one uses a LAT signal to latch data from the serial shift register to one of the internal registers (config, color, etc). However, the target register is indicated by how many consecutive SCLK cycles the LAT signal is asserted, and data is latched on LAT deassertion.
For example, if lat is asserted during the ...
- ... 15 last SCLK cycles, the configuration register is open for writing and the last 16 bits are trashed
- ... 5 last SCLK cycles, data is written to the configuration register
- ... last SCLK cycle, data is written to the color register of the current LED and so on.
Since all those "commands" do not align to the usual 8 bits of a SPI word, there is no way to toggle a gpio at some arbitrary precise moment of a SPI transfer, two solutions are possible:
- full SPI bit banging without using hardware SPI at all
- partial bit-banging during the last 16 bits of a transaction
Of course the second solution is the ideal one, since it will be faster than pure bit-banging, but I cannot figure out how to make a pin alternate at will between being part of the SPI driver and manually controlled, since the SPI driver takes ownership of the Pin struct, and cannot give it back.
let sclk = gpioa.pa5.into_alternate_push_pull(&mut gpioa.cr1);
let miso = gpioa.pa6;
let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.cr1);
let mut spi = Spi::spi1(
hal.SPI1,
(sclk, miso, mosi),
&mut afio.mapr,
/* more crap */
);
// sclk & co have been moved in the SPI struct
// In the driver
let led: [u8; 6] = [/* LED color data */];
spi.transfer(led[0..3]); // Write first 4 bytes
// Bit-bang last 2 bytes with LAT signal
let (sclk, miso, mosi) = spi.release(); // <--- THIS is what I am looking for
let sclk = sclk.into_push_pull();
// ... and so on ...
Is there an existing API to achieve this I am not aware of? Is there a way to circumvent this limitation?