cancel
Showing results for 
Search instead for 
Did you mean: 

Problem reading via I2C - no EV7 event

peter_lanius
Associate II
Posted on January 08, 2010 at 07:11

Problem reading via I2C - no EV7 event

7 REPLIES 7
peter_lanius
Associate II
Posted on May 17, 2011 at 13:36

Hi,

I am struggling to work out why I can't read from my HMC5843 magnetic field sensor via I2C. I am using a STM32F106RB6 bare metal board with the HMC5843 connected via I2C with 4.7K pull-up resistors. I am using CrossWorks 2.0 for ARM, in case it matters.

I can write ok, but on the first read, the code fails. The I2C_DR register contains the correct data byte, but the EV7 (I2C_EVENT_MASTER_BYTE_RECEIVED) event is not being generated.

I believe I am following the communication guidelines on page 633 of the RM0008 -

Quote:

In case a single byte is to be received, the Acknowledge disable and the Stop condition generation are made just after EV6 (in EV6_1, just after ADDR is cleared).

I am not really sure what the waveforms from the DSO are telling me, I have attached images of the SCL and SDA lines for the last two actions on the bus: 1) Re-Start/writing the read address (0x3D) and 2) Receiving the data byte (which should be 0x48 and the I2C_DR register indeed contains 0x48). Right at the end is a little spike, but no NACK/STOP.

Any help would be greatly appreciated.

Here is my code:

Code:

/**

* @brief Read a byte from the specified register of the HMC sensor

* @param ReadAddr : 8bit read address of the HMC register

* @retval The content of the specified register

*/

uint8_t I2C_HMC_ReadByte(uint8_t ReadAddr)

{

// define a local byte variable for the data received

uint8_t ByteReceived = 0x00;

/* While the bus is busy */

while(I2C_GetFlagStatus(I2C_HMC, I2C_FLAG_BUSY));

/* Send STRAT condition */

I2C_GenerateSTART(I2C_HMC, ENABLE);

/* Test on EV5 and clear it */

while(!I2C_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_MODE_SELECT));

/* Send HMC address for write */

I2C_Send7bitAddress(I2C_HMC, HMC_SLAVE_ADDR, I2C_Direction_Transmitter);

/* Test on EV6 and clear it */

while(!I2C_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

/* Send the HMC's internal register address to read from */

I2C_SendData(I2C_HMC, ReadAddr);

/* Test on EV8 and clear it */

while(!I2C_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send STRAT condition a second time */

I2C_GenerateSTART(I2C_HMC, ENABLE);

/* Test on EV5 and clear it */

while(!I2C_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_MODE_SELECT));

/* Send HMC address for read */

I2C_Send7bitAddress(I2C_HMC, HMC_SLAVE_ADDR, I2C_Direction_Receiver);

/* Test on EV6 and clear it */

while(!I2C_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

/* Single Byte Read - Disable Acknowledgment */

I2C_AcknowledgeConfig(I2C_HMC, DISABLE);

/* Send STOP condition */

I2C_GenerateSTOP(I2C_HMC, ENABLE);

/* Test on EV7 and clear it */

if(I2C_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_BYTE_RECEIVED))

{

/* Receive 1 byte of data */

ByteReceived = I2C_ReceiveData(I2C_HMC);

}

/* Enable Acknowledgment to be ready for another reception */

I2C_AcknowledgeConfig(I2C_HMC, ENABLE);

return ByteReceived;

}

tomas23
Associate II
Posted on May 17, 2011 at 13:36

Hello Peter,

I strongly discourage you to use the function I2C_CheckEvent, because as soon as there is some additional flag present in I2C->SR1 or SR2, the function will fail even if the wanted bit is there.

Better check the events on a bit masking basis and follow the notes in reference manual and/or errata sheet.

peter_lanius
Associate II
Posted on May 17, 2011 at 13:36

Thanks edison.

It does indeed work if I comment out the check for the EV7 event before the call to I2C_ReceiveData().

The problem remains though that the bits in SR1/2 that should be set (BUSY, MSL, RXNE) are not actually set. Doesn't that still indicate some kind of protocol/communication failure?

ngaylard
Associate II
Posted on May 17, 2011 at 13:36

I suggest you read the application note on using the I2C there is some detail in solving problems. I had I2C lockups until I implemented the procedure below (from the app note) and we now have very stable I2C comms.

***

In the case where the STM32 is Master Receiver and application software does not

guarantee that the acknowledge is disabled before the slave sends the last byte, it is

recommended not to read DataN_2, so that after DataN_1, the communication is stretched

(both RxNE and BTF are set). Then, clear the ACK bit before reading DataN-2 in DR to

ensure it will be cleared before the DataN acknowledge pulse. After that, just after reading

DataN_2, set the STOP/ START bit and read DataN_1. After RxNE is set, read DataN.

This is illustrated below:

When 3 bytes remain to be read:

– RxNE = 1 => Nothing (DataN-2 not read)

– DataN-1 received

– BTF = 1 because both Shift and DR registers are full: DataN-2 in DR and DataN-1

in the shift register => SCL tied low: no other data will be received on the bus.

– Clear ACK bit

– Read DataN-2 in DR => This will launch the DataN reception in the shift register

– DataN received (with a NACK)

– Program START/STOP

– Read DataN-1

– RxNE = 1

– Read DataN

This procedure ensures that ACK is cleared before the DataN

peter_lanius
Associate II
Posted on May 17, 2011 at 13:36

Thanks ArmNewbie.

I looked at the Application Note. My case relates to the single byte read:

Quote:

Case of a single byte to be received:

– In the ADDR event, clear the ACK bit

– Clear ADDR

– Program the STOP/START bit.

– Read the data after the RxNE flag is set.

I am doing those things (see the code in the original post) and I believe I am doing them in the right order. I am not fussed about BUSY and MSL not being set, but I am confused that RxNE is not set - even though there is a data byte in I2C_DR.

peter_lanius
Associate II
Posted on May 17, 2011 at 13:36

Hi,

I have managed to solve it by following the code from the Application Note, not the text.

Here is my -now working- code:

Code:

uint8_t I2C_HMC_ReadByte(uint8_t ReadAddr)

{

// define a local byte variable for the data received

uint8_t ByteReceived = 0x00;

__IO uint32_t temp;

/* While the bus is busy */

while(I2C_GetFlagStatus(I2C_HMC, I2C_FLAG_BUSY));

/* Send STRAT condition */

I2C_GenerateSTART(I2C_HMC, ENABLE);

/* Test on EV5 and clear it */

while(!HMC_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_MODE_SELECT));

/* Send HMC address for write */

I2C_Send7bitAddress(I2C_HMC, HMC_SLAVE_ADDR, I2C_Direction_Transmitter);

/* Test on EV6 and clear it */

while(!HMC_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

/* Send the HMC's internal register address to read from */

I2C_SendData(I2C_HMC, ReadAddr);

/* Test on EV8 and clear it */

while(!HMC_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send STRAT condition a second time */

I2C_GenerateSTART(I2C_HMC, ENABLE);

/* Test on EV5 and clear it */

while(!HMC_CheckEvent(I2C_HMC, I2C_EVENT_MASTER_MODE_SELECT));

/* Send HMC address for read */

I2C_Send7bitAddress(I2C_HMC, HMC_SLAVE_ADDR, I2C_Direction_Receiver);

/* Wait until ADDR is set */

while (!I2C_GetFlagStatus(I2C_HMC, I2C_FLAG_ADDR));

/* Clear ACK */

I2C_AcknowledgeConfig(I2C_HMC, DISABLE);

__disable_irq();

/* Clear ADDR flag */

temp = I2C_HMC->SR2;

/* Program the STOP */

I2C_GenerateSTOP(I2C_HMC, ENABLE);

__enable_irq();

while ((I2C_GetLastEvent(I2C_HMC) & 0x0040) != 0x000040); /* Poll on RxNE */

/* Read the data */

ByteReceived = I2C_ReceiveData(I2C_HMC);

/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */

while ((I2C_HMC->CR1&0x200) == 0x200);

/* Enable Acknowledgement to be ready for another reception */

I2C_AcknowledgeConfig(I2C_HMC, ENABLE);

return ByteReceived;

}

ErrorStatus HMC_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)

{

uint32_t lastevent = 0;

uint32_t flag1 = 0, flag2 = 0;

ErrorStatus status = ERROR;

/* Check the parameters */

assert_param(IS_I2C_ALL_PERIPH(I2Cx));

assert_param(IS_I2C_EVENT(I2C_EVENT));

/* Read the I2Cx status register */

flag1 = I2Cx->SR1;

flag2 = I2Cx->SR2;

flag2 = flag2 << 16;

/* Get the last event value from I2C status register */

lastevent = (flag1 | flag2) & FLAG_Mask;

/* Check whether the bits required by the I2C_EVENT are set */

if ((lastevent&I2C_EVENT) == I2C_EVENT )

{

/* SUCCESS: bits are set as per I2C_EVENT */

status = SUCCESS;

}

else

{

/* ERROR: status is different from I2C_EVENT */

status = ERROR;

}

/* Return status */

return status;

}

wojciech23
Associate II
Posted on May 17, 2011 at 13:36

All my problems with in I2C in STM32 and others microcontrollers was to big pull up resistors.

In my current hardware sum of resistor is only about 1k4 and i2c work OK with 100kbit transfer.