SAMB11 I2C

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

I'm trying to use I2C on SAMB11 Xplained Pro and test case is to read the temperature of the sensor on board. Before SAMB11 I have totally avoided ASF and now I'm really starting to get fed up with it. So it may be that I don't know at all how to use ASF, but I just can't get it to work.

I started with the Battery Info example case. Then I started ASF Wizard and added i2c master in polled mode (is this what I'm supposed to do when adding new ASF features???). I'm reading SAM I2C bus driver application note, SAMB11 driver API manual and the header files AS7.0 put to my solution directory. All three have different members for i2c_master_config. Then there is this mysterious "module". How am I supposed to know where to find that. I went through the header files and found EXT1_I2C_MODULE. Maybe that's it, I have no idea.  I2C in EXT1 header is connected to the temperature sensor, so it could be.

Also the packet had different members and there was no  i2c_master_enable(), which was called in the application note.

So my non-working code (does nothing on the pins, jams at the first write)  SORRY CODE INSERT NOT WORKING

#define DATA_LENGTH 10
static uint8_t write_buffer[DATA_LENGTH] = {
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
};
static uint8_t read_buffer[DATA_LENGTH];

#define SLAVE_ADDRESS 0x48 //Temperature sensor on SAMB11 Xplained Pro

#define TIMEOUT 1000

struct i2c_master_module i2c_master_instance;
static void configure_i2c_master(void)
{
  static uint8_t init=0;
  /* Initialize config structure and software module. */
  struct i2c_master_config config_i2c_master;
 
  i2c_master_get_config_defaults(&config_i2c_master);
  /* Initialize and enable device with config. */
  i2c_master_init(&i2c_master_instance,EXT1_I2C_MODULE ,
          &config_i2c_master);
  //  i2c_master_enable(&i2c_master_instance);
  if(!init)
    {
      DBG_LOG("I2C: clockd %d PADs  %ld %ld\n", config_i2c_master.clock_divider, config_i2c_master.pin_number_pad0, config_i2c_master.pin_number_pad1);
      DBG_LOG("I2C: PMUXs %ld %ld\n", config_i2c_master.pinmux_sel_pad0, config_i2c_master.pinmux_sel_pad1);
      init=1;
    }
}

 

In main I have tried at different locations to do

    
    /* Configure device and enable. */
    configure_i2c_master();
    /* Timeout counter. */
    uint16_t timeout = 0;
    /* Init i2c packet. */
    struct i2c_master_packet packet = {
      .address = SLAVE_ADDRESS,
      .data_length = 1,
      .data = write_buffer,
    };
    
    DBG_LOG("Starting to Write I2C\n");
    /* Write buffer to slave until success. */
    while (i2c_master_write_packet_wait(&i2c_master_instance, &packet) !=
           STATUS_OK) {
      /* Increment timeout counter and check if timed out. */          
      DBG_LOG("Write_loop %d\n", timeout);
      if (timeout++ == TIMEOUT) {
        break;
      }
    }
    /* Read from slave until success. */
    packet.data = read_buffer;
    packet.data_length = 2;
    DBG_LOG("Starting to Read I2C\n");
    while (i2c_master_read_packet_wait(&i2c_master_instance, &packet) !=
           STATUS_OK) {
      /* Increment timeout counter and check if timed out. */
      DBG_LOG("Read_loop %d\n", timeout);
      if (timeout++ == TIMEOUT) {
                        break;
      }
    }
    DBG_LOG("Temperature read:0x%02X 0x%02X %d", read_buffer[0], read_buffer[1],(uint16_t) read_buffer[0]);

 

 

This is the console output I get:

Initializing Battery Service Application
Initializing SAMB11
BD Address:0xF8F005F51BA5, Address Type:0
BLE Started Adv
I2C: clockd 16 PADs  8 9

I2C: PMUXs 2 2

Starting to Write I2C

 

So what am I doing wrong? Both pins are high and there is a 700 uA current, if I ground them (4.7k pull up, not active without power). I guess ASF should handle making the pins output/input as needed by I2C. So many hours wasted already on this ASF monster to do simple things I could have done without it much faster with decent datasheet.

Last Edited: Wed. Apr 26, 2017 - 09:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not clear to me if this has anything to do with wireless or Bluetooth?? Should this thread be moved elsewhere?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

I don't know. It has to do with SAMB11, which seems to be very different from other SAM devices although it is a cortex M0 and is only used for Bluetooth.

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

You have posted in the Internet of things/Wireless/Bluetooth forum, is your question in relation to any of these? If you don't know no one else will.

 

I only see I2C questions in your post.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

No it's not related to these, except for the chip.

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

"I started with the Battery Info example case"

Seems odd, why don't you start with the I2C master example?

 /Lars

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

I was looking at the Atmel Start examples and there isn't one related to I2C. But there is one in ASF examples. I'll give it a try.

I'm quite confused about Atmel Start vs. ASF. Which one should I use and why? They provide completely different set of functions for the same job. I have managed to get the ADC working with Atmel Start + my own modification based on that code. Atmel Start seems to have less layers and maybe a bit easier to understand.

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

OK it works now with ASF. The problem was with i2_master_init (taken from other SAM I2C app note), which didn't exist. i2c_enable does! Also it must be called with "i2c_master_instance.hw" instead of "&i2c_master_instance".

Now I still have to work out the Atmel Start one, since as far as I know you can't mix Atmel Start and ASF.

10-20 hours of work for each simple module to get it working. I feel so stupid. Can ASF/Atmel Start really be this difficult. Has been much easier for me without those, while using AVR.

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

Now the Atmel Start version of I2C works as well.

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

Is there a way to set a timeout for I2C synchronous master configuration in ASF4 (Atmel Start generated code)? SAMB11 seems to hang every now and then when reading the i2c temperature sensor on Xplained Pro. Debugging shows it hangs in "_i2c_m_sync_transfer" at

		while (!hri_i2c_get_TRANSMIT_STATUS_TX_FIFO_EMPTY_bit(hw)) {
		}

Looking at the scope SCL is outputting continuos pulse at 2 MHz and SDA shows a 1 us wide pulse every 4.5 us. So what is going on? The i2c is supposed to be set to 1 MHz in Atmel Start, but seems to be working at 2 MHz. When it works, it still has 2 MHz SCL, but it's not continuous (about 4.5 us long runs with break). And SDA doesn't show pulses 4.5 us appart. It is writing 0x01 0x60 to 7 bit slave address 0x48. So the 2 bit wide could be 0x60 written continously at 4.5 us intervals. Is that what i2c hardware does when it fails to get valid resosponce from the slave?

 

Atmel Start generated initialisation used:


void I2C_0_PORT_init(void)
{

	gpio_set_pin_function(LP_GPIO_15, PINMUX_LP_GPIO_15_M_I2C0_SCL);

	gpio_set_pin_function(LP_GPIO_8, PINMUX_LP_GPIO_8_M_I2C0_SDA);
}

void I2C_0_CLOCK_init(void)
{
}

void I2C_0_init(void)
{
	I2C_0_CLOCK_init();
	i2c_m_sync_init(&I2C_0, I2C0);
	I2C_0_PORT_init();
}

And test write+read (doesn't work for negative temperatures):

static void I2C_0_example(uint16_t *temperature)
{
	struct io_descriptor *I2C_0_io;
	uint8_t buffer[2];
	uint16_t res;
	int32_t temp;
	i2c_m_sync_get_io_descriptor(&I2C_0, &I2C_0_io);
	i2c_m_sync_enable(&I2C_0);
	i2c_m_sync_set_slaveaddr(&I2C_0, 0x48, I2C_M_SEVEN);

	buffer[0]=0x01;
	buffer[1]=0x60;
	//	DBG_LOG("I2C write");
	io_write(I2C_0_io, buffer, 2); //Sets 12 bit resolution for temperature
	buffer[0]=0x00;
	io_write(I2C_0_io, buffer, 1); //Sets Temperature pointer


	//DBG_LOG("I2C read");
	io_read(I2C_0_io, buffer, 2);
	res=buffer[1]+256*buffer[0];
	temp=(res*16*100)/4096;
	//res=temp;
	//	DBG_LOG("Temperature %d", res);
	*temperature=temp;

}

 

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

How is NACK handled with SAMB11? The basic code generated by Atmel Start seems to be "bad code" shown in this example from a competitor: http://processors.wiki.ti.com/in...

// BAD CODE!!! Would hand in case we get NACKed!
// Wait for "XRDY" flag to transmit data
while ( !(*I2C_STR & ICSTR_ICXRDY) );

However, you should change it to look like this:

// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
while ( !(*I2C_STR & (ICSTR_ICXRDY|ICSTR_ARDY)) );
 
// If a NACK occurred, SCL is held low and STP bit cleared
if ( *I2C_STR & ICSTR_NACK )
{
	*I2C_MDR |= ICMDR_STP;	// send STP to end transfer
	*I2C_STR = ICSTR_NACK;	// clear NACK bit
	return I2C_FAIL;
}

I don't want to use purely callback based solution, since sensor data needs to be read without extra delay and before the BLE event loop goes any further. What are my options? Make my own I2C handler? Or make callback for NACK condition (how, NACK is not mentioned in the very slim SAMB11 datasheet!) and try to stop the busy wait from there.

 

Atmel Studio gives some hints, I couldn't find elsewhere. Looking at IO registers in opens a hint window for RECIVER_STATUS/NAK bit (not NACK!) saying that "Active high when NAK is received. I2C module will retry transmission unless transmission aborted by the flush register". Then there is another hint for I2C_FLUSH saying writing to it will flush both RX and TX FIFO and TX FIFO will abort ongoing transaction when the current byte has been transmitted.