collapse

Welcome!



Welcome to Robot Rebels, an online robot maker community.

Register today to post your projects, ask questions, share knowledge and meet like-minded people from around the world.


The RobotRebel.org Community

Author Topic: Coding a Nano i2c Slave  (Read 152 times)

BaldwinK

  • Member
  • ****
  • B
  • Posts: 12
Coding a Nano i2c Slave
« on: October 25, 2017, 05:40:27 AM »
In a distributed system using intelligent leg modules and a central controller, each 4-motor leg module could be addressed as an i2c slave. The Nano is reasonably compact, has 18 usable I/O pins and is very cheap.

For earlier projects I used various PICAXE chips but needed higher mathematical capability.  Transitioning to the Arduino IDE I wrote master i2c bit banging code for a Nano as a learning exercise. It worked well enough to interface to IMU chips etc and to teach me to watch out for semicolons and double equals.

Of course the slave chips use hardware to detect fast edges and it is quite difficult to use software loops for the same effect. I had also missed the chapter on i2c in the Atmel datasheet because it is headed TWI.

It turns out writing code for an i2c slave is a lot easier using the Atmel registers.

Using the Hardware

First load the slave address (hex 50 say):

    TWAR = 0x50;                 //slave address to Atmel

Then turn on the hardware i2c function using the control register:

    TWCR = B01000100;            //set TWEA, enable Atmel i2c
    TWCR = TWCR | B10000000;     //hit the flag to get it going

Now wait for the status register to see what has occurred:

    while (!(TWCR & B10000000)); //wait flag to read status

Let’s assume the master is going to write (send data to us):

    if (TWSR == 0x60) {          //test status for addr + W found
                                 //the address found is in the data register

We hit the flag and wait for the first data byte:

    TWCR = TWCR | B10000000;     //hit the flag
    while (!(TWCR & B10000000)); //wait flag

    if (TWSR != 0x80)            //test status for data received ok
    goto error_handler;

    inbyte = TWDR;               //the first byte is in the data register
    }

Continue as required. Obviously things are a little more complicated but the detail can be added once you get the idea. The Atmel datasheet is a must read and pay special attention to the protocol of Nacking the last byte.

Trimming the Protocol

My quadruped project has specific needs so the i2c protocol can be tailored to suit the need for speed etc.

Each of the four motors needs byte values for:

    Actual position in degrees  (read only)
    Next setpoint in degrees    (read/write)
    Current duty cycle 0 to 255 (read only)
    Maximum duty cycle 0 to 255 (read/write)

Driving the motors at twice normal voltage is good for torque but if a 50% duty cycle is exceeded for too long the motors or drivers will cook. This calculation needs a 64-byte fifo for a one second moving average of the PWM value. The motor power is removed for each period the maximum value is exceeded. It sounds like braking on gravel in a car fitted with an ABS system.

All data transfers will be four bytes long. Makes the thinking simpler.

The four parameters will not use a separate register address byte; the extra two bits can be a subset of the leg address.

Atmel got there first with the TWAMR bit-masking of the TWAR:

    TWAMR = 0x0C;                //mask out lower bits (Reg address)

So there is no switching from writing the register address, sending a restart, then reading the data bytes.  Whether reading or writing, transfers can be completed in less than 150uS.

Synchronising the Processes

Each slave Nano has to calculate four PID equations compensating for non-linear potentiometers, update duty cycle values, scale for each PWM and control the half bridges. This may take 12-13mS of the 15mS cycle time.  Keeping the cycle-time constant simplifies the calculus because the .dt elements can be removed.

Once its housekeeping is done, the slave will be ready to listen to the i2c bus. The master can then send or receive i2c instructions to each slave before the cycle restarts.

Neither process is interrupted but we do need to keep them meshing together.

The Atmel hardware can be configured for a ‘general call’ address 0x00.  The LSB of the TWAR register is set to enable the slave to respond to its own address and the general call address:

    TWAR = i2cadd | 0x01;        //slave address to Atmel, allow general call

Once the address is seen the slaves will start their own processes and will not listen to the i2c bus for a while:

    if (TWSR == 0x70)            //test status for general call
    goto house_keeping

The master is also free for a time to do its own thing.  Then when millis() counts out 13mS it must converse on the i2c bus. At 15mS it must send the general call address, finishing with a stop bit to keep everyone happy.

 

* Search


* Recent Topics

Just scary to me... by jinx
[November 16, 2017, 03:05:30 AM]


"Artie" version 3.0 (RTV3) by jinx
[November 14, 2017, 03:11:04 AM]


Anycubic Kossel (pulley) by Bajdi
[November 13, 2017, 04:48:04 PM]


grbl-LPC by jinx
[November 12, 2017, 02:48:46 PM]


mks ftf2.4 simple bezel by jinx
[November 11, 2017, 04:18:13 PM]


Controllers by jinx
[November 11, 2017, 06:48:21 AM]


Magnetometer vs. Electric Motor by ZeroMax
[November 08, 2017, 02:22:47 PM]


Raspberry Pi / Python eBook - free for the next 11 hours! by MEgg
[November 02, 2017, 06:10:53 PM]


who's using atom by jinx
[November 02, 2017, 03:49:38 AM]


3d review of a delta by jinx
[October 27, 2017, 11:30:38 PM]


Coding a Nano i2c Slave by BaldwinK
[October 25, 2017, 05:40:27 AM]


Drawdio by mogul
[October 24, 2017, 02:35:00 PM]


My scope focuser upgrade by jscottb
[October 22, 2017, 03:13:23 PM]


thermoplastic bed surface by Bajdi
[October 22, 2017, 03:12:37 PM]


Kossel Build by Deity
[October 20, 2017, 11:23:27 AM]

* Recent Posts

Re: Just scary to me... by jinx
[November 16, 2017, 03:05:30 AM]


Just scary to me... by Protowrxs
[November 15, 2017, 05:31:10 PM]


Re: "Artie" version 3.0 (RTV3) by jinx
[November 14, 2017, 03:11:04 AM]


Re: Anycubic Kossel (pulley) by Bajdi
[November 13, 2017, 04:48:04 PM]


Re: Anycubic Kossel (pulley) by Deity
[November 13, 2017, 04:08:05 PM]


Re: "Artie" version 3.0 (RTV3) by lukeyes2
[November 12, 2017, 06:29:44 PM]


grbl-LPC by jinx
[November 12, 2017, 02:48:46 PM]


mks ftf2.4 simple bezel by jinx
[November 11, 2017, 04:18:13 PM]


Controllers by jinx
[November 11, 2017, 06:48:21 AM]


Magnetometer vs. Electric Motor by ZeroMax
[November 08, 2017, 02:22:47 PM]


Re: Raspberry Pi / Python eBook - free for the next 11 hours! by MEgg
[November 02, 2017, 06:10:53 PM]


Re: "Artie" version 3.0 (RTV3) by lukeyes2
[November 02, 2017, 10:47:29 AM]


Re: who's using atom by jinx
[November 02, 2017, 03:49:38 AM]


Re: "Artie" version 3.0 (RTV3) by Bajdi
[November 01, 2017, 04:11:20 PM]


Re: who's using atom by Bajdi
[November 01, 2017, 04:08:47 PM]