I2C on SamD21 trouble

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

I'm somewhat confused as to how I'm supposed to use Atmel's I2C module. As far as I know, I2C works like this:

 

1 Start bit -> 7 bits (slave address) -> 1 bit (read/write bit) -> 1 acknowledgement bit -> 8 bits (register address) -> 1 acknowledgement bit -> 8 data bits with data for the register -> stop bit. Or it's something like that anyways.

 

Now I'm trying to use Atmel's module, and I don't know where or when I'm supposed to put the data I want to write to the register. Here's my code:

 

#include <asf.h>

#include "drivers/usart_driver.h"

 

#define TIMEOUT 1000

#define MPU_9250_ADDR 0b1101000

static struct i2c_master_config i2c_conf;

static struct i2c_master_module i2c_mod;

 

static uint8_t data_write[1] = { 0x75 };

struct i2c_master_packet i2c_packet = 

{

.address =  MPU_9250_ADDR,

.data = data_write,

.data_length = 1,

.high_speed = true, //MAXIMUM OVERDRIVE

.ten_bit_address = false,

.hs_master_code = 0x0,

};

 

int main (void)

{

system_init();

boogity();

int buff_write = 0;

int buff_read = 0;

i2c_master_get_config_defaults(&i2c_conf);

i2c_master_init(&i2c_mod, SERCOM2, &i2c_conf);

i2c_master_enable(&i2c_mod);

enum status_code statuz;

while((statuz = i2c_master_write_packet_wait_no_stop(&i2c_mod, &i2c_packet)) != STATUS_OK)

{

if(++buff_write >= TIMEOUT)

{

printf("Timeout. =( \n");

buff_write = 0;

break;

}

}

 

while(i2c_master_read_packet_wait_no_stop(&i2c_mod, &i2c_packet) != STATUS_OK)

{

if(++buff_read >= TIMEOUT)

{

printf("Timeout READ. =( \n");

buff_read = 0;

break;

}

}

//printf("%#x\n", (uint8_t)statuz);

printf("%#x\n", data_write[0]);

while (1) {

/* Is button pressed? */

}

return 0;

}

This code is probably looking pretty rough, but I'm sort of just mashing example code in with my code to see how this thing works. Here I write 0x75, which should give me back 0x71, and it does. I'm simply writing nothing to that register and it's returning me a value. What if I need to change the value of a register? Like if I need to change the baud rate or something, how do I write a specific hexa value to it?

 

In I2C by itself, I figure I would do something like this: Start bit -> Slave address -> register address -> new register value -> end bit

 

I tried using "i2c_master_write_byte" but all it asks for is the module and byte to send. I don't know how to tell it where to send this byte.

 

This topic has a solution.
Last Edited: Wed. Dec 27, 2017 - 09:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's possible I don't understand your question but I you really are asking about a multi byte write operation it's as simple as 

static uint8_t data_write[2] = { 0x75, 0 };
struct i2c_master_packet i2c_packet = 
{
.address =  MPU_9250_ADDR,
.data = data_write,
.data_length = 2,
.
.
.

and perform the write with i2c_master_write_packet_wait (i.e., not going to read after so the stop condition is wanted here).

/Lars

 

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

Lajon wrote:

It's possible I don't understand your question but I you really are asking about a multi byte write operation it's as simple as 

static uint8_t data_write[2] = { 0x75, 0 };
struct i2c_master_packet i2c_packet =
{
.address =  MPU_9250_ADDR,
.data = data_write,
.data_length = 2,
.
.
.

and perform the write with i2c_master_write_packet_wait (i.e., not going to read after so the stop condition is wanted here).

/Lars

 

 

I think I am confused as to how these addresses work on my slave device. Let's say I have a register I want to write to called CONFIG. Here I maybe want to change one of its bits to configure something.

 

 

This register's hex address is 1A, so I would write to the register 1A. How do I change the bits this register contains? Do I just write to 1A and then whatever value I want to write into that register? Like this:

 

static uint8_t data_write[2]= { 0x1A, /*data to write to address 1A here*/ };

//then I write to the packet that uses this data array

 

Or am I thinking the wrong way?

 

And if this IS the way I write data to a register, how does my function know the difference between me writing to a register and me simply writing to get data back from registers?

Last Edited: Wed. Dec 27, 2017 - 07:23 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Yes that is how you write, exactly as in my example above. 

And if this IS the way I write data to a register, how does my function know the difference between me writing to a register and me simply writing to get data back from registers?

You implement two functions, one for writing and one for reading, the reading function will include the repeated start, i.e., it writes the register address using  i2c_master_write_packet_wait_no_stop and then reads.

/Lars

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

Lajon wrote:

Yes that is how you write, exactly as in my example above. 

And if this IS the way I write data to a register, how does my function know the difference between me writing to a register and me simply writing to get data back from registers?

You implement two functions, one for writing and one for reading, the reading function will include the repeated start, i.e., it writes the register address using  i2c_master_write_packet_wait_no_stop and then reads.

/Lars

Lajon wrote:

Yes that is how you write, exactly as in my example above. 

And if this IS the way I write data to a register, how does my function know the difference between me writing to a register and me simply writing to get data back from registers?

You implement two functions, one for writing and one for reading, the reading function will include the repeated start, i.e., it writes the register address using  i2c_master_write_packet_wait_no_stop and then reads.

/Lars

 

Alright, thanks