예제 #1
0
void clockInit(void)
{
    /*
    		Enable internal 32 MHz ring oscillator and wait until it's
    		stable. Divide clock by two with the prescaler C and set the
    		32 MHz ring oscillator as the main clock source.
    */
    CLKSYS_Enable( OSC_RC32MEN_bm );
    CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_2_gc );
    do {} while ( CLKSYS_IsReady( OSC_RC32MRDY_bm ) == 0 );
    CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC32M_gc );
}
예제 #2
0
char system_clocks_init(void)
{

	 /******************************************************************
   * System Clock 32MHz (XOSC Quarz 16MHz, PLL Faktor 2)
   ******************************************************************/

  /* Nach dem Reset ist die Quelle des Systemtaktes der interne
     2MHz RC-Oszillator (System Clock Selection: RC2MHz)
  */

  // Oszillator XOSC konfigurieren (12..16MHz, 256 clocks startup time)
  CLKSYS_XOSC_Config( OSC_FRQRANGE_12TO16_gc,
                      false,
                      OSC_XOSCSEL_XTAL_256CLK_gc );

  // Oszillator XOSC enable
  CLKSYS_Enable( OSC_XOSCEN_bm );

  // Warten bis der Oszillator bereit ist
  do {} while ( CLKSYS_IsReady( OSC_XOSCRDY_bm ) == 0 );

  // PLL source ist XOSC, Multiplikator x2
  CLKSYS_PLL_Config( OSC_PLLSRC_XOSC_gc, 2 );

  // Enable PLL
  CLKSYS_Enable( OSC_PLLEN_bm );

  // Prescalers konfigurieren
  CLKSYS_Prescalers_Config(CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc );

  // Warten bis PLL locked
  do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );

  // Main Clock Source ist Ausgang von PLL
  CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );

  // Nun ist der System Clock 32MHz !

  /* Hinweis:
     32kHz TOSC kann nicht in Verbindung mit PLL genutzt werden, da
     die minimale Eingangsfrequenz des PLLs 400kHz beträgt.
  */

	return(1);	
} // Sets System Clock to 32MHz
예제 #3
0
/** \brief Initialize and set cpu and periheral clocks.
 *
 * CPU clock frequencies set are:
 * -CPU: 32HMZ
 * -Peripheral Prescaling: NONE */
void setup_clocks(void) {

   // set 32MHZ oscillator as CPU clock source
   CLKSYS_Enable(OSC_RC32MEN_bm);                          // enable
   do { nop(); } while (!CLKSYS_IsReady(OSC_RC32MRDY_bm)); // wait til stable
   CLKSYS_Main_ClockSource_Select(CLK_SCLKSEL_RC32M_gc);   // select for CPU

   // disable all presacalers, until we decide otherwise
   CLKSYS_Prescalers_Config(CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc);

   // set up external 32KHz oscillator (NOTE: first param is ignored)
   CLKSYS_XOSC_Config(OSC_FRQRANGE_04TO2_gc, false, OSC_XOSCSEL_32KHz_gc);

   // set internal 32KHz oscillator as source for DFLL and autocalibrate 32MHz
   CLKSYS_Enable(OSC_XOSCEN_bm);                          //enable
   do { nop(); } while (!CLKSYS_IsReady(OSC_XOSCRDY_bm)); // wait til stable
   CLKSYS_AutoCalibration_Enable(OSC_RC32MCREF_bm, true); // true == ext 32KHz

   // disable unused oscillators (internal 2MHz and 32KHz oscillators)
   CLKSYS_Disable(OSC_RC2MEN_bm | OSC_RC32KEN_bm);
}
/*! \brief This function enables the internal 32MHz oscillator and the
 *         prescalers needed by the HiRes extension.
 *
 *  \note  The optimization of the compiler must be set above low to ensure
 *         that the setting of the CLK register is set within 4 clock cylcles
 *         after the CCP register is set.
 */
void ConfigClockSystem( void )
{
	/*  Enable internal 32 MHz ring oscillator and wait until it's
	 *  stable.
	 */
	CLKSYS_Enable( OSC_RC32MEN_bm );
	do {} while ( CLKSYS_IsReady( OSC_RC32MRDY_bm ) == 0 );
	
	CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC32M_gc );
	
	/*  Configure PLL with the 32 MHz ring oscillator/4 as source and
	 *  multiply by 16 to get 128 MHz PLL clock and enable it. Wait
	 *  for it to be stable and set prescalers B and C to divide by four
	 *  to set the CPU clock to 32 MHz.
	 */
	CLKSYS_PLL_Config( OSC_PLLSRC_RC32M_gc, 16 );
	CLKSYS_Enable( OSC_PLLEN_bm );
	CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_2_2_gc );
	do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );
		
	CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );
}
예제 #5
0
void InitClock ()
{
	/* Clock Setup */
	
	/* Enable for external 2-9 MHz crystal with quick startup time
		* (256CLK). Check if it's stable and set it as the PLL input.
		*/
	CLKSYS_XOSC_Config( OSC_FRQRANGE_2TO9_gc, false, OSC_XOSCSEL_EXTCLK_gc );
	CLKSYS_Enable( OSC_XOSCEN_bm );
	do {} while ( CLKSYS_IsReady( OSC_XOSCRDY_bm ) == 0 );
	
	/*  Configure PLL with the 8 MHz external clock as source and
		*  multiply by 4 to get 32 MHz PLL clock and enable it. Wait
		*  for it to be stable and set prescaler C to divide by two
		*  to set the CPU clock to 16 MHz.
		*/
	CLKSYS_PLL_Config(OSC_PLLSRC_XOSC_gc, 4 );
	CLKSYS_Enable( OSC_PLLEN_bm );
	CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_2_gc );
	do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );
	CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );
}
예제 #6
0
int main(void)
{
	CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc );


	// CLKOUT on PC7
	PORTC.DIRSET = (1<<7);
	PORTCFG.CLKEVOUT = PORTCFG_CLKOUT_PC7_gc;


	tbar_init();

	xb_init();

	PORTB.DIRSET = 1; // set PB0 as output

	DEBUG_PORT.DIRSET = DEBUG_RED + DEBUG_GREEN;


	while(1)
	{
		//uint8_t i;
		// wait for incoming transmission from Zigbee
		// TODO : make this into interrupt-driven stuffs

		_delay_ms(600);

		// signal that we're ready
		debug_blink(DEBUG_GREEN);

		while(1)
		{
			//debug_blink(DEBUG_GREEN);
			char byte = 0;
			XB_GetChar(byte);
			if(byte == 0x7e)
			{
				uint8_t length = xb_decode_packet(packet);

				if(length>0)
				{
					uint8_t i;
					for(i=0;i<length; i++)
					{
						TB_PutChar(packet[i]);
					}
					debug_blink(DEBUG_GREEN);
				}
				else
					debug_blink(DEBUG_RED);
			}
		}

		// signal that we've started receiving
		debug_blink(DEBUG_RED);

		


		// decode packet

		// send data out T port
	/*
		for (i=0; i<sizeof(Coord.name)/sizeof(char); i++)
		{
			while( (USARTT.STATUS & USART_DREIF_bm) == 0);
			USARTT.DATA = Coord.name[i];
			
		}
		*/

	/*	xb_send_array_new(blah, sizeof(blah)/sizeof(char), &Coord);
		xb_send_array_new(blah, sizeof(blah)/sizeof(char), &Gizmo1);*/
		// flash green led
		
		//USARTT_PORT.OUTTGL = (1<<USARTT_TX);
	}
}
예제 #7
0
파일: task2.c 프로젝트: HamboLagos/pit_crew
int main(void)
{
	// Configure switches
	PORTCFG.MPCMASK = 0xFF; // Configure several PINxCTRL registers at the same time
	SWITCHPORTL.PIN0CTRL = (SWITCHPORTL.PIN0CTRL & ~PORT_OPC_gm) | PORT_OPC_PULLUP_gc; //Enable pull-up to get a defined level on the switches

	SWITCHPORTL.DIRCLR = 0xFF; // Set port as input

	// Configure LEDs
	PORTCFG.MPCMASK = 0xFF; // Configure several PINxCTRL registers at the same time
	LEDPORT.PIN0CTRL = PORT_INVEN_bm; // Invert input to turn STK600 leds on when port value is 1

	LEDPORT.DIRSET = 0xFF; 	// Set port as output
	LEDPORT.OUT = 0xA0;  // Set initial value

	unsigned int counter = 0;

	while (1)
	{

		/*  Change the clock source to the internal 2MHz. Disable PLL.
		 *  Configure PLL with the 2 MHz RC oscillator as source and
		 *  multiply by 15 to get 30 MHz PLL clock and enable it. Wait
		 *  for it to be stable and set prescaler C to divide by two
		 *  to set the CPU clock to 15 MHz
		 */
		if ( (SWITCHPORTL.IN & PIN0_bm) == 0 )
		{
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC2M_gc );

			CLKSYS_Disable( OSC_PLLEN_bm );

			CLKSYS_PLL_Config( OSC_PLLSRC_RC2M_gc, 15 );
			CLKSYS_Enable( OSC_PLLEN_bm );
			CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_2_gc );
			do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );

			LEDPORT.OUTCLR = 0x1F;
			LEDPORT.OUTSET = PIN0_bm;
		}

		/*  Configure PLL with the 2 MHz RC oscillator as source and
		 *  multiply by 15 to get 30 MHz PLL clock and enable it. Wait
		 *  for it to be stable and set prescaler B and C to divide by two
		 *  to set the CPU clock to 7.5 MHz
		 */
		if ( (SWITCHPORTL.IN & PIN1_bm) == 0 )
		{
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC2M_gc );

			CLKSYS_Disable( OSC_PLLEN_bm );

			CLKSYS_PLL_Config( OSC_PLLSRC_RC2M_gc, 15 );
			CLKSYS_Enable( OSC_PLLEN_bm );
			CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_2_2_gc );
			do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );

			LEDPORT.OUTCLR = 0x1F;
			LEDPORT.OUTSET = PIN1_bm;
		}


		/*  Configure PLL with the 2 MHz RC oscillator as source and
		 *  multiply by 6 to get 12 MHz PLL clock and enable it. Wait
		 *  for it to be stable and set prescaler B and C to divide by two
		 *  to set the CPU clock to 3 MHz
		 */
		if ( (SWITCHPORTL.IN & PIN2_bm) == 0 )
		{
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC2M_gc );

			CLKSYS_Disable( OSC_PLLEN_bm );

			CLKSYS_PLL_Config( OSC_PLLSRC_RC2M_gc, 6 );
			CLKSYS_Enable( OSC_PLLEN_bm );
			CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_2_2_gc );
			do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );

			LEDPORT.OUTCLR = 0x1F;
			LEDPORT.OUTSET = PIN2_bm;
		}


		/*  Dynamically change prescaler:
		 *  Set prescaler A to divide by 2, prescaler B with no division,
		 *  and prescaler C to divide by 2. This will give the CPU a freqency
		 *  of 1/4th of the input freqency. Input freqency will depend on the
		 *  previous switch that has been pressed.
		 */
		if ( (SWITCHPORTL.IN & PIN3_bm) == 0 )
		{
			CLKSYS_Prescalers_Config( CLK_PSADIV_2_gc, CLK_PSBCDIV_1_2_gc );
			LEDPORT.OUTSET = PIN3_bm;
		}


		/*  
		 *  Add code here for generating 62 MHz to clkper4 and 15.5 MHz to the CPU
		 */
		if ( (SWITCHPORTL.IN & PIN4_bm) == 0 )
		{
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC2M_gc );

			CLKSYS_Disable( OSC_PLLEN_bm );

			CLKSYS_PLL_Config( OSC_PLLSRC_RC2M_gc, 31 );
			CLKSYS_Enable( OSC_PLLEN_bm );
			CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_2_2_gc );
			do {} while ( CLKSYS_IsReady( OSC_PLLRDY_bm ) == 0 );
			CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_PLL_gc );

			LEDPORT.OUTCLR = 0x1F;
			LEDPORT.OUTSET = PIN4_bm;

		}



		// Blink LEDS after the loop has been run several times
		// This gives us visual feedback on the MCU speed
		counter++;
		if (counter > 20000 )
		{
			LEDPORT.OUTTGL = 0xE0;
			counter=0;
		}


	}
}
예제 #8
0
/**
 * Main is used to:
 * Initialize drivers
 * Create threads
 * Pass drivers structures to threads
 */
int main( void ) {
    /*
     * Enable internal 32 MHz ring oscillator and wait until it's
     * stable. Set the 32 MHz ring oscillator as the main clock source.
     */
    CLKSYS_Enable( OSC_RC32MEN_bm );
    CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc );
    do {} while ( CLKSYS_IsReady( OSC_RC32MRDY_bm ) == 0 );
    CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC32M_gc );

    //Enable watchdog timer, which will be reset by timer
    WDT_EnableAndSetTimeout( WDT_PER_1KCLK_gc );
    /*
     * Do all configuration and create all tasks and queues before scheduler is started.
     * It is possible to put initialization of peripherals like displays into task functions
     * (which will be executed after scheduler has started) if fast startup is needed.
     * Interrupts are not enabled until the call of vTaskStartScheduler();
     */
    // Enable the Round-Robin Scheduling scheme.Round-Robin scheme ensures that no low-level
    // interrupts are “starved”, as the priority changes continuously
    PMIC_EnableRoundRobin();

    //Create and start the timer, which will reset Watch Dog Timer
    xTimerStart(xTimerCreate((signed char*)"WDT",500, pdTRUE, 0, watchdogTimerCallback), 0);
    //---------Use USART on PORTC----------------------------
    Serial usartFTDI = Serial(&USARTE0, BAUD9600, 128, 10);

    // Initialize SPI slave on port D
    SpiSlave spiSlave = SpiSlave(&SPIC,false,SPI_MODE_1_gc,64);
    // Initialize SPI master on port C
    SpiMaster spiMaster = SpiMaster(&SPID, false, SPI_MODE_1_gc, false, SPI_PRESCALER_DIV4_gc);
    SpiDevice spiDevice = SpiDevice(&spiMaster, &PORTD, SPI_SS_bm);

    //---------Start LED task for testing purposes-----------
    ledRGB = LedGroup(3);
    ledRGB.add(&PORTF, 0x04,1 );//R
    ledRGB.add(&PORTF, 0x08,1 );//G
    ledRGB.add(&PORTF, 0x02,1 );//B
    ledRGB.set(BLUE);
    LedProcessorThread ledRGBEThread = LedProcessorThread(&ledRGB, GREEN, 500, "RGB", 64, configLOW_PRIORITY);

    LedGroup ledString = LedGroup(7);
    ledString.add(&PORTA, 0x02, 0);
    ledString.add(&PORTA, 0x04, 0);
    ledString.add(&PORTA, 0x08, 0);
    ledString.add(&PORTA, 0x10, 0);
    ledString.add(&PORTA, 0x20, 0);
    ledString.add(&PORTA, 0x40, 0);
    ledString.add(&PORTA, 0x80, 0);
    LedProcessorThread ledStringThread = LedProcessorThread(&ledString, "STR", 64, configLOW_PRIORITY);

    // ***** Start main Looper
    Looper looper = Looper(10, "LPR", 750, configNORMAL_PRIORITY);
    //XXX why it is not working if on the heap not on the stack?
    //ExampleHandler *exampleHandler = (ExampleHandler*) pvPortMalloc(sizeof(ExampleHandler));
    //*exampleHandler = ExampleHandler(looper, spiDevice, ledStringQueue, usartFTDI);
    ExampleHandler exampleHandler = ExampleHandler(&looper, &spiDevice, &ledStringThread, &usartFTDI);
    // ****** Register commands for the interpreter
    CommandInterpreter interpreter = CommandInterpreter();
    interpreter.registerCommand(Strings_SpiExampleCmd, Strings_SpiExampleCmdDesc, &exampleHandler, EVENT_RUN_SPI_TEST);
    interpreter.registerCommand(Strings_BlinkCmd, Strings_BlinkCmdDesc, &exampleHandler, EVENT_BLINK);
    CommandInterpreterThread cmdIntThreadFTDI = CommandInterpreterThread(&interpreter, 32, &usartFTDI, "I12", 128, configNORMAL_PRIORITY);

    PinChangeController pinChangeController = PinChangeController();
    pinChangeController.registerOnPinChangeListener(&exampleHandler, &PORTD, PIN2_bm, PORT_OPC_TOTEM_gc, PORT_ISC_RISING_gc);

    // ****** Start stand-alone tasks
    SpiSlaveThread spiSlaveThread = SpiSlaveThread(&spiSlave, &usartFTDI, "SLV", 128, configLOW_PRIORITY);

    /* Start scheduler. Creates idle task and returns if failed to create it.
     * vTaskStartScheduler never returns during normal operation. It is unlikely that XMEGA port will need to
     * dynamically create tasks or queues. To ensure stable work, create ALL tasks and ALL queues before
     * vTaskStartScheduler call.
     * Interrupts would be enabled by calling PMIC_EnableLowLevel();*/
    vTaskStartScheduler();

    /* Should never get here, stop execution and report error */
    while(true) ledRGB.set(PINK);
    return 0;
}
예제 #9
0
int main(void)
{
  //! set the power reduction register to minimize current consumption
  init_power_reduction();
  //! set CPU clock to 32MHz and enables the DFLL32MHz
  clock_init();           
  //! initialize the LCD module
  init_lcd();
  //! display all the segments in LCD
  lcd_show_all();        
  //! initialize the GPIO pins
  init_ioport();
  //! initializes the UART
  init_UART();
  //! load the calibration data from flash
  ADC_CalibrationValues_Load(&ADCA);
  //! get the ADC offset value
  get_offset();
  //! initialize the ADC
  init_ADC();
  //! load the calibration value from eeprom
  init_eeprom();
  //! initilize RTC to external clock and 1 sec interrupt
  rtc_init();
  //! initilize the timer
  init_timer();  

  while(1)
    {
      //! rtc_flag is set
      if (rtc_flag == 1)
      {
        //! perform the calculation of metering paramters
        calculate();
        //for debugging
        if(cover_open_flag ==1)
        PORTD.OUTTGL = PIN3_bm;
        //TCC1.CTRLA = ( TCC1.CTRLA & ~TC1_CLKSEL_gm ) | TC_CLKSEL_DIV64_gc;
        TCC1.INTCTRLA = (TCC1.INTCTRLA & ~(TC1_OVFINTLVL_gm | TC1_ERRINTLVL_gm))|TC1_OVFINTLVL0_bm;
        //! if power on detected
        if(power_status_flag == POWER_ON_DETECTED) 
        {
          //! change the clock frequency to 32MHz
          CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc );
          //! switch off the battery
          PORTD.PIN4CTRL	= PORT_OPC_WIREDANDPULL_gc;
          //PORTD.OUTSET	= PIN4_bm;
          //! initialize gpio pins
          init_ioport();
          //! change the sleep mode to ideal sleep
          SLEEP.CTRL = (SLEEP.CTRL & ~SLEEP_SMODE_gm)| SLEEP_SMODE_IDLE_gc;
          //! enable ADC & Timer
          ADC_Enable(&ADCA);
          TCC1.CTRLA = ( TCC1.CTRLA & ~TC1_CLKSEL_gm ) | TC_CLKSEL_DIV64_gc;
          //! initialize lcd module
          init_lcd();
          //! update power status flag
          power_status_flag = POWERED_UP;
        }
        //! update the LCD display
        lcd_disp_key();
        tamper_check();
        if( active_power[0] > max_demand )
        {
          max_demand = active_power[0];
        }
        //! check for calibration flag and proceed and call the appropriate calibration funtion
        if(calibration_flag != 0)
        {
          //! checking the calibration flag for calibrating the date & time
          if (calibration_flag == 1)
          { calibrate_time_date();  }
          //! checking the calibration flag for calibrating the voltage
          else if (calibration_flag == 2)
          { calibrate_voltage();    }
          //! checking the calibration flag for calculating the offset value
          else if (calibration_flag == 3)
          { calibrate_no_load();    }
          //! checking the calibration flag for calculating the phase angle variation
          else if (calibration_flag == 4)
          { calibrate_phase();	    }
          //! checking the calibration flag for calculating watt varition
          else if (calibration_flag == 5)
          { calibrate_watt();       }
          else if (calibration_flag == 6)
          //! checking the calibration flag for calibrating the current            
          { calibrate_current();    }
        }
        rtc_flag = 0;
        __watchdog_reset();
      }
      //! checking the power_status, if power off is detected
      else if(power_status_flag == POWER_OFF_DETECTED)
      {
        //! switch on the battery
        PORTD.PIN4CTRL	= PORT_OPC_WIREDAND_gc;
        //PORTD.OUTCLR  = PIN4_bm;
        //! change the sleep mode to power save mode
        SLEEP.CTRL = (SLEEP.CTRL & ~SLEEP_SMODE_gm)| SLEEP_SMODE_PSAVE_gc;  
        //! switch off the LCD
        lcd_command(LCD_COMMAND,0x02);
        //! change reset the gpio pin
        facilitatePowersaving();
        //! disable the ADC
        ADC_Disable(&ADCA);
        //! disable the timer
        TCC1.CTRLA = ( TCC1.CTRLA & ~TC1_CLKSEL_gm ) | TC_CLKSEL_OFF_gc;
        //! clear all the varilable used in for energy calculation
        meter_flush();
        //! reduce the cpu clock frequency to minimize power consumption
        CLKSYS_Prescalers_Config( CLK_PSADIV_64_gc, CLK_PSBCDIV_1_1_gc );
        //! update power status flag
        power_status_flag = POWER_OFF;
        __watchdog_reset();
      }
      //! goes to sleep
      SLEEP.CTRL |=  SLEEP_SEN_bm;
      asm("sleep");
    }
}
예제 #10
0
void init_clock(void)
{
    //////////////////////////////////////////////////////////
    /* system clock setup */

    /* start the 32MHz ring oscillator ticking */
    /* ticks at 32MHz */
    CLKSYS_Enable(OSC_RC32MEN_bm);
    
    /* set the clock prescaler to divide by 1 */
    /* ticks at 32MHz */
    CLKSYS_Prescalers_Config(CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc);

    /* enable mid-priority interrupts */
    PMIC.CTRL |= PMIC_MEDLVLEN_bm;
    PMIC.CTRL |= PMIC_LOLVLEN_bm;

    //////////////////////////////////////////////////////////
    /* clock 1 setup */
    /* we use clock 1 for control loops because the avr-gcc headers
     * only have the registers for PWMing TC0 */

    /* medium-priority interrupt */
    TCC1.INTCTRLA = (TCC1.INTCTRLA & ~TC1_OVFINTLVL_gm) | TC_OVFINTLVL_MED_gc;

    /* divide main clock source by 2 */
    /* ticks at 16MHz */
    TCC1.CTRLA = (TCC1.CTRLA & ~TC1_CLKSEL_gm) | TC_CLKSEL_DIV2_gc;

    /* count to 1600 before looping. */
    /* ticks at 10kHz */
    /* we use this for handling control loops */
    TCC1.PER = 1600;

    //////////////////////////////////////////////////////////
    /* clock 0 setup */
    
    TCD0.CTRLB = 0x00;

    /* low-priority interrupt */
    TCD0.INTCTRLA = (TCD0.INTCTRLA & ~TC0_OVFINTLVL_gm) | TC_OVFINTLVL_LO_gc;

    /* divide main clock source by 2 */
    /* ticks at 16MHz */
    TCD0.CTRLA = (TCD0.CTRLA & ~TC0_CLKSEL_gm) | TC_CLKSEL_DIV2_gc;

    /* count to 65536 before looping. */
    /* ticks at about 250Hz */
    /* we use its A and B comparators for motor PWM */
    TCD0.PER = PWM_PERIOD;

    /* single-slope PWM with both CCA and CCB enabled */
    TCD0.CTRLB = (TCD0.CTRLB & ~TC0_WGMODE_gm) | TC_WGMODE_SS_gc | TC0_CCAEN_bm | TC0_CCBEN_bm;

    //////////////////////////////////////////////////////////
    /* start things ticking */

    /* wait until the 32MHz oscillator is stable */
    do {nop();} while (CLKSYS_IsReady(OSC_RC32MRDY_bm) == 0);
    /* and select it */
    CLKSYS_Main_ClockSource_Select(CLK_SCLKSEL_RC32M_gc);
}