コード例 #1
0
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);
}
コード例 #2
0
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
  if (toneIsActive && (outputPin != lastOutputPin))
    noTone(lastOutputPin);

  //
  // Calculate best prescaler divider and comparator value for a 16 bit TC peripheral
  //

  uint32_t prescalerConfigBits;
  uint32_t ccValue;

  ccValue = toneMaxFrequency / frequency - 1;
  prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1;

  if (ccValue > TONE_TC_TOP)
  {
    ccValue = toneMaxFrequency / frequency / 2 - 1;
    prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2;

    if (ccValue > TONE_TC_TOP)
    {
      ccValue = toneMaxFrequency / frequency / 4 - 1;
      prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4;

      if (ccValue > TONE_TC_TOP)
      {
        ccValue = toneMaxFrequency / frequency / 8 - 1;
        prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8;

        if (ccValue > TONE_TC_TOP)
        {
          ccValue = toneMaxFrequency / frequency / 16 - 1;
          prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16;

          if (ccValue > TONE_TC_TOP)
          {
            ccValue = toneMaxFrequency / frequency / 64 - 1;
            prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64;

            if (ccValue > TONE_TC_TOP)
            {
              ccValue = toneMaxFrequency / frequency / 256 - 1;
              prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256;

              if (ccValue > TONE_TC_TOP)
              {
                ccValue = toneMaxFrequency / frequency / 1024 - 1;
                prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024;
              }
            }
          }
        }
      }
    }
  }

  toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1);

  // Enable GCLK for TC4 and TC5 (timer counter input clock)
  GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5));
  while (GCLK->STATUS.bit.SYNCBUSY);

  resetTC(TONE_TC);

  // Set Timer counter Mode to 16 bits
  TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;

  // Set TONE_TC mode as match frequency
  TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;

  TONE_TC->COUNT16.CTRLA.reg |= prescalerConfigBits;

  TONE_TC->COUNT16.CC[TONE_TC_CHANNEL].reg = (uint16_t) ccValue;
  WAIT_TC16_REGS_SYNC(TONE_TC)

  // Configure interrupt request
  NVIC_DisableIRQ(TONE_TC_IRQn);
  NVIC_ClearPendingIRQ(TONE_TC_IRQn);
  NVIC_SetPriority(TONE_TC_IRQn, 0);
  NVIC_EnableIRQ(TONE_TC_IRQn);

  portToggleRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTTGL.reg);
  portClearRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTCLR.reg);
  portBitMask = (1ul << g_APinDescription[outputPin].ulPin);

  // Enable the TONE_TC interrupt request
  TONE_TC->COUNT16.INTENSET.bit.MC0 = 1;

  lastOutputPin = outputPin;
  digitalWrite(outputPin, LOW);
  pinMode(outputPin, OUTPUT);
  toneIsActive = true;

  // Enable TONE_TC
  TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
  WAIT_TC16_REGS_SYNC(TONE_TC)
}
コード例 #3
0
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
  // Configure interrupt request
  NVIC_DisableIRQ(TONE_TC_IRQn);
  NVIC_ClearPendingIRQ(TONE_TC_IRQn);
  
  if(!firstTimeRunning)
  {
    firstTimeRunning = true;
    
    NVIC_SetPriority(TONE_TC_IRQn, 0);
      
    // Enable GCLK for TC4 and TC5 (timer counter input clock)
    GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5));
    while (GCLK->STATUS.bit.SYNCBUSY);
  }
  
  if (toneIsActive && (outputPin != lastOutputPin))
    noTone(lastOutputPin);

  //
  // Calculate best prescaler divider and comparator value for a 16 bit TC peripheral
  //

  uint32_t prescalerConfigBits;
  uint32_t ccValue;

  ccValue = toneMaxFrequency / frequency - 1;
  prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1;
  
  uint8_t i = 0;
  
  while(ccValue > TONE_TC_TOP)
  {
    ccValue = toneMaxFrequency / frequency / (2<<i) - 1;
    i++;
    if(i == 4 || i == 6 || i == 8) //DIV32 DIV128 and DIV512 are not available
     i++;
  }
  
  switch(i-1)
  {
    case 0: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2; break;
    
    case 1: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4; break;
    
    case 2: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8; break;
    
    case 3: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16; break;
    
    case 5: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64; break;
      
    case 7: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256; break;
    
    case 9: prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024; break;
    
    default: break;
  }

  toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1);

  resetTC(TONE_TC);

  uint16_t tmpReg = 0;
  tmpReg |= TC_CTRLA_MODE_COUNT16;  // Set Timer counter Mode to 16 bits
  tmpReg |= TC_CTRLA_WAVEGEN_MFRQ;  // Set TONE_TC mode as match frequency
  tmpReg |= prescalerConfigBits;
  TONE_TC->COUNT16.CTRLA.reg |= tmpReg;
  WAIT_TC16_REGS_SYNC(TONE_TC)

  TONE_TC->COUNT16.CC[TONE_TC_CHANNEL].reg = (uint16_t) ccValue;
  WAIT_TC16_REGS_SYNC(TONE_TC)

  portToggleRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTTGL.reg);
  portClearRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTCLR.reg);
  portBitMask = (1ul << g_APinDescription[outputPin].ulPin);

  // Enable the TONE_TC interrupt request
  TONE_TC->COUNT16.INTENSET.bit.MC0 = 1;
  
  if (outputPin != lastOutputPin)
  {
    lastOutputPin = outputPin;
    digitalWrite(outputPin, LOW);
    pinMode(outputPin, OUTPUT);
    toneIsActive = true;
  }

  // Enable TONE_TC
  TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
  WAIT_TC16_REGS_SYNC(TONE_TC)
  
  NVIC_EnableIRQ(TONE_TC_IRQn);
}