Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Hang when calling noTone() #372

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

Open
ir-mark opened this issue May 20, 2025 · 1 comment
Open

Hang when calling noTone() #372

ir-mark opened this issue May 20, 2025 · 1 comment

Comments

@ir-mark
Copy link

ir-mark commented May 20, 2025

The function resetTC() waits for timer counter sync or reset in an infinite loop because it is interrupted by an ISR that also calls resetTC()

resetTC() is called from:

  • Tone_Handler() (Interrupt Service Routine)
  • tone() (but interrupts are disabled when it's called)
  • noTone() (HANG)

It can happen that an interrupt can occur while noTone() is performing resetTC(). The interrupt service routine will also perform resetTC(), and when execution returns to noTone() in the middle of performing resetTC() it will hang.

File: Tone.cpp
Function: noTone (uint32_t outputPin)

void noTone (uint32_t outputPin)
{
  if(firstTimeRunning)
  {
    resetTC(TONE_TC);
    digitalWrite(outputPin, LOW);
    toneIsActive = false;
  }
}

Hang Fix:

void noTone (uint32_t outputPin)
{
  if(firstTimeRunning)
  {
    NVIC_DisableIRQ(TONE_TC_IRQn);
    resetTC(TONE_TC);
    NVIC_EnableIRQ(TONE_TC_IRQn);

    digitalWrite(outputPin, LOW);
    toneIsActive = false;
  }
}

resetTC():

static inline void resetTC (Tc* TCx)
{
  // Disable TCx
  TCx->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
  WAIT_TC16_REGS_SYNC(TCx)

  // Reset TCx
  TCx->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
  WAIT_TC16_REGS_SYNC(TCx)
  while (TCx->COUNT16.CTRLA.bit.SWRST);
}

Interrupt Service Routine:

void Tone_Handler (void)
{
  if (toggleCount != 0)
  {
    // Toggle the ouput pin
    *portToggleRegister = portBitMask;

    if (toggleCount > 0)
      --toggleCount;

    // Clear the interrupt
    TONE_TC->COUNT16.INTFLAG.bit.MC0 = 1;
  }
  else
  {
    resetTC(TONE_TC);
    *portClearRegister = portBitMask;
    toneIsActive = false;
  }
}

@ir-mark
Copy link
Author

ir-mark commented May 20, 2025

I am unable to fork this repository to provide a pull request with the fix because I already have a fork of the source https://github.com/arduino/ArduinoCore-samd as https://github.com/ir-mark/ArduinoCore-samd.

How do I work around this limitation of GitHub?

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

No branches or pull requests

1 participant