Home > Software design >  ATtiny402 ADC output is strange
ATtiny402 ADC output is strange

Time:08-27

Implemented a simple ADC program in ATtiny402 using MPLAB X IDE and PICKI4 as the debugger. A potentiometer is connected to the PA2 pin as an input. In the program, the ADC conversion result from the ADC0.RES value is observed 0xFFBC while the ADC voltage level is the same as the reference level, but the expected is 0x3FF. For the other voltage levels the ADC0.RES value is also strange (not in the range 0x0 to 0x3FF). But if I right shift the ADC0.RES value to 6 bit the result range becomes 0x0 to 0x3FE which is close to the value referred to in the datasheet (10-bit MAX and MIN value).

So simply I am shifting 6 bits to the right of ADC0.RES value to get the ADC result, while I think this should not be required, only ADC0.RES can provide the conversion result.

So, Am I missing something, and why this 6-bit right shift is required?

#define F_CPU 20000000UL // CLK frequency is configured to 20 MHz by protected write
#include <avr/io.h>
#include <avr/interrupt.h>

FUSES = {
    .WDTCFG = 0x00, // WDTCFG {PERIOD=OFF, WINDOW=OFF}
    .BODCFG = 0x00, // BODCFG {SLEEP=DIS, ACTIVE=DIS, SAMPFREQ=1KHz, LVL=BODLEVEL0}
    .OSCCFG = 0x02, // OSCCFG {FREQSEL=20MHZ, OSCLOCK=CLEAR}
    .TCD0CFG = 0x00, // TCD0CFG {CMPA=CLEAR, CMPB=CLEAR, CMPC=CLEAR, CMPD=CLEAR, CMPAEN=CLEAR, CMPBEN=CLEAR, CMPCEN=CLEAR, CMPDEN=CLEAR}
    .SYSCFG0 = 0xC4, // SYSCFG0 {EESAVE=CLEAR, RSTPINCFG=UPDI, CRCSRC=NOCRC}
    .SYSCFG1 = 0x07, // SYSCFG1 {SUT=64MS}
    .APPEND = 0x00, // APPEND {APPEND=User range:  0x0 - 0xFF}
    .BOOTEND = 0x00, // BOOTEND {BOOTEND=User range:  0x0 - 0xFF}
};

LOCKBITS = 0xC5; // {LB=NOLOCK}

volatile uint16_t adcVal = 0 ; 

void clock_conf(){
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, !CLKCTRL_PEN_bm); // prescaler disabled
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSC20M_gc); //20MHz clock
}

void io_config(){
    PORTA.PIN2CTRL = PORT_ISC_INPUT_DISABLE_gc ; //PA2 digital input buffer and pull-up is disabled
}

void adc_init(){
    ADC0.CTRLA = ADC_FREERUN_bm;                    //Set ADC to free running Mode
    ADC0.CTRLA |= ADC_ENABLE_bm ;                   //enable ADC

    ADC0.CTRLB = ADC_SAMPNUM_ACC64_gc;                //SET the ADC to sum 64 samples
    ADC0.CTRLC |= (1<<ADC_SAMPCAP_bp) | (1<<VREF_ADC0REFSEL0_bp) | (ADC_PRESC_DIV128_gc <<  ADC_PRESC_gp )  ; //reference voltage  5v on VDD and pre-scaler is 128
    ADC0.CTRLD = ADC_INITDLY_DLY256_gc;                //Set the init delay before first sample
    ADC0.MUXPOS = ADC_MUXPOS_AIN2_gc;                //SET PA2 as the input for the ADC
    ADC0.INTCTRL = ADC_RESRDY_bm;                    //enable the result ready interrupt

    ADC0.COMMAND = ADC_STCONV_bm;                    // Start the conversion
}

ISR(ADC0_RESRDY_vect){
    adcVal =  ADC0.RES >> 6 ;  // (ADC0.RES >> 6) returns in range (0x0 to 0x3FE)
}

int main(void) {
    io_config()  ;
    clock_conf() ;
    adc_init()  ;

    sei()  ;
    while (1) {

    }
}

CodePudding user response:

You have

ADC0.CTRLB = ADC_SAMPNUM_ACC64_gc;    //SET the ADC to sum 64 samples

So that is why you needed to divide by 64 (right shift by 6 bits).

  • Related