SAM D10 i2c slave no AMATCH or well, anything. [SOLVED]

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

Hi,

 

Recently i have been trying to get a SAM D10 to communicate with a nordic nrf51422, in order to use the self programming function of the SAM to program it OTA. So far i have run into many issues, however now it is all behaving as expected, but it doesn't work. In the ASF there is a driver for the i2c slave, which i am running in polled mode. It was written for a D21, however there was not too many changes required to get it running on the D10. when i initialise the i2c module in slave mode, it returns STATUS_OK, however when going to i2c_slave_read_packet_wait, it just returns STATUS_TIMEOUT, i have disabled the timeout temporarily, and it never receives anything. I have got as far as seeing that the flags for amatch, data ready etc, never get set. The master is working with loads of other i2c devices, such as EEPROMS, Accelerometers, and PMICs, so it is definitely the SAM that is the fault here. I have uart working, which i use for debugging, the driver for that was from a D21, and it worked straight away, no tweaks required. The data on the scope looks perfect, no problems with pullups, or start conditions, the atmel just doesn't do anything. My config is below. Thanks in advance for any help. By the way, this code might appear a little rough, still fairly new to programming, and i have spent a lot of caffeine fuelled hours on this, so please excuse any bad practise. I am using the SAM D10 Xplained board for this, and i have also tried using an Arduino as a master, with no luck.

 

/* Buffer size for I2C receiver array */
#define I2C_DATA_LENGTH 128

/* Address for I2C slave */
#define I2C_SLAVE_ADDRESS 0x00

/* Address mask for i2c slave */
#define I2C_SLAVE_ADDRESS_MASK 0x80

// Module definitions
#define EXT1_I2C_MODULE              SERCOM1
#define EXT1_I2C_SERCOM_PINMUX_PAD0  PINMUX_PA22C_SERCOM1_PAD0
#define EXT1_I2C_SERCOM_PINMUX_PAD1  PINMUX_PA23C_SERCOM1_PAD1
//#define EXT1_I2C_SERCOM_DMAC_ID_TX   SERCOM1_DMAC_ID_TX
//#define EXT1_I2C_SERCOM_DMAC_ID_RX   SERCOM1_DMAC_ID_RX

static void configure_i2c_slave(void)
{

	uart_send_string("\r\n--i2c slave module config started");
	struct i2c_slave_config config_i2c_slave;
	i2c_slave_get_config_defaults(&config_i2c_slave);

	config_i2c_slave.address      = I2C_SLAVE_ADDRESS;
	config_i2c_slave.address_mask = I2C_SLAVE_ADDRESS_MASK;
	config_i2c_slave.address_mode = I2C_SLAVE_ADDRESS_MODE_RANGE ;
	config_i2c_slave.pinmux_pad0  = EXT1_I2C_SERCOM_PINMUX_PAD0;
	config_i2c_slave.pinmux_pad1  = EXT1_I2C_SERCOM_PINMUX_PAD1;
	config_i2c_slave.transfer_speed = I2C_SLAVE_SPEED_STANDARD_AND_FAST;
	config_i2c_slave.buffer_timeout = 100000;

	uint8_t errstring;
	errstring = i2c_slave_init(&i2c_slave_instance, EXT1_I2C_MODULE, &config_i2c_slave);
	switch (errstring){
	case STATUS_OK:
	uart_send_string("\r\n--  STATUS_OK");
	break;
	case STATUS_ERR_DENIED:
	uart_send_string("\r\n--  STATUS_ERR_DENIED");
	break;
	case STATUS_BUSY:
	uart_send_string("\r\n--  STATUS_BUSY");
	break;
	case STATUS_ERR_ALREADY_INITIALIZED:
	uart_send_string("\r\n--  STATUS_ERR_ALREADY_INITIALIZED");
	break;
	default:
	uart_send_string("\r\n-- unknown error");
	break;
	}
	i2c_slave_enable(&i2c_slave_instance);
	uart_send_string("\r\n-- i2c slave module config finished");
}

//useful part of the main function, the rest is irrelavent to this topic

	struct i2c_slave_packet packet;
	uint8_t read_buffer;
	uint32_t len = 0;
	packet.data_length = 1;
	packet.data = read_buffer;
	char str[20];
	/* Read 4 bytes of data from master */
	uart_send_string("\r\n-- waiting for packet(s) ");
	int stat = !STATUS_OK;
	while ( stat != STATUS_OK){
		stat = i2c_slave_read_packet_wait(&i2c_slave_instance, &packet);
		switch (stat){
			case STATUS_OK:
			uart_send_string("\r\n-- STATUS_OK ");
			break;
			case STATUS_ERR_DENIED:
			uart_send_string("\r\n-- STATUS_ERR_DENIED ");
			break;
			case STATUS_ERR_IO:
			uart_send_string("\r\n-- STATUS_ERR_IO ");
			break;
			case STATUS_ERR_BAD_FORMAT:
			uart_send_string("\r\n-- STATUS_ERR_BAD_FORMAT ");
			break;
			case STATUS_ERR_INVALID_ARG:
			uart_send_string("\r\n-- STATUS_ERR_INVALID_ARG ");
			break;
			case STATUS_ERR_ALREADY_INITIALIZED:
			uart_send_string("\r\n-- STATUS_ERR_ALREADY_INITIALIZED ");
			break;
			case STATUS_ERR_TIMEOUT:
			uart_send_string("\r\n-- STATUS_ERR_TIMEOUT ");
			break;
			case STATUS_ABORTED:
			uart_send_string("\r\n-- STATUS_ABORTED ");
			break;
			default:
			sprintf(str, "\r\n-- %d ", stat);
			uart_send_string("\r\n-- unknown error! ");
			uart_send_string(str);
			break;
		}

	}
		uint8_t buf = 0;
		sprintf(buf, "\r\n-- Recieved %d ", read_buffer);
		uart_send_string(buf);

 

 

Last Edited: Wed. Jan 6, 2016 - 08:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/* Address for I2C slave */
#define I2C_SLAVE_ADDRESS 0x00

/* Address mask for i2c slave */
#define I2C_SLAVE_ADDRESS_MASK 0x80

Swap the address values, in range mode the lower limit is in the mask register and the upper limit is the address.

 

    uint8_t read_buffer;
	uint32_t len = 0;
	packet.data_length = 1;
	packet.data = read_buffer;

I bet you have a warning here, packed.data must be the address of your buffer so &read_buffer in this case.
 

		uint8_t buf = 0;
		sprintf(buf, "\r\n-- Recieved %d ", read_buffer);

You can't sprintf to a 0 destination (probably a warning here also).

BTW, the ASF "getting started" example sets up stdio, i.e., printf will work, no need to sprintf to a buffer.

/Lars
 

 

 

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

Thanks for the advice LaJon,  I have tired both ways on the address mask and address as top and bottom, none seemed to work, i must have not changed it back. I don't remeber seeing a warning for the read_packet, but i see your point, i will change that also. I would expect an error to be returned though if the read buffer is wrong, or i would expect it to ack the address and then have a problem. This is a bit of a pain, because thats what they have in the ASF, i haven't changed the read buffer code at all, as i presumed it would work. Actually i may have modified it, as read_buffer used to be an array (but it never worked then either), to my understanding if i pass an array to a function, it decays to a pointer anyway. oversight from me, so i will fix that.

 

You are right on the warnings for sprintf, however it does actually work, the error was something like discards const qualifier or something, but if printf can do the job on its own, then i will do thanks. 

 

I will try the read buffer when i get home, i hope it works. I have spent a long time on this. Also i have spotted something that could be another error in the ASF, will put it below. 

 

As far as i understand, and also from a document i found on the FAQ from Atmel, is that there is no register or hardware difference between the D11 and D10 in terms of i2c, it just needs different pins, which i have changed, so i have tired the ASF i2c driver (polled) for a D11, no changes other than the pins, and that didn't work either. There was another error which i had overlooked and spotted last night, where i was using SERCOM1 for the UART, and the i2c, but i have fixed this, and also gone back to fixed address mode, and no luck either. Really does seem like a tough nut to crack for something so simple.

 

http://atmel.force.com/support/a...

 

in this function, taken from i2c_slave.c from ASF, if you look on the 6th line, the sercom module is set to look at the i2cm module, not the i2cS module, i changed it in the function below this one, no luck either, and there were no warnings or errors from the change so i assume it is now correct. Please let me know if i am wrong.

static enum status_code _i2c_slave_wait_for_bus(
		struct i2c_slave_module *const module)
{
	/* Sanity check arguments */
	Assert(module);
	Assert(module->hw);

	SercomI2cm *const i2c_module = &(module->hw->I2CM);

	/* Wait for reply */
	uint16_t timeout_counter = 0;
	while ((!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY)) &&
			(!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC)) &&
			(!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH))) {

		/* Check timeout condition */
		if (++timeout_counter >= module->buffer_timeout) {
			return STATUS_ERR_TIMEOUT;
		}
	}
	return STATUS_OK;
}
static enum status_code _i2c_slave_wait_for_bus(
		struct i2c_slave_module *const module)
{
	/* Sanity check arguments */
	Assert(module);
	Assert(module->hw);

	SercomI2cs *const i2c_module = &(module->hw->I2CS);

	/* Wait for reply */
	uint16_t timeout_counter = 0;
	while ((!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY)) &&
			(!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC)) &&
			(!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH))) {

		/* Check timeout condition */
		if (++timeout_counter >= module->buffer_timeout) {
			return STATUS_ERR_TIMEOUT;
		}
	}
	return STATUS_OK;
}

 

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

Hi, 

 

Thanks for the help on some of the issues i was having, after trawling the internet after many times, i stumbled across an app note from atmel, explaining a load of i2c stuff, and it provided code for a D21, which was a bit different, and the code was completely different to what is in the ASF, but it worked after a couple of tweaks. I am bit disappointed that nothing from the ASF would work for me though. Thanks gor your time.