Efficient Implementation of Multi-Slave TWI

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear all,

I am coding a device that responds on multiple slave TWI addresses. I'd like to do it in a way that is fast, yet still portable from one project to another.

Semantically, I want to do something like:

void PerformAction(uint8_t slaveAddress)
{
    switch (slaveAddress)
    {
        case 0x50: SlaveHandler_0x50(); break;
        case 0x51: SlaveHandler_0x51(); break;
        /* ... */
        default: break;
    }
}

Which has two disadvantages:
* I need to change the driver code every time I want to add (or change a slave)
* The compiler may/may not generate fast code for us (of course, we can look at the source)

I was thinking something like building an array of function pointers at compile time as an alternative:

FunctionPointer table[128] = {
    [0x51] = SlaveHandler_0x51,
    [0x52] = SlaveHandler_0x52,
};

Which, although constant time, will chew through ram and will probably push the entire register context to the stack.

So, I'm looking at ideas to make it as fast as possible and require as few changes in the driver as possible.

Ideally, I'd like to see something like (in something.h)

#include "twi_slave_driver.h"

void SlaveHandler_0x50();

// Some macro that will help automatically build the table
SET_SLAVE_HANDLER(0x50, SlaveHandler_0x50);

Any ideas?

-- Damien

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The I2C bus need no fast timing, because the slave can tell the master, when it was ready for next data (release the SCL line).

Using function pointers inside interrupts was not a good idea, since it make the code slower (tons of push/pop).
The switch statement generate the faster code in conjunction with inline functions.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

danni wrote:
The I2C bus need no fast timing, because the slave can tell the master, when it was ready for next data (release the SCL line).

True, but it allows other things to respond faster if I get out of the interrupt faster.

Quote:

Using function pointers inside interrupts was not a good idea, since it make the code slower (tons of push/pop).
The switch statement generate the faster code in conjunction with inline functions.

I noticed that when I looked at the example XMEGA TWI code and what it generated. For a single slave, it wasn't really a problem, but for a multi-slave, I'm looking to make it as clean as I can get away with.

-- Damien

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I understand not your problem, why you need different routines for different addresses.

Why not use the same routine for all and access only different data buffers?

And then the main do the different stuff on these buffers.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please describe exactly what you want to do:

1. Is it one AVR that performs as several slaves?

2. Or several AVRs that each perform as a single slave?

The TWI module will respond to a single slave address in TWAR. Or it can respond to a 'general call address'.

I suppose you can have a 'priority' slave address say 0xA0/0xA1. And this lives in your TWAR.

The ISR() works normally for these addresses. But if you get a TW_SR_SLA_NACK then you reset the TWI state machine just as if you had got a TW_SR_SLA_ACK state.

Judging by the slave addresses you are quoting, it looks as if you are emulating a memory device.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

danni wrote:
I understand not your problem, why you need different routines for different addresses.

Why not use the same routine for all and access only different data buffers?

And then the main do the different stuff on these buffers.

Peter

Because there's different logic, actions and events that get raised for each of the "slaves" implemented.

-- Damien

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Please describe exactly what you want to do:

1. Is it one AVR that performs as several slaves?

Yes.

Quote:

Judging by the slave addresses you are quoting, it looks as if you are emulating a memory device.

Amongst other things :)

-- Damien

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So you are going to have to mangle the TWI state machine.

As danni has suggested, you access different buffers. And if you are performing different functionality for each device, use switch statement or a function pointer.

The ISR() execution time is going to be fairly irrelevant. The I2C bus is not exactly a high speed device.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any chance you would like to have a PC emulating the slaves? Have you checked out what TotalPhase Aardvark I2C adapter can do?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jepael wrote:
Any chance you would like to have a PC emulating the slaves? Have you checked out what TotalPhase Aardvark I2C adapter can do?

We've used an Aardvark for different projects, especially writing a bootloader on an stk600 before we got real hardware. In this case, the AVR is a slave to a host processor on a custom board implementing several different functions.

-- Damien