/* This example shows how to configure TCC0 for basic timer operation. The timer will run at the main clock frequency (32MHz) so we need to do a bit of math to derive the number of clock cycles to arrive at the desired microsecond time out. */ void startTimer(uint16_t microseconds) { uint32_t cycles; // There are 31.25 nano seconds per clock cycle. // So we multiply the micro seconds by the clock period to determine // the number of clock cycles to achieve the microsecond timeout. // That number of cycles becomes our TOP value. // We will use 32 nano seconds to preclude floating point arithmetic. cycles = 32*microseconds; // Set period/TOP value. TCC0.CCA = cycles; // Set the CNT to 0. TC_SetCount(&TCC0, 0); /* Enable Input "Capture or Compare" channel A. */ TC0_EnableCCChannels( &TCC0, TC0_CCAEN_bm ); // Select clock source and start the timer. TC0_ConfigClockSource( &TCC0, TC_CLKSEL_DIV1_gc ); // Enable CCA interrupt. TC0_SetCCAIntLevel( &TCC0, TC_CCAINTLVL_LO_gc ); PMIC.CTRL |= PMIC_LOLVLEN_bm; }
void setup_Timer(){ //16 ms TC0_ConfigClockSource( &TCC0, TC_CLKSEL_DIV8_gc ); //TC0_ConfigClockSource( &TCC0, TC_CLKSEL_DIV1024_gc ); TC_SetPeriod( &TCC0, 0xFA00 ); //Es el periodo o TOP Value para que se active la interrupción. (Equivale a 16ms) //TC_SetPeriod( &TCC0, 0x7A12 ); }
/* * Setup timer 1 compare match A to generate a tick interrupt. */ static void prvSetupTimerInterrupt(void) { //Use TCC0 as a tick counter. If this is to be changed, change ISR as well TC0_t * tickTimer = &TCC0; //select the clock source and pre-scale by 64 TC0_ConfigClockSource(tickTimer, TC_CLKSEL_DIV64_gc); //set period of counter tickTimer->PER = configCPU_CLOCK_HZ / configTICK_RATE_HZ / 64 - 1; //enable interrupt and set low level TC0_SetOverflowIntLevel(tickTimer, TC_OVFINTLVL_LO_gc); //enable low level interrupts PMIC_EnableLowLevel(); }
// This function initializes the PWMs void Init_PWM( void ) { // Set PWM outputs MOTOR_OUTPUT.DIRSET = 0x03; // PD0/PD1 set as outputs // Configure timer TC0_ConfigWGM(&MOTOR_TIMER, TC_WGMODE_SS_gc); TC0_EnableCCChannels(&MOTOR_TIMER, TC0_CCAEN_bm|TC0_CCBEN_bm); TC_SetCompareA(&MOTOR_TIMER, 0); TC_SetCompareB(&MOTOR_TIMER, 0); TC_SetPeriod(&MOTOR_TIMER, MAX_PWM); TC0_ConfigClockSource(&MOTOR_TIMER, TC_CLKSEL_DIV1_gc); // 32MHz }
/** \brief Initializes the library timer 0 or 1 based on given timer parameter. * * Sets up the given timer for use with this library. This involves setting the * clock prescaler and mode, but the period and overflow interrupt enable are * left to the SM_move() and ISR for the corresponding timer. * * This function also handles mapping the appropriate speed ramp to the * * \param[in] motor The motor to initialize the timer for * \param[in] timer The timer to initialize (TIMER0 or TIMER1) */ static void SM_timer_init(SM_t *motor, SM_timer_t timer) { /* 32M/256 == 125K Hz*/ if (timer == SM_TIMER_NEEDLE) { TC0_ConfigWGM(&TIMER_NEEDLE, TC_WGMODE_NORMAL_gc); TC0_ConfigClockSource(&TIMER_NEEDLE, TC_CLKSEL_DIV256_gc); needle_motor = motor; } else { TC1_ConfigWGM(&TIMER_RING, TC_WGMODE_NORMAL_gc); TC1_ConfigClockSource(&TIMER_RING, TC_CLKSEL_DIV256_gc); ring_motor = motor; } motor->timer = timer; }
// Configures PWM output on compare a b and c for single slope pwm, with hires, and clk source as sys clk void configPWM (volatile TC0_t * tc, HIRES_t * hires, uint16_t period) { TC_SetPeriod (tc, period ); TC0_ConfigWGM (tc, TC_WGMODE_NORMAL_gc ); // set to single slope pwm generation mode TC0_EnableCCChannels (tc, TC0_CCAEN_bm); // enable compare A TC0_EnableCCChannels (tc, TC0_CCBEN_bm); // enable compare B TC0_EnableCCChannels (tc, TC0_CCCEN_bm); // enable compare C TC0_EnableCCChannels (tc, TC0_CCDEN_bm); // enable compare D //~ TC0_SetCCAIntLevel (tc, TC_CCAINTLVL_HI_gc); TC0_SetCCBIntLevel (tc, TC_CCBINTLVL_LO_gc); //~ TC0_SetCCCIntLevel (tc, TC_CCCINTLVL_HI_gc); //~ TC0_SetCCDIntLevel (tc, TC_CCDINTLVL_HI_gc); TC0_SetOverflowIntLevel (tc, TC_OVFINTLVL_LO_gc); PMIC.CTRL |= PMIC_HILVLEN_bm; TC0_ConfigClockSource (tc, TC_CLKSEL_DIV1_gc); HIRES_Enable (hires, HIRES_HREN_TC0_gc); }
void battery_init() { PORTD.DIRSET = PIN4_bm | PIN5_bm | PIN6_bm; // battery level indicator PORTD.OUT = 0x00; PORTC.DIRSET = PIN7_bm; // signal to stop the boost converters PORTC.OUTSET = PIN7_bm; // start with the converters stopped to avoid power // surges on the battery. When the voltage recovers // the converters will be enabled again PORTC.DIRCLR = PIN6_bm; // input V_USB_CHG PORTE.DIRCLR = PIN3_bm; // input CHG_STAT // update once for each second (1Hz) TC_SetPeriod(&TCE0, 31250); TC0_ConfigClockSource(&TCE0, TC_CLKSEL_DIV256_gc); TC0_ConfigWGM(&TCE0, TC_WGMODE_NORMAL_gc); TC0_EnableCCChannels(&TCE0, TC0_CCAEN_bm); TC0_SetCCAIntLevel(&TCE0, TC_CCAINTLVL_LO_gc); }
int main( void ) { /* To toggle a LED, set pin 0 as output and high so the LED is default off. */ LEDPORT.OUTSET = PIN0_bm; LEDPORT.DIRSET = PIN0_bm; //Add code here that sets the timer compare value for channel A //ie. CCA register for the TCC0 /* We need to start the counter with correct prescaling, * and make it count to a specific TOP value, as we did in task1. * To do this we use the driver functions supplied in TC_driver.c, study the source * file to see how the timer is configured */ TC_SetPeriod(&TCC0, 0xFFFF); TC0_ConfigClockSource(&TCC0, TC_CLKSEL_DIV64_gc); /* This code turn on the LED on compare match, and turn the LED off on timer overflow */ while(1) { if((TCC0.INTFLAGS & TC0_OVFIF_bm) != 0) { TCC0.INTFLAGS = TC0_OVFIF_bm; // Clear the TC_OVFIF by writing a logical 1 to the flag LEDPORT.OUTSET = PIN0_bm; // Turn off LED } if((TCC0.INTFLAGS & TC0_CCAIF_bm) !=0) { TCC0.INTFLAGS = TC0_CCAIF_bm; //Clear the TC_CCAIF by writing a logical 1 to the flag TCC0.CCABUF += 0x1000; //Update the CCABUF register with a new value to change the LED on time. LEDPORT.OUTCLR = PIN0_bm; //Turn on LED } } }
void TCE0_init() { /* Select a Waveform Genreation mode and the CC channels to use*/ TC0_ConfigWGM( &TCE0, TC_WGMODE_SS_gc ); TC0_EnableCCChannels( &TCE0, TC0_CCAEN_bm); // only CCA is used TC_SetPeriod( &TCE0, 60000); /* The corresponding port pins MUST be output for the Waveform to be visible */ PORTE.DIRSET = 0xFF; PORTE.OUTSET = 0xFF; //set port high to switch LEDs off, take INVEN into account /* To have inverted ouput on some pins we set the corresponding INVEN bit for the pin*/ TC0_ConfigClockSource(&TCE0, TC_CLKSEL_DIV1_gc); }
void configDelayTimer (volatile TC0_t * tc) { TC_SetPeriod (tc, (uint16_t)65535); // set tc period TC0_ConfigWGM (tc, TC_WGMODE_NORMAL_gc); // normal timer countermode TC0_ConfigClockSource (tc, TC_CLKSEL_DIV1024_gc); }
int main( void ) { /* To change the duty cycle for the PWM for the LED control, use a variable to increase/decrease the * CCx registers once for each period */ int16_t pwm_delta = 300; // Add code to select a Single Slope PWM as Waveform Generation mode. // This is done by setting the WGM bits,in the CTRLB register for the TC. /* Add code to enable the CC channels we wish to use. Each channel must be separately enabled * by setting the corresponding CCxEN bits in the CTRLB register for the TC. * Code for enabling CCA is already added, but add code to enable CCB, CCC and CCD */ TCE0.CTRLB |= TC0_CCAEN_bm; //Insert code to enable CC for the other channels, B, C and D. /* The corresponding port pins MUST be ouput for the Waveform to be visible * on the pin. For TCE0 the corresponding port is PORTE, and pin 0 to 3 for * CC channel A to D */ PORTE.DIRSET = 0x0F; /* Note how the inverted signal is always controlled from the Port pin configuration in XMEGA * This can be used with all other peripherals connected to the pin to have inverted output. * Below is example code on how you can set inverted ouput on a pin using the Pin Control Register*/ //PORTE.PIN0CTRL &= ~PORT_INVEN_bm; /* Set a compare value for each compare channel, just as in task2. * The compare value decide the PWM duty cycle for the waveform. * * Code for CC channel A is added, add code for channel B, C, and D * with the compare value 3000 */ TC_SetCompareA(&TCE0, 3000); //Insert function calls to set the other compare values /* Using the TC_driver we set the Period and * start the timer with no prescaling */ TC_SetPeriod(&TCE0, 60000); TC0_ConfigClockSource(&TCE0, TC_CLKSEL_DIV1_gc); while(1) { /* The code check if the overflow flag is set, * if so it clears the flag and sets a new duty cycle for all * CC channels */ /* Check if overflow flag (OVFIF) is set, * clear flag and set a new duty cycle */ if(TC_GetOverflowFlag(&TCE0) != 0) { TC_ClearOverflowFlag(&TCE0); //Clear the IF by writing a logical 1 to the flag if(TCE0.CCA >= 59000) { //Some "random" values above 0 and below TOP is selected pwm_delta = -300; //for the PWM changes, and make the LED look ok. } else if(TCE0.CCA <= 5000) { pwm_delta = +300; } TCE0.CCABUF += pwm_delta; //Change the compare value to change duty cycle TCE0.CCBBUF += pwm_delta; TCE0.CCCBUF += pwm_delta; TCE0.CCDBUF += pwm_delta; } } }
// This function initializes system tick void Init_SysTick( void ) { TC_SetPeriod(&TCF0, 124); // 125 ticks at 31.25KHz = 4ms periods TC0_ConfigClockSource(&TCF0, TC_CLKSEL_DIV1024_gc); // 32MHz/1024=31.25KHz TC0_SetOverflowIntLevel(&TCF0, TC_OVFINTLVL_LO_gc); // Enable interrupts for overflow }
//----------------------------------------------------------------------------- // functions //----------------------------------------------------------------------------- void adc_init(void) { /* Note: port_init() must be run before this function, so that the inputs are set correctly. We are using both ADCs. So everything will be set up for ADCA && ADCB. */ // Load the production calibration data into each ADC. // This data was taken by Atmel and is stored in the micro. // This function takes care of the whole process for you. ADC_CalibrationValues_Load(&ADCA); ADC_CalibrationValues_Load(&ADCB); // Set the mode of operation for each ADC // Signed operation mode is required for the differential configuration. ADC_ConvMode_and_Resolution_Config(&ADCA,signed_y,ADC_RESOLUTION_12BIT_gc); ADC_ConvMode_and_Resolution_Config(&ADCB,signed_y,ADC_RESOLUTION_12BIT_gc); // Set ADC clocks // 32MHz / 128 = 250KHz // I currently have no explanation for this choice // Atmel documentation states that you need to stay within the recommended // ADC frequencies, but I cannot find the specific numbers. ADC_Prescaler_Config(&ADCA, ADC_PRESCALER_DIV128_gc); ADC_Prescaler_Config(&ADCB, ADC_PRESCALER_DIV128_gc); // Select reference to be external reference on PIN0 for A and B ADC_Reference_Config(&ADCA, ADC_REFSEL_AREFA_gc); ADC_Reference_Config(&ADCB, ADC_REFSEL_AREFB_gc); // Setup all channels to have differential input and 1X gain ADC_Ch_InputMode_and_Gain_Config(&ADCA.CH0,ADC_CH_INPUTMODE_DIFF_gc, ADC_CH_GAIN_1X_gc); // V1 ADC_Ch_InputMode_and_Gain_Config(&ADCA.CH1,ADC_CH_INPUTMODE_DIFF_gc, ADC_CH_GAIN_1X_gc); // V2 ADC_Ch_InputMode_and_Gain_Config(&ADCA.CH2,ADC_CH_INPUTMODE_DIFF_gc, ADC_CH_GAIN_1X_gc); // reference ADC_Ch_InputMode_and_Gain_Config(&ADCB.CH0,ADC_CH_INPUTMODE_DIFF_gc, ADC_CH_GAIN_1X_gc); // I1 ADC_Ch_InputMode_and_Gain_Config(&ADCB.CH1,ADC_CH_INPUTMODE_DIFF_gc, ADC_CH_GAIN_1X_gc); // I2 ADC_Ch_InputMode_and_Gain_Config(&ADCB.CH2,ADC_CH_INPUTMODE_DIFF_gc, ADC_CH_GAIN_1X_gc); // reference // Select the input pins for each ADC. /* See AnodV2.1.sch eagle file: V1 - A1 V2 - A2 I1 - B1 I2 - B2 Ref - A0,A3,B0,B3 */ ADC_Ch_InputMux_Config(&ADCA.CH0, ADC_CH_MUXPOS_PIN1_gc, \ ADC_CH_MUXNEG_PIN3_gc); // V1 ADC_Ch_InputMux_Config(&ADCA.CH1, ADC_CH_MUXPOS_PIN2_gc, \ ADC_CH_MUXNEG_PIN3_gc); // V2 ADC_Ch_InputMux_Config(&ADCA.CH2, ADC_CH_MUXPOS_PIN3_gc, \ ADC_CH_MUXNEG_PIN3_gc); // Offset calib ADC_Ch_InputMux_Config(&ADCB.CH0, ADC_CH_MUXPOS_PIN1_gc, \ ADC_CH_MUXNEG_PIN3_gc); // V1 ADC_Ch_InputMux_Config(&ADCB.CH1, ADC_CH_MUXPOS_PIN2_gc, ADC_CH_MUXNEG_PIN3_gc); // V2 ADC_Ch_InputMux_Config(&ADCB.CH2, ADC_CH_MUXPOS_PIN3_gc, ADC_CH_MUXNEG_PIN3_gc); // Offset calib // Configure the ADCA.CH2 interrupt. // This will trip once a reading on channel 2 has been completely resolved. // I am assuming the chan 0 and 1 of both ADCs will have their results completed // when chan 2 is done. This is based from the Xmega A manual (sect 25) ADC_Ch_Interrupts_Config(&ADCA.CH1, ADC_CH_INTMODE_COMPLETE_gc, \ ADC_CH_INTLVL_LO_gc); //Enable ADCs ADC_Enable(&ADCA); ADC_Enable(&ADCB); // Wait until common mode voltage is stable so tha bypass transients are not passed. // What is the difference between the 32 and 8 MHz versions, // and which one do I want? ADC_Wait_32MHz(&ADCA); ADC_Wait_32MHz(&ADCB); // The TCD0 timer will periodically trigger an event that will create an event // on channel 0. (Xmega A manual sect 6) eflags.setEventSource = EVSYS_SetEventSource(0, EVSYS_CHMUX_TCD0_OVF_gc); TC0_ConfigClockSource(&TCD0, TC_CLKSEL_DIV8_gc); TCD0.PER = 200; // 1/f = 1/(32MHz/DIVx/PER) --- 200---50us---20KHz // This is moved to the adc_test() fun. May want to enable it here later. // enable timer overflow int and set priority to low. //TCD0.INTCTRLA = TC_OVFINTLVL_LO_gc; // An event on eventChan 0 will trigger a sweep of chan 0,1 in ADCA && ADCB. // I do not know what would happen if an event happened on eventChan 1,2,3. ADC_Events_Config(&ADCA, ADC_EVSEL_0123_gc, ADC_EVACT_SWEEP_gc); ADC_Events_Config(&ADCB, ADC_EVSEL_0123_gc, ADC_EVACT_SWEEP_gc); ADC_SweepChannels_Config(&ADCA, ADC_SWEEP_01_gc); ADC_SweepChannels_Config(&ADCB, ADC_SWEEP_01_gc); // Calibration routine for the ADCs // Find offset with two pins shorted together. // Steve also found the offset for the current with 0 current flowing into them, // but did not do an equivalent for voltage. I will leave this out for now. offset_A = ADC_Offset_Get_Signed(&ADCA, &(ADCA.CH2), true); offset_B = ADC_Offset_Get_Signed(&ADCB, &(ADCB.CH2), true); }