Newsgroup: it.hobby.elettronica.digitale
Titolo: Curiosità su ATMEGA32 e capture

Ciao, sto facendo un contagiri con ATMEGA32 AVR + compilatore GCC.
 
Utilizzo il capture per leggere il regime di rotazione fornito da un 
sensore HALL in un range da circa 20 a 6000 Hz. Il processore, 
clockato 8 MHz con oscillatore interno, oltre all'interrupt CAPTURE si 
trova a dover gestire un timer CTC che viene richiamato ogni 5 mS.
Il TMR1 è incrementato tramite prescaler / 8, quindi ad 1 MHz.
Utilizzando questa parte di codice per copiare in una mia variabile il 
registro TMR1 catturato, oltre i 4 KHz *precisi*, ottenevo nella 
variabilie 'cattura' (unsigned int) valori assolutamente incoerenti ed 
apparentemente casuali
 
 
//__interrupt void int_capture(void)
ISR(TIMER1_CAPT_vect){
temp_h=ICR1H;
temp_l=ICR1L;
cattura = temp_l +(temp_h<<8);
 
 
Così invece funziona perfettamente fino ad oltre 6 KHz
 
//__interrupt void int_capture(void)
ISR(TIMER1_CAPT_vect){
cattura=ICR1;
 
Qualcuno mi saprebbe spiegare il motivo, tanto per capire ?
Grazie.
 
 
Ciao,
Pier.
 
www.piergm.com
 

 Grazie.
 
Perché devi leggere prima ICR1L di ICR1H.
La lettura di ICR1L triggera/latcha il contenuto di ICR1H in un registro temporaneo accessibile con comodo.
Quindi:
 
//__interrupt void int_capture(void)
ISR(TIMER1_CAPT_vect){
temp_h=ICR1L;
temp_l=ICR1H;
cattura = temp_l +(temp_h<<8);
 
dovrebbe funzionare regolarmente.
 
Piccio.

 temp_h=ICR1H;
...
 
O direttamente così:
 
cattura = ICR1L;
cattura += ICR1H<<8;
 
Non ricordo se il registro temporaneo che si affaccia su ICR1H è condiviso con altri registri MSB dello stesso contatore: nel dubbio, meglio inibire le interruzioni durante la lettura dei 16 bit in modo da rendere atomica l'esecuzione.
 
Piccio.
 


Ciao,
Pier.
 
www.piergm.com
 
 


 
Ciao,
Pier.
 
www.piergm.com
 

 Non ricordo se il registro temporaneo che si affaccia su ICR1H è condiviso
 > con altri registri MSB dello stesso contatore: nel dubbio,
 > meglio inibire le interruzioni durante la lettura dei 16 bit
 > in modo da rendere atomica l'esecuzione.
 
In effetti è così, come dice il datasheet:
 
It is important to notice that accessing 16-bit registers are atomic 
operations. If an interrupt occurs between the two
instructions accessing the 16-bit register, and the interrupt code 
updates the temporary register by accessing the
same or any other of the 16-bit Timer Registers, then the result of the 
access outside the interrupt will be corrupted.
Therefore, when both the main code and the interrupt code update the 
temporary register, the main code must dis-
able the interrupts during the 16-bit access.
 
Però non sarei così leggero a disattivare le interruzioni, solo perché 
ho un dubbio su quello che può succedere. Disattivare le interruzioni 
non è praticamente mai una Cosa Giusta.
 
Il problema esiste se un registro a 16-bit viene letto/scritto sia in 
background (fuori interrupt) sia in foreground (in interrupt). Io non 
penso che sia così facile trovarsi in questa situazione.
 
Se stai usando il capture, probabilmente andrai solo a leggere ICR1 in 
interrupt, ma fuori interrupt difficilmente lo andrai a toccare.


 
Ciao,
Pier.
www.piergm.com
 
 
 
 
 


Potresti provare anche a azzerare i bit Msb di ICR1L
(MSB |= (LSB & 0x00ff);
Nel cast qualche compilatore non azzera i bit e quindi somma valori 
sbagliati a causa di un valore casuale nel byte Msb della variabile 
castata a int.
ciao
Angelo
 

 
Esatto, il registro viene letto solo in ISR capture per cui la
 cosa mi pare sospetta. Ho riscontrato un'altro problema collegato
 alla frequenza di ingresso del capture TMR1 ma che riguarda la
 int routine del TMR0 CTC timer : sopra una frequenza da
 verificare, ma che temo siano i soliti 4 kHz, non leggo
 correttamente degli ingressi digitali che son comuni ai segmenti
 di un display. In pratica, in tmr0 ISR, ogni 5 mS aggiorno
 ciclicamente tre led 7 segmenti e, sempre nella stessa routine,
 ogni 100 mS inverto la direzione di alcuni bit per leggere lo
 stato dei pulsanti che condividono le linee dei segmenti.
 
 
-- 
Ciao,
Pier.
 
www.piergm.com
 
 
 
----Android NewsGroup Reader----
http://usenet.sinaapp.com/
 

   stato dei pulsanti che condividono le linee dei segmenti.
 
Lavorare con gli interrupt è sempre molto delicato. Se posti un po' di 
codice, si riesce a fare qualche valutazione meglio.
 
 

 
 
Spero di non aver fatto casino con copia incolla...
 
 
ISR(TIMER0_COMP_vect){
 
 
TCNT0=101; //5 mS @ 8 MHz
 
/***************************************
ARRIVO QUI OGNI 5 mS
****************************************/
 
count2_temp++; //contatore per 50 mS
 
 
 
//gestione pulsanti
 
 
if(count2_temp==20){ //ogni 100 mS
count2_temp=0;
DDRB=0;//drivers segmenti come ingressi
 
PORTC &=~60; //spengo driver cifre
PORTB=255; //attivo pullup su tutti
 
 
unsigned char maskpuls;
 
maskpuls=~PINB&15; //maschera pulsanti
 
  if(maskpuls){ //se almeno 1 pulsante premuto
 
 
					count_antirimb++;
					if(count_antirimb>10)count_antirimb=10;
 
	if(maskpuls==4){ //up_press
 
										if(count_antirimb==BUTTON_RETARD || co
unt_antirimb==10)up_press=1; 
 
										} //end up press
if(maskpuls==8){ //down_press
 
 
																		if(count_antirimb==BUTTON_RETARD ||
 count_antirimb==10)down_press=1; //dopo 300 mS, o ripetizione
 dopo 1.9 sec
 
 
																	} //end down_press
 
 
					if(maskpuls==12){ //up and down
												if(count_antirimb==6)up_down_long_press=1; 
 
 
											} 
 
			   }else { //end almeno 1 pulsante premuto
 
							count_antirimb=0; //nessun pulsante premuto, azzero antirimbalzo
 
 
							} //end else almeno 1 pulsante premuto
 
 
DDRB=255;//drivers segmenti come uscite
 
} //end ogni 100 mS
 
//SCANSIONE CIFRE
 
scan++;
if (scan==4)scan=0;
 
unsigned char temp1;
//qui ogni 5 mS
 
//gestisco multiplexing display
 
switch(scan){
  case 0:
  PORTC &=~60;
  temp1=pgm_read_byte(&(led_map[cifra1]));
  PORTB=temp1;
  if(dot_decimal)PORTB &=~ 4; //accendo punto decimale...
  PORTC |= 32;
 
   break;
 
  case 1:
 
  PORTC &=~60;
 
  temp1=pgm_read_byte(&(led_map[cifra2]));
  PORTB=temp1;
  PORTC |=16;
 
   break;
 
  case 2:
 
  PORTC &=~60;
  temp1=pgm_read_byte(&(led_map[cifra3]));
  PORTB=temp1;
 //PORTB=0;
  //if(dot_2cifra)PORTB &=~ 4; //accendo punto decimale...
  PORTC |= 8;
 
   break;
 
  case 3:
 
  PORTC &=~60;
 
  temp1=pgm_read_byte(&(led_map[cifra4]));
  PORTB=temp1;
 
  if(cifra4==0)PORTB=pgm_read_byte(&(led_map[10])); //spengo
 
  if (dot_up)PORTB &=~ 2;
  if (dot_down)PORTB &=~ 128;
  if (dot_right)PORTB &=~ 16;
  PORTC |= 4;
 
 
 break;
} //end switch scan
 
asm("nop");
 
 
 
} //end interrupt TMR0 routine
 
//__interrupt void int_capture(void)
ISR(TIMER1_CAPT_vect){
//temp_h=ICR1H;
//temp_l=ICR1L;
//cattura = temp_l +(temp_h<<8);
 
cattura=ICR1;
 
//cattura = ICR1L;
//cattura += ICR1H<<8;
 
capt_count=N_CICLI_ZERORPM;
//over_tim=0;
 
 
if(TIFR&4){
 
offset=(65535-cattura_old)+cattura;
TIFR |=4;
}
else{
 
 
offset=cattura-cattura_old;
}
 
cattura_old=cattura;
 
 
conta_c++;
offset_accumulo=offset_accumulo + offset;
 
 
} //end capture interrupt routint


manca questo, in timer interrupt...ho fatto un po di casino sorry 
 
if(capt_count){capt_count--;}else{giri=0;
 
low_freq_flag=1;} //non arrivano impulsi sui giri !!


RISOLTO, il problema risiedeva nella parte di codice relativa al 
cambio di direzione della porta condivisa da segmenti ed ingressi e 
successiva lettura dello stato : cambiavo direzione, attivavo i pullup 
ed all'istruzione dopo leggevo per cui, suppongo anche per le capacità 
parassite, in determinate condizioni di visualizzazione (freq. alta = 
ultime cifre accese) lo stato degli inputs veniva letto in maniera errata.
 
**********************
Parte di codice errata
**********************
 
DDRB=0;//drivers segmenti come ingressi
PORTC &=~60; //spengo driver cifre
PORTB=255; //attivo pullup su tutti
unsigned char maskpuls;
 
maskpuls=~PINB&15; //maschera pulsanti
 
 
***************************
Parte di codice funzionante
***************************
 
DDRB=0;//drivers segmenti come ingressi
PORTB=255; //attivo pullup su tutti
PORTC &=~60; //spengo driver cifre
asm("nop");
unsigned char maskpuls;
 
maskpuls=~PINB&15; //maschera pulsanti
 
 
Grazie e ciao,
Pier.
 
www.piergm.com