2012-06-15 09:08 AM
Hello guys,
I've got the following problem: I'm trying to read a register of a gyroscope with I²C. Everything works fine as long as I'm using several delays during the I²C communication. This wasn't a problem until yet, where I noticed that exact those delays lock the CPU completely down. So now I need to figure out why this code keeps freezing without delays: uint8_t I2C_Read_Byte(uint8_t __slave_addr, uint8_t __reg_addr) { uint8_t __retval; while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Transmitter); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, __reg_addr); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) ; I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Receiver); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); Delay_us(57); /* freezing without delay */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) ; I2C_AcknowledgeConfig(I2C1, DISABLE); __retval = I2C_ReceiveData(I2C1); Delay_us(101); /* same here */ I2C_GenerateSTOP(I2C1, ENABLE); Delay_us(111); /* and here */ I2C_AcknowledgeConfig(I2C1, ENABLE); return __retval; } I'd be very greatful for any help! Best regards and thanks in advance, Wolfram2012-06-19 05:55 AM
------------------ Okay, seing that touching the ''edit'' button is a no-go here, I won't touch it anymore --------------------
It's not the ''edit'' button, it just happens from time to time. What mostly works is: save the text to an external editor, than leave the thread, than reenter the thread again, and try to post it again. I suggest: Make the delay function non-blocking. Use a timer, and return true/false if time has expired or not. Call it repeatedly instead. Turn your receive function into a state machine, and not a sequencial code. Again, call it repeatedly, until successful. You might get several microseconds jitter, don't know if that matters for a 200Hz sensor signal.2012-06-19 08:45 AM
The I2C bus is a beast
incorrect
The ST32 implementation of the I2C bus is a beast
correct Erik2012-07-08 01:15 AM
Awesome!
I managed to solve it now! The problem indeed was the AcknowledgeConfig. Seems like one of the devices doesn't acknowledge the writte read address operation. Correct code now is: uint8_t I2C_Read_Byte(uint8_t __slave_addr, uint8_t __reg_addr) { uint8_t __retval; while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Transmitter); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, __reg_addr); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) ; I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Receiver); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); I2C_AcknowledgeConfig(I2C1, DISABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) ; __retval = I2C_ReceiveData(I2C1); I2C_GenerateSTOP(I2C1, ENABLE); I2C_AcknowledgeConfig(I2C1, ENABLE); return __retval; } I managed to push the time footprint of the function down to 2480 - 2500 µs :) Yay! But then I realised another problem: the timers weren't working at all. No matter what I set the timer to (TIM1, Period 360000, Clock_Div_1, Count_Up, UpdateInterrupt) I would just constantly run at 1MHz. I then thought ''oh, I have to clar the interrupt pending bit''. But then the timer just fired one single time ang got stuck then. Also manually resetting the counter to 0 didn't work. So I ended up with using the SysTick, set to 200Hz (360000 Ticks @ 72MHz). Thanks for all your help! Best regards, Wolfram