Vadná série ATmega16-16PU z GMe?

Mám stupidní program. Nastavený časovač, pomocí jehož přerušení neguju stav LED (blikám s ní). Negace stavu LED je podmíněná podmínkou, dejme tomu “stav==163”.
Pak mám dvě procedurky, jedna udělá stav=163 (zapne blikání) a druhá udělá stav=79 (vypne blikání). To dementní AVR studio to není schopné přeložit bez chyby.
Zde máte zdrojový kód kompletní. Zatím ten program nedělá nic jiného, než že při příchodu “z” po UARTu zařízení zapne, případně “v” vypne. Přičemž stav indikuje LED, která bliká, nebo svítí trvale, v případě zapnutí. Ten kód je prostě nefunkční.


// pouzite hlavickove soubory, makra

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

#define F_CPU 11059200U  //frekvence Xtalu procesoru 11,0592MHz
#include <util/delay.h>

//definice BaudRate pro UART

#define UBRRH_2400   1 
#define UBRRL_2400   31 


char tcr_div1; //sw delicka citace tccr2
char stav; //stav zarizeni: 0:"vypnute", 1:"zapnute"


void Init_Portu(void) //inicializace portu
{
  PORTA = 0b00000000; //vstupy ADC
  DDRA  = 0b00000000;
  PORTB = 0b00000001; //PB0 - zapinani napajeni cidel log. 0
  DDRB  = 0b00000001;
  PORTC = 0b00001111; //PC3:0 - jumpery, PC6:5 stavova LED
  DDRC  = 0b01100000;
  PORTD = 0b00000000;  //UART vystupy PD1:0
  DDRD  = 0b00000011;
}


void Init_Periferii(void)  //Inicializuje periferie 
{
 
  //Init RS232
  //Rx & Tx enable, 8 bit, parity none
  UCSRA = 0;
  UCSRB = (1<<RXEN)|(1<<TXEN);
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
  UBRRH = UBRRH_2400;
  UBRRL = UBRRL_2400;
  //Init ADC
  //ADC enable, external reference, :128
  ADMUX = 0;
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
  //TCCR2
  //CTC mode, :1024, CTC on 107, CTC INT enable
  TCCR2 = (1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);
  OCR2 = 107;
  TIMSK = (1<<OCIE2);
  tcr_div1 = 0;
}


// parametr channel urcuje vstup ADC (0-7)
//vraci navzorkovanou hodnotu (0-1023)
int ADC_Convert(char channel)  
{
  ADMUX = (ADMUX & 0xF0)|(channel & 0x0F);
  ADCSRA |= (1<<ADSC);
  while (ADCSRA & (1<<ADSC));
  return ADC;
}



void Ser_SendByte(char b)  //odesle byte UARTem
{
  while (!(UCSRA & (1<<UDRE))); //pockame na prazdny UDR buffer
  UDR = b;
  while (!(UCSRA & (1<<TXC))); //pockame na odeslani
  UCSRA |= (1<<TXC); //vynulujeme TXC flag
}

char Ser_ReceiveByte(void) //precte data z UARTu
{
  return UDR;
}

char Ser_WaitingData(void) //vrati 1 pokud cekaji data k precteni 
{                          //z UARTu, jinak 0
  if (UCSRA & (1<<RXC)) 
  {
    return 1;
  } else {
    return 0;
  }
}


void LED_Green_On(void)     //rozsviti zelenou LED
{
  PORTC |= 0b00100000;
}

void LED_Green_Off(void)  //zhasne zelenou LED
{
  PORTC &=~0b00100000;
}

void LED_Yellow_On(void)  //rozsviti zlutou LED
{
  PORTC |= 0b01000000;
}

void LED_Yellow_Off(void) //zhasne zlutou LED
{
  PORTC &=~0b01000000;
}

void Device_On(void)
{
  stav = 67;
  LED_Green_On(); //v zapnutem stavu LED musi svitit trvale
  PORTB &=~0x01; //zapne napajeni cidlum
}

void Device_Off(void)
{
  stav = 163;
  LED_Green_Off(); 
  PORTB |= 0x01;  //vypne napajeni cidel
}
// ******************************** ISR ******************************


ISR(TIMER2_COMP_vect)
{
  tcr_div1++;

  if (tcr_div1 == 100)
  {
    tcr_div1 = 0;

	if (stav == 163) LED_Green_On(); //Tady fakt už nevim co s tim
  }


  if ((tcr_div1 == 5)&&(stav == 163))  //nemluvě o tomhle. Prostě to bliká furt, ať je tam číslo jaké chce.
  {
    LED_Green_Off();
  }
}


// ******************************** MAIN *****************************

char rxd;


int main (void)
{

  Init_Portu(); 
  Init_Periferii();
  sei();

  Device_On();


  while (1)
  {
    
    while (!Ser_WaitingData());
	rxd =  Ser_ReceiveByte();

	switch (rxd)
	{
      case 'z': 
	  {
        Device_On();
		break;
	  }

	  case 'v':
	  {
	    Device_Off();
		break;
      }

	}

  

  
  }
     
  while (1) ;
}

Poslední dobou mám sto chutí vrátit se k assembleru. I když tam to neni omoc lepší, protože už jednou se mi stalo, že prostě konkrétní instrukce za sebou je překladač přeložil chybně. Musel jsem mezi to dát NOP aby to začlo fungovat. DAl jsem si tu práci, a ten blok instrukcí našel:

[code]ldi R16, 0b00001110 ;nastavime timer2: Tosc/256, CTC mode - tedy 15625Hz
out TCCR2, R16
ldi R16, 125 ;porovnavame s hodnotou 125 => preruseni vznika 125/s
out OCR2, R16
ldi R16, 0b10000000 ;povolime preruseni od compare match timer 2
out TIMSK, R16

				sei		;CHYBNE??
				nop

				clr R16
				sts TL_Start, R16
				sts TL_Stop, R16
				sts TL_Plus, R16
				sts TL_Minus, R16
				sts TL_Set, R16

[/code]

Bez toho NOP (ale nepamatuju si to jistě) jsem tu instrkci SEI nenašel snad vůbec v té přeložené binárce.
Přejít zpět na ASM podporuje mě i ještě to, že v C se nedá pořádně pracovat se stringy, musíte si zakydat SRAM, jinak to prostě nejde.
Hledáním jedné chyby v C jsem dnes strávil víc než 3 hodiny. V ASM bych buď tu chybu vůbec neudělal, a nebo jí našel za pár minut. Cčko bohužel příliš pro mě není. Nemám se kde ho naučit, a nikdo v něm pořádně neumí, aby mi poradil (teda nikdo koho znám)

V 99,9% případů je chyba mezi klávesnicí a židlí :wink:
Je to jako téměř vždy neznalost C. Kód jsem nečetl celý, ale máš tam globální proměné, ke kterým přistupuješ i v přerušení. To musíš překladači říct, jinak k nim optimalizuje přístup za účelem zrychlení a místo operace v každém průchodu smyčkou ji provede jen 1x nazačátku.
Před deklarace globálních prom. využívaných v přerušení dávej “volatile”.
Co se týká textu v SRAM, to je také snadno řešitelné. Stačí se podívat do manuálu gcc(avr-libc-user-manual.pdf) a hledat “PROGMEM”.

No jo, opravdu jsem debil. Na to volatile jsem úúúplně zapomněl. Přitom jsem to slovíčko již používal. Přidal jsem to tam, a už to najednou začlo pracovat.
Na ty stringy jsem se tu ptal, jen jsem trochu to jaksi nepochopil. Jestli to je v manuálu ke GCC, tak se tam podívám, tam jsem to nehledal. Nevěděl jsem, že to tam bude.Každopádně, to co jsem zde o těch string pochopil je to, že stejnak ho muím zkopírovat do SRAM. Ale mě zajímalo, zda když chci kopírovat text z FLASH do LCD, jeslti je možné ho kopírovat přes SRAM pouze po jednom byte (tak jsme to dělal v ASM). Je šetří to paměť, i čas procesoru, než to kopírovat celé, a znova kopírovat do LCD.
Tu chybu okolo SEI myslím že klávesnicí a židlí vysvětlit nelze. To by chtělo hlubší prozkoumání.
Jinak díky za nakopnutí s tím volatile :wink:

Do SRAM ani nemusíš. Překladač totiž použije instrukci LPM, jejímž cílem je registr. Pokud to tedy např. budeš cpát rovnou na port, o SRAM text ani nemusí zavadit.
V manuálu to určo najdeš, je tam i uložení pole pro čtení do SRAM, což je vpodstatě to samé.
S tím sei netuším. Problém to sice neřeší, ale chodilo by to kdyby bylo CLR před SEI?

LPM umět musí, jinak by to nemoh ani celé kopírovat do SRAM. Tohle zatím nechávám nedořešené, nejdřív si přečtu help, pak se kdyžtak zeptám na detajly.
S tím CLR a SEI už an to kašlu. To bylo asi před 10ti měsíci, kdy jsme to psal. Ani už si nepamatuju, v čem přesně byl problém. Nyní si jen pamatuju že něco bez toho NOP nefungovalo.

Každopádně, nyní mám velmi akutní jiný problém.
Ten program, co jsem nyní poslal, je pro ATmegu16. V AVR studiu mám v project/options nastavenou atmegu16, v ponyprogu to taky správně programuju správně, fuse by měly být ok. Po večeři aktualizuju ten program, co je zde v prvním příspěvku vlákna. Můžete se prosím podívat, proč ten program nechodí na ATmega16-16PU? Když ho nahraju do záložní ATmega32-16PU (změním v project options na megu32 a v ponyprogu patřičně taky - chodí to, no problém)
Jde o to, že ATmega16-16PU se tváří, jako když má spálený port C, nebo prostě vadná. LEDka kterou mám na PC6 (5) svítí trvale, přes pull-up. Přestože ten je vypnutý, a na výstupu má být log0. Na log1 to neregauje vůbec. Furt jen ten pullup. Některé další piny se chovají stejně.
Ta ATmega16-16pu byla koupená před 13ti dny. Táty jí byl dnes reklamovat, udělal v gme pořádný humbuk, naštěstí mu jí vyměnili. Tak jsme tam pích tu novou. Stejný problém.
Mám poddezření na zmetkovou sérii. Co mi doporučujete? Obrátit se na gme s žádostí o vysvětlení?
Ještě jí zkusím hodit do nepájka, a otestovat primitivním programem, kterým jen nahodím všude log1, případně nuly, nebo zapnu pullupy, a ozkouším každý pin.
Díky moc.
PS: po večeři, tj 30minut, aktualizuju ten program, jak vypadá aktuálně.

Zkus vypnout JTAG :wink:
Nedávno jsem psal pro známýho primitivní stopky na M16 a zaboha jsem nemoh přijít na to, proč mi ukazuje nesmysly na portu C připojená segmentovka. Po vytažení JTAGu nastala drobná změna. Ve fuses jsem tedy JTAG vypnul, předrátoval to na ISP a hle - všechno maká :slight_smile:.

Vypnout JTAG? Jako zakázat ho ve fuses? Já programuju odjakživa STK200, takže tudy cesta si myslím nevede, ale podívám se na to. Že by jako default byl JTAG zaplý od výroby? (přitom ATmega32 tento problém nemá…)
Zkontroluju to, díky za dobrý nápad. Já ani nevím, jak JTAG funguje, natož kam se to připojuje 8)

všechny megy co mají jtag, ho mají z výrobny zapnutý ! Čili nelze je použít jako I/O piny

…tak jak mi potom vysvětlíš, že megu32, kterou jsem kdysi koupil jsem prostě naprogramoval, a napoprvé šla? Ve fuse jsem nikdy neupravoval nic kromě oscilátoru (CKSEL, CKOPT, SUT). Zajímavý. Tak aspoň že nyní vím, oč jde.
piityy - díky za vysvětlení, vypnutí JTAGu ve FUSE pomohlo.