I2C of LSM6DSD33 on Atmega328P

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

So I recently bought an IMU from Pololu (https://www.pololu.com/product/2738). I've used their old versions of IMUs in the past, but now that I got this new one, I am unable to connect to it via I2C. I am not getting anything at all from the accelerometer. By reading the datasheet, it's only a matter of setting a few registers. When I do that, however, nothing happens. Here's the datasheet of the LSM6DSD33 https://www.pololu.com/file/down...

 

here's my code:

 

#define F_CPU 14745600

#define IMU_ADDR 0b1101011 // Gyrosensor + Accelerometer address (1101011)
#define STATUS_REG 0x20
// Accelerometer
#define CTRL9_XL 0x18 // To enable axes
#define CTRL1_XL 0x60 // High-performance mode register
#define INT1_CTRL 0x01 // Acc Data ready interrupt on INT1
#define OUTX_L_XL 0x28 // Acc out X,l
#define OUTX_H_XL 0x29 // Acc out, X,h

#include <stdio.h>
#include <math.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

#include <inttypes.h>
#include <util/delay.h>

// C libraries
extern "C"
{
#include "libs/uart.h"
#include "libs/delay.h"
}

// setups TWI (Two Wire Interface A.K.A I2C)
void TWISetup() {

	// Set up TWI module to 368,640 Hz
	// SCLfreq = Fclock/(16+2*TWBR*(prescaler))

	// Set up TWI but rate to 3
	TWBR = 3;
	// Prescaler to 4
	TWSR |= (1 << TWPS0);
	// Enable TWI
	TWCR |= (1 << TWEN);

}

// Start signal function
void TWIStart() {

	// From datasheet page 226
	TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // Send start condition

	while (!(TWCR & (1 << TWINT))); // Wait for TWINT Flag set. This indicates that the START condition has been transmitted

}

void TWIStop() {

	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); // Transmit STOP condition
}

void TWIWrite(uint8_t data) {

	//Load SLA_W into TWDR Register. Clear TWINT bit in
	//TWCR to start transmission of address
	TWDR = data;
	TWCR = (1 << TWINT) | (1 << TWEN);

	//Wait for TWINT Flag set. This indicates that the SLA+W has
	//been transmitted, and ACK/NACK has been received.
	while (!(TWCR & (1 << TWINT)));
}

// Read with ACK (Acknowledge bit)
uint8_t TWIReadACK() {

	//TWI Interrupt Flag, TWI Enable Bit, TWI Enable Acknowledge Bit
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
	//Wait for TWINT Flag set.
	while (!(TWCR & (1 << TWINT)));
	return TWDR;

}

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

	uint8_t status;
	status = TWSR & 0xF8;

	return status;

}

// Read byte
int16_t ReadByte(uint8_t DEVADDR, uint8_t regAddress) {

	//send start
	TWIStart(); // ST

	TWIWrite((DEVADDR << 1) | 0); // SAD+W (Slave address) + Write bit

	TWIWrite(regAddress); // Register adddress (SUB)
						  //send repeated start
	TWIStart(); // SR

	TWIWrite((DEVADDR << 1) | 1); // SAD + R

	int16_t data = TWIReadNACK(); // NMAK

	TWIStop(); // SP

	return data;

}

// Writes one byte
void writeByte(uint8_t DEVADDR, uint8_t regAddress, uint8_t data) {

	TWIStart(); // Starts

	TWIWrite((DEVADDR << 1) | 0); // SAD+W (Slave address) + Write bit

	TWIWrite(regAddress); // Register adddress (SUB)

	TWIWrite(data); // Data to write

	TWIStop(); // Stops I2C

}

int main(void)
{

	// init serial port
	uart_init();
	// Serial port
	FILE uart_stream;
	uart_stream.put = uart_putchar;
	uart_stream.get = uart_getchar;
	uart_stream.flags = _FDEV_SETUP_RW;

	uart_read();

	TWISetup();

	writeByte(IMU_ADDR,CTRL9_XL, 0b00111000); // X Y Z access enabled
	writeByte(IMU_ADDR,CTRL1_XL, 0b01100000); // Acc = 416Hz (High-Performance mode) : ODR_XL [3:0] 0110
	writeByte(IMU_ADDR,INT1_CTRL, 0b00000001); // Acc Data Ready interrupt on INT1

	uint8_t out_x_a; // Accelerometer output

	uint8_t STATUS;
	uint8_t MASK = 0b00000001;

	printf_P(PSTR("Reading Acc:\r\n")); // "#" Means end of line, "*" is where line begins
	while (1) {

		STATUS = ReadByte(IMU_ADDR, STATUS_REG);
		uint8_t STATUS_LSB = STATUS & MASK; // Get the last bit status
		if (STATUS_LSB) // Read LSB
		{
			printf_P(PSTR("Output Acc")); // "#" Means end of line, "*" is where line begins
			out_x_a = ReadByte(IMU_ADDR, OUTX_L_XL);
			printf_P(PSTR(": %d\r\n"), out_x_a); // "#" Means end of line, "*" is where line begins
		}
		else {
		}

	}

	return 0;
}

 

According to the dasheet settng the registers is the only thing needed to power on accelerometer

 

 

Then it says something about using the STATUS register to expect new data, which I am using too.

 

 

So basically I am doing everything I should be doing according to the datasheet... The i2c code I am using should work well on the atmega328p, it's the one I've been using for a while for another IMU... Anyone have worked with the LSM6DSD33? Thanks!

Last Edited: Sat. Feb 24, 2018 - 09:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure you have the correct slave address, and are using it in the correct way?

 

See: https://www.avrfreaks.net/comment...

 

Easy test: Is the slave ACKing its address?

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

I am forever gobsmacked by I2C device datasheets.    It is incredibly difficult to find the Slave address.

 

I will just have to believe you when you say 0b1101011 i.e. 7-bit 0x6B (8-bit 0xD6)

 

You appear to be using the 7-bit address correctly.   Your writeByte() and readByte() functions do not check for ACK/NAK.

 

Any I2C library should test the result of an i2c_start(slave) call.    If the Slave does not respond there is no point in attempting any transactions.

I always advise using the Fleury library.    It provides return values.   It is easy to use.   It is easy to understand.

 

David.

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

david.prentice wrote:
I am forever gobsmacked by I2C device datasheets.    It is incredibly difficult to find the Slave address.

I agree.

 

angry

 

I am also gobsmacked by software writers who cannot clearly state the format they require for the Slave address.

 

angry

 

 

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

david.prentice wrote:

I am forever gobsmacked by I2C device datasheets.    It is incredibly difficult to find the Slave address.

 

I will just have to believe you when you say 0b1101011 i.e. 7-bit 0x6B (8-bit 0xD6)

 

You appear to be using the 7-bit address correctly.   Your writeByte() and readByte() functions do not check for ACK/NAK.

 

Any I2C library should test the result of an i2c_start(slave) call.    If the Slave does not respond there is no point in attempting any transactions.

I always advise using the Fleury library.    It provides return values.   It is easy to use.   It is easy to understand.

 

David.

 

Well not reading ACK/NAK values is one thing.... But what could it be? Does it has to do anything with the fact that I omitted the 4.7k pull-up resistors? I mean, I tried with them on and still nothing. (According to the diagram of the breakout board, there are some 10k resistors in the SDA/SDK lines).

 

According to Pololu, it's the right address btw (the default one)... I've tested their products before and they are not usually wrong lol

Last Edited: Sun. Feb 25, 2018 - 06:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lcruz007 wrote:
According to Pololu, it's the right address btw 

You seem to have missed the point of #2 (which is echoed in #3 & #4):

 

I wrote:
Are you sure you have the correct slave address, and are using it in the correct way?

It's not just about having the right value - you have to know whether it is

  • purely the 7-bit address, right-aligned in a byte;
  • the 7-bit address, left-aligned in a byte;
  • the 7-bit address, plus the R/W bit, in a byte;
  • or something else ... ?!

 

and that applies both to the hardware documentation, and the software using it.

 

EDIT

 

To summarise, it's not just about sending all the right bits - you also have to send them in the right positions!

 

http://www.dailymail.co.uk/video...

 

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: Sun. Feb 25, 2018 - 11:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

God provided the Arduino.     Buy a Uno clone for about $5.    Pololu have got example software for the Arduino.

This will verify that your hardware is working and show you the capabilities of your IMU board.

 

If you really want to ignore the Arduino,   follow these steps:

 

1.  Download Fleury library.

2.  Add external pullup resistors on SDA, SCL lines (if not already on the pcb)

3.  Connect your board.

4.  Run an I2C scanner to detect all the Slaves on the I2C bus.

5.  Write your application using the correct Slave addresses.   (Fleury expects 8-bit address values)

6.  Use the return value from the i2c_start(), i2c_write(), ... library functions.

7.  Write a known value to a Slave register.    Read the Slave register.

8.  Many devices have an ID or documented register read value at reset.

9.  This makes an excellent first test.   i.e. verify the ID

 

This strategy of writing a write_register_value() and a read_register_value() helper function applies to every I2C device.   And to most intelligent hardware.

 

Then you can add the next layer of functionality.   e.g. reading the acceleration,  position, ...

 

David.

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

david.prentice wrote:
This strategy of writing a write_register_value() and a read_register_value() helper function applies to every I2C device

Absolutely. And not just for I2C - similarly for SPI, and others ...

 

The only proviso is that some registers will not read-back the same value that was written - so RTFM carefully to ensure that you pick a suitable one!

 

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

david.prentice wrote:
Fleury expects 8-bit address values

So do those 8 bits include the R/W bit, or what?

 

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

Yes.   If the 7-bit address is 0x6B the 8-bit write address is (0x6B << 1) i.e. 0xD6

and the 8-bit read address is ( (0x6B << 1) | 1) i.e. 0xD7

 

All hardware chips require the 8-bit value.    Some libraries require 7-bit and some require 8-bit.   You read the documentation to tell you which style to use.

 

From a practical point of view,   an interrupt driven library will probably use 7-bit because it will write some bytes and then read some bytes as part of its Interrupt Service Routine.

A polled library is more likely to let the User call primitive functions.

 

David.

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

david.prentice wrote:
You read the documentation to tell you which style to use.

That's where the trouble lies - it is all too often not clear.

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: 1

But libraries are clear. Wire.h uses 7-bit. Fleury's i2cmaster.h uses 8-bit. Atmel's AVR315, AVR316 app notes use 7-bit because their examples use interrupts. Arduino Wire.h use interrupts. Codevision twi.h uses interrupts.
.
I would expect a hardware chip datasheet to show the Slave address on Page #1.
They seldom make it very clear. Timing diagrams are often your best method.
.
I could not find the Slave address in the datasheet anywhere. I am not at a PC. I will have another attempt.
.
David.

 

Edit.   The link in the OP's message was to an App Note and not the datasheet of the LSM6DS33 or the LIS3MDL.

 

Woo-hoo.  LIS3MDL has the info in Table 11. SAD+read/write patterns on page #17.    LSM6DS33 has the info in Table 11. SAD+Read/Write patterns on page #29.

 

Once I had the datasheets it was relatively easy to find.    I searched the App Note multiple times with no success. for Slave, I2C, SAD, ...

 

DS1307.   page#12 of 14

AT24C512.  page #10 of 22

PCF8574. page #8 of 24

 

Last Edited: Sun. Feb 25, 2018 - 02:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

But libraries are clear. Wire.h uses 7-bit. Fleury's i2cmaster.h uses 8-bit. Atmel's AVR315, AVR316 app notes use 7-bit because their examples use interrupts. Arduino Wire.h use interrupts. Codevision twi.h uses interrupts.
.
I would expect a hardware chip datasheet to show the Slave address on Page #1.
They seldom make it very clear. Timing diagrams are often your best method.
.
I could not find the Slave address in the datasheet anywhere. I am not at a PC. I will have another attempt.
.
David.

 

Edit.   The link in the OP's message was to an App Note and not the datasheet of the LSM6DS33 or the LIS3MDL.

 

Woo-hoo.  LIS3MDL has the info in Table 11. SAD+read/write patterns on page #17.    LSM6DS33 has the info in Table 11. SAD+Read/Write patterns on page #29.

 

Once I had the datasheets it was relatively easy to find.    I searched the App Note multiple times with no success. for Slave, I2C, SAD, ...

 

DS1307.   page#12 of 14

AT24C512.  page #10 of 22

PCF8574. page #8 of 24

 

 

You were right... That wasn't the datasheet of the LSM6DS33, that was the problem all along. I was using some register addresses incorrectly. I found the correct addresses on the real datasheet, it works now. Thanks for pointing that out. 

 

Thank you!

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

lcruz007 wrote:
I was using some register addresses incorrectly.

Note that register addresses are an entirely different thing from the I2C Slave address.

 

I found the correct addresses on the real datasheet

Always refer to the real datasheet as your key source of reference.

 

 

And, if at all possible, always get it direct from the manufacturer's site - rather than via some 3rd-party (which may be out-of-date).

 

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...