Sto cercando di usare il timer1(arduino uno, in modalità CTC) ma viene settato a 8bit invece che 16, ovvero tutti i registri sembrano lavorare solo a 8bit anche se li assegno direttamente in H e L la parte alta non lavora.
io lo setto cosi:
TIMSK1 |= (1 << OCIE1A);
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << WGM12) | (1 << CS11 );
TCNT1 = 0;
OCR1A = 3000;
ora se vado a rileggere OCR1A vale 184.....?????
pure TCNT1 va solo da 0 a 255 e quindi a 8bit, come mai? cosa devo settare?
Leggilo così:
ocr1aReg = OCR1A;
Oppure prova prima a leggere il byte low e poi high, se funziona solo così hai un problema con il compilatore.
Ciao.
ho gia letto/settato OCR1AH e L ma non funzia! p......
Neanche usano una variabile di supporto!
Dirò una cretinata. Prima di lavorare su quei registri, hai messo la cli(); ?
@nid! si, ho anche provato a disabilitare in manuale gli interrupt ma niente......
Mi postate un codice funzionante che lo testo....
Mi sarà scappato un flag che non riesco a trovare.........xD!
Credo che ti stia sfuggendo questo, da pag. 117 del datasheet:
The 16-bit counter is mapped into two 8-bit I/O memory locations: Counter High (TCNT1H) containing the upper
eight bits of the counter, and Counter Low (TCNT1L) containing the lower eight bits. The TCNT1H Register can
only be indirectly accessed by the CPU. When the CPU does an access to the TCNT1H I/O location, the CPU
accesses the high byte temporary register (TEMP). The temporary register is updated with the TCNT1H value
when the TCNT1L is read, and TCNT1H is updated with the temporary register value when TCNT1L is written.
This allows the CPU to read or write the entire 16-bit counter value within one clock cycle via the 8-bit data bus.
Se non ti risulta molto chiaro... Beh, non sei l'unico
.
mmmm.....e quale è la procedura per leggere TCNT1?
In effetti l'interrupt sembra venire chiamato esattamente quando voglio!
Solo che al suo interno vorrei aspettare che TCNT1 diventi 1500 prima di eseguire la seconda operazione.....ma se leggo solo il LOW Word non è possibile! mannaggia.....idee?
Pare basti questo:
unsigned int i;
/* Read TCNT1 into i */
i = TCNT1;
Evidentemente però il tipo deve essere esattamente unsigned int (AKA uint16_t AKA word).
Ma, noto ora, meglio ancora fare (pag. 115):
unsigned int TIM16_ReadTCNT1( void ) {
unsigned char sreg;
unsigned int i;
/* Save global interrupt flag */
sreg = SREG;
/* Disable interrupts */
_CLI();
/* Read TCNT1 into i */
i = TCNT1;
/* Restore global interrupt flag */
SREG = sreg;
return i;
}
Prova a mettere uno più nop dopo la lettura.
Se vedi il mio post sulla gestione 4 tasti, nella funzione update_display(), che questa istruzione _asm_nop();, se la tolgo non funziona più.
http://forum.arduino.cc/index.php?topic=344708.0
La procedura di lettura è corretta. Il registro TCNT1 è doble buffered, la mcu legge il contatatore del timer interno e lo trasferisce su TCNT1. Il compilatore dovrebbe gestire la lettura dei 16 bit in un solo ciclo CPU, senza la necessità di leggere primo il low byte.
PS: per adesso ho sotto mano un 644 posso fare la prova solo su questo.
Ciao.
ho provato con uint16_t e ho provato anche a leggere direttamente TCNT1H e TCNT1L solo che la parte alta non la legge in nessun modo, neanche disabilitando gli interrupt.
L'unica cosa che non ho provato è mettere un paio di NOP, bho, dopo vado a leggere bene il datasheet cosa dice, mannaggia!
L'ho scoperto perché questo codice nella isr mi bloccava tutto:
while ( TCNT1 < _SVP ) NOP;
O meglio funzionava fino a che non ho impostato _SVP ad un valore superiore a 255, per arrivarci mi ha fumato la testa!
Vado ad indagare....
Aspetta leggi nella ISR?
Non facciamo che il compilatore carica il valore in un registro interno?
Prova con volatile uint16_t i;
si leggo nella isr, avevo già provato....e non funge....ho provato anche a leggerlo al di fuori della isr ma non funge lo stesso, ne TCNT1 ne OCR1A, entrambi mi danno un valore a 8 bit invece che 16.....
domani provo con la funzione che è scritta sul datasheet, ma mi sembra assurdo, bho!
Domani posto un firmware con la speranza che qualcuno lo possa provare.
Adesso faccio qualche test anch'io!
Mi sembra di aver capito che Arduino setti il timer a 8 bit ma non sono riuscito a capire come ripristinarlo, vado a vedere su github cosa combina arduino
eccolo
// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
sbi(TCCR1A, WGM10);
in wiring.c
Però io setto TCCR1A = 0 e quindi dovrebbe tornare a posto, forse mi conviene controllare che effettivamente venga azzerato quel registro.
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << WGM12) | (1 << CS11 );
TCNT1 = 0;
OCR1A = 3000;
//TIMSK1 |= (1 << OCIE1A);
#if defined(TCCR1A) && defined(WGM10)
TCCR1A |= _BV(WGM10);
#endif
Anche a me ritorna valori da non più di 8 bit, mentre sensa la #if defined.. ecc, stampa correttamente 3000.
Non ho potuto abilitare l'interrupt TIMSK1, a causa del programma che ha ospitato il test.
PS: no Arduino IDE, no Arduino lib, no avr-g++, ATmega644A
Ciao.
Ecco, se i bit WGM12 e WGM10 sono settati insieme, il timer va in Fast PWM 8-bit mode!
@Maurotec non avevo dubbi che senza le librerie Arduino andasse........
Devo capire perché non ritorna in modalità 16bit, prova a mettere la #ifdef prima di settare il timer e vedere se una volta impostato con quel codice ritorna a 16bit.
Il problema è che Arduino lo setta a 8 bit ma poi io non riesco a riabilitare i 16bit....almeno adesso so il perché e sicuramente domani dovrei farcela....
Già fatto, prima sempre nel main lavora a 16, dopo ad 8.
Ma cbi e sbi in quale header si trovano, l'ho cercate ma non ci stanno nella avr-libc, ahhhh, si sono nel core di Arduino è deprecate in avr-libc, come non detto.
Dove si trovano quelle istruzioni?
@MauroTec intendevo il contrario, prima a 8bit e poi il passaggio a 16bit....
#define sbi(port, bit) (port) |= (1 << (bit))
#define cbi(port, bit) (port) &= ~(1 << (bit))