Issue with I2C2 and SPI2

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

wbober
Posts: 5
Joined: Mon Nov 07, 2011 10:29 am

Re: Issue with I2C2 and SPI2

Post by wbober »

Giovanni wrote:The current driver can only work in DMA mode, it would require changes in oder to work without DMA, it is what wbober decided to do but I don't have any update about this.

Giovanni


Our ChibiOS repository is here https://bitbucket.org/sastrion/chibios/. The modified driver is in chibios/os/hal/platforms/STM32/i2c_lld.c. To use interrupts insted of DMA you need to define STM32_I2C_USE_IRQ somewhere in the makefile. We're using the driver in production code, so it should work. Let me know if you need assistance with it.

Kind regards,
Wojtek
User avatar
cruz_91
Posts: 16
Joined: Tue Dec 25, 2012 10:00 pm

Re: Issue with I2C2 and SPI2

Post by cruz_91 »

Today We improved code. Last code has bug and i2c stucks sometimes. Current code works as it should.

Karol
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Issue with I2C2 and SPI2

Post by Giovanni »

Hi,

Which code has a bug? could you explain?

Giovanni
User avatar
cruz_91
Posts: 16
Joined: Tue Dec 25, 2012 10:00 pm

Re: Issue with I2C2 and SPI2

Post by cruz_91 »

Ok, so maybe first: I work with Wojtek (wbober).
We tested our old I2C IRQ code and sometimes we could see errors.
We've got i2c temperature sensor. It looked like STM could read values from sensor, but after few hours all values were read the same. I read carefully whole datasheet and catch some bugs in code.
some more important changes (in my opinion):
-> changed I2C abort operation. I used code from branch 2.6 STM32/I2Cv2. PE bit can nicely stop I2C
-> It's good to set ACK and POS in I2C_EV5_MASTER_MODE_SELECT state for 2 bytes lenght operation (RM0008, site: 735, second point -> Set POS and ACK )

After these changes sensor began to work properly.
Code is available in our repository:
https://bitbucket.org/sastrion/chibios/

Karol
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Issue with I2C2 and SPI2

Post by Giovanni »

Thanks for clarifying, I will look into bringing the changes into the mainline code.

Giovanni
User avatar
Korken
Posts: 270
Joined: Wed Apr 02, 2014 4:09 pm
Has thanked: 5 times
Been thanked: 6 times

Re: Issue with I2C2 and SPI2

Post by Korken »

I too saw this problem when sending lots of small packets over I2C in my old code.
This is something that is clearly stated in the reference manual (p 832-833), so it should be added.
With my old code I had many days of frustrating strange bugs until I found this in the reference manual.

When I look at the code for 3.0.0, you do not seem to follow the correct procedure for the "For N > 2-byte reception, from N-2 data reception" either.
Or does the DMA fix this for you? When I made my old code for this I chopped it up into three transfers to correctly set bits in between transfers (N > 2 reception, N = 2 reception and final reception).
Because you seem to set the NACK at I2C_EV6_MASTER_REC_MODE_SELECTED, but it should be in I2C_EV8_2_MASTER_BYTE_TRANSMITTED? (BTF = 1).

Please correct me if I have interpreted the code wrong (I'm looking at the I2Cv1 i2c_lld driver).


Plus in cruz_91's code, line 336 (chibios / os / hal / platforms / STM32 / i2c_lld.c):
According to the reference manual p832 you sould set ACK low, not high if I read this correctly.
enly1
Posts: 38
Joined: Wed Oct 09, 2013 10:21 pm

Re: Issue with I2C2 and SPI2

Post by enly1 »

wbober wrote:
Giovanni wrote:The current driver can only work in DMA mode, it would require changes in oder to work without DMA, it is what wbober decided to do but I don't have any update about this.

Giovanni


Our ChibiOS repository is here https://bitbucket.org/sastrion/chibios/. The modified driver is in chibios/os/hal/platforms/STM32/i2c_lld.c. To use interrupts insted of DMA you need to define STM32_I2C_USE_IRQ somewhere in the makefile. We're using the driver in production code, so it should work. Let me know if you need assistance with it.

Kind regards,
Wojtek


Hi Wojtek

I need assistance with this code ...

I have working code for DMA I2C on STMF103 processor with a 2 byte read workaround for single byte reads working fine on 2.6.4, but really need I2C and SPI at the same time, so was looking at your lib.
I pulled it down, knocked up the #define to trigger the code and dropped it into STM32 as you have and its picked up and compiles fine.

However, the code doesn't work in the original form. i.e. if I leave the 2 byte read workaround in, it never seems to pick up stop bits and just locks. If I remove that code, it seemed to pass the first request for a single byte read, but the next call (same line repeated) never concluded. Need to I2CStop the driver to be able to do anything after it timed out. Seems to be sitting in the interrupt handler waiting for stop bits that never arrive.

Obviously, if you're willing to help, I can knock together a simple test harness to simplify debugging. PS - The I2C device is a MPU6050 chip, but i'm only reading the WHO_AM_I register in the test (although main code is full IMU)

Any ideas if it works on an STMF103 or what my issue may be?
enly1
Posts: 38
Joined: Wed Oct 09, 2013 10:21 pm

Re: Issue with I2C2 and SPI2

Post by enly1 »

Couple of points i've noticed since posting:

1. you're original branch seems to be 2.4.x - do you know if this is okay to be used on 2.6.4 ?
2. If I just repeat a single byte read, it seems to work fine, however initialising I2C breaks SPI, so the reason for using this interupt driven driver seems a bit defunct.

Will need to check the 2.6.4 driver codebased for I2Cv1 and SPI drivers to see whats going on, but a little too low level for a newbie like me.
enly1
Posts: 38
Joined: Wed Oct 09, 2013 10:21 pm

Re: Issue with I2C2 and SPI2

Post by enly1 »

Sorry to hijack thread, but given the purpose of the I2C Interupt in this thread was to get I2C + SPI working together, seemed relevant. Shout if you want it moved to a dedicated debug thread...

Simple test harness code - SPI/MMC works perfectly if I2C is stopped before MMC functions.

Explanation: If you comment i2cstop in the following section, SPI functions fail.

Code: Select all

// If I2C remains enabled, SPI functions will not work
  // If i2cStop called, SPI Functions operate correctly
  i2cStop(&I2CD2);

If you leave it un-commented then you are able to enable I2C and perform the operation as long as you disable I2C before SPI operation. See commented block below ...

Code: Select all

/*
 * If this block is enabled, function operates normally as i2cStop called before next SPI operation
    i2cStart(&I2CD2, &i2cfg1);
    // Interupt mode = Single byte read working fine, actually 2 byte read never completes - no stop bits
    // If i2cStop called, SPI Functions operate correctly
    retcode = i2cMasterTransmitTimeout(&I2CD2, addr, txbuf, 1, rxbuf, 1, 10 );
    if (retcode == RDY_OK) {
      chprintf((BaseSequentialStream*) &SD3, "I2C MPU6050 Detected on I2C2 - ID : 0x%x\n\r", rxbuf[0]);
    }
    // If I2C remains enabled, SPI functions will not work
    i2cStop(&I2CD2);
*/

Full debugging code block for main.c ( with I2C2 enabled, SPI2 Enabled, USARTS3 Enabled ):

Code: Select all

/* Debug I2c Interupt + SPI Concurrent */

#include "ch.h"
#include "hal.h"
#include "chprintf.h"

#include "ff.h"

#define MPU6050_WHO_AM_I           0x75   // R

static const I2CConfig i2cfg1 = {
    OPMODE_I2C,
    360000,
    FAST_DUTY_CYCLE_16_9,
};

/* MMC/SD over SPI driver configuration.*/
MMCDriver MMCD1;
static SPIConfig hs_spicfg = {NULL, GPIOB, SD_SPI_CS, 0};   /* Maximum speed SPI configuration (18MHz, CPHA=0, CPOL=0, MSb first).*/
static SPIConfig ls_spicfg = {NULL, GPIOB, SD_SPI_CS, SPI_CR1_BR_2 | SPI_CR1_BR_1};   /* Low speed SPI configuration (281.250kHz, CPHA=0, CPOL=0, MSb first).*/
static MMCConfig mmccfg = {&SPID2, &ls_spicfg, &hs_spicfg};

FATFS MMC_FS;
FIL fdst;
static bool_t fs_ready = FALSE;
static char fbuff[512];

int main(void) {

  FRESULT   err;

  char buff[100];       // f_read data buffer

  uint8_t txbuf[2];
  uint8_t rxbuf[2];
  msg_t retcode = 1;
  unsigned int bw;

  int addr = 0b1101000;         // MPU6050 Device Address
  txbuf[0] = MPU6050_WHO_AM_I;  // WhoAmI Register Address

  halInit();
  chSysInit();

  sdStart(&SD1, NULL);
  sdStart(&SD3, NULL);

  chprintf((BaseSequentialStream*) &SD3, "\x1b[2J\rStarting Debug of I2C ...\n\r");

  i2cInit();
  i2cStart(&I2CD2, &i2cfg1);

  // If I2C remains enabled, SPI functions will not work
  // If i2cStop called, SPI Functions operate correctly
  i2cStop(&I2CD2);

  mmcObjectInit(&MMCD1);
  mmcStart(&MMCD1, &mmccfg);

  fs_ready = FALSE;
  if (!mmcConnect(&MMCD1)) {
    err = f_mount(0, &MMC_FS);
    if (err != FR_OK) {
      mmcDisconnect(&MMCD1);
    } else {
        fs_ready = TRUE;
    }
  }

  if (fs_ready){
    // err used in debugger only - not worth coding nice output
    err=f_open(&fdst, "0:/RaceData/racedata.dat", FA_CREATE_ALWAYS | FA_WRITE);
    err=f_write(&fdst, "Hello World read back from DataFile\n\r", 37, &bw);
    err=f_sync(&fdst);
    err=f_close(&fdst);
  }

  // Loop forever reading contents of file and sending to SD3 Serial
  // Or fail if I2C not stopped
  while(1)
  {

/*
 * If this block is enabled, function operates normally as i2cStop called before next SPI operation
    i2cStart(&I2CD2, &i2cfg1);
    // Interupt mode = Single byte read working fine, actually 2 byte read never completes - no stop bits
    // If i2cStop called, SPI Functions operate correctly
    retcode = i2cMasterTransmitTimeout(&I2CD2, addr, txbuf, 1, rxbuf, 1, 10 );
    if (retcode == RDY_OK) {
      chprintf((BaseSequentialStream*) &SD3, "I2C MPU6050 Detected on I2C2 - ID : 0x%x\n\r", rxbuf[0]);
    }
    // If I2C remains enabled, SPI functions will not work
    i2cStop(&I2CD2);
*/

    if (fs_ready) {

      err=f_open(&fdst, "0:/RaceData/racedata.dat", FA_OPEN_ALWAYS | FA_READ);
      if (err == FR_OK)
      {
        int pos=0;
        int fsize = f_size(&fdst);
        while ((pos<fsize) && (err == FR_OK))
        {
          err = f_read(&fdst, &buff[0], 100, &bw);
          buff[bw] = 0;
          if (bw > 0) chprintf((BaseSequentialStream*) &SD3, "%s", &buff);
          pos+=bw;
        }
        f_close(&fdst);
      } else {
        chprintf((BaseSequentialStream*) &SD3, "Failed to open file\n\r");
      }
    } else {
      chprintf((BaseSequentialStream*) &SD3, "Filesystem not ready\n\r");
    }
  }
}

Sorry for using the FF Lib for SPI, but it was already compiled into my project and the easiest way to trigger SPI.

Any thoughts / things I could try.
Post Reply