I am new to the tinyavr 1 series microcontrollers. I've tried copying the basic example out of the Microchip TB3209 guide, but it doesn't seem to do anything.
I use the below code, where PA3 is an LED and PA6 is my ADC pin. All it's supposed to do is on boot, read the ADC pin, and if it is below the threshold, do nothing, otherwise turn the LED on. But not matter if I have the ADC grounded or pulled to 5V, it always gets a reading from the ADC that is higher than the threshold.
The below code is straight from Microchip.
/* ATMEL ATTINY212
Pin 6 is /RESET
+-\/-+
Vcc 1| |8 GND
DAC TXD PA6 2| |7 PA3 SCK
RXD PA7 3| |6 PA0 UPDI RESET
SDA MOSI PA1 4| |5 PA2 MISO SCL
+----+
PA3 is the LED output pin
PA6 is the ADC pin AIN6
*/
#define F_CPU 3333333UL // Default Setting micro to 3.33MHz
// #define F_CPU 20000000UL // Setting micro to 20MHz
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t adcVal;
void ADC0_init(void);
uint16_t ADC0_read(void);
void ADC0_init(void)
{
/* Disable digital input buffer */
PORTA.PIN6CTRL &= ~PORT_ISC_gm;
PORTA.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc;
/* Disable pull-up resistor */
PORTA.PIN6CTRL &= ~PORT_PULLUPEN_bm;
ADC0.CTRLC = ADC_PRESC_DIV4_gc /* CLK_PER divided by 4 */
| ADC_REFSEL_INTREF_gc; /* Internal reference */
ADC0.CTRLA = ADC_ENABLE_bm /* ADC Enable: enabled */
| ADC_RESSEL_10BIT_gc; /* 10-bit mode */
/* Select ADC channel */
ADC0.MUXPOS = ADC_MUXPOS_AIN6_gc;
}
uint16_t ADC0_read(void)
{
/* Start ADC conversion */
ADC0.COMMAND = ADC_STCONV_bm;
/* Wait until ADC conversion done */
while ( !(ADC0.INTFLAGS & ADC_RESRDY_bm) )
{
;
}
/* Clear the interrupt flag by writing 1: */
ADC0.INTFLAGS = ADC_RESRDY_bm;
return ADC0.RES;
}
int main(void)
{
ADC0_init();
adcVal = ADC0_read();
// set PA3 to output mode
PORTA.DIR |= (1 << 3);
if(adcVal > 10) {
// PA3 LED on
PORTA.OUTSET = (1 << 3);
} else {
// PA3 LED off
PORTA.OUTCLR = (1 << 3);
}
while (1)
{
;
}
}
As of the board, it's working with a blink or digital input code properly. It's just a SOIC to DIP adapter on a bread board going to an LED (with CLR) and a potentiometer.
I am new to the tinyavr 1 series microcontrollers. I've tried copying the basic example out of the Microchip TB3209 guide, but it doesn't seem to do anything.
I use the below code, where PA3 is an LED and PA6 is my ADC pin. All it's supposed to do is on boot, read the ADC pin, and if it is below the threshold, do nothing, otherwise turn the LED on. But not matter if I have the ADC grounded or pulled to 5V, it always gets a reading from the ADC that is higher than the threshold.
The below code is straight from Microchip.
/* ATMEL ATTINY212
Pin 6 is /RESET
+-\/-+
Vcc 1| |8 GND
DAC TXD PA6 2| |7 PA3 SCK
RXD PA7 3| |6 PA0 UPDI RESET
SDA MOSI PA1 4| |5 PA2 MISO SCL
+----+
PA3 is the LED output pin
PA6 is the ADC pin AIN6
*/
#define F_CPU 3333333UL // Default Setting micro to 3.33MHz
// #define F_CPU 20000000UL // Setting micro to 20MHz
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t adcVal;
void ADC0_init(void);
uint16_t ADC0_read(void);
void ADC0_init(void)
{
/* Disable digital input buffer */
PORTA.PIN6CTRL &= ~PORT_ISC_gm;
PORTA.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc;
/* Disable pull-up resistor */
PORTA.PIN6CTRL &= ~PORT_PULLUPEN_bm;
ADC0.CTRLC = ADC_PRESC_DIV4_gc /* CLK_PER divided by 4 */
| ADC_REFSEL_INTREF_gc; /* Internal reference */
ADC0.CTRLA = ADC_ENABLE_bm /* ADC Enable: enabled */
| ADC_RESSEL_10BIT_gc; /* 10-bit mode */
/* Select ADC channel */
ADC0.MUXPOS = ADC_MUXPOS_AIN6_gc;
}
uint16_t ADC0_read(void)
{
/* Start ADC conversion */
ADC0.COMMAND = ADC_STCONV_bm;
/* Wait until ADC conversion done */
while ( !(ADC0.INTFLAGS & ADC_RESRDY_bm) )
{
;
}
/* Clear the interrupt flag by writing 1: */
ADC0.INTFLAGS = ADC_RESRDY_bm;
return ADC0.RES;
}
int main(void)
{
ADC0_init();
adcVal = ADC0_read();
// set PA3 to output mode
PORTA.DIR |= (1 << 3);
if(adcVal > 10) {
// PA3 LED on
PORTA.OUTSET = (1 << 3);
} else {
// PA3 LED off
PORTA.OUTCLR = (1 << 3);
}
while (1)
{
;
}
}
As of the board, it's working with a blink or digital input code properly. It's just a SOIC to DIP adapter on a bread board going to an LED (with CLR) and a potentiometer.
Share Improve this question edited Feb 5 at 18:10 emacs drives me nuts 4,01218 silver badges40 bronze badges asked Jan 30 at 20:25 Erik VincentErik Vincent 112 bronze badges 3- You are showing the code (and rightly so). What makes you think that your hardware is correctly set up? Was assembling required? Supply voltage attached? Right way round? Etc. you know what I mean. I assume this is the "HelloWorld" version for that embedded environment, right? Or is there anything simpler you could try? Maybe a digital input instead of the ADC? Or maybe just some basic debugger comissioning test? – Yunnosch Commented Jan 31 at 6:32
- You should probably read the ADC result before clearing the flag. Store it in a temporary variable, then clear the flag, then return the temporary variable's value. – Lundin Commented Jan 31 at 8:46
- Maybe you want the ADC reading and LED action in the loop? – emacs drives me nuts Commented Jan 31 at 17:29
1 Answer
Reset to default 0So, I've determined the example in the Microchip ADC Technical Brief just doesn't work for whatever reason. However, I have written code that does work. Below is that code:
/*
* t212 adc.c
*
* Created: 1/30/2025 2:43:59 PM
* Author : erik.vincent
*/
/* ATMEL ATTINY212
Pin 6 is /RESET
+-\/-+
Vcc 1| |8 GND
DAC TXD PA6 2| |7 PA3 SCK
RXD PA7 3| |6 PA0 UPDI RESET
SDA MOSI PA1 4| |5 PA2 MISO SCL
+----+
PA3 is the LED output pin
PA6 is the ADC pin AIN6
*/
#define F_CPU 3333333UL // Default Setting micro to 3.33MHz
// #define F_CPU 20000000UL // Setting micro to 20MHz
#define ADC_SHIFT_DIV64 (6) // ADC Sample Accumulator 0x06 is 64 samples
#include <avr/io.h>
#include <util/delay.h>
void adc_init (void);
uint16_t read_adc(void);
void adc_init (void) {
ADC0_CTRLA = (0 << ADC_RUNSTBY_bp) | (0 << ADC_RESSEL_10BIT_gc) | (1 << ADC_ENABLE_bp); // Disabled run in standby, enabled ADC & full 10-bit resolution
VREF_CTRLA = (1 << VREF_ADC0REFSEL0_bp); // ADC voltage reference = 1.1V (0x1)
ADC0_CTRLC = (1 << ADC_SAMPCAP_bp) | (0 << ADC_REFSEL_gp); // Set Internal reference, set reduced size of sampling capacitance, set prescaler to CLK_PER/4
ADC0_CTRLD = (1 << ADC_INITDLY1_bp) | (0 << ADC_ASDV_bp) | (0 << ADC_SAMPDLY0_bp); // These bits define the delay when initializing the ADC or changing the source of the reference voltage.
ADC0_SAMPCTRL = (1 << ADC_SAMPLEN4_bp); // 0x10, These bits control the ADC sampling time in number of CLK_ADC cycles,
ADC0_CTRLB = ADC_SAMPNUM_ACC64_gc; // 64 samples
ADC0_MUXPOS = 6; // Set to AIN6
}
uint16_t read_adc(void) {
// Read ADC
uint16_t adc_val = 0;
uint16_t adc_ave = 0; // ADC average from accumulator
_delay_ms(1); // give it a moment to switch
ADC0_COMMAND = (1 << ADC_STCONV_bp); // Start conversion//Writing a '1' to this bit in single-shot mode starts one conversion.
while (ADC0_COMMAND & (1 << ADC_STCONV_bp)); // while conversion is on-going
_delay_ms(10);
adc_val = ((ADC0_RESH << 8) | ADC0_RESL); // ADC conversion result to make sure ADC reading is good
adc_val = ((ADC0_RESH << 8) | ADC0_RESL); // Do it a second time, because the first time will be bogus
adc_ave = adc_val >> ADC_SHIFT_DIV64; // Get average value from ADC sampler
return adc_ave;
}
int main(void)
{
adc_init();
uint16_t adcVal = read_adc();
// set PA3 to output mode
PORTA.DIR |= (1 << 3);
if(adcVal > 10) {
// PA3 LED on
PORTA.OUTSET = (1 << 3);
} else {
// PA3 LED off
PORTA.OUTCLR = (1 << 3);
}
while (1) {
;
}
}