cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_GPIO_EXTI_Callback() Only called half the time.

JustSomeGuy
Senior

The code I wrote for the B-L072Z-LRWAN1 is supposed to count pulses on a falling-edge external interrupt pin. The pulse source is an Arduino which toggles its GPIO on and off every 5ms, for a 10ms pulse period. after 6 seconds, the B-L072Z-LRWAN1 transmits the accumulated pulses to a receiving B-L072Z-LRWAN1 device (using proprietary peer-to-peer communication [confirmed to work properly]), which after 6 seconds should receive a count of 600 pulses. The 6 second timer has been confirmed to trigger a callback every 6 seconds.

My issue is that only 300 pulses are being send, which implies that the interrupt is only being called or incrementing every other time. There is an IoT bridge which takes the pulse input from both the arduino and the receiving STM32 device, and displays the pulse count on an IoT platform. the graph shows that the pulse rate for the STM32 is exactly half of what is coming from the Arduino. After debugging, I confirmed that the sending device is sending the wrong number of 300 pulses. Can anyone tell me the reason for this? 

Here is a screenshot of the gpio configuration:

Screenshot 2024-10-30 113050.png

here is the cubeMX configuration function:

 

 

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, PA15_RESERVED_Pin|PA12_RESERVED_Pin|PA1_RESERVED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GREEN_LED_Pin|BLUE_LED_Pin|RED_LED_Pin|TCXO_PWR_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, PC1_RESERVED_Pin|PC0_RESERVED_Pin|PC2_RESERVED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA15_RESERVED_Pin PA12_RESERVED_Pin PA1_RESERVED_Pin */
  GPIO_InitStruct.Pin = PA15_RESERVED_Pin|PA12_RESERVED_Pin|PA1_RESERVED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : GREEN_LED_Pin BLUE_LED_Pin RED_LED_Pin TCXO_PWR_Pin */
  GPIO_InitStruct.Pin = GREEN_LED_Pin|BLUE_LED_Pin|RED_LED_Pin|TCXO_PWR_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PB9 PB8 PB15 PB11
                           PB12 PB10 */
  GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8|GPIO_PIN_15|GPIO_PIN_11
                          |GPIO_PIN_12|GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PA14 PA10 PA13 PA8
                           PA11 PA9 PA0 PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_10|GPIO_PIN_13|GPIO_PIN_8
                          |GPIO_PIN_11|GPIO_PIN_9|GPIO_PIN_0|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB4_RESERVED_Pin PB1_RESERVED_Pin TEST_RANGE_Pin PB0_RESERVED_Pin */
  GPIO_InitStruct.Pin = PB4_RESERVED_Pin|PB1_RESERVED_Pin|TEST_RANGE_Pin|PB0_RESERVED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PC13 PC14 PC15 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PC1_RESERVED_Pin PC0_RESERVED_Pin PC2_RESERVED_Pin */
  GPIO_InitStruct.Pin = PC1_RESERVED_Pin|PC0_RESERVED_Pin|PC2_RESERVED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PH0 PH1 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

  /*Configure GPIO pin : PULSE_INPUT_Pin */
  GPIO_InitStruct.Pin = PULSE_INPUT_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(PULSE_INPUT_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : ENTER_SETUP_Pin */
  GPIO_InitStruct.Pin = ENTER_SETUP_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(ENTER_SETUP_GPIO_Port, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);

  HAL_NVIC_SetPriority(EXTI2_3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);

  HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

 

 

here is the interrupt callback function:

 

 

//this function is called when an external interrupt is triggered
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	/*if the interrupt is triggered from the pulse input pin, increment the pulse 
        counter*/
  if(GPIO_Pin == PULSE_INPUT_Pin)
	pulseCount++;
}

 

 

for good measure, here is the code for the arduino which sends the pulses to the STM32 (sorry in advance; arduino sucks, I know):

 

 

#define ledPin 13
#define pulse_1 4
#define pulse_2 5
#define PULSE_WIDTH 5000 //5 mS

uint32_t timestamp = 0;
bool state = LOW;

void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);
  pinMode(pulse_1, OUTPUT);
  pinMode(pulse_2, OUTPUT);
  digitalWrite(pulse_1, LOW);
  digitalWrite(pulse_2, LOW);
  digitalWrite(ledPin, LOW);
  timestamp = micros();
}

void loop() {
  if((micros() - timestamp) >= PULSE_WIDTH)
  {
    digitalWrite(pulse_1, state);
    digitalWrite(pulse_2, state);
    timestamp = micros();
    digitalWrite(ledPin, state);
    (state == HIGH) ? state = LOW : state = HIGH;
  }
}

 

 

And here is what is showing up on the IoT platform. Sometimes the controller sends the correct 600 pulses, and sometimes it sends 300. The units are not important, as this is only to show if the number of pulses sent match what is sent from the arduino or not. the dip at 11:00 is just from me disconnecting the receiving device for a few minutes.

Screenshot 2024-10-30 142615.png

23 REPLIES 23

From the top of the post:

"after 6 seconds, the B-L072Z-LRWAN1 transmits the accumulated pulses to a receiving B-L072Z-LRWAN1 device (using proprietary peer-to-peer communication)"

"After debugging, I confirmed that the sending device is sending the wrong number of 300 pulses."

With that information, I thought people could put 2 and 2 together that the sending device is the non-working device, i.e. 131.072 kHz. My apologies for not being clear enough.

Why do you say forget HAL at those speeds? Is it too process-heavy?

Some very rough estimations:

Interrupt entry and exit takes ca. 30 clock cycles by the MCU alone. A single line of simple C code translates to 3..6 instructions = ca. 6 clock cycles. Just think about the number of code lines spent on multiple indirections with HAL-based solution.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Good point, however the pulse input is max 100 Hz. The interrupt callback is just incrementing a value. Let's say 40 clock cycles? In that case, it should be able to handle around 3000 interrupts every second (131072 / 40) if that's all the controller is doing. The only other process it is doing in the meantime is running the LP timer which triggers an interrupt every second. The only processor-intensive process is the LoRa transmission, but if I increase the transmission time to 15 minutes between transmissions (and set LP timer to interrupt every minute), I still get the same behaviour.

> The interrupt callback is just incrementing a value. Let's say 40 clock cycles?

The Cube/HAL layer between the vector and and callback is a non-negligible piece of code itself.

Try something different: in the EXTI ISR, toggle some GPIO Output pin, and observe on oscilloscope/LA together with the input signal.

JW