Skip to content
Snippets Groups Projects

xmega adc singlended no gain

  • Clone with SSH
  • Clone with HTTPS
  • Embed
  • Share
    The snippet can be accessed without any authentication.
    Authored by Jake Read

    lots of other missing files here, but the ADC code is all there

    init_adc() starts it up, kick_adc() runs on a timer, and asks for a conversion to start. on completion that conversion fires the ISR at the bottom of the file, that starts control() loop where the actual ADC read is line 248

    if I remember this correctly, it's on PB0 on the breadboardboard

    main.c 7.96 KiB
    /*
     * atkbbb.c
     *
     * Created: 9/21/2018 4:18:52 PM
     * Author : Jake
     */ 
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "hardware.h"
    #include "fastmath.h"
    #include "pin.h"
    #include "adc.h"
    
    // PC1 is D2 / PWM
    // PC7 is EN
    // PC2 is IN1
    // PC3 is IN2
    
    void clock_init(void){
    	OSC.XOSCCTRL = OSC_XOSCSEL_XTAL_256CLK_gc | OSC_FRQRANGE_12TO16_gc; // select external source
    	OSC.CTRL = OSC_XOSCEN_bm; // enable external source
    	while(!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait for external
    	OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | OSC_PLLFAC0_bm | OSC_PLLFAC1_bm; // select external osc for pll, do pll = source * 3
    	//OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | OSC_PLLFAC1_bm; // pll = source * 2 for 32MHz std clock
    	OSC.CTRL |= OSC_PLLEN_bm; // enable PLL
    	while (!(OSC.STATUS & OSC_PLLRDY_bm)); // wait for PLL to be ready
    	CCP = CCP_IOREG_gc; // enable protected register change
    	CLK.CTRL = CLK_SCLKSEL_PLL_gc; // switch to PLL for main clock
    }
    
    void uarts_init(void){
    	rb_init(&up0rbrx);
    	rb_init(&up0rbtx);
    	pin_init(&up0rxled, &PORTF, PIN0_bm, 0, 1);
    	pin_init(&up0txled, &PORTF, PIN1_bm, 1, 1);
    	uart_init(&up0, &USARTF0, &PORTF, PIN2_bm, PIN3_bm, &up0rbrx, &up0rbtx, &up0rxled, &up0txled);
    	
    	uart_start(&up0, SYSTEM_BAUDA, SYSTEM_BAUDB);
    	
    	ups[0] = &up0;
    }
    
    void atkps_init(void){
    	atkport_init(&atkp0, 0, &up0);
    }
    
    // -------------------------------- PWM GEN CODE
    
    void set_pwm_ccb(uint16_t val){
    	// clamp
    	if(val > 4095){
    		val = 4095;
    	}
    	
    	uint8_t vall = (uint8_t) val;
    	uint8_t valh = (uint8_t) (val >> 8);
    	
    	TCC0.CCBBUFL = vall;
    	TCC0.CCBBUFH = valh;
    }
    
    // this is ~16khz 
    void hbridge_pwm_init(void){
    	PORTC.DIRSET = PIN1_bm;
    	
    	TCC0.CTRLA = TC_CLKSEL_DIV1_gc;
    	TCC0.CTRLB = TC_WGMODE_DSBOTH_gc | (1 << 5);
    	
    	uint16_t per = 4096;
    	uint8_t perl = (uint8_t) per;
    	uint8_t perh = (uint8_t) (per >> 8);
    	
    	TCC0.PERBUFL = perl;
    	TCC0.PERBUFH = perh;
    
    	set_pwm_ccb(1);
    }
    
    // -------------------------------- CONTROL TICKER 
    
    // this is ~ 4khz
    void control_ticker_init(void){
    	TCD1.CTRLA = TC_CLKSEL_DIV8_gc; 
    	TCD1.CTRLB = TC_WGMODE_NORMAL_gc;
    	
    	uint16_t per = 4096;
    	uint8_t perl = (uint8_t) per;
    	uint8_t perh = (uint8_t) (per >> 8);
    	
    	TCD1.PERL = perl;
    	TCD1.PERH = perh;
    	
    	TCD1.INTCTRLA = TC_OVFINTLVL_MED_gc;
    }
    
    // -------------------------------- ADC CODE
    
    void init_adc(void){
    	/*
    	inits adc for single-ended operation, unsigned, on PB0
    	*/
    	ADCB.CALL = SP_ReadCalibrationByte(PROD_SIGNATURES_START + ADCBCAL0_offset);
    	ADCB.CALH = SP_ReadCalibrationByte(PROD_SIGNATURES_START + ADCBCAL1_offset);
    	
    	ADCB.CTRLB = ADC_RESOLUTION_12BIT_gc;// | ADC_CONMODE_bm; // conmode is for signed ADC 
    	
    	ADCB.REFCTRL = ADC_REFSEL_INTVCC_gc;
    	
    	ADCB.PRESCALER = ADC_PRESCALER_DIV16_gc;
    	
    	ADCB.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
    	ADCB.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN0_gc;
    	
    	ADCB.CH0.INTCTRL = ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_MED_gc;
    		
    	// start it up 
    	ADCB.CTRLA |= ADC_ENABLE_bm;
    }
    
    void kick_adc(void){
    	ADCB.CH0.CTRL |= ADC_CH_START_bm;
    }
    
    uint16_t lookup[128] = {
    	2047, 2147, 2247, 2347, 2446, 2544, 2641, 2736, 2830, 2922, 3011, 3099, 3184, 3266, 3345, 3421, 3494, 3563, 3629, 3691, 3749, 3802, 3852, 3897, 3938, 3974, 4005, 4032, 4054, 4071, 4084, 4091, 4094, 4091, 4084, 4071, 4054, 4032, 4005, 3974, 3938, 3897, 3852, 3802, 3749, 3691, 3629, 3563, 3494, 3421, 3345, 3266, 3184, 3099, 3011, 2922, 2830, 2736, 2641, 2544, 2446, 2347, 2247, 2147, 2047, 1947, 1847, 1747, 1648, 1550, 1453, 1358, 1264, 1172, 1083, 995, 910, 828, 749, 673, 600, 531, 465, 403, 345, 292, 242, 197, 156, 120, 89, 62, 40, 23, 10, 3, 0, 3, 10, 23, 40, 62, 89, 120, 156, 197, 242, 292, 345, 403, 465, 531, 600, 673, 749, 828, 910, 995, 1083, 1172, 1264, 1358, 1453, 1550, 1648, 1747, 1847, 1947
    };
    
    void init_dac(void){
    	// DAC0 on PB2
    	// DAC1 on PB3 
    	DACB.CTRLB = (DACB.CTRLB & ~DAC_CHSEL_gm) | DAC_CHSEL_DUAL_gc;
    	DACB.CTRLC = (DACB.CTRLC & ~(DAC_REFSEL_gm | DAC_LEFTADJ_bm)) | DAC_REFSEL_AVCC_gc;
    	DACB.CTRLA = (DACB.CTRLA & ~DAC_CH0EN_bm) | DAC_CH1EN_bm | DAC_ENABLE_bm;
    }
    
    void init_encoder(void){
    	pin_init(&spiEncCsPin, &PORTD, PIN4_bm, 4, 1);
    	spi_init(&spiEnc, &USARTD1, &PORTD, PIN6_bm, PIN7_bm, PIN5_bm, &spiEncCsPin);
    	spi_start(&spiEnc, 1);
    	ams5047_init(&ams5047, &spiEnc);
    }
    
    void init_control_vars(){
    	// counter for poscontrol
    	ctcntr = 0;
    	
    	// current control variables 
    	cc_r = 0; // current control reading 
    	cc_l = 0; // current control last 
    	cc_t = 750; // current control target 
    	cc_err = 0; // current control error 
    	cc_edt = 0; // current control error derivative 
    	cc_ei = 0; // current control error integral 
    	
    	// current control parameters
    	cc_kpn = 18;
    	cc_kpdp = 2;
    	
    	cc_kin = 20;
    	cc_kidp = 5;
    	
    	// control encoder variables 
    	pc_r = 0; // position control reading
    	pc_l = 0; // position control last reading
    	pc_t = 8192; // target ! // 8192 mid
    	pc_err = 0; // position control error 
    	pc_edt = 0; // position control error derivative
    	pc_ei = 0; // position control error integral 
    	
    	pc_kpn = 24;
    	pc_kpdp = 3;
    	
    	pc_kin = 4;
    	pc_kidp = 8;
    	
    	pwm_output = 0;
    }
    
    // control hooks
    
    void set_pc_t(uint32_t pcktval){
    	if(pcktval > 16384){
    		pcktval = 16384;
    	}
    	pc_t = pcktval;
    }
    
    void set_cc_t(uint16_t val){
    	if(val > 4096){
    		val = 4096;
    	}
    	cc_t = val;
    }
    
    // comment this code out
    // write hwinterface for setting setpoint
    // write wraparound / shortest-walk-to-pt
    // swing some weight
    // write update tuning variables 
    // draw new hardware, print 
    
    void control(){
    	ctcntr ++;
    	pin_set(&stldbg);
    	if(ctcntr & 0b00000100){
    		// position loop: 1/4th control loop 
    		ctcntr = 0;
    		
    		// get that encoder value
    		pc_l = pc_r;
    		ams5047_read(&ams5047, &pc_r);
    		//DACB.CH1DATA = pc_r >> 2;
    		
    		// get that error
    		pc_err = (int32_t)pc_t - (int32_t)pc_r;
    		DACB.CH1DATA = abs(pc_err) >> 2;
    		// k term 
    		pc_kterm = (pc_err * pc_kpn) >> pc_kpdp;
    		
    		// roll on to that integral, then limit 
    		pc_iterm += (pc_err * pc_kin) >> pc_kidp;
    		if(pc_iterm > 4096){
    			pc_iterm = 4096;
    		} else if (pc_iterm < -4096){
    			pc_iterm = -4096;
    		}
    		
    		pc_term = pc_kterm + pc_iterm;
    		
    		// find direction based on current error 
    		if(pc_term < 0){
    			pin_set(&stlerr);
    			pin_set(&pin_inv);
    		} else {
    			pin_clear(&stlerr);
    			pin_clear(&pin_inv);
    		}
    		
    		// set targets in abs() ? 
    		pc_term = abs(pc_term);
    		set_cc_t(pc_term);
    		DACB.CH1DATA = cc_t;
    	} 
    	// do pzwork if ~ 4th cc tick 
    	
    	cc_l = cc_r;
    	cc_r = ADCB.CH0.RES;
    	
    	// error
    	cc_err = (int32_t)cc_t - (int32_t)cc_r;
    	
    	// integral, and limits 
    	// rethink this ? 
    	cc_ei += cc_err;
    	if(cc_ei > 2048){
    		cc_ei = 2048;
    	} else if (cc_ei < -2048){
    		cc_ei = -2048;
    	}
    	
    	// check for zero-pwm and then assert 
    	pwm_output = ((cc_err * cc_kpn) >> cc_kpdp) + ((cc_ei * cc_kin) >> cc_kidp);
    	if(pwm_output < 0){
    		pwm_output = 0;
    		//pin_clear(&stlerr);
    	}
    	//DACB.CH1DATA = pwm_output;
    	set_pwm_ccb(pwm_output);
    	pin_clear(&stldbg);
    }
    
    int main(void)
    {
    	// start clock
    	clock_init();
    	
    	// start networking hardware
    	uarts_init();
    	atkps_init();
    	
    	// allow interrupts (and set handlers below)
    	sei();
    	PMIC.CTRL |= PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
    	
    	// lights
    	pin_init(&stlclk, &PORTE, PIN2_bm, 2, 1);
    	pin_init(&stlerr, &PORTE, PIN3_bm, 3, 1);
    	pin_set(&stlerr);
    	
    	// debug tick
    	pin_init(&stldbg, &PORTB, PIN1_bm, 1, 1);
    	pin_clear(&stldbg);
    	
    	// hbridge begin
    	pin_init(&pin_en, &PORTC, PIN7_bm, 7, 1);
    	pin_clear(&pin_en);
    	pin_init(&pin_inv, &PORTC, PIN6_bm, 6, 1);
    	pin_init(&pin_in1, &PORTC, PIN2_bm, 2, 1);
    	pin_init(&pin_in2, &PORTC, PIN3_bm, 3, 1);
    	
    	// set direction '0'
    	pin_clear(&pin_inv);
    	pin_set(&pin_in2);
    	pin_clear(&pin_in1); // in2 = 4.3v ? 
    	
    	hbridge_pwm_init();
    	
    	pin_set(&pin_en);
    	
    	// adc begin
    	init_adc();
    	
    	// dac begin
    	init_dac();
    	
    	// spi begin
    	init_encoder();
    	
    	// begin control ticker
    	init_control_vars();
    	control_ticker_init();
    	
    	uint16_t tck = 0;
    	uint16_t angle = 0;
        while (1) 
        {
    		atkport_scan(&atkp0, 2);
    		tck ++;
    		if(!fastModulo(tck, 4096)){
    			pin_toggle(&stlclk);
    		}
        }
    }
    
    
    ISR(USARTF0_RXC_vect){
    	uart_rxhandler(&up0);
    }
    
    ISR(USARTF0_DRE_vect){
    	uart_txhandler(&up0);
    }
    
    ISR(TCD1_OVF_vect){
    	//pin_toggle(&stlerr);
    	kick_adc();
    }
    
    ISR(ADCB_CH0_vect){
    	control();
    }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment