I2C implementation for STM32
Re: I2C implementation for STM32
I phrased that wrong; when it was crashing (extra delays are working so far!), the whole system would halt so it wasn't the device timing out, something in the driver was causing a crash. I am using timeouts in my code to ensure that the thread does not lock.
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: I2C implementation for STM32
Are you using debug options?
If no, try using them and see if something is caught.
If yes, is it possible the system halts because something has been caught?
Anyway the thing to understand is to see if the problem can be replicated using the I2C alone.
Giovanni
If no, try using them and see if something is caught.
If yes, is it possible the system halts because something has been caught?
Anyway the thing to understand is to see if the problem can be replicated using the I2C alone.
Giovanni
Re: I2C implementation for STM32
I had these debug options enabled:
Is it worth enabling the others?
I'm pleased to say that the problem hasn't returned yet, but I think that there is still some obscure case in which an unstable slave can crash the os. I experienced the same problem when I was using an ITG3200, so maybe barthess might be able to recreate it on his board to verify, by removing initialisation delays?
I'll try and put together a simple test case in the next few days. I'll also hook it up to a logic analyser and capture what happens when it crashes.
Code: Select all
/**
* @brief Debug option, system state check.
* @details If enabled the correct call protocol for system APIs is checked
* at runtime.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
#define CH_DBG_SYSTEM_STATE_CHECK TRUE
#endif
/**
* @brief Debug option, parameters checks.
* @details If enabled then the checks on the API functions input
* parameters are activated.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_CHECKS TRUE
#endif
/**
* @brief Debug option, consistency checks.
* @details If enabled then all the assertions in the kernel code are
* activated. This includes consistency checks inside the kernel,
* runtime anomalies and port-defined checks.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_ASSERTS TRUE
#endif
/**
* @brief Debug option, trace buffer.
* @details If enabled then the context switch circular trace buffer is
* activated.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_TRACE FALSE
#endif
/**
* @brief Debug option, stack checks.
* @details If enabled then a runtime stack check is performed.
*
* @note The default is @p FALSE.
* @note The stack check is performed in a architecture/port dependent way.
* It may not be implemented or some ports.
* @note The default failure mode is to halt the system with the global
* @p panic_msg variable set to @p NULL.
*/
#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_STACK_CHECK FALSE
#endif
/**
* @brief Debug option, stacks initialization.
* @details If enabled then the threads working area is filled with a byte
* value when a thread is created. This can be useful for the
* runtime measurement of the used stack.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
#define CH_DBG_FILL_THREADS FALSE
#endif
/**
* @brief Debug option, threads profiling.
* @details If enabled then a field is added to the @p Thread structure that
* counts the system ticks occurred while executing the thread.
*
* @note The default is @p TRUE.
* @note This debug option is defaulted to TRUE because it is required by
* some test cases into the test suite.
*/
#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
#define CH_DBG_THREADS_PROFILING TRUE
#endif
Is it worth enabling the others?
I'm pleased to say that the problem hasn't returned yet, but I think that there is still some obscure case in which an unstable slave can crash the os. I experienced the same problem when I was using an ITG3200, so maybe barthess might be able to recreate it on his board to verify, by removing initialisation delays?
I'll try and put together a simple test case in the next few days. I'll also hook it up to a logic analyser and capture what happens when it crashes.
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: I2C implementation for STM32
You could try to enable the trace buffer and look at the events that crashed the system, the buffer is available for inspection after a crash.
Giovanni
Giovanni
Re: I2C implementation for STM32
I'm yet to have time to find the cause of the problem I described in the above posts, but I've just noticed something new.
I implemented a method for calculating CPU usage and printing via serial:
I was using this to check that enabling FPU actually did something (and it did; my 'heavy' processing code when from about 10% cpu to < 0.001%). But what I also noticed is that one of my I2C servicing threads was at about 9% CPU usage itself!
I'm reading from an MPU6050 which is a combined accelerometer and gyroscope. I have to read 14 bytes to get 3 axis acceleration, 3 axis rotation, and temperature info. I find that if I read just 13 bytes then the CPU usage is basically 0%. Once I read 14, it jumps up to about 9%.
Anyone got any ideas what might be causing the extra cpu usage?
I've attached logic sniffer dumps for the 13byte and 14byte read cases.
Edit: here's some more details:
I implemented a method for calculating CPU usage and printing via serial:
Code: Select all
while(true) {
Thread *thd = chRegFirstThread();
systime_t total = 0;
systime_t times[20];
const char * names[20];
uint8_t i = 0;
do {
times[i] = chThdGetTicks(thd);
total += times[i];
names[i] = thd->p_name;
} while((++i < 20) && (thd = chRegNextThread(thd)));
for(uint8_t j=0; j < i; j++) {
cPrintf("%s: %d\r\n", names[j], (int)(((float)times[j]/(float)total)*100000.0f));
}
I was using this to check that enabling FPU actually did something (and it did; my 'heavy' processing code when from about 10% cpu to < 0.001%). But what I also noticed is that one of my I2C servicing threads was at about 9% CPU usage itself!
I'm reading from an MPU6050 which is a combined accelerometer and gyroscope. I have to read 14 bytes to get 3 axis acceleration, 3 axis rotation, and temperature info. I find that if I read just 13 bytes then the CPU usage is basically 0%. Once I read 14, it jumps up to about 9%.
Anyone got any ideas what might be causing the extra cpu usage?
I've attached logic sniffer dumps for the 13byte and 14byte read cases.
Edit: here's some more details:
- I get 0 cpu usage for other devices when reading 14bytes
- I've tried inserting some sleep routines in the while loop in i2c_lld_master_transmit_timeout to ensure that wasn't hogging the cpu
- Attachments
-
- mpu.zip
- (18.97 KiB) Downloaded 263 times
Re: I2C implementation for STM32
Using OS ticks for measuring purpose produce adequate results in case of heavy long time functions. I observe similar results in my case - thread polling TMP75 sensor consume more CPU time than accelerometer thread. Try to use one of hardware timers instead.
Re: I2C implementation for STM32
That makes a lot of sense. I'm reading the sensors at 1kHz, so it is not unreasonable that the number of ticks is high when not much else is happening on the system.
Thanks barthess, you've put my mind at rest
Thanks barthess, you've put my mind at rest
Re: I2C implementation for STM32
I'm trying to use I2C to communicate with an OV7670 (see here for a code sample). It seems to require some delays in between i2c commands. Indeed, if I try to read from the device the first attempt times out and the second never returns. This behaviour is consistent.
So I'm trying to implement an improvement to the i2c driver which would add the option to insert a delay inbetween the tx and rx stages of i2cMasterTransmitTimeout(), and if possible also a delay after sending the device address. From looking at the code, i2c_lld_serve_event_interrupt() seems to handle the transition from tx to rx, so it should be possible to insert a delay without massive changes to the driver, is that correct?
So I'm trying to implement an improvement to the i2c driver which would add the option to insert a delay inbetween the tx and rx stages of i2cMasterTransmitTimeout(), and if possible also a delay after sending the device address. From looking at the code, i2c_lld_serve_event_interrupt() seems to handle the transition from tx to rx, so it should be possible to insert a delay without massive changes to the driver, is that correct?
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: I2C implementation for STM32
It is an interrupt handler so adding a delay would require a virtual timer or a GPT dependency.
Is that delay required by the specific I2C slave or by something in the driver itself?
Giovanni
Is that delay required by the specific I2C slave or by something in the driver itself?
Giovanni
Return to “Development and Feedback”
Who is online
Users browsing this forum: No registered users and 42 guests