Jump to content

An I2C address enumeration scheme


Duggle
 Share

Recommended Posts

I've got some micro controllers in a sensor network attached to the I2C bus.

The bus master is a STM32 core at the moment.

Prior to talking with the sensors over the I2C (which is working great btw) I want to go into an "address assignment" mode. This involves placing a series of clock pulses on the SCL line.

The sensors listen to the clock pulses and output (Open Drain) on the SDA line at the rising edge of the clock. They actually output a unique serial number over 32 clock pulses.

On the falling edge they read the state of the SDA line. If the bit of the serial number is high, but the sensor reads low, then the sensor "drops out" until the next 32bits are clocked.

If a sensor has not dropped out by the end of the 32nd bit, it's I2C address is the count. It then drops out.

The core finishes enumerating when it reads 0xffffffff. This means that all of the devices on the bus has a unique I2C address.

Ive searched the mios files and found a confusing array of GPIO functions and structures.

  • I want to make SCL of I2C port 1 an open drain (or pushpull) output.
  • make it go high and low
  • make the SDA pin an input
  • read the state of the SDA pin
  • Initialise the I2C port and use it in the usual way

Any hints greatfully accepted!

Link to comment
Share on other sites

For such a purpose you can re-use some code from MIOS32_IIC_TransferWait


// added by wackazong
// see also http://midibox.org/forums/topic/15770-sda-stuck-low-on-i2c-transfer/
// try to deblock a SDA line that is stuck low by bit-banging out a clock signal
// and waiting until the send buffer of any slave is empty

// disable interrupts
I2C_ITConfig(iicx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);

I2C_Cmd(I2C2, DISABLE);
GPIO_InitTypeDef GPIO_InitStructure;

// reconfigure IIC pins to push pull
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Pin = MIOS32_IIC0_SCL_PIN;
GPIO_Init(MIOS32_IIC0_SCL_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = MIOS32_IIC0_SDA_PIN;
GPIO_Init(MIOS32_IIC0_SDA_PORT, &GPIO_InitStructure);

u32 i;
for (i=0; i<16; i++) {
/*Reset the SDA Pin*/
GPIO_ResetBits(GPIOB, MIOS32_IIC0_SDA_PIN);
MIOS32_DELAY_Wait_uS(1000);
/*Reset the SCL Pin*/
GPIO_ResetBits(GPIOB, MIOS32_IIC0_SCL_PIN);
MIOS32_DELAY_Wait_uS(1000);
/*Set the SCL Pin*/
GPIO_SetBits(GPIOB, MIOS32_IIC0_SCL_PIN);
MIOS32_DELAY_Wait_uS(1000);
/*Set the SDA Pin*/
GPIO_SetBits(GPIOB, MIOS32_IIC0_SDA_PIN);
MIOS32_DELAY_Wait_uS(1000);
}

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

GPIO_InitStructure.GPIO_Pin = MIOS32_IIC0_SCL_PIN;
GPIO_Init(MIOS32_IIC0_SCL_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = MIOS32_IIC0_SDA_PIN;
GPIO_Init(MIOS32_IIC0_SDA_PORT, &GPIO_InitStructure);

I2C_Cmd(I2C2, ENABLE);

// re-initialize peripheral
MIOS32_IIC_InitPeripheral(iic_port);
[/code]

For Open Drain mode, use GPIO_Mode_Out_OD instead of GPIO_Mode_Out_PP

For input mode, use GPIO_Mode_IN_FLOATING (No pull device necessary, since the pin is pulled externally)

Reading the pin: e.g. with GPIO_ReadOutputDataBit(GPIOB, MIOS32_IIC0_SDA_PIN);

If you want to use direct access instead of these low-level driver functions, have a look into the perfectly documented low-level driver under $MIOS32_PATH/drivers/STM32F10x/v3.3.0/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c

For accessing the pins of the second port, use MIOS32_IIC1* defines instead.

They are only defined in mios32_iic.c internally - you have to copy them into your application (they will make your application device dependent anyhow)

Best Regards, Thorsten.

Link to comment
Share on other sites

Thank you so much!

I'll study this carefully, but a quick question I haven't been able to sort out: On what pins/port of core STM32 is the second IIC port?

They are here:


#define MIOS32_IIC1_SCL_PORT GPIOB
#define MIOS32_IIC1_SCL_PIN GPIO_Pin_6
#define MIOS32_IIC1_SDA_PORT GPIOB
#define MIOS32_IIC1_SDA_PIN GPIO_Pin_7
[/code]

-> search in http://www.ucapps.de/mbhp/mbhp_core_stm32_v2.pdf for PB6 and PB7 -> J19:SI and J19:SC

Best Regards, Thorsten.

Link to comment
Share on other sites

Thanks, I think I'll change to using this second port for the sensor network.

Im using an extra GPIO port pin to switch bus power on and off, in order to reset the sensors and put them in the address assignment state (part of their bootloader).

This means just one connector for both IIC and power switch (J19 as it happens).

The normal fixed address IIC devices can be attached to first IIC port.

I've got the address assignment part working well using the Transferwait code as a template. Your hint has saved me LOTs of time, so thanks again!

(I'll post some code soon in case anyone is interested).

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...