cancel
Showing results for 
Search instead for 
Did you mean: 

Master/Slave I2C on the same interface

Harvey White
Senior III
Posted on August 11, 2017 at 22:57

I'm working on getting two microprocessors to talk.  One of them is an F446, the other is an L432.  The communications scheme is that (for example) the 446 sends a message to the L432, which then executes it (command for a graphics display).  The L432 then assumes master mode, and sends a message to the F446 confirming execution.

The display infrastructure works, the message building works, but using Cube32, there's a problem.

The reply from the L432 never gets sent. 

I have an RTOS task reading buffers, looking for a full one.  With the right status and address, the Master_send_IT routine is called and the buffer sent.

At the same time, since the node (any processor) can be accessed as a slave, another RTOS task is waiting for a message, and there's the problem. 

Under cube32, getting a slave message is a task that leaves the interface in busy_rx status.  This effectively blocks the transmit task.

Apparently, according to the Cube32 writers, one never uses the I2C any differently.

I've solved the problem in Atmel XMEGA's by writing the interrupt routine myself, which I could do, but I'd rather not.

The only tentative solution I have is to have the transmit task cycle through one buffer scan, then call receive message (programmed receive and blocking) with a 1 ms timeout, then if there is no error, execute a slave command, otherwise scan the TX buffers again looking for something.

Working on an interrupt basis is nicer, but I'd have to abort the interrupt receive, reset the peripheral, and see if there's a message to be responded to.

Just to make a point, the L432 is not intended to originate a message without the F446 first sending a command.  The F446 will be the only device sending unsolicited messages. 

Is it reasonable to leave the interface in slave mode (which is normal) and then use the addressed interrupt hook to start up a receive task?  That task would then call the normal (either programmed or otherwise) read routine to build a buffer, then go from there.

The overall flow is:  Send command to slave, slave executes command.  Slave then assumes master role and sends status message to former master. 

Anybody do this before?

Any ideas?

Harvey

3 REPLIES 3
Harvey White
Senior III
Posted on August 20, 2017 at 06:16

OK, as a follow up:

What I was asking for was help in doing a multi-master I2C setup.  Apparently, nobody really does those, because I wasn't really able to find any guidance.  Didn't need code, but the steps to take and things to watch out for would have been nice. 

What I managed to do was get the two processors talking, A to B and B to A, but with the listening processor not trying to talk at all.  In an asynchronous system, that's not a viable setup.  Having any processor trying to send and receive in a time multiplexed mode blocked both transmission and reception.  Not sure why, but the hardware allows it.  It's likely that Cube32 and HAL software can't handle it.

A working solution, however, is to go back to the old master/slave system, which is more or less proven to work.  The flow is adapted from the two boards application notes, comments on that later.

Send command to slave

Send request for reply length (can use this for long processes in slave).

read two bytes for length.

request reply

read (now known) number of bytes

A previous solution with the Xmega processors involved writing the ISR, and adjusting the message length when the appropriate number of characters had been sent.  This takes more transactions, but works around the limitation of the HAL routines which require an exact message length.  The command is not exact, but the slave ignores the AF error.

Two boards:  No error detection, no retries, no timeouts.  Those need to be added to make a decent solution.  With the above scheme, as long as you get a message or message/reply, the two processors should stay in sync.

Posted on August 21, 2017 at 08:08

Haven't experimented I2C multi-master for a while since Access Bus times (which was quickly faded out for USB). Most display controllers are slave devices. Depending on the speed of communication and number of signals, there is I2C (Single Master/Slave) with Interrupt, SPI 3 wire with interrupt, SPI 4 wires (rare because data read back is considered waste of time, as ESD+register corruption risk forces you to refresh registers regularly anyway), here there is usually an extra bit 'Command/Data' which either is a wire or an extra bit in the protocol). Then the usual 8 bit 8080/6800 parallel interface, etc... Multi-master is more complex, hence the middleware exception management more complex and difficult to debug/validate.

Posted on August 21, 2017 at 16:06

Some clarification here.  I have a daughter board with an Epson S1D13781 (SPI graphics chip), run by an F446RET Nucleo 64 board.  That's the master device.  I also have an L432 Nucleo 32 board running an Optrex COG parallel input 128 x 64 graphics display.  That's the slave device.  Both processors are running essentially the same software, running under freeRTOS. 

What I wanted was master/slave for any device, no dedicated slaves.  This did not work.  No transmission, no reception.

What I got was master/slave, with a talking stick permission to be a master (unimplemented, but it will work) for any slave device.  I do have an SRQ line for smart devices.  Depending on pinouts, there's a secondary local I2C bus, on which the processor is always a master.

Master to hardware device is working, at least (only tested so far) for 24Cxxx memories.  Other devices to be done.  Not worried about that.  I do a lot of I2C from hardwired board to hardwired board, with WiFi or perhaps NRF24L01 another option. 

With some adaptation for retries and some error trapping, I have the master/slave I2C working.

Send command (slave executes and builds reply buffer)

Send command to return 2 byte count (slave sends this, size of reply now known and slave is ready)

Send command to reply (slave goes into transmit mode, master reads determined number of bytes)

The only unknown message length is the command(error handled gracefully)

What the HAL implementation layers (and the board to board example especially) do not have is timeouts waiting for ready and (I think) error recovery methods. 

The advantage of the method above splits a sequence into simple command/reply, which is easier to handle when out of sequence or interrupted.  Wifi will go to the multi-master approach, which will work there, and will handle variable length messages.

As to whether or not this is reliable, I have a simple update display with a string running, and it's been running for 16 hours, 100 commands/second, 1.5 million commands, and no errors.  It does do error logging per registered off-board address.

So not talking to the displays except through a processor.