Problem med ADC på Attiny26

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Problem med ADC på Attiny26

Inlägg av MaggoT »

Hej!
Jag sitter och labbar med att styra en unipolär stegmotor (från en skrivare) med en AVR Attiny26, koden nedan funkar precis som tänkt såhär långt, motorn snurrar medsols konstant.

Nu till problemet, jag tänkte koppla in en potentiometer på ADC3 (PA4) som man kan styra hastigheten med.
Jag försöker köra ADC:n i "free running mode" och uppdatera en global variabel med nya värdet inuti en interrupt, men när jag försöker göra något med denna variabel inuti main och kompilerar koden så ökar storleken på hex-filen från 800 bytes till 14kB (och ryms således inte i MCU:ns flashminne).

Jag förstår inte varför detta händer, om jag förstått saken rätt så beror det på att man gör flyttalsberäkningar med en MCU som inte stöder detta(?) Men det bör ju inte ske i denna kod eller?

Här är koden såhär långt, kompilerar med avr-gcc.
Det är alltså första raden inuti while(1), dly = adcvalue, som ställer till det. Samma sak händer om jag sätter _delay_ms(adcvalue);.

Kod: Markera allt

/*********************************************************************
* Unipolar stepper motor driver test code
*
* Device: attiny26
*********************************************************************/
#define F_CPU 8000000UL
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

// Speed pot ADC value
uint8_t adcvalue = 0;

// ADC conversion complete interrupt
ISR(ADC_vect)
{
	adcvalue = ADCH;
}

int main(void)
{
	// Stepper motor outputs on PA0-PA3
	DDRA |= (1 << PA0) | (1 << PA1) | (1 << PA2) | (1 << PA3);
	// Set all outputs low
	PORTA = 0x00;
	
	// Set up ADC
	// AVCC as ref
	// Left adjust result
	// Use ADC3 (PA4)
	ADMUX |= (1 << ADLAR) | (1 << MUX1) | (1 << MUX0);
	
	// ADC enable
	// Start conversion
	// Free running mode
	// ADC complete interrupt enable
	// 1/128 prescaler
	ADCSR |= (1 << ADEN) | (1 << ADSC) | (1 << ADFR) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); 
	
	// Enable global interrupts
	sei();


	uint8_t dly = 200;

	while(1)
	{
		//dly = adcvalue;
		
		// A 0001 1
		PORTA = 0x01;
		_delay_ms(dly);
		
		// AB 0011 3
		PORTA = 0x03;
		_delay_ms(dly);
		
		// B 0010 2
		PORTA = 0x02;
		_delay_ms(dly);
		
		// BC 0110 6
		PORTA = 0x06;
		_delay_ms(dly);
		
		// C 0100 4
		PORTA = 0x04;
		_delay_ms(dly);
		
		// CD 1100 12
		PORTA = 0x0C;
		_delay_ms(dly);
		
		// D 1000 8
		PORTA = 0x08;
		_delay_ms(dly);
		
		// DA 1001 9
		PORTA = 0x09;
		_delay_ms(dly);
	}
}
Tacksam för lite vägledning.
- MaggoT
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Problem med ADC på Attiny26

Inlägg av jesse »

adcvalue ska väl vara av typen "volatile" också? Så att den inte optimeras bort.

14kB :shock:

Inte ens flyttalskod skulle ge sådan stor fil. Måste vara något annat konstigt fel som uppstår vid kompilering. Kan inte se något direkt fel i koden så här på rak arm.

Man kanske kan följa koden i disassemblern?
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Re: Problem med ADC på Attiny26

Inlägg av MaggoT »

Här kommer disassembly-filerna, det går lite ovanför mitt huvud :D
Med ovannämnda rad bortkommenterad: http://pastebin.com/MmB4eynZ
Stora varianten: http://pastebin.com/Sgy7mBT5

Märkte just en annan grej, om jag kommenterar bort allt inuti while(1) förutom dly = adcvalue, så uppkommer inte problemet. Men om jag skriver såhär

Kod: Markera allt

dly = adcvalue;
_delay_ms(dly);
så är hex-filen uppe i 12kB igen, frågan kvarstår dock, varför :)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med ADC på Attiny26

Inlägg av sodjan »

Är "dly" typ-kompatibel mot parametern till _delay_ms() ?
snigelen
Inlägg: 815
Blev medlem: 8 maj 2009, 11:02:14
Ort: Lund

Re: Problem med ADC på Attiny26

Inlägg av snigelen »

Du kan inte använda variabler som argument till _delay_ms(), det måste vara ett konstant uttryck. Annars kommer det att utföras flyttalsberäkningar och du får inte alls den fördröjning du tänkt dig. Detta står i manualen. Det är alltså flyttalsrutiner som länkas med och det är därför ditt program blir så stort. (Om man vill använda flyttal skall man ange -lm till länkaren så länkas betydligt mindre och effektivare flyttalsutiner med, men det är nog inte aktuellt på en tiny26).

Edit: Länk till manualen. Se "Note:" nr. 2.
Senast redigerad av snigelen 26 juni 2011, 13:05:58, redigerad totalt 1 gång.
Användarvisningsbild
Icecap
Inlägg: 26655
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Problem med ADC på Attiny26

Inlägg av Icecap »

Som sodjan skriver: kan "_delay_ms()" ta variabler? De brukar väl bara kunde ta konstanter efter vad jag har sett...

Men man kan ju enkelt fixa det:

Kod: Markera allt

dly = adcvalue;
while(dly)
  {
  dly--;
  _delay_ms(1);
  }
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Re: Problem med ADC på Attiny26

Inlägg av MaggoT »

Ahaa, nu blev det lite klarare :)
Intressant, har inte haft en aning om att _delay_ms() inte kan ta variabler som argument på dethär sättet, har för mig att jag gjort så tidigare men det kan ha varit med någon Mega32 eller liknande, där problemet "gått obemärkt". Nu vet man iallafall. Och tack Icecap för den koden, bra tips om man någon gång skulle behöva just denna funktion.

Tror jag försöker få till en timer som "stegar" fram motorn som nästa steg istället för att använda delays, det känns som en snyggare lösning.

Btw, en följdfråga, finns det något smidigt sätt att med binära
operatorer "skifta" bitarna enligt sekvensen ovan?
Dvs:
0001
0011
0010
0110
0100
osv...
Nu rör det ju iofs sig bara om 8 "lägen" så det spelar kanske inte så stor roll, men det kunde vara lärorikt att veta om det går.

Jag får tacka för all hjälp såhär långt! :tumupp:
Användarvisningsbild
Icecap
Inlägg: 26655
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Problem med ADC på Attiny26

Inlägg av Icecap »

Jag brukar göra en uppslagstabell.

Kod: Markera allt

const unsigned char Roll_It[] = {0x01, 0x03, 0x02, 0x06, 0x04, osv};
unsigned char Index;

sedan är det enkelt:
Porten = Roll_It[Index++];
if(Index >= sizeof(Roll_It)) Index = 0;
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Re: Problem med ADC på Attiny26

Inlägg av MaggoT »

Okej, det verkar vara en smidig lösning.
Tack!
Skriv svar