Arduino_Core_STM32
Arduino_Core_STM32 copied to clipboard
FR: TSC
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.
Any contribution are welcome.
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?
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.
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?
Sorry, I moved on to esp32.
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):
- 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) - 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
- Added some global variables to the top of my ino file:
const int touchThreshold = 50;
TSC_HandleTypeDef htsc;
TSC_IOConfigTypeDef IoConfig;
int baselineTouch = 0;
- 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);
}
}
- 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();
}
- 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.