cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746-Disco I2C Touch Panel ID replying with 0x00 CMSIS-only

ilyus
Senior II

STM32F746-Disco

Capacitive Touch Panel FT5336

STM32CubeIDE, Windows 10

CMSIS-only

I'm developing my first I2C driver for STM32F746 using CMSIS-only, and I've decided it would be great to test my I2C skills on built-in capacitive touch panel FT5336. I used ST-provided ft5336.c/.h to get register addresses (since FT5336 datasheet actually doesn't have them). So obviously my first thing to try is to read Chip ID register.

Initially, I've developed DMA driver for it (yeah I can do DMA but still haven't tried I2C), but as I was running into an issue, I made a step back and went full blocking way. Interestingly enough, the results were identical.

What I do:

I write slave address in write mode (ACK), followed by ID register (NACK).

Then I give it a little pause (~30us, well above datasheet ~10us for start setup; tried different).

Then I write slave address in read mode (ACK), and receive 0x00 (NACK).

I've carefully examined my signal with oscilloscope and logic analyzer, made sure timings are correct and all. I can write (master send) as much as I want (including with DMA), but I'm failing at reading, it seems. I'm not sure on what side the error is. Obviously, the panel works if I run TouchGFX project on it. I looked at TouchGFX-generated code in case I see something there, but I didn't find anything that would stand out to me. I don't have any other I2C-device at hand to test it with.

I2C3 setup:

void i2c_setup(I2C_TypeDef *I2C) {
 
	I2C->CR1 &= ~I2C_CR1_PE; //make sure the peripheral is off
 
	/*
	 * Analog filter enables, digital noise filter disabled
	 * Interrupts disabled
	 * */
	I2C->CR1 = 0x00; //reset
	I2C->CR1 |= (0x00 << I2C_CR1_ANFOFF_Pos) | (0x00 << I2C_CR1_DNF_Pos);
 
	/*
	 * Set WRITE mode
	 * 7-bit mode (ADD10=0)
	 * Load 7-bit Slave Address
	 */
	I2C->CR2 = 0x00; //reset
	I2C->CR2 |= (0x00 << I2C_CR2_RD_WRN_Pos) | (FT5336_I2C_SLAVE_ADDRESS << I2C_CR2_SADD_Pos);
 
	/*
	 * TIMING
	 * 100kHz I2C
	 * */
	I2C->TIMINGR = 0x00; //reset
	I2C->TIMINGR |= (0x06 << I2C_TIMINGR_PRESC_Pos) | (0x02 << I2C_TIMINGR_SCLDEL_Pos) | (0x00 << I2C_TIMINGR_SDADEL_Pos) | (0x1E << I2C_TIMINGR_SCLH_Pos)
			| (0x2A << I2C_TIMINGR_SCLL_Pos);
 
	I2C->CR1 |= I2C_CR1_PE; //activate peripheral
 
}
void i2c_sendByte(uint8_t data, I2C_TypeDef *I2C) {
	I2C->CR2 &= ~I2C_CR2_NBYTES; //make sure number of bytes to transmit is cleared
	I2C->CR2 |= (0x01 << I2C_CR2_NBYTES_Pos); //set number of bytes to send to 1
	I2C->CR2 |= I2C_CR2_AUTOEND; //stop bit after sent byte
	I2C->CR2 &= ~I2C_CR2_RD_WRN; //master requests write transfer
	while (!(I2C->ISR & I2C_ISR_TXE)); //wait while transmit data register is empty (just in case, whatever)
	//Slave address set in setup
	I2C->TXDR = data;
	I2C->CR2 |= I2C_CR2_START; //set start bit
}
 
void i2c_receiveByte(uint8_t *data, I2C_TypeDef *I2C) {
	I2C->CR2 &= ~I2C_CR2_NBYTES; //make sure number of bytes to transmit is cleared
	I2C->CR2 |= (0x01 << I2C_CR2_NBYTES_Pos); //set number of bytes to 1
	I2C->CR2 |= I2C_CR2_AUTOEND; //stop bit after sent byte
	I2C->CR2 |= I2C_CR2_RD_WRN; //master requests write transfer
 
	I2C->CR2 |= I2C_CR2_START; //set start bit
	while (!(I2C->ISR & I2C_ISR_RXNE)); //wait while receive data register is not empty
	*data = I2C->RXDR;
}

How I actually run it all in main.c (removed irrelevant UART pieces that work):

i2c_setup(I2C3);
uint8_t i2c3_id_register;
while (1) {
		while (I2C3->ISR & I2C_ISR_BUSY);
		for (uint32_t i = 0; i < 1000; i++); //lame pause
		i2c_sendByte(0xA8, I2C3);
		while (I2C3->ISR & I2C_ISR_BUSY);
		for (uint32_t i = 0; i < 1000; i++); //lame pause
		i2c_receiveByte(&i2c3_id_register, I2C3);
 
	}

The screenshot if from the logic analyzer, so I actually see what's physically happening on the line, processing the data is not an issue here. Scope gave the same picture. I'm not sure about what I'm doing wrong.

0693W00000LwbKmQAJ.png

1 ACCEPTED SOLUTION

Accepted Solutions
ilyus
Senior II

Unfortunately, there is no document with FT5336 registers and possible I can deduce basic functionality, such as how to read one data point (Read register 0x02 - number of touches), read coordinate registers afterwards, but I have no way of knowing how to configure it - there is no information of what various configuration registers do and mean, what bits change what, at least not for all of them (there are various misc registers). Pretty much going in with intuition. The datasheet of the FT5336 is on the net, but it has actually everything except the register addresses themselves and what individual bits mean.

To my surprise, I found more information about its specifics (but not all yet) on russian forums, which sometimes link to obscure english forums (and sometimes don't). Will keep digging original ST code, unfortunately, it's split between the files.

Still, it's kinda strange that the datasheet of FT5336 simply doesn't have registers.

Due to my phenomenal googling skills, I have just found this document, can't read it all right now, but a few first registers match (and so do their bits). It does actually seem like register map of the FT5336 (maybe! needs verification! Will keep posted!): https://www.lcd-module.com/fileadmin/eng/pdf/zubehoer/FT5x06_5x16_FTS_AN_CTPM_Ver1_1_application_note.pdf

View solution in original post

5 REPLIES 5
KnarfB
Principal III

How look the first TouchGFX generated I2C commands on the bus? Do you spot a difference?

hth

KnarfB

Yeah I don't know what I didn't come up with this idea, although I posted this shortly before the end of the day. Will definitely do this on Monday. Could be something on hardware setup side (timing, something else). Will scope and edit it in. Thanks for the (obvious, but forgotten by me) idea!

So that we're talking about the same thing: https://github.com/STMicroelectronics/STM32CubeF7/blob/master/Drivers/BSP/Components/ft5336/ft5336.h

I did logic-analyze working TouchGFX example. The first thing that happens is writing 0x00 to register 0x52 of FT5336 (0x70+Ack - 0x52 + Ack - 0x00 + Ack). The problem is, register 0x52 is not listed among FT5336 registers. There is no such register in ft5336.h, but it's ACK'ed.

After this, it only reads FT5336_GEST_ID_REG ((uint8_t)0x01) and gets 0xFF in return. Once. /* Gesture ID register */

After this, it only reads FT5336_TD_STAT_REG ((uint8_t)0x02) /* Touch Data Status register : gives number of active touch points (0..5) */

and keeps reading that 0x02 register and getting 0xFF indefinitely (I wasn't touching the screen) at 60Hz.

Interestingly enough, 0xFF is not a valid value of register 0x01 as per ft5336.h:

/* Possible values of FT5336_GEST_ID_REG */
#define FT5336_GEST_ID_NO_GESTURE           ((uint8_t)0x00)
#define FT5336_GEST_ID_MOVE_UP              ((uint8_t)0x10)
#define FT5336_GEST_ID_MOVE_RIGHT           ((uint8_t)0x14)
#define FT5336_GEST_ID_MOVE_DOWN            ((uint8_t)0x18)
#define FT5336_GEST_ID_MOVE_LEFT            ((uint8_t)0x1C)
#define FT5336_GEST_ID_SINGLE_CLICK         ((uint8_t)0x20)
#define FT5336_GEST_ID_DOUBLE_CLICK         ((uint8_t)0x22)
#define FT5336_GEST_ID_ROTATE_CLOCKWISE     ((uint8_t)0x28)
#define FT5336_GEST_ID_ROTATE_C_CLOCKWISE   ((uint8_t)0x29)
#define FT5336_GEST_ID_ZOOM_IN              ((uint8_t)0x40)
#define FT5336_GEST_ID_ZOOM_OUT             ((uint8_t)0x49)

And it seems register 0x02, containing number of touch points detected, is supposed to return 0-5, not 0xFF.

And yet it somehow works. I will try to touch the screen and record the communication. I only have so many hands tho. Will post my developments here. Something fishy is going on, and I can't wrap my head around it yet. Undocumented register, strange values read from registers, yet it works...I will also dig deeper into the generated code.

EDIT: as the first thing, I get a write to A4 register with value 0x00, which is

 /* Interrupt mode register (used when in interrupt mode) */
#define FT5336_GMODE_REG                    ((uint8_t)0xA4)
 
#define FT5336_G_MODE_INTERRUPT_MASK        ((uint8_t)0x03)
#define FT5336_G_MODE_INTERRUPT_SHIFT       ((uint8_t)0x00)
 
  /* Possible values of FT5336_GMODE_REG */
#define FT5336_G_MODE_INTERRUPT_POLLING     ((uint8_t)0x00)
#define FT5336_G_MODE_INTERRUPT_TRIGGER     ((uint8_t)0x01)

Interrupt polling. The rest for now is the very same 0x02 register returning 0xFF against all logic. (No touches yet)

ilyus
Senior II

Unfortunately, there is no document with FT5336 registers and possible I can deduce basic functionality, such as how to read one data point (Read register 0x02 - number of touches), read coordinate registers afterwards, but I have no way of knowing how to configure it - there is no information of what various configuration registers do and mean, what bits change what, at least not for all of them (there are various misc registers). Pretty much going in with intuition. The datasheet of the FT5336 is on the net, but it has actually everything except the register addresses themselves and what individual bits mean.

To my surprise, I found more information about its specifics (but not all yet) on russian forums, which sometimes link to obscure english forums (and sometimes don't). Will keep digging original ST code, unfortunately, it's split between the files.

Still, it's kinda strange that the datasheet of FT5336 simply doesn't have registers.

Due to my phenomenal googling skills, I have just found this document, can't read it all right now, but a few first registers match (and so do their bits). It does actually seem like register map of the FT5336 (maybe! needs verification! Will keep posted!): https://www.lcd-module.com/fileadmin/eng/pdf/zubehoer/FT5x06_5x16_FTS_AN_CTPM_Ver1_1_application_note.pdf

TouchGFX just doesn't do any ID matching in multiple examples I tried, it never addresses ID register. It goes straight to sampling touches, and the file with registers I found seems to work. I will figure the rest out on my own.