• Trill
  • Integrating Trill flex with STM32

Hi, I was following the step in trill sensors to implement the code in the STM32. I am using nucleo-h723zg, but all the board will work the same. I am using trill flex sensor with default address (no soldering on the address part) with i2c1 channel in the stm board.

Here is my code snippet of main.c. First parts are the definition section, and the second part is the code in the main function.

uint8_t gI2cAddress = 0x48 << 1;
//uint8_t gI2cAddress = 0x48; 
const unsigned int kTimeout = 100;


enum {
  kOffsetCommand = 0,
  kOffsetData = 4
};
enum {
  kCommandNone = 0,
  kCommandMode = 1,
  kCommandScanSettings = 2,
  kCommandPrescaler = 3,
  kCommandNoiseThreshold = 4,
  kCommandIdac = 5,
  kCommandBaselineUpdate = 6,
  kCommandMinimumSize = 7,
  kCommandAdjacentCentroidNoiseThreshold = 8,
  kCommandAutoScanInterval = 16,
  kCommandIdentify = 255,
};
enum { kNumTouches = 30 };

enum {
    kModeCentroid = 0,
    kModeRaw = 1,
    kModeBaseline = 2,
    kModeDiff = 3
};
uint16_t firstLocation = 0;
uint16_t firstSize = 0;
`


`
uint8_t identifyBuf[] = {kOffsetCommand, kCommandIdentify};
	int ret = HAL_I2C_Master_Transmit(&trillHi2c, gI2cAddress, identifyBuf, sizeof(identifyBuf), kTimeout);
	if(HAL_OK != ret) {
	    uint32_t error = HAL_I2C_GetError(&hi2c1);
	    printf("I2C Transmission Error: %ld\n", error);
		   fprintf(stderr, "Error: send identify command, I2C Error: %d\n\r", ret);
	}
	HAL_Delay(10);
	uint8_t receiveBuffer[4];
	ret = HAL_I2C_Master_Receive(&trillHi2c, gI2cAddress, receiveBuffer, sizeof(receiveBuffer), kTimeout);
	if(HAL_OK != ret) {
	fprintf(stderr, "Error: receive identify command, I2C Error: %d \n\r", ret);
	printf("identify: %#4x %#4x %#4x %#4x\n\r", receiveBuffer[0], receiveBuffer[1], receiveBuffer[2], receiveBuffer[3]);
	}
	printf("identify: %#4x %#4x %#4x %#4x\n\r", receiveBuffer[0], receiveBuffer[1], receiveBuffer[2], receiveBuffer[3]);
	HAL_Delay(10);
	uint8_t diffBuf[] = {kOffsetCommand, kCommandMode, kModeCentroid};
	ret = HAL_I2C_Master_Transmit(&trillHi2c, gI2cAddress, diffBuf, sizeof(diffBuf), kTimeout);
	if(HAL_OK != ret) {
	fprintf(stderr, "Error: send mode command\n\r");
//	return 1;
	}
	// update baseline
	uint8_t updateBaselineBuffer[] = {kOffsetCommand, kCommandBaselineUpdate};
	ret = HAL_I2C_Master_Transmit(&trillHi2c, gI2cAddress, updateBaselineBuffer, sizeof(updateBaselineBuffer), kTimeout);
	if(HAL_OK != ret) {
	fprintf(stderr, "Error: send update baseline command\n\r");
	}
	uint8_t transmitBuffer[] = {kOffsetData};
	ret = HAL_I2C_Master_Transmit(&trillHi2c, gI2cAddress, transmitBuffer, sizeof(transmitBuffer), kTimeout);
	if(HAL_OK != ret) {
	fprintf(stderr, "Error: prepare to read command\n\r");	}
	while(1) {
	uint8_t receiveBuffer[kNumTouches * 2 * 2];
	ret = HAL_I2C_Master_Receive(&trillHi2c, gI2cAddress, receiveBuffer, sizeof(receiveBuffer), kTimeout);
	if(HAL_OK != ret) {
	  fprintf(stderr, "Error: blocking receive\n\r");
	  return 1;
	}
	for(unsigned int n = 0; n < kNumTouches; ++n)
	{
	  uint16_t location = ((receiveBuffer[2 * n] << 8) + receiveBuffer[2 * n + 1]);
	  uint16_t size = ((receiveBuffer[2 * n + kNumTouches * 2] << 8) + receiveBuffer[2 * n + 1 + kNumTouches * 2]);
	  if(location != 0xffff)
	  {
		if(0 == n)
		{
		  firstLocation = location;
		  firstSize = size;
		}
		printf("[%d] %d %d, \n\r", n, location, size);
	  }
	}
	  printf("\n\r reading done? \n\r ");
	  		HAL_Delay(500);

However, it always giving "I2C Transmission Error: 32
Error: send identify command, I2C Error: 1". Of course, the other identification codes give error:
"Error: receive identify command, I2C Error: 1
identify: 0 0 0 0
identify: 0 0 0 0
Error: send mode command
Error: send update baseline command
Error: prepare to read command
Error: blocking receive"

I am pretty sure I followed the all the convention in the datasheet, but I am still getting this error. I2C1 channel gets 48MHz clock and I set the i2c as fast mode (400Hz). Could you help me to find what's wrong with the code / setup?
Or should I use DMA setting or timer? If so, could you guide me how to setup the right DMA/timer with i2c for trill flex?

Thank you!!

Check in the source what error 32 means. Do you have pull ups on the scl and data lines?

Thank you for the reply!
Error 32 is timeout error, (https://www.disca.upv.es/aperles/arm_cortex_m3/llibre/st/STM32F439xx_User_Manual/stm32f4xx__hal__i2c_8h_source.html#l00191), which is 0x00000020U. If I change the kTimeout into HAL_MAX_DELAY, then it stuck in the first part,
int ret = HAL_I2C_Master_Transmit(&trillHi2c, gI2cAddress, identifyBuf, sizeof(identifyBuf), kTimeout);
if(HAL_OK != ret) {
uint32_t error = HAL_I2C_GetError(&hi2c1);
printf("I2C Transmission Error: %ld\n", error);
fprintf(stderr, "Error: send identify command, I2C Error: %d\n\r", ret);
return 1;
}

Yes, I put the pull ups on both scl and sda.

Physical pullups or the stm32 pins' internal pullups? The latter may not be enough .

Aside from that, I assume you double checked the pin out in cubemx ?

Thank you for your answer! I put physical pullup and it works well!
However, I still have question on the sensor output - my sensor gives Following outputs:
[5] 0 16191, [6] 0 16191, [7] 0 16191, [8] 0 16191, [9] 0 16191, [10] 0 16191, [11] 0 16191, [12] 0 16191, [13] 0 16191, [14] 0 16191, [15] 0 16191, [16] 0 16191, [17] 0 16191, [18] 0 16191, [19] 0 16191, [20] 0 16191, [21] 0 16191, [22] 0 16191, [23] 0 16191, [24] 0 16191, [25] 0 16191, [26] 0 16191, [27] 0 16191, [28] 0 16191, [29] 0 16191,
It's all 0 output even I press the sensor hard. Also, it's not giving all 30 touches but starting from 5 - Do you know what's happening on here? I tried both kModeCentroid and kModeRaw for uint8_t diffBuf[] = {kOffsetCommand, kCommandMode, kModeRaw}; But it still gives me the same output...

You seem to be putting the sensor in centroid mode. The maximum number of touches in this mode is 5, but you are reading 30 of them. The first 5 will be 0xffff 0xffff so they don't get printed. The remaining ones are reading garbage from memory and so they get printed.

What I do with STM32 is to use the Trill Linux library with a STM32-specific I2c.h file. Then you can do the setup/initialisation as usual and either

  • call trill.readI2c() from your main loop or,
  • if you want to use DMA, set up the DMA as usual and then call trill.newData() from the DMA callback (In this code the DMA callback calls tr_newData() which in turn calls trill.newData())

Thank you for your recommendation! I was able to use thrill.readI2C() function and trill linux library. It works well!!