cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103REY I2C master receiver issue when 2 bytes, interrupt driver

fabienv
Associate
Posted on January 24, 2013 at 17:42

Hello,

I have an issue while 2 STM32F103REY are connected through i2c, 7bits addressing.

It works good in the following cases:

master transmitter

master receiver for 1 byte

master receiver for n bytes, n >=2

Not ok for master receiver for 2 bytes.

The driver used is a custom one. It uses interrupt.

Surprisingly, the ''AN2824 I2C master programming examples (DMA, interrupts, polling)'' describe no examples with master receiver based on interrupt ?

There are only DMA and polling examples for this cases. Does it means no robust solution is possible with interrupt ?

The issue happens during a first 2 bytes reception but is only seen on the next reception.

3 interrupts occurs to read 3 bytes instead of 2 interrupts to read 2 bytes.

The unexpected extra read data is lost, as not read before the next reception (it is unexpected).

- Based on the errata sheet, I guess the best matched issue is the one reported as ''Some software events must be managed before the current byte is

being transferred'' and applying to EV6_1.

 I have tried in the handler interrupt routines to ''Stretch SCL line between ADDR bit is cleared and ACK is cleared''

but without success.

                    //GPIOB_CRL 0x40010C00

                    //GPIOB_ODR 0x40010C00 + 0xC

                    //GPIOB_BSRR 0x40010C00 + 0x10

                    // set SCL gpio7, CNF7[1:0] bit 31-30 to 01: General purpose output Open-drain

// no change of the GPIO mode as it is corretcly setup

                    uint32_t bsrr = *(volatile uint32_t *) 0x40010C00;

                    bsrr &= 0x7FFFFFFF;

                    bsrr |= 0x70000000;

                    *(volatile uint32_t *) 0x40010C00 = bsrr;

                    // clear bit7

                    *(volatile uint32_t *) 0x40010C10 |= (1<<(16+7));//same result with *(volatile uint32_t *) 0x40010C0C &= 0xFFFFFF7F

but the bit7 is stuck at 1 and this do nothing while is effective on an un-used IO.

So I guess the I2C interface continue to drive SCL to 1 and the software request to  go low level is then not efficient ?

My investigation to change the GPIO alternate through AFIO, conclude that this is not possible during communication.

I'd like clear code examples on how to do that.

- I then try to  mask interrupt as mentionned in AN2824 for the polling case but here during the interrupt handler. This was not efficient too.

I have looked for information on the forum without success.

Maybe there was a post, as user lanchon wrote ''I've posted master mode i2c code that works and a couple of posts detailing limitations of the i2c macrocell, look them up if you want'' but I have found nothing like this.

Also I guess even if some of the issues described in the errata sheet have not been seen, they have to be workaround for robustness. Regarding the un-sucess  for the first one, no clear synthesis for the whole and not enough detailed how to do (no code) for me, I really need your help.

Thanks in advance

#i2c #i2c
1 REPLY 1
fabienv
Associate
Posted on January 25, 2013 at 16:33

Hi,

While I have still the same issue, I mix up with gpio.

By default gpiob6 is SCL and gpiob7 is SDA.

I wrongly seen gpio7 as SCL instead of SDA and it is at ''1'' between b)  and e) code execution of below procedure.

But in fact, gpiob6/SCL is at ''0''.

In the errata sheet CD00190234, p19:

Workaround 3 (only for EV6_1 and EV6_3 events used in method 2)

EV6_1 event (used in master receiver 2 bytes):

Stretch SCL line between ADDR bit is cleared and ACK is cleared:

a) ADDR=1

b) Configure SCL I/O as GPIO open-drain output low

c) Clear ADDR by reading SR1 register followed by reading SR3

d) Program ACK=0

e) Configure SCL I/O as Alternate Function open drain

So for b) with a cleaner code on the right SCL gpio than this so poor one below is:

           uint32_t * gpiob_odr = (volatile uint32_t *) 0x40010C0C;

            uint32_t * gpiob_bsrr = (volatile uint32_t *) 0x40010C10;

            uint32_t * gpiob_crlh = (volatile uint32_t *) 0x40010C04;

            uint32_t * gpiob_crll = (volatile uint32_t *) 0x40010C00;

                    //01: General purpose output Open-drain and

                    //11: Output mode, max speed 50 MHz.

                    (*gpiob_crll) &= 0xF7FFFFFF;

                    (*gpiob_crll) |= 0x07000000;

                    //clear bit6 so gpiob6 i2c1 SCL without remaping

                    *gpiob_bsrr |= (1<<(16+6));

and e)

                    //11: Alternate function output Open-drain

                    //11: Output mode, max speed 50 MHz.

                    (*gpiob_crll) |= 0x0F000000;

Anyway, that changes nothing about the issue, still 3 bytes received instead of 2.

If somebody encountered such issue, I like you to share how you deal with it.