MPR121 i2c touch keypad with Wire library

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
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.


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 ?

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:

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(){

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

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?

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

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.

Mon Aug 14, 2017 12:27 am

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 , and see if that supports repeated start … 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

Mon Aug 14, 2017 12:39 am

I can recommend buying a cheap 8 channel logic analyser

There is an excellent video on YouTube

You can get something working for under $10

e.g. search for “CY7C68013A Module Logic Analyzer” … 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. … r&_sacat=0

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

Mon Aug 14, 2017 8:34 am

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”):

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

if (master == true) {
// transmit buffer (blocking)
switch(i2c_master_write(&_i2c, txAddress, txBuffer, txBufferLength))

Mon Aug 14, 2017 10:24 am
If you have a github account, I would raise an issue for this on the stm32duino github account as fpSTM is quite proactive about these things, and as he works for STM, sometimes he can get support when things are missing from the HAL

Wed Aug 16, 2017 9:42 pm
Hi Roger,

Sorry for late answering, I’ve just finished the test code for generating “repeated start” with i2c hardware peripheral. As it can be seen the hardware is able to do it, only i2c libraries don’t realize the “stopless” transmission. I attahced the sketch I worked on to demonstrate the things. Although the sample code does not care about any errors during communication, it is working on my desk. I can read all registers of MPR121 correctly.

In the meantime I created a free Github account (szilvasyz), because I had none.

Do you think there is any chance to put handling of this “stopless transmission” case in the main Wire lib code?


Wed Aug 16, 2017 10:29 pm
I don’t know that much about I2C, but I am happy to change the core as long as it does not break things for other users.

I am also happy to add new API functions if necessary to enable this mode

Sat Oct 27, 2018 1:18 pm
[RogerClark – Wed Aug 16, 2017 10:29 pm] –
I don’t know that much about I2C, but I am happy to change the core as long as it does not break things for other users.

I am also happy to add new API functions if necessary to enable this mode

Did you get any further with this Roger? Just wondering – bought a cheap MPR121 board from china for my midi sequencer project.
No worries if not, it can lurk in my spares tin :D

(Hope nobody minds me ressurecting this thread, it just seemed so directly tied to it, didnt seem sensible to start a new one).

Thu Jan 31, 2019 6:26 am

There are now several I2C peripherals available needing the i2c RepeatStart option.

I’ve been trying to get a VEML6072 sensor working with BluePill and run into the same issue.
It works just fine with an Arduino UNO where the “endTransmission(false)” works by omitting the i2c_stop state.

Wonder whether anyone have succeeded in using/modifying the Wire library to implement RepeatStart?

Thanks much.

Thu Jan 31, 2019 8:15 pm
I found “SoftWire” solved the problem. That library does include support for RepeatStart.

Please see my example for interfacing a VELM6075 uV sensor with a BluePlill.


Leave a Reply

Your email address will not be published. Required fields are marked *