8000 Hang when calling noTone() · Issue #372 · adafruit/ArduinoCore-samd · GitHub
[go: up one dir, main page]

Skip to content
Hang when calling noTone() #372
Open
@ir-mark

Description

@ir-mark

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;
  }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    0