vypnutí optimalizace v AVR studiu?

Chci se zeptat , jestli existuje tato možnost. Mám problém s tím, že v programu se opakuje několikrát po sobě volání stejné funkce - vždy ale s jinými parametry překladač vytvoří asm kód jeno pro jedno volání - myslí si , že jsem blbý a proč to tam píšu několikrát :smiley: .

Vypnout optimalizaci je jednoduché ale špatné řešení.
Můžeš sem dát kompletní překladu schopnou ukázku problému?

Problém s optimalizacemi je většinou způsoben nevhodnou konstrukcí kódu/neznalostí C. Jejich vypínání není řešení problému, jen zalepení, kterým si navíc můžeš způsobit nefunkčnost jiných částí programu (převážně těch závislých na delay).

Ano, nastav si optimalizacny parameter na hodnotu -O0.

Ako uz bolo spomenute vyssie, je to zla cesta ak sa nou snazis odstranit chybu v programe. Iba ju tym zamaskujes.

Tak nakonec jsem to našel, optimalizace vypnul avše je OK.

Vaše připomínky bych bral, kdyby se jednalo o můj kód, ale já jsem zkoušel rozchodit kód vygenerovaný programem AvrWiz, který mimochodem doporučuje sám Martin alias Torgeir na mikrozone.sk/download.php?view.35 a tam si myslím že chyby nebudou.

// generated with AvrWiz (by g@greschenz.de)
// -----------------------------------------
// cpu:     ATmega8
// speed:   16 mhz (max: 16 mhz)
// voltage: 5 V
// ram:     1024 bytes (0x0060-0x045f)
// rom:     4096 bytes (0x0000-0x0fff)
// eeprom:  512 bytes (0x0000-0x01ff)
// -----------------------------------------

#include <avr/io.h>
#include <avr/interrupt.h>

#if !defined (__AVR_ATmega8__)
#error __AVR_ATmega8__ not defined !
#endif

#if !defined (F_CPU)
#define F_CPU 16000000
#endif

#define RAMSTART 0x0060
#define RAMSIZE (RAMEND-RAMSTART)

#define sleep()
// --------------------
// --- multitasking ---
// --------------------

#define STACK_SIZE	36
#define NUM_TASKS 2

typedef void (*TaskFunction)();

// times & cycles at 16MHz and CLK/1024:
typedef enum TaskPrio
{
	TaskPrioLowLow		= 0xff,	// 1024 cycles (64 us)
	TaskPrioLow			= 0xe0,	// 32*1024 cycles (2048 us)
	TaskPrioMedium		= 0xc0,	// 64*1024 cycles (4096 us)
	TaskPrioHigh		= 0xa0,	// 96*1024 cycles (6144 us)
	TaskPrioHighHigh	= 0x00	// 256*1024 cycles (16384 us)
} TaskPrio;

typedef enum TaskState
{
	TaskStateActive = 0,
	TaskStateWaiting = 1
} TaskState;

typedef volatile struct Task
{
	volatile unsigned char sreg;
	volatile unsigned char *sp;
	volatile TaskPrio prio;
	volatile TaskState state;
	volatile unsigned char stack[STACK_SIZE];
} Task;

// create task & add to task-list
void taskCreate(Task *t, TaskFunction f, TaskPrio prio);

// trigger a task switch
// if called from the main thread it starts the scheduler
void taskSwitch();

typedef struct TaskSignal
{
	Task *waitTask;
} TaskSignal;

// signal & wait functions
void taskSignal(TaskSignal *s);
void taskWait(TaskSignal *s);

#define PUSH(r) asm volatile("push r"#r);
#define POP(r) asm volatile("pop r"#r);

static volatile signed char currentTask = -1;
static volatile Task *tasks[NUM_TASKS];

void taskCreate(Task *t, TaskFunction f, TaskPrio prio)
{
	cli();
	signed char a;
	unsigned char *s = (unsigned char *)(t->stack + sizeof(t->stack) - 3);
	for (a=31; a>=0; a--) *s-- = 0;
	t->sreg = 0;
	t->sp = (unsigned char *)(t->stack + sizeof(t->stack) - 3);
	t->prio = prio;
	t->stack[sizeof(t->stack)-2] = ((unsigned int)f)>>8;
	t->stack[sizeof(t->stack)-1] = ((unsigned int)f)&0xff;
	for (a=0; a<NUM_TASKS; a++)
	{
		if (!tasks[a])
		{
			tasks[a] = t;
			break;
		}
	}
	sei();
}

void taskSwitch()
{
	cli();
	TCNT0 = 0xf0;
	TCCR0 = (1<<CS00);
	TIMSK |= (1<<TOIE0);
	sei();
	sleep();
}

void taskSignal(TaskSignal *s)
{
	cli();
	s->waitTask->state = TaskStateActive;
	taskSwitch();
}

void taskWait(TaskSignal *s)
{
	cli();
	Task *t = tasks[currentTask];
	t->state = TaskStateWaiting;
	s->waitTask = t;
	taskSwitch();
}

void TIMER0_OVF_vect() __attribute__ ( ( signal, naked ) );
ISR(TIMER0_OVF_vect)
{
	PUSH(31);PUSH(30);PUSH(29);PUSH(28);PUSH(27);PUSH(26);PUSH(25);PUSH(24);
	PUSH(23);PUSH(22);PUSH(21);PUSH(20);PUSH(19);PUSH(18);PUSH(17);PUSH(16);
	PUSH(15);PUSH(14);PUSH(13);PUSH(12);PUSH(11);PUSH(10);PUSH( 9);PUSH( 8);
	PUSH( 7);PUSH( 6);PUSH( 5);PUSH( 4);PUSH( 3);PUSH( 2);PUSH( 1);PUSH( 0);
	TCCR0 = (1<<CS02) | (1<<CS00);
	Task *current = 0;
	if (currentTask >= 0)
	{
		current = tasks[currentTask];
		current->sreg = SREG;
		current->sp = (unsigned char *)(SP + 32);
	}
	do
	{
		currentTask++;
		if (currentTask >= NUM_TASKS)
			currentTask = 0;
		current = tasks[currentTask];
	}
	while (!(current && current->state==TaskStateActive));
	if (current)
	{
		TCNT0 = current->prio;
		SREG = current->sreg;
		SP = (unsigned int)(current->sp - 32);
	}
	POP( 0);POP( 1);POP( 2);POP( 3);POP( 4);POP( 5);POP( 6);POP( 7);
	POP( 8);POP( 9);POP(10);POP(11);POP(12);POP(13);POP(14);POP(15);
	POP(16);POP(17);POP(18);POP(19);POP(20);POP(21);POP(22);POP(23);
	POP(24);POP(25);POP(26);POP(27);POP(28);POP(29);POP(30);POP(31);
	asm volatile("reti");
}


// -------------------------
// --- application tasks ---
// -------------------------

Task task1;
void taskFunction1()
{
	for (;;)
	{
		// ... ;
	}
}

Task task2;
void taskFunction2()
{
	for (;;)
	{
		// ... ;
	}
}


// --------------
// --- main() ---
// --------------

int main()
{
	taskCreate(&task1, taskFunction1, TaskPrioLow);
	taskCreate(&task2, taskFunction2, TaskPrioLow);
	sei(); // enable interrupts
	taskSwitch();
	return 0;
}

Problém 1) v mainu je dvakrát po sobě volaná fce taskCreate(…) a i když má vždy jiné parametry - v překladu je kód jen pro jedno volání.

Problém 2) fce taskFunction1() a taskFunction1() nejsou volány nikde v programu přímo ale v přerušení se nastavuje PC na adresu, kde funkce začíná a překladač je považuje taktéž za zbytečné.

Abych ale zachoval možnost optimalizovat aspoň mnou napsaný kód bylo by dobré vypínat optimalizaci jen někde - třeba Codevision má na to direktivy #pragma opt- a #pragma opt+ - umí něco takového i GCC ? - s výše uvedenými jsem v GCC neuspěl

Mohl bys, prosím, editovat svůj příspěvek a napsat před kód (code)
a za kód (/code), ale s hranatými závorkami místo kulatých.
Předělávat všechny ty kolečka je dost pracné.

Ale zkusil jsem přeložit s optimalizací Os a nevidím chybu.
Přikládám část souboru .lss.

Ani v přerušení nevidím, že by překladač něco vynechal.
LSS.gif

tak jsem to upravil - a já jsem si furt říkal, jak se to asi dělá?

ale zpět k problému: zkusil jsem tedy optimalizace znovu zapnout a kupodivu volání funkcí už je v pořádku ale funkce taskFunction1(),taskFunction2() se stejně nevytvoří. No nic - asi překladač ošálím nějakým podmíněným voláním s nesplnitelnou podmínkou.
asm.jpg

Ale vytvoří, jenomže v nich není nic než nekonečná smyčka, takže ten kód označený vykřičníkama je správný.

To mně taky napadlo a proto ještě než jsem to hodil sem tak jsem zkusil funkce naplnit jednoduchými příkazy.

[code]int c;
Task task1;
void taskFunction1()
{

static char a;
for (;:wink:
{
a++;
c+=a;
}
}

Task task2;
void taskFunction2()
{
static char b;
for (;:wink:
{
b++;
c+=b;
}
}[/code]

a ukázka z překladu z předchozího příspěvku je právě z tohoto

pak jsem tedy main upravil takto[code]int main()
{
char xx=0;
taskCreate(&task1, taskFunction1, TaskPrioLow);
taskCreate(&task2, taskFunction2, TaskPrioLow);

if(xx)
	{
    taskFunction1();
     taskFunction2();
     }	

sei(); // enable interrupts
taskSwitch();
return 0;
}[/code]
a je to v pořádku

edit: tak néééé - je to ještě horší - nevšiml jsem si že mám vypnutou optimalizaci

Ty funkce není v main třeba volat ne? O jejich provoz by se měl starat ten balast kolem.

Vůbec bych se nedivil, kdyby ti překladač takto naplněné funkce vyhodil. Nedělají totiž vůbec nic užitečného a ani jsi mu nijak nenaznačil, že to tam za každou cenu chceš… (volatile aspoň před jednou proměnnou)

Jako testovací kód použij nějakou operaci s portem.
Tu překladač určitě nevyhodí.

Všimni si kódu, který jsi použil pro testování:

static char a; for (;;) { a++; c+=a;
Hodnota proměnné “c” není nikde v kódu dál využitá, je zbytečná.
Proto optimalizátor odstraní řádek “c+=a”.

Hodnota proměnné “a” není použitá k ničemu jinému
než k přičtení ke zbytečné proměnné “c”.
Proto optimalizátor odstraní i řádek “a++”.

Tato vlastnost optimalizátoru nás může znervózňovat při testování,
ale ve skutečnosti je užitečná, protože odstraní zbytečné části kódu.

Pokud pro testování zavedeme nějakou proměnnou, deklarujeme ji jako volatile.
Pokud je totiž nějaká proměnná označena slovem volatile, nebude kompilátor žádným způsobem optimalizovat její užití.

Nebo, jak jsem psal výše, použijeme porty.
Ty jsou už definovány jako “volatile”.

Upozornil bych ještě na jeden z mála případů, kdy naopak chceme
aby se neužitečný kód vykonal.
Je to klasická prázdná smyčka pro časové zpoždění.

Aby fungovala, napíšeme ji takto:

for(volatile int i=0;i<1000;i++) ;

Pravda, pravda - ovšem podle této logiky nedělá nic užitečného celý program - pouze přepíná dvě neužitečné funkce - pak by ale překladač neměl přeložit vůbec nic a ještě mi vynadat :slight_smile: :slight_smile: :slight_smile: .

Omyl :wink:. Jednak je toho mnoho prováděno na HW úrovni(a už to samo nemůže vyhodit) a dále je tam spousta zpracovávaných proměnných jako “volatile”.
Naproti tomu ve tvém kódu nebyl ani náznak ničeho, co nesmí být vyhozeno nebo co koná užitečnou činnost.

Já bych to shrnul asi takto:

V původním dotazu byla stížnost, že optimalizátor vynechává části kódu.

Ukázali jsme, že nevynechává nic.

Tady mohla diskuze skončit.

Zbytek je o tom, že když se do programu přidávají nějaké testovací proměnné, tak by měly být deklarovány jako volatile.

Je to příliš složité?