Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FR: TSC #1098

Open
sixtyfive opened this issue Jun 12, 2020 · 6 comments
Open

FR: TSC #1098

sixtyfive opened this issue Jun 12, 2020 · 6 comments

Comments

@sixtyfive
Copy link

Knowing about #247, which seems to be about touch screens only, I'd like to request the feature of touch sensing control to be added to Arduino_Core_STM32. The TSC is part of many STM32s, even down to the STM32F042x4 series, and using touch buttons is quite popular, so I think it would be a good thing to have available without having to resort to direct HAL programming.

@fpistm
Copy link
Member

fpistm commented Jun 12, 2020

Any contribution are welcome.

@sixtyfive
Copy link
Author

According to one of the datasheets, it's as simple as copy-pasting the following init code:

/* Configure TCS */
/* With a charge transfer around 2.5μs */
/* (1) Select fPGCLK = fHCLK/32,
       Set pulse high = 2xtPGCLK,Master
       Set pulse low = 2xtPGCLK
       Set Max count value = 16383 pulses
       Enable TSC */
/* (2) Disable hysteresis */
/* (3) Enable end of acquisition IT */
/* (4) Sampling enabled, G2IO4 */
/* (5) Channel enabled, G2IO3 */
/* (6) Enable group, G2 */
TSC->CR = TSC_CR_PGPSC_2 | TSC_CR_PGPSC_0 | TSC_CR_CTPH_0 | TSC_CR_CTPL_0 
        | TSC_CR_MCV_2 | TSC_CR_MCV_1 | TSC_CR_TSCE; /* (1) */
TSC->IOHCR &= (uint32_t)(~(TSC_IOHCR_G2_IO4 | TSC_IOHCR_G2_IO3)); /* (2) */
TSC->IER = TSC_IER_EOAIE; /* (3) */
TSC->IOSCR = TSC_IOSCR_G2_IO4; /* (4) */
TSC->IOCCR = TSC_IOCCR_G2_IO3; /* (5) */
TSC->IOGCSR |= TSC_IOGCSR_G2E; /* (5) */

And then creating (???) an interrupt:

/* End of acquisition flag */
if((TSC->ISR & TSC_ISR_EOAF) == TSC_ISR_EOAF) {
  TSC->ICR = TSC_ICR_EOAIC; /* Clear flag */
  AcquisitionValue = TSC->IOGXCR[1]; /* Get G2 counter value */
}

In its most simple form, what would be required to get from that to something like this:

bool led_state = false;

void toggle_led()
{
  led_state = !led_state;
}

void main()
{
  /* i didn't check if PB14 and PB15 match with the above example! */
  pinMode(PB14, INPUT);
  pinMode(PB15, INPUT);
  attachTSC(digitalPinToInterrupt(PB14), digitalPinToInterrupt(PB15)), toggle_led, CHANGE);
}

void loop()
{
  digitalWrite(LED_BUILTIN, led_state);
}

With my extremely limited understanding of the code from the datasheet, it seems to me that just implementing that imaginary attachTSC function might somehow already be enough?

@someone755
Copy link

Sorry to revive an old issue. I don't think it's necessary to play around with the registers, or sift through the 1000 page reference manuals; The repository already hosts the *_hal_tsc.c drivers. While I don't use stm32duino, I have this bit of code in my STM32CubeIDE project that returns the value of the counter, based entirely off the instructions given at the top of this file specifically (my project uses the F303K8 Nucleo board):

HAL_StatusTypeDef tsc_status; /* HAL_OK       = 0x00U,
                                 HAL_ERROR    = 0x01U,
                                 HAL_BUSY     = 0x02U,
                                 HAL_TIMEOUT  = 0x03 */
TSC_GroupStatusTypeDef tsc_groupstatus; /* TSC_GROUP_ONGOING   = 0x00UL,
                                           TSC_GROUP_COMPLETED = 0x01UL */
tsc_status = HAL_TSC_IODischarge(&htsc,ENABLE); // DISCHARGE STATUS
HAL_Delay(1);
tsc_status = HAL_TSC_Start(&htsc); // START STATUS
tsc_status = HAL_TSC_PollForAcquisition(&htsc); // POLL STATUS
tsc_groupstatus = HAL_TSC_GroupGetStatus(&htsc,TSC_GROUP3_IDX); // GROUP STATUS
tsc_value = HAL_TSC_GroupGetValue(&htsc,TSC_GROUP3_IDX); // VALUE

The TSC configuration and initialization is done automatically by configuring the .ioc file in ST's IDE (even the htsc variable comes predefined), so I'm not really sure if anything extra is required in stm32duino.

NB: In my project there is also a tsl_user.c file with some supposedly easy-to-use functions, but I can't make heads or tails from it. One should be able to use those functions alongside the "STM Studio" program to help calibrate the design (as per AN4316), but since I can't get it to work, I've opted to ignore the whole shebang.

Hope any of this helps. I agree it would be great to have touch sensing implemented in a project like this.

@johnnytolengo
Copy link

johnnytolengo commented Apr 2, 2023

I have a similar issue with a NUCLEO-F072RB
The HAL_TSC_GroupGetStatus(&TscHandle, TSC_GROUP1_IDX) always returns TSC_GROUP_ONGOING

did you make it work?

@sixtyfive
Copy link
Author

Sorry, I moved on to esp32.

@Timo614
Copy link

Timo614 commented Jan 30, 2024

I was able to get this to work with a STM32WB5MM-DK.

I did the following (it took me awhile and I went through quite a bit of trial and error before I was able to get things working):

  1. Copied the default conf for my hal https://github.com/stm32duino/Arduino_Core_STM32/blob/main/system/STM32WBxx/stm32wbxx_hal_conf_default.h adding it to the project as hal_conf_custom.h (see https://github.com/stm32duino/Arduino_Core_STM32/blob/main/system/STM32WBxx/stm32wbxx_hal_conf.h#L7)
  2. Moved the following out of the #if 0 block to under the #include "stm32yyxx_hal_conf.h":
#define HAL_GPIO_MODULE_ENABLED
#define HAL_TSC_MODULE_ENABLED
  1. Added some global variables to the top of my ino file:
const int touchThreshold = 50;
TSC_HandleTypeDef htsc;
TSC_IOConfigTypeDef IoConfig;
int baselineTouch = 0;
  1. I added this logic for the interrupt handler but I couldn't get the interrupt logic itself to work (would just trigger immediately for me when I started with interrupt enabled and I don't understand the logic well enough at this point to debug in further). Instead of relying on the interrupt for now I'm handling the logic in a way based on approach given via someone755's comment (a step further below in my loop logic).
extern "C" {
  void TSC_IRQHandler(void) {
    HAL_TSC_IRQHandler(&htsc);
  }
}
  1. In my setup section setup the pins for my motherboard based on what I saw in the schematic (PC7 is the shield one)
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF9_TSC;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF9_TSC;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF9_TSC;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF9_TSC;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /* TSC interrupt Init */  
  __HAL_RCC_TSC_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  htsc.Instance = TSC;
  htsc.Init.CTPulseHighLength = TSC_CTPH_1CYCLE;
  htsc.Init.CTPulseLowLength = TSC_CTPL_1CYCLE;
  htsc.Init.SpreadSpectrum = DISABLE;
  htsc.Init.SpreadSpectrumDeviation = 1;
  htsc.Init.SpreadSpectrumPrescaler = TSC_SS_PRESC_DIV1;
  htsc.Init.PulseGeneratorPrescaler = TSC_PG_PRESC_DIV4;
  htsc.Init.MaxCountValue = TSC_MCV_8191;
  htsc.Init.IODefaultMode = TSC_IODEF_OUT_PP_LOW;
  htsc.Init.SynchroPinPolarity = TSC_SYNC_POLARITY_FALLING;
  htsc.Init.AcquisitionMode = TSC_ACQ_MODE_NORMAL;
  htsc.Init.MaxCountInterrupt = DISABLE;
  htsc.Init.ChannelIOs = 0;
  htsc.Init.ShieldIOs = 0;
  htsc.Init.SamplingIOs = 0;
  if (HAL_TSC_Init(&htsc) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_NVIC_SetPriority(TSC_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(TSC_IRQn);

  IoConfig.ChannelIOs = TSC_GROUP6_IO2;
  IoConfig.ShieldIOs = TSC_GROUP4_IO2;
  IoConfig.SamplingIOs = TSC_GROUP4_IO1|TSC_GROUP6_IO1;

  if (HAL_TSC_IOConfig(&htsc, &IoConfig) != HAL_OK) {
    /* Initialization Error */
    Error_Handler();
  }
  1. In my loop logic to fetch if I have a touch:
  uint32_t tsc_status;
  uint32_t tsc_groupstatus;
  uint32_t tsc_value;
  tsc_status = HAL_TSC_IODischarge(&htsc,ENABLE); // DISCHARGE STATUS
  HAL_Delay(1);
  tsc_status = HAL_TSC_Start_IT(&htsc); // START STATUS
  tsc_status = HAL_TSC_PollForAcquisition(&htsc); // POLL STATUS
  tsc_groupstatus = HAL_TSC_GroupGetStatus(&htsc,TSC_GROUP6_IDX); // GROUP STATUS
  tsc_value = HAL_TSC_GroupGetValue(&htsc,TSC_GROUP6_IDX); // VALUE
  baselineTouch = max<uint32_t>(baselineTouch, tsc_value);
  if (baselineTouch > 0 && tsc_value <= baselineTouch - touchThreshold) {
    STLink.println("Touch detected");
  }

Logic works for me with the tsc_value returned when not touching as a mostly consistent value and once I touch it I noticed it drops about 80 or so which I then used as the trigger. There was additional touch sensing logic from the STM32 examples but I struggled to even get this part and touching itself working so I am just happy it works consistently with this approach and stm32duino.

Passing along in case it's helpful to anyone else. Works with touch detection of button presses at least as a start here. Quite a bit of code to figure out if one button is pressed but I felt absolutely terrible about leaving the giant touch button unused on my development kit so pressed on to this point of at least working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

5 participants