cancel
Showing results for 
Search instead for 
Did you mean: 

STM 32 F4 Discovery I2C Hanging Up

s210088362
Associate II
Posted on November 21, 2013 at 15:51

Hi, I am having a problem with using the I2C on the STM 32 F4 discovery to read 3 DevanTech SRF-08 ultrasonic sensors, There was a previous post on this matter, but it was unresolved as far as I know, clive1 did indiacte that the problem was in addressing, 10 bit vs 7 bit but I dont know how to make it work never the less, please can you help me. 

I am pasting the Initialisation code for the I2C and the fucntions I am using the try and read the ultrasonics. (I am working in the free version of Atollic True Studio)

// Setup the IIC3 peripheral for the UltraSonic Sensors

void init_I2C3(void){

GPIO_InitTypeDef GPIO_InitStruct;

I2C_InitTypeDef I2C_InitStruct;

// enable APB1 peripheral clock for I2C3

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C3, ENABLE);

// enable clock for SCL and SDA pins

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

/* setup SCL and SDA pins

 * 1. SCL on PA8 and SDA on PC9

*/

// Configure the SCL pin

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; // SCL is on PA8

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed

GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven high

GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // enable pull up resistors

GPIO_Init(GPIOA, &GPIO_InitStruct); // initialize GPIOA

// Configure the SDA pin

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; // SDA is on PC9

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed

GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven high

GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // enable pull up resistors

GPIO_Init(GPIOC, &GPIO_InitStruct); // init GPIOC

// Connect I2C3 pins to AF

GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_I2C3); // SCL

GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C3); // SDA

// configure I2C3

I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHz

I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C mode

I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard

I2C_InitStruct.I2C_OwnAddress1 = 0x00; // own address, not relevant in master mode

I2C_InitStruct.I2C_Ack = I2C_Ack_Disable; // disable acknowledge when reading (can be changed later on)

I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses

I2C_Init(I2C3, &I2C_InitStruct); // init I2C1

// enable I2C3

I2C_Cmd(I2C3, ENABLE);

}

/* Function to Start I2C communications with specific device */

void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){

// wait until I2C1 is not busy anymore

while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

// Send I2C1 START condition

I2C_GenerateSTART(I2Cx, ENABLE);

// wait for I2C1 EV5 --> Slave has acknowledged start condition

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

// Send slave Address for write

I2C_Send7bitAddress(I2Cx, address, direction);

/* wait for I2C1 EV6, check if

* either Slave has acknowledged Master transmitter or

* Master receiver mode, depending on the transmission

* direction

*/

if(direction == I2C_Direction_Transmitter){

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

}

else if(direction == I2C_Direction_Receiver){

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

}

}

/* Function to write one byte to the I2C device */

void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)

{

I2C_SendData(I2Cx, data);

// wait for I2C1 EV8_2 --> byte has been transmitted

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

}

/* Function to read the first byte from the I2C device */

uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){

// enable acknowledge of recieved data

I2C_AcknowledgeConfig(I2Cx, ENABLE);

// wait until one byte has been received

while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );

// read data from I2C data register and return data byte

uint8_t data = I2C_ReceiveData(I2Cx);

return data;

}

/* Function to read a single byte from the I2C device */

uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){

// disabe acknowledge of received data

// nack also generates stop condition after last byte received

// see reference manual for more info

I2C_AcknowledgeConfig(I2Cx, DISABLE);

I2C_GenerateSTOP(I2Cx, ENABLE);

// wait until one byte has been received

while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );

// read data from I2C data register and return data byte

uint8_t data = I2C_ReceiveData(I2Cx);

return data;

}

/* Function to stop communication with the I2C device */

void I2C_stop(I2C_TypeDef* I2Cx){

// Send I2C1 STOP Condition

I2C_GenerateSTOP(I2Cx, ENABLE);

}

/* Read all three light sensors and distance sensors and save to relevant state variables */

void Read_Ldr_Us(){

// For the left sensor.

int HighByte=111;

int LowByte=333;

I2C_start(I2C3, USleftAddr>>1, I2C_Direction_Transmitter);

I2C_write(I2C3,0x01);

I2C_start(I2C3, USleftAddr>>1, I2C_Direction_Receiver);

stLDRleft=I2C_read_ack(I2C3);

HighByte=I2C_read_ack(I2C3);

LowByte=I2C_read_nack(I2C3);

stUSleft= ((unsigned int)HighByte <<  + LowByte);

I2C_stop(I2C3);

// For the front sensor.

I2C_start(I2C3, USfrontAddr>>1, I2C_Direction_Transmitter);

I2C_write(I2C3,0x01);

I2C_start(I2C3, USfrontAddr>>1, I2C_Direction_Receiver);

stLDRfront=I2C_read_ack(I2C3);

HighByte=I2C_read_ack(I2C3);

LowByte=I2C_read_nack(I2C3);

stUSfront= ((unsigned int)HighByte <<  + LowByte);

I2C_stop(I2C3);

// For the right sensor.

I2C_start(I2C3, USrightAddr>>1, I2C_Direction_Transmitter);

I2C_write(I2C3,0x01);

I2C_start(I2C3, USrightAddr>>1, I2C_Direction_Receiver);

stLDRright=I2C_read_ack(I2C3);

HighByte=I2C_read_ack(I2C3);

LowByte=I2C_read_nack(I2C3);

stUSright= ((unsigned int)HighByte <<  + LowByte);

I2C_stop(I2C3);

}

Please can you have a look at this and tell me what is wrong, I am tearing my hair out! Please comment if I need to add any more information. 

#stm32 #stm32f4 #i2c #discovery #clive1 #clive1 #ieeprom
9 REPLIES 9
s210088362
Associate II
Posted on November 22, 2013 at 00:23

This is where I am trying to test the I2C. Please can you respond, Clive :) , Deadline for the project is two days!!

// testing for I2C debugging

int received_data[2];

STM_EVAL_LEDToggle(LED4);

I2C_start(I2C3, 0x00<<1, I2C_Direction_Transmitter); // start a transmission in Master transmitter mode

STM_EVAL_LEDToggle(LED6);

I2C_write(I2C3, 0x00); // write one byte to the slave

I2C_write(I2C3, 0x51); // write another byte to the slave

I2C_stop(I2C3); // stop the transmission

Delay(70);

I2C_start(I2C3, 0x00<<1, I2C_Direction_Receiver); // start a transmission in Master receiver mode

received_data[0] = I2C_read_ack(I2C3); // read one byte and request another byte

received_data[1] = I2C_read_nack(I2C3); // read one byte and don't request another byte, stop transmission

char result[10];

siprintf(result,''The Bytes Read are : %i  , %i '',received_data[0],received_data[1]);

USART_puts(USART2,result);

I have marked the line where it is hanging in the start function. 

/* Function to Start I2C communications with specific device */

void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){

// wait until I2Cx is not busy anymore

STM_EVAL_LEDToggle(LED6);

while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));// it is hanging on  this line 

STM_EVAL_LEDToggle(LED6);

// Send I2C1 START condition

I2C_GenerateSTART(I2Cx, ENABLE);

// wait for I2C1 EV5 --> Slave has acknowledged start condition

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

STM_EVAL_LEDToggle(LED5);

// Send slave Address for write

I2C_Send7bitAddress(I2Cx, address, direction);

STM_EVAL_LEDToggle(LED6);

/* wait for I2C1 EV6, check if

* either Slave has acknowledged Master transmitter or

* Master receiver mode, depending on the transmission

* direction

*/

STM_EVAL_LEDToggle(LED6);

if(direction == I2C_Direction_Transmitter){

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

}

else if(direction == I2C_Direction_Receiver){

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

}

STM_EVAL_LEDToggle(LED5);

}

Posted on November 22, 2013 at 00:54

This is where I am trying to test the I2C. Please can you respond, Clive :) , Deadline for the project is two days!!

So no pressure on me then! As an ex-Philips guy I've done about as much I2C work as anyone should ever have too. Do I at least get a prize?

Stuck in BUSY, yeah I might look very carefully at the actual state of the SDA/SCL lines, and there external pull-ups. I might also observe in all working examples ST calls I2C_Cmd(x, ENABLE); before I2C_Init(x,y); I'd make sure I really understood what 7-bit address is physically placed on the bus, and what the slave wants. And I'd make sure I observed the ACK coming back.

If all else fails drive the bus manually. At least then you can deliver something functional without the asinine ST implementation killing you.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
s210088362
Associate II
Posted on November 22, 2013 at 05:58

Thank-you Clive, I tried changing the order of the init and enable, when watching the bus with a scope I don't get anything happening at all, nothing appears to be placed on the bus. Could there be some manipulation in a config  file or something to enable the I2C3?  

The addresses of my slave devices are 0xE0, 0xE2 and 0xE4, could this be an issue? 

Do you have some bit banging code? If not I will read the UM10204 and get to work :)

s210088362
Associate II
Posted on November 22, 2013 at 08:06

New Idea, I have a PIC which is already interfaced to the ultrasonic sensors, so I can send the ranging data form it over USART, but I am already using USART 2 and 3 and 1. The DAC seems to collide with the USART6 RX on the discovery board, can I still use this RX somehow?

Please tell me all..

Kyle 

Posted on November 22, 2013 at 22:54

The addresses of my slave devices are 0xE0, 0xE2 and 0xE4, could this be an issue?

Well it probably will be if you're right shifting them, because it's the 7 high order bits which are placed on the bus. You need to validate the signal on the bus, and the ACK from the slave. If the slave does not ACK you're not communicating with it properly. You need to do this with a scope or analyzer, and it should be the #1 thing on your list to check.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on November 22, 2013 at 23:05

The DAC seems to collide with the USART6 RX on the discovery board, can I still use this RX somehow?

USART6 using PC6/PC7 should be quite serviceable, it's used on the STM32F4-DIS-BB breakout board.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
emalund
Associate III
Posted on November 22, 2013 at 23:11

I am having a problem with using the I2C on the STM 32 F4 discovery to read 3 DevanTech SRF-08 ultrasonic sensors

 

 

just a question I guess could be valid:

what is the distance between the micro and the sensor

Erik
s210088362
Associate II
Posted on November 23, 2013 at 11:28

The cable run is about 100 MM, untwisted and not shielded, but it is not in a noisy environment, thank you for asking though :)

s210088362
Associate II
Posted on November 23, 2013 at 11:35

Thank you for your assistance Clive, I have used the PIC idea and everything is now up and running, I will get the I2C working at some stage in the future :)