I2C implementation for STM32

This forum is dedicated to feedback, discussions about ongoing or future developments, ideas and suggestions regarding the ChibiOS projects are welcome. This forum is NOT for support.
User avatar
Badger
Posts: 346
Joined: Mon Apr 18, 2011 6:07 pm
Location: Bath, UK
Contact:

Re: I2C implementation for STM32

Postby Badger » Mon Jan 30, 2012 6:04 pm

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.

User avatar
Giovanni
Site Admin
Posts: 12749
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 696 times
Been thanked: 573 times
Contact:

Re: I2C implementation for STM32

Postby Giovanni » Mon Jan 30, 2012 7:07 pm

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

User avatar
Badger
Posts: 346
Joined: Mon Apr 18, 2011 6:07 pm
Location: Bath, UK
Contact:

Re: I2C implementation for STM32

Postby Badger » Mon Jan 30, 2012 11:55 pm

I had these debug options enabled:

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.

User avatar
Giovanni
Site Admin
Posts: 12749
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 696 times
Been thanked: 573 times
Contact:

Re: I2C implementation for STM32

Postby Giovanni » Tue Jan 31, 2012 8:52 am

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

User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Location: Minsk, Belarus
Been thanked: 7 times

Re: I2C implementation for STM32

Postby barthess » Wed Feb 01, 2012 11:37 am

Hi Badger,
If you create test case I will try to catch the error.

User avatar
Badger
Posts: 346
Joined: Mon Apr 18, 2011 6:07 pm
Location: Bath, UK
Contact:

Re: I2C implementation for STM32

Postby Badger » Sun Mar 25, 2012 4:44 pm

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:

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 106 times

User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Location: Minsk, Belarus
Been thanked: 7 times

Re: I2C implementation for STM32

Postby barthess » Sun Mar 25, 2012 5:57 pm

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.

User avatar
Badger
Posts: 346
Joined: Mon Apr 18, 2011 6:07 pm
Location: Bath, UK
Contact:

Re: I2C implementation for STM32

Postby Badger » Sun Mar 25, 2012 6:05 pm

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 :D

User avatar
Badger
Posts: 346
Joined: Mon Apr 18, 2011 6:07 pm
Location: Bath, UK
Contact:

Re: I2C implementation for STM32

Postby Badger » Mon Apr 02, 2012 1:18 pm

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?

User avatar
Giovanni
Site Admin
Posts: 12749
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 696 times
Been thanked: 573 times
Contact:

Re: I2C implementation for STM32

Postby Giovanni » Mon Apr 02, 2012 2:06 pm

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


Return to “Development and Feedback”

Who is online

Users browsing this forum: No registered users and 1 guest