xmega adc singlended no gain
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();
}
Please register or sign in to comment