Best approach for intercepting SPI bus traffic - Page 1
Forum section: electronics / projects

author: HwAoRrDk
author_rank: Super Contributor
timestamp: March 12, 2018, 05:30:00 pm
content: I have a device that uses SPI to talk to its LCD character-based front panel display, which simply plugs in via wires to the main board. What I would like to do (and what I have seen done in the past by others) is to have the LCD display some auxiliary information instead of the standard, but to also be able to switch back to the standard display at any point.The display has the usual SPI lines: SCK, MOSI, and SS - but no MISO as it doesn't talk back. It also has a couple of extra lines: RS and AC, which I believe are used to as 'register selection' and 'address change' inputs that affect what the LCD does with data sent over MOSI.The way I have seen this been done before is that the MOSI line is cut, and a 2:1 mux (i.e. SPDT analog switch) - an SN74LVC1G3157 I believe - is inserted. It is connected such that by default the MOSI line passes straight through as normal, but when the mux is switched, the MOSI line is split. The mainboard side goes instead to the MOSI input of the third-party MCU, and the LCD side is instead connected to the 3rd-party MCU's MISO pin. The SCK, SS, RS and AC are simply tapped by the 3rd-party MCU, going either to the appropriate SPI (SCK, SS) or general I/O (RS, AC) pins. So, essentially, the 3rd-party MCU masquerades as the LCD slave, and the actual LCD becomes a slave to the MCU, where the MCU instead of talking back via its MISO to the real master on the mainboard, is talking to the LCD instead.However, I am not convinced this is the best way to do it, because I think it has some downsides. The first is that it is all still reliant on the existing SCK. If the mainboard is not clocking that line, no communication is possible. Luckily, it appears the mainboard is constantly talking to the LCD, so this appears not to be an actual problem. However, I think the fact that the RS and AC lines are still shared may be problematic, because if the mainboard happens to toggle them at the wrong time, then whatever you're actually trying to write to the LCD may be wrongly interpreted.A better solution I'm thinking is to split the SPI bus completely and use an MCU with two SPI peripherals, with each side connected to one. One will act completely as if it were the LCD slave, and one will act as the new master to the LCD. And, to provide pass-through when the MCU is 'off', perhaps use something like a 74HC365 non-inverting hex buffer? How does this sound?

author: SparkyFX
author_rank: Frequent Contributor
timestamp: March 12, 2018, 08:55:26 pm
content: Usually (afaik) SCK and SS (Slave/Chip Select) need to be timed and communication usually starts by pulling CS low, so if there is any chance that a switchover occurs asynchronous or misses a clock tick, you would need to start over by pulling CS low. Without being able to control the clock you would not have control over the length of data, not to mention special cases in which the clock needs to be pulled longer to a state while some writing occurs or whatever. Some SPI specs contain such details that require full software contol over SCK or at least CS.I assume it would be less critical to go with a solution in which the MCU handles all display communication.Of course all that said without any detailed logs or info about the display used.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: March 12, 2018, 09:26:38 pm
content: Yes, I am not sure how the previous solution I've seen handles switchover potentially happening in the middle of a transfer. Difficult to imagine it doing something like de-asserting CS and hoping that the partial data received by the LCD doesn't mess it up. I'm not even sure electrically how it would override CS - the pin on the MCU would be fighting that of the SPI master on the mainboard.I have a feeling that solution must always be actively monitoring the SPI bus - even when ostensibly 'off' - and timing the user request for switchover to whenever CS is high. Then just "riding the tail" of the mainboard SPI master's activity and transmitting its own data on its MISO to the LCD whenever a transfer comes in on MOSI. Control of the clock is not really important, as the data length per transfer never changes - the LCD only ever takes 8 bits per transfer.

author: Buriedcode
author_rank: Super Contributor
timestamp: March 13, 2018, 02:52:01 am
content: I would put an MCU between the main MCU and LCD. It's task for the most part is just to repeat its input - you could then wait for appropriate conditions to add "extra" on the then stuff sent to the LCD.Using an MCU with two SPI ports (obviously) and DMA would make this easier. If the main MCU writes a lot of data, but you need to add something in between those, you'll need a ring buffer/FIFO.With Cortex M0's being pretty cheap these days, it shouldn't be too hard to get a SAMD21 or something. even those "blue pill" (STM32?) that are everywhere. Even if 99% of the time its literally just parroting the input, having the MCU there makes upgrades easier.

author: David Hess
author_rank: Super Contributor
timestamp: March 13, 2018, 07:56:51 pm
content: Quote from: HwAoRrDk on March 12, 2018, 09:26:38 pmThat is probably what I would do but I would multiplex the clock and other lines as needed. So the auxiliary MCU watches say -CS from the master MCU to know when to switch the multiplexer. I am not fond of using analog multiplexers in place of digital ones so would go with some variation of a 74157 or similar.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: April 05, 2018, 05:32:35 pm
content: I have been working some more on this little project, and have successfully rigged up a proof-of-concept using an Arduino board.I have the device's mainboard SPI bus connected with the Arduino as a slave, and the LCD connected with the Arduino as master on a second SPI bus. My code takes the input SPI transfers (plus the accompanying state of the extra RS and AC lines) and stuffs them in a FIFO buffer, with the main loop processing that buffer and applying the command data to a replication of the LCD's internal memory banks (it has three: one for characters displayed, one for icons, and one for custom character patterns). I also have a processing stage that filters and/or modifies commands before applying them. Then, at regular intervals, I have code sending out commands on the second SPI bus to apply that replicated state to the LCD (i.e. just writing the entirety of each memory bank).With this solution, I'm still having trouble coming up with ideas of how I can turn my interception on and off, switching from passing through the original SPI communication to the LCD, to the aforementioned split SPI buses. As I previously postulated in my first post, I think I could use a 74HC365 to do the switching, but the main problem I think would be timing.For turning 'on', I could watch the CS line on my MCU's slave SPI interface and only switch the '365 when CS returns high (i.e. after a transfer is complete). If this happens in the middle of a train of communication from the mainboard (generally, a communication consists of one transfer to select which LCD memory bank and address, followed by one or more data transfers), it won't matter, as when I turn my interception 'on', I'll be clearing the display anyway.It's turning 'off' that I think is going to be more tricky. If the user commands to turn off, I could simply discard any further incoming transfers from the mainboard, wait until my FIFO buffer is empty, make one last display update, then wait until the slave CS line goes high to switch the '365 back to pass-through. However, again, what if this happens halfway through a train of communication from the mainboard? For example, if the last thing my MCU did to the display was to write to character display memory, but then the mainboard's communication resumes halfway through it writing to icon RAM, you'd end up with nonsense data on the character display! I don't know how I could synchronise things so I could time a switch-off to coincide with a dead time in the mainboard's communication. Any suggestions appreciated.While I'm here, I also have a further question more general to SPI. Is it possible to have two slave devices on the same SPI bus that work at different clock speeds? I'm wondering this because I'd like to put a second slave device on my MCU's second SPI bus, alongside the LCD display. The LCD display operates at a maximum of 1MHz SCK, but the other device I'd want to operate at 10MHz. I suppose I can switch SCK speeds back-and-forth when communicating with each device, but will feeding a non-selected, idle slave an SCK signal that is way higher than what it's designed for have any adverse effects?