Does the Atmega328p support more than 1 I2C slaves?

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

Hi,

 

I am connecting an Atmega328p to an IMU (LSM6DS33) and a OLED display (SSD1306) both as I2C slaves (and of course the AVR as the master). I have tried the code separately and they work! However, when I try to enable them at the same time, the LCD nor the IMU work. 

 

Here's my approach:

 

// I2C.h

#ifndef _I2C_H_
#define _I2C_H_

#include <stdint.h>
#include <util/twi.h>

#define SCL_CLOCK  100000L

class I2C {
public:
    I2C();
    void init(uint8_t address);
    uint8_t start();
    uint8_t write(uint8_t data);
	uint8_t i2c_read_ack(void);
	uint8_t TWIReadNACK(void);
	uint8_t TWIReadStatus();
    void stop(void);
	uint8_t GET_DEVADDR(){return address;};
private:
    uint8_t address;
    uint8_t twi_status_register;
};

#endif

 

// I2C.CPP
#define F_CPU 14745600
#include "I2C.h"

I2C::I2C() {}

void I2C::init(uint8_t address) {
    this->address = address;
    TWSR = 0;
    TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
}

uint8_t I2C::start() {
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while(!(TWCR & (1<<TWINT)));

    twi_status_register = TW_STATUS & 0xF8;
    if ((this->twi_status_register != TW_START) && (this->twi_status_register != TW_REP_START)) {
        return 1;
    }

    TWDR = address;
    TWCR = (1<<TWINT) | (1<<TWEN);

    while(!(TWCR & (1<<TWINT)));

    this->twi_status_register = TW_STATUS & 0xF8;
    if ((this->twi_status_register != TW_MT_SLA_ACK) && (this->twi_status_register != TW_MR_SLA_ACK)) {
        return 1;
    }

    return 0;
}

uint8_t I2C::write(uint8_t data) {
    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);

    while(!(TWCR & (1<<TWINT)));

    this->twi_status_register = TW_STATUS & 0xF8;
    if (this->twi_status_register != TW_MT_DATA_ACK) {
        return 1;
    } else {
        return 0;
    }
}

uint8_t I2C::i2c_read_ack(void)
{

	// start TWI module and acknowledge data after reception
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
	// wait for end of transmission
	while (!(TWCR & (1 << TWINT)));
	// return received data from TWDR
	return TWDR;
}

//read byte with NACK
uint8_t I2C::TWIReadNACK()
{
	TWCR = (1 << TWINT) | (1 << TWEN);
	//Wait for TWINT Flag set.
	while (!(TWCR & (1 << TWINT)));
	return TWDR;
}

// Check status
uint8_t I2C::TWIReadStatus() {

	uint8_t status;
	status = TWSR & 0xF8;

	return status;

}

void I2C::stop(void) {
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    while(TWCR & (1<<TWSTO));
}

 

int main(void)
{
	// I2C devices (objects)
	// LCD
	Framebuffer fb; // Instantiate framebuffer for drawing
	Framebuffer *FB; // Instantiate framebuffer for drawing
	FB = &fb; // Pointer -- We need a pointer to reference the object and pass it as argument
	// IMU
	IMU imu_ag; // IMU accelerometer and gyroscope
	IMU *imu1; // Pointer
	imu1 = &imu_ag;

	fb.drawBitmap(0); // THIS IMAGE DOESN'T SHOW UP WHEN THE IMU IS ENABLED
	fb.show();

}

 

Basically when the objects are created, a sequence of commands are written to the devices that consist of the following:

For the SSD1306:

// Inside constructor of Framebuffer (ssd1306)   ... uint8_t command as argument

    i2c.start();
    i2c.write(0x00);
    i2c.write(command);
    i2c.stop();

And for the IMU:

// Inside constructor of IMU .. uint8_t regAddress, uint8_t data as arguments
	i2c.start(); // I2C start signal (ST)
	i2c.write((i2c.GET_DEVADDR() << 1) | 0); // SAD+W (Slave address) + Write bit
	i2c.write(regAddress);  // Register adddress (SUB)
	i2c.write(data);  // Data to write
	i2c.stop(); // Send stop I2C

 

 

This is the library I am using for the SSD1306 by the way (don't know if it's relevant as this is more of a I2C problem): https://github.com/tibounise/SSD...

Like I said, things work fine if the IMU is not enabled... aka if I dont't create the object imu_ag to enable another I2C device. It's only working with either the IMU or the display, but not both.

 

Both of the devices are using different addresses of course. The AVR does support multiple devices right? What could be wrong with my approach? Any ideas?

 

 

Thanks in advance.

 

 

P.S No, I'd rather not use the Arduino lol

 

 

Last Edited: Fri. Mar 2, 2018 - 11:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The entire point of I2C is precisely that it is a bus and, thus, can support multiple slaves!

 

Doesn't your I2C library provide any status returns from its functions? - see edit below

 

surprise

 

Please post your schematic - see Top Tip #1.

 

Have you looked at the I2C wires with a scope, logic analyser, or I2C analyser to see what's actually happening?

 

Use the debugger to step through your code & see what's happening.

 

lcruz007 wrote:
I'd rather not use the Arduino

Why not?

 

At least try it on an Arduino to verify that your hardware is OK ...

 

 

EDIT

 

Oh yes, your I2C functions do provide status returns - so use them!!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Mar 2, 2018 - 11:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A Bus is designed for multiple devices.   Just like an automobile bus takes many passengers.

 

Some of the Ebay SSD1306 displays were not designed properly.   They do not ACK the I2C.    There are special Arduino libraries that cope with this crap behaviour.

 

If your Display does ACK correctly,  it should work fine with other Slaves on the bus.

 

I suggest that you test your hardware with the proven Arduino library code.   (whether you like it or not)

 

When you have verified the hardware,  we can offer advice regarding I2C.    You obviously do not know how to use I2C.

 

David.

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

david.prentice wrote:
Some of the Ebay SSD1306 displays ... do not ACK the I2C

That's the kind of thing that should be detected by the I2C code, and reported in a status return ...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lcruz007 wrote:
Any ideas?
mega328PB has two TWI.

Microchip Technology Inc

Microchip

ATmega328PB - 8-bit AVR Microcontrollers

http://www.microchip.com/wwwproducts/en/atmega328pb

...

... two byte-oriented 2-wire serial interfaces, ...

...

 

"Dare to be naïve." - Buckminster Fuller

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

gchapman wrote:

lcruz007 wrote:
Any ideas?
mega328PB has two TWI.

Microchip Technology Inc

Microchip

ATmega328PB - 8-bit AVR Microcontrollers

http://www.microchip.com/wwwproducts/en/atmega328pb

...

... two byte-oriented 2-wire serial interfaces, ...

...

 

TWI/I2C supports multiple slaves by default so moving one to the other bus wastes the two pins and does not solve the OP's problem.

 

 

As is always stressed here, Use a PROVEN library to test your hardware BEFORE rolling your own.  I always recommend Peter Fleury's library for I2C MASTER Interface:

 

http://homepage.hispeed.ch/peter...

 

Once you have things working in hardware with his code, THEN roll your own...But why if Peters does the work for you?

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

jgmdesign wrote:
does not solve the OP's problem.

Yes, it does - especially if the problem is, as David suggested, that one of the slaves does not play nice with the I2C.

 

And, if the OP has the pins free, then that's not a problem.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

jgmdesign wrote:
does not solve the OP's problem.

Yes, it does - especially if the problem is, as David suggested, that one of the slaves does not play nice with the I2C.

 

And, if the OP has the pins free, then that's not a problem.

 

 

Indeed - I stand corrected.  

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

But, in general, it does seem a waste to use separate busses & consequent extra pins with just 1 slave on each.

 

Defeats the object.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Basically when the objects are created, a sequence of commands are written to the devices that consist of the following:

For the SSD1306:

// Inside constructor of Framebuffer (ssd1306)   ... uint8_t command as argument

    i2c.start();
    i2c.write(0x00);
    i2c.write(command);
    i2c.stop();

And for the IMU:

The SSD1306 sequence is complete pants.    The IMU sequence looks ok.

 

Follow the advice to verify hardware with Arduino.

Then we can help with your hand-rolled code.

 

The I2C class looks ok.   It is just a question of learning how to use it.

 

Personally I would put all the I2C devices onto the hardware TWI bus.    But this is only possible if your SSD1306 can ACK properly.

 

David.

Last Edited: Fri. Mar 2, 2018 - 03:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

There are a lot of bad I2C libraries and bad I2C chips out there.

Combine that with the relative complexity of I2C (compared to uart or spi) and you have plenty of opportunities for failure to creep in.

 

Could it be that both chips are responding to the same I2C address?

Could it be that both (breakout ?) boards have I2C pullups and they are too strong together?

Could it be that bus capacitance is too much with both boads attached?

 

If you have confidence in your library then I would start by checking the I2C channels with a scope for bus conflicts / errors.

Then I would fire up my USD 5 Logic analyer (24M 8ch from Ali / Ebay) with an I2C protocol analyser (Sigrok) and look at any inconsistencies on the I2C bus.

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Paulvdh wrote:
you have plenty of opportunities for failure to creep in.

 

Could it be that both chips are responding to the same I2C address?

Could it be that both (breakout ?) boards have I2C pullups and they are too strong together?

Could it be that bus capacitance is too much with both boads attached?

 

Hence the suggestion to at least try it on an Arduino - to rule out such things ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
Hence the suggestion to at least try it on an Arduino - to rule out such things ...
Much better to look at the signal integrity on a scope.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Guys,

 

I solved the problem! I was sending the ST+DEVADDR signal twice. It was a stupid mistake on my part... The I2C class was OK, as well as the hardware. 

 

 

Thank you so much for all your help.

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

lcruz007 wrote:
I solved the problem!

So please mark the solution - see tips below

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...