MPR121 i2c touch keypad with Wire library

szilvasyz
Posts: 6
Joined: Sun Aug 13, 2017 10:06 am

MPR121 i2c touch keypad with Wire library

Post by szilvasyz » Sun Aug 13, 2017 11:08 am

Hi All,

(I am a new member here, so excuse me if my problem is not relevant here. If so, please write me, where to discuss my problem, thanks.)

Last two days I have tried to use a touch keypad assembled with MPR121 chip with my "blue pill" generic STM32 board (STM32F103C8T6). As I saw there is an Adafruit library to handle this hardware, but unforunatelly compiling that library runs into an error. The error comes up because there is no "endTransmission(uint8)" method in the STM32's Wire library.

Looking after this special use of "endTransmission()" in the Adafruit library I found that the library closes the transmission the way the stop condition is not to be sent ("endTransmission(false)") at the end of register addressing.

Further investigations showed me that with STM32's Wire library I can communicate with other i2c devices (I tried PCF8574 and DS1621) without any problem. Reading the datasheet of MPR121 I found that there is a special communication protocol case that seems cannot be realized using STM32 Wire library.

Reading a register from MPR121 needs a communication as follows:
1. sending start condition
2. sending slave address for write mode
3. reading slave ACK
4. sending register address
5. reading slave ACK
6. SENDING REPEATED START CONDITION
7. sending slave address for read mode
8. reading slave ACK
9. reading data byte (register cotent)
10. sending master NAK
11. sending stop condition

I could not make the sequence above using STM32 Wire library. The most critical point of the sequence is step 6, sending a repeated start condition; if you send a stop condition followed by a start condition instead, you would not read the desired register data but always get zero in step 9.

Yesterday evening I wrote a bit-banging i2c communication sketch that could send a repeated start condition at step 6 and I could read all the registers of MPR121 correctly.

Maybe there is a method to generate the sequence above with Wire lib but it is unknown for me. If so, please write me how to do!

At this point - if I am right and the desired sequence cannot be assembled by STM32 Wire lib - I cannot decide what would be the best solution:
- writing my own bit-banging code for handling this HW?
- modifying STM32 Wire library for myself to handle endTransmission(false) calls corectly?
- putting a request (where, how?) to modify Wire library as above?

Please help me for solution. Thank you in advance.

Regards,
Zoltan

User avatar
RogerClark
Posts: 7447
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: MPR121 i2c touch keypad with Wire library

Post by RogerClark » Sun Aug 13, 2017 11:23 am

There is a bit banged version of the wire lib, called SoftWire in the library

We recently swapped to using Hardwire but I don't think all possible cases have been checked

Can you look in the Wire library and see what functionality is missing ?

szilvasyz
Posts: 6
Joined: Sun Aug 13, 2017 10:06 am

Re: MPR121 i2c touch keypad with Wire library

Post by szilvasyz » Sun Aug 13, 2017 12:04 pm

Hi Roger,

I've just checked on Github, there are two types of endTransmission() function in WireBase. It seems those are handling the stop condition the same way as the AVR version of Wire lib:

Code: Select all

uint8 WireBase::endTransmission(bool stop) {
    uint8 retVal;
    if (tx_buf_overflow) {
        return EDATA;
    }
    retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below
    tx_buf_idx = 0;
    tx_buf_overflow = false;
    return retVal;//SUCCESS;
}

uint8 WireBase::endTransmission(){
    endTransmission(true);
}
I have libraries installed on my machine dated as 24th of June this year. I will update libraries today evening and report if the problem is solved.

Many thanks!

User avatar
RogerClark
Posts: 7447
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: MPR121 i2c touch keypad with Wire library

Post by RogerClark » Sun Aug 13, 2017 12:07 pm

I switched the default Wire lib to Hardware I2C about a week ago.

Let me know whether the new version works for you

szilvasyz
Posts: 6
Joined: Sun Aug 13, 2017 10:06 am

Re: MPR121 i2c touch keypad with Wire library

Post by szilvasyz » Sun Aug 13, 2017 8:38 pm

Hi Roger,

There are good and bad news. The good news is that Adafruit's MPR121 lib can simply be compiled with latest STM32 Wire lib. There are no missing function calls or other compile errors. The bad is the communication is not working yet, the library cannot see the MPR121 chip on the i2c bus.

I took further investigations: tried to compile and run the Adafruit's MPR121 test, my Wire lib MPR121 register-read test and my bit-banging MPR121 register-read test scketches on three different boards: Arduino Pro Mini with ATmega328P (powered from 3.3V), Arduino DUE with ATSAM3X8E and STM32 blue pill with STM32F103C8T6. The results are depressing: only the Pro Mini worked well with "factory" Wire library, even the DUE has faulted the tests. BTW all boards passed the bit-banging tests.

I have attached two small sketches to present the problem. Both sketches can be compiled to the three boards mentioned above and can be checked with a real MPR121 device.

(If I have time I will examine the STM32 datasheet to see if its i2c peripheral can handle this special "repeated start" condition.)

Any further idea?
Attachments
my_i2c_scanner_wire.ino
Wire lib MPR121 register-read test
(3.24 KiB) Downloaded 6 times
stm32_soft_i2c.ino
Bitbanging MPR121 register-read test
(2.96 KiB) Downloaded 6 times

User avatar
RogerClark
Posts: 7447
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: MPR121 i2c touch keypad with Wire library

Post by RogerClark » Sun Aug 13, 2017 9:32 pm

do you have a logic analyser to check the bus speed ?

I think it should be set to the default, which is 100khz, but I have not verified that with a logic analyser as all the I2C devices I have seem to happily work up to and beyond 400k

szilvasyz
Posts: 6
Joined: Sun Aug 13, 2017 10:06 am

Re: MPR121 i2c touch keypad with Wire library

Post by szilvasyz » Sun Aug 13, 2017 11:12 pm

Unfortunately I have no logic analyzer. I will think about inventing something to ensure the bus speed. But I am afraid it is really not the problem.

I took another try to use SoftWire library in my "Wire tes code" with success! Then I copied the Adafruit MPR121 library and modified it to use SoftWire instead of Wire resulting a good-working touch-button test on my blue pill.

But there is an interesting thing: browsing the source files of STM32 Wire (which is actually HardWire) library I cannot found anything in the transmit code that would care about the "stop" parameter of the endTransmission(bool) fuction. I see, that endTransmission() with no parameter calls endTransmission(bool) with "true", but in the body of endTransmission(bool) I could not see anything regarding the given "stop" parameter. Maybe I missed something.
In the SoftWire files I found the code snipplets what do a "repeated start" condition instead of "stop" at the end of transmit if "stop" parameter is false, furthermore there is no "start" generation at the beginning of the receiving loop in this case.

As I looked into the STM32 "RM0008 Reference manual" I cannot sure that the hardware peripheral can generate a "repeated start" in 7-bit addressing mode. I saw mentioning "repeated start" condition only in contact of 10-bit addressing mode.

User avatar
RogerClark
Posts: 7447
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: MPR121 i2c touch keypad with Wire library

Post by RogerClark » Mon Aug 14, 2017 12:27 am

@szilvasyz

I forget who submitted the updated Hardware core that we now use, but I know there was a thread about it on the forum, so perhaps you could track down the person who wrote it and ask them about this, as I don't have detailed knowledge of the hardware I2C on the STM32.

The alternative is to try using STM's own official Arduino core for the F103 github.com/stm32duino , and see if that supports repeated start

https://github.com/stm32duino/Arduino_C ... e/Wire.cpp
Which makes calls to STM's HAL

But its possible to look in the HAL code to see what hardware registers its interacting with, and possibly see how to add the feature to libmaple if it exists

User avatar
RogerClark
Posts: 7447
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: MPR121 i2c touch keypad with Wire library

Post by RogerClark » Mon Aug 14, 2017 12:39 am

BTW.

I can recommend buying a cheap 8 channel logic analyser

There is an excellent video on YouTube https://www.youtube.com/watch?v=dobU-b0_L1I

You can get something working for under $10

e.g. search for "CY7C68013A Module Logic Analyzer"

https://www.ebay.com/sch/i.html?_odkw=C ... r&_sacat=0

Or for virtually the same price you can get one in a box with a few cables

Search on "USB 24MHz 8CH Logic Analyzer"

e.g.

https://www.ebay.com/sch/i.html?_odkw=L ... r&_sacat=0

These also seem compatible with the old Saleae PC "Logic" software, or can be used with the open source Sigrok Pulseview

szilvasyz
Posts: 6
Joined: Sun Aug 13, 2017 10:06 am

Re: MPR121 i2c touch keypad with Wire library

Post by szilvasyz » Mon Aug 14, 2017 8:34 am

@Roger,

I looked at the code of HAL-calling Wire lib you suggested, but I cannot see any trace of using the sendStop parameter (even it is marked az "UNUSED"):

Code: Select all

uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
  UNUSED(sendStop);
  int8_t ret = 4;

  if (master == true) {
    // transmit buffer (blocking)
    switch(i2c_master_write(&_i2c, txAddress, txBuffer, txBufferLength))
    {
Furthermore in "HAL_I2C_Master_Transmit" function of the HAL's i2c core code there is a conditionless stop generation at the end of the successful transmit:

Code: Select all

    /* Generate Stop */
    hi2c->Instance->CR1 |= I2C_CR1_STOP;

    hi2c->State = HAL_I2C_STATE_READY;
    hi2c->Mode = HAL_I2C_MODE_NONE;
    
    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);

    return HAL_OK;
I searched the internet and found several "repeated start" problems belonging to STM32 MCUs, but I saw only software (bit-banging) solutions for them. Now I have no more idea, except trying if I can generate the repeated start condition at all using the i2c peripheral register-level access. Tonight it will be tested.

Post Reply