Exemplo n.º 1
0
// Right now, PWM output only works on the pins with
// hardware support.  These are defined in the appropriate
// pins_*.c file.  For the rest of the pins, we default
// to digital output.
void analogWrite( uint32_t ulPin, uint32_t ulValue )
{
#if 0 // pwm test
#if 1 // port configuration
    *(volatile unsigned int *)0x44000010 |= 1 << 8;   //GPIOx->OUTENSET

    //PAD_AFConfig(PAD_PC, GPIO_Pin_8, 0x01/*PAD_AF1*/); ///< PAD Config - LED used 2nd Function	// (0x01 <<  8)
    *(volatile unsigned int *)(0x41002080 + 0x20) &= ~0x03/*PAD_AF1*/;	// (0x01 <<  8)
//    *(volatile unsigned int *)(0x41002080 + 0x20) |= 0x01/*PAD_AF1*/;	// (0x01 <<  8)

    *(volatile unsigned int *)0x44000010 |= 1 << 9;   //GPIOx->OUTENSET

    *(volatile unsigned int *)(0x41002080 + 0x24) &= ~0x03/*PAD_AF1*/;	// (0x01 <<  8)
//    *(volatile unsigned int *)(0x41002080 + 0x24) |= 0x01/*PAD_AF1*/;	// (0x01 <<  8)
#endif // port configuration
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
    /* Select Timer/Counter mode as Timer mode */ 
    //PWM_CHn->TCMR = PWM_CHn_TCMR_TimerMode;                      
//    *(volatile unsigned int *)0x40005324 = (0x0ul);  // ch3
    *(volatile unsigned int *)0x40005024 = (0x0);
    /* Set Prescale register value */
    //PWM_CHn->PR = PWM_TimerModeInitStruct->PWM_CHn_PR;        
//    *(volatile unsigned int *)0x40005314 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1;    
    *(volatile unsigned int *)0x40005014 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1;    
    /* Set Match register value */
    //PWM_CHn->MR = PWM_TimerModeInitStruct->PWM_CHn_MR;        
//    *(volatile unsigned int *)0x40005318 = 80000;
    *(volatile unsigned int *)0x40005018 = 80000;
    /* Set Limit register value */
    //PWM_CHn->LR = PWM_TimerModeInitStruct->PWM_CHn_LR;         
//    *(volatile unsigned int *)0x4000531C = 100000; // 80% duty cycle
    *(volatile unsigned int *)0x4000501C = 100000; // 80% duty cycle
    /* Select Up-down mode */
    //PWM_CHn->UDMR = PWM_TimerModeInitStruct->PWM_CHn_UDMR;     
//    *(volatile unsigned int *)0x40005320 = (0x0ul);        //PWM_CHn_UDMR_UpCount
    *(volatile unsigned int *)0x40005020 = (0x0);        //PWM_CHn_UDMR_UpCount
    /* Select Periodic mode */ 
    //PWM_CHn->PDMR = PWM_TimerModeInitStruct->PWM_CHn_PDMR;     
//    *(volatile unsigned int *)0x40005334 = (0x1ul);        //PWM_CHn_PDMR_Periodic
    *(volatile unsigned int *)0x40005034 = (0x1);        //PWM_CHn_PDMR_Periodic

//------------------------------------------------------------------------------------------
    /* Select Timer/Counter mode as Timer mode */ 
    //PWM_CHn->TCMR = PWM_CHn_TCMR_TimerMode;                      
//    *(volatile unsigned int *)0x40005324 = (0x0ul);  // ch3
    *(volatile unsigned int *)0x40005124 = (0x0ul);
    /* Set Prescale register value */
    //PWM_CHn->PR = PWM_TimerModeInitStruct->PWM_CHn_PR;        
//    *(volatile unsigned int *)0x40005314 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1;    
    *(volatile unsigned int *)0x40005114 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1;    
    /* Set Match register value */
    //PWM_CHn->MR = PWM_TimerModeInitStruct->PWM_CHn_MR;        
//    *(volatile unsigned int *)0x40005318 = 80000;
    *(volatile unsigned int *)0x40005118 = 80000;
    /* Set Limit register value */
    //PWM_CHn->LR = PWM_TimerModeInitStruct->PWM_CHn_LR;         
//    *(volatile unsigned int *)0x4000531C = 100000; // 80% duty cycle
    *(volatile unsigned int *)0x4000511C = 100000; // 80% duty cycle
    /* Select Up-down mode */
    //PWM_CHn->UDMR = PWM_TimerModeInitStruct->PWM_CHn_UDMR;     
//    *(volatile unsigned int *)0x40005320 = (0x0ul);        //PWM_CHn_UDMR_UpCount
    *(volatile unsigned int *)0x40005120 = (0x0ul);        //PWM_CHn_UDMR_UpCount
    /* Select Periodic mode */ 
    //PWM_CHn->PDMR = PWM_TimerModeInitStruct->PWM_CHn_PDMR;     
//    *(volatile unsigned int *)0x40005334 = (0x1ul);        //PWM_CHn_PDMR_Periodic
    *(volatile unsigned int *)0x40005134 = (0x1ul);        //PWM_CHn_PDMR_Periodic

//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
        //PWM->SSR &= PWM_SSR_SS3_Stop;
//        *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 3);
        *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 0);
        //PWM_CHn->PEEER = outputEnDisable; 
//        *(volatile unsigned int *)0x40005328 = (0x2ul);
        *(volatile unsigned int *)0x40005028 = (0x2ul);

//------------------------------------------------------------------------------------------
        //PWM->SSR &= PWM_SSR_SS3_Stop;
//        *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 3);
        *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 1);
        //PWM_CHn->PEEER = outputEnDisable; 
//        *(volatile unsigned int *)0x40005328 = (0x2ul);
        *(volatile unsigned int *)0x40005128 = (0x2ul);

//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------

        //PWM->SSR |= PWM_SSR_SS3_Start;
//        *(volatile unsigned int *)0x40005804 |= (0x1ul << 3);
        *(volatile unsigned int *)0x40005804 |= (0x1ul << 0);

//------------------------------------------------------------------------------------------
        //PWM->SSR |= PWM_SSR_SS3_Start;
//        *(volatile unsigned int *)0x40005804 |= (0x1ul << 3);
        *(volatile unsigned int *)0x40005804 |= (0x1ul << 1);




    while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ;
    *(volatile unsigned long *) 0x4000D000 = 'P';
    while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ;
    *(volatile unsigned long *) 0x4000D000 = 'W';
    while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ;
    *(volatile unsigned long *) 0x4000D000 = 'M';
while(1);
#endif

#if 1
//------------------------------------------------------------------------------------------
    *(volatile unsigned int *)(0x42000010 + pwm_pin_tbl[ulPin].port_num) |= 1 << pwm_pin_tbl[ulPin].pin_num;   //GPIOx->OUTENSET
    //PAD_AFConfig(PAD_PC, GPIO_Pin_8, 0x01/*PAD_AF1*/); ///< PAD Config - LED used 2nd Function	// (0x01 <<  8)
    *(volatile unsigned int *)(0x41002000 + pwm_pin_tbl[ulPin].af_base + pwm_pin_tbl[ulPin].pin_num * 4) &= ~0x03/*PAD_AF1*/;	// (0x01 <<  8)
    *(volatile unsigned int *)(0x41002000 + pwm_pin_tbl[ulPin].af_base + pwm_pin_tbl[ulPin].pin_num * 4) |= pwm_pin_tbl[ulPin].af_num/*PAD_AF1*/;	// (0x01 <<  8)
//------------------------------------------------------------------------------------------
//PWM-n
    /* Select Timer/Counter mode as Timer mode */ 
    *(volatile unsigned int *)(0x40005024 + pwm_pin_tbl[ulPin].pwm_num) = (0x0);
    /* Set Prescale register value */
    *(volatile unsigned int *)(0x40005014 + pwm_pin_tbl[ulPin].pwm_num) = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1;    
    /* Set Match register value */
    *(volatile unsigned int *)(0x40005018 + pwm_pin_tbl[ulPin].pwm_num) = 400 * ulValue;     //MR
    /* Set Limit register value */
    *(volatile unsigned int *)(0x4000501C + pwm_pin_tbl[ulPin].pwm_num) = 102400; // 80% duty cycle
    /* Select Up-down mode */
    *(volatile unsigned int *)(0x40005020 + pwm_pin_tbl[ulPin].pwm_num) = (0x0);        //PWM_CHn_UDMR_UpCount
    /* Select Periodic mode */ 
    *(volatile unsigned int *)(0x40005034 + pwm_pin_tbl[ulPin].pwm_num) = (0x1);        //PWM_CHn_PDMR_Periodic

//------------------------------------------------------------------------------------------
        //PWM->SSR &= PWM_SSR_SS3_Stop;
        *(volatile unsigned int *)0x40005804 &= ~(0x1 << pwm_pin_tbl[ulPin].pwm_pin);
        //PWM_CHn->PEEER = outputEnDisable; 
        *(volatile unsigned int *)(0x40005028 + pwm_pin_tbl[ulPin].pwm_num) = 0x2;

//------------------------------------------------------------------------------------------
        //PWM->SSR |= PWM_SSR_SS3_Start;
        *(volatile unsigned int *)0x40005804 |= (0x1ul << pwm_pin_tbl[ulPin].pwm_pin);

#if 0  // pwm serial character out
    while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ;
    *(volatile unsigned long *) 0x4000D000 = 'P';
    while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ;
    *(volatile unsigned long *) 0x4000D000 = 'W';
    while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ;
    *(volatile unsigned long *) 0x4000D000 = 'M';
#endif  // pwm serial character out

#endif













#if 0
  uint32_t attr = g_APinDescription[ulPin].ulPinAttribute ;
//   uint32_t pwm_name = g_APinDescription[ulPin].ulTCChannel ;
  uint8_t isTC = 0 ;
  uint8_t Channelx ;
  Tc* TCx ;
  Tcc* TCCx ;

  if ( (attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG )
  {
    if ( ulPin == 24 )  // Only 1 DAC on A0 (PA02)
    {
      	ulValue = mapResolution(ulValue, _writeResolution, DAC_RESOLUTION);
    	DAC->DATA.reg = ulValue & 0x3FF;  // Dac on 10 bits.
		DAC->CTRLA.bit.ENABLE = 1; // DAC Enabled
/////////////////////////////////////		syncDAC();
      	return;
    }
	

  }

  if ( (attr & PIN_ATTR_PWM) == PIN_ATTR_PWM )
  {
    if ( (g_APinDescription[ulPin].ulPinType == PIO_TIMER) || g_APinDescription[ulPin].ulPinType == PIO_TIMER_ALT )
    {
      pinPeripheral( ulPin, g_APinDescription[ulPin].ulPinType ) ;
    }

    switch ( g_APinDescription[ulPin].ulPWMChannel )
    {
      case PWM3_CH0 :
                TCx = TC3 ;
                Channelx = 0 ;
                isTC = 1 ;
            break;

      case  PWM3_CH1:
                TCx = TC3 ;
                Channelx = 1;
                isTC = 1;
            break;

      case  PWM0_CH0 :
                TCCx = TCC0;
                Channelx = 0;
            break;

      case  PWM0_CH1 :
                TCCx = TCC0;
                Channelx = 1;
            break;

      case  PWM0_CH4 :
                TCCx = TCC0;
                Channelx = 0;
            break;

      case  PWM0_CH5 :
                TCCx = TCC0;
                Channelx = 1;
            break;

      case  PWM0_CH6 :
                TCCx = TCC0;
                Channelx = 2;
            break;

      case  PWM0_CH7 :
                TCCx = TCC0;
                Channelx = 3;
            break;

      case  PWM1_CH0 :
                TCCx = TCC1;
                Channelx = 0;
            break;

      case  PWM1_CH1 :
                TCCx = TCC1;
                Channelx = 1;
            break;

      case  PWM2_CH0 :
                TCCx = TCC2;
                Channelx = 0;
            break;

      case  PWM2_CH1 :
                TCCx = TCC2;
                Channelx = 1;
            break;
    }


    // Enable clocks according to TCCx instance to use
    switch ( GetTCNumber( g_APinDescription[ulPin].ulPWMChannel ) )
    {
      case 0: // TCC0
                //Enable GCLK for TCC0 (timer counter input clock)
                GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ;
            break;

      case 1: // TCC1
                //Enable GCLK for TCC1 (timer counter input clock)
                GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ;
            break;

      case 2: // TCC2
                //Enable GCLK for TCC2 (timer counter input clock)
                GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 )) ;
            break;

      case 3: // TC3
                //Enable GCLK for TC3 (timer counter input clock)
                GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 ));
            break;

      case 4: // TC4
                //Enable GCLK for TC4 (timer counter input clock)
                GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 ));
            break;

      case 5: // TC5
                //Enable GCLK for TC5 (timer counter input clock)
                GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 )) ;
            break;
    }

    // Set PORT
    if ( isTC )
    {
      // -- Configure TC
      //DISABLE TCx
      TCx->COUNT8.CTRLA.reg &=~(TC_CTRLA_ENABLE);
      //Set Timer counter Mode to 8 bits
      TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8;
      //Set TCx as normal PWM
      TCx->COUNT8.CTRLA.reg |= TC_CTRLA_WAVEGEN_NPWM;
      //Set TCx in waveform mode Normal PWM
      TCx->COUNT8.CC[Channelx].reg = (uint8_t) ulValue;
      //Set PER to maximum counter value (resolution : 0xFF)
      TCx->COUNT8.PER.reg = 0xFF;
      // Enable TCx
      TCx->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE;
    }
    else
    {
      // -- Configure TCC

      //DISABLE TCCx
      TCCx->CTRLA.reg &=~(TCC_CTRLA_ENABLE);
      //Set TCx as normal PWM
      TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
      //Set TCx in waveform mode Normal PWM
      TCCx->CC[Channelx].reg = (uint32_t)ulValue;
      //Set PER to maximum counter value (resolution : 0xFF)
      TCCx->PER.reg = 0xFF;
      //ENABLE TCCx
      TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ;
    }

    return ;
  }

  // -- Defaults to digital write
  pinMode( ulPin, OUTPUT ) ;

  if ( ulValue < 128 )
  {
    digitalWrite( ulPin, LOW ) ;
  }
  else
  {
    digitalWrite( ulPin, HIGH ) ;
  }
#endif

}
// Right now, PWM output only works on the pins with
// hardware support.  These are defined in the appropriate
// pins_*.c file.  For the rest of the pins, we default
// to digital output.
void analogFastWrite(uint32_t pin, uint32_t value)
{
  PinDescription pinDesc = g_APinDescription[pin];
  uint32_t attr = pinDesc.ulPinAttribute;

  if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
  {
    // DAC handling code

    if (pin != PIN_A0) { // Only 1 DAC on A0 (PA02)
      return;
    }

    value = mapResolution(value, _writeResolution, 10);

    syncDAC();
    DAC->DATA.reg = value & 0x3FF;  // DAC on 10 bits.
    syncDAC();
    DAC->CTRLA.bit.ENABLE = 0x01;     // Enable DAC
    syncDAC();
    return;
  }

  if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
  {
    value = mapResolution(value, _writeResolution, 8);  // change to 10 for 10 bit... must also change  TCx->COUNT8.PER.reg = 0x3FF
    uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
    uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
    static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];

    if (!tcEnabled[tcNum]) {
      tcEnabled[tcNum] = true;

      if (attr & PIN_ATTR_TIMER) {
        #if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
        // Compatibility for cores based on SAMD core <=1.6.2
        if (pinDesc.ulPinType == PIO_TIMER_ALT) {
          pinPeripheral(pin, PIO_TIMER_ALT);
        } else
        #endif
        {
          pinPeripheral(pin, PIO_TIMER);
        }
      } else {
        // We suppose that attr has PIN_ATTR_TIMER_ALT bit set...
        pinPeripheral(pin, PIO_TIMER_ALT);
      }

      uint16_t GCLK_CLKCTRL_IDs[] = {
        GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
        GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
        GCLK_CLKCTRL_ID(GCM_TCC2_TC3),  // TCC2
        GCLK_CLKCTRL_ID(GCM_TCC2_TC3),  // TC3
        GCLK_CLKCTRL_ID(GCM_TC4_TC5),   // TC4
        GCLK_CLKCTRL_ID(GCM_TC4_TC5),   // TC5
        GCLK_CLKCTRL_ID(GCM_TC6_TC7),   // TC6
        GCLK_CLKCTRL_ID(GCM_TC6_TC7),   // TC7
      };
      GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_IDs[tcNum]);
      while (GCLK->STATUS.bit.SYNCBUSY == 1);

      // Set PORT
      if (tcNum >= TCC_INST_NUM) {
        // -- Configure TC
        Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
        // Disable TCx
        TCx->COUNT8.CTRLA.bit.ENABLE = 0;
        syncTC_8(TCx);
        // Set Timer counter Mode to 8 bits, normal PWM
        TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8 | TC_CTRLA_WAVEGEN_NPWM;
        syncTC_8(TCx);
        // Set the initial value
        TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
        syncTC_8(TCx);
        // Set PER to maximum counter value (resolution : 0xFF)
        TCx->COUNT8.PER.reg = 0xFF;
        syncTC_8(TCx);
        // Enable TCx
        TCx->COUNT8.CTRLA.bit.ENABLE = 1;
        syncTC_8(TCx);
      } else {
        // -- Configure TCC
        Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
        // Disable TCCx
        TCCx->CTRLA.bit.ENABLE = 0;
        syncTCC(TCCx);

        // Set TCx as normal PWM
        TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
        syncTCC(TCCx);
        // Set the initial value
        TCCx->CC[tcChannel].reg = (uint32_t) value;
        syncTCC(TCCx);
        // Set PER to maximum counter value (resolution : 0xFF)
        TCCx->PER.reg = 0xFF; //change to 0x43FF for 10 bit... must also change mapping above
        syncTCC(TCCx);
        // Enable TCCx
        TCCx->CTRLA.bit.ENABLE = 1;
        syncTCC(TCCx);
      }
    } else {
      if (tcNum >= TCC_INST_NUM) {
        Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
        TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
        syncTC_8(TCx);
    } else {
        Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
        TCCx->CTRLBSET.bit.LUPD = 1;
        syncTCC(TCCx);
        TCCx->CCB[tcChannel].reg = (uint32_t) value;
        syncTCC(TCCx);
        TCCx->CTRLBCLR.bit.LUPD = 1;
        syncTCC(TCCx);
      }
    }
    return;
  }

  // -- Defaults to digital write
  pinMode(pin, OUTPUT);
  value = mapResolution(value, _writeResolution, 8);
  if (value < 128) {
    digitalWrite(pin, LOW);
  } else {
    digitalWrite(pin, HIGH);
  }
}