@jo_berry come suggerito in questa discussione mi sono spostato nella sezione italiana ...
Sto cercando di capire come funzionano i timer GPT su Arduino Uno R4 Minima, l'User’s Manual del RA4M1 spiega in dettaglio come utilizzare i vari registri ma per scrivere un po di codice sto imparando ad utilizzare direttamente l'FSP implementato nel core dell'IDE 2.3.2. Come esempio ho preso la libreria R4SwRTC che non fa altro che avviare un timer GPT (il primo dei 6 che trova libero) a 100Hz (0.01secondi) e incrementare 100 volte il contatore timerCount ... 0.01 x 100 = 1 secondo! Percio' dopo 1 secondo il contatore timerCount si azzera e riparte. Per ovviare alla mancanza del quarzo esterno il contatore non si eguaglia perfettamente a 100 ... ma a un numero decimale vicino a 100 ... questo permette, collegando un oscilloscopio sul pin D7, di avere il contatore dei secondi molto preciso.
#include "FspTimer.h"
#define TMR_FREQ_HZ 100.05 /* If timer goes forward, decrease the frequency, if it lags, increase the frequency */
#define CNT_CMPR 100 /* 100 GPT timer cycles == 1 second (GPT timer is set to 0.01 seconds ... becouse 100Hz means 0.01sec)*/
#define pinD7 ((volatile unsigned char *) 0x4004085F) // ARDUINO UNO MINIMA D7 Register address (To check frequency with an oscilloscope on D7 pin)
#define pinD13 ((volatile unsigned char *) 0x4004086F) // ARDUINO UNO MINIMA D13 Register address
#define ON 0x05
#define OFF 0x04
static volatile uint64_t timerCount = 0;
//static volatile time_t unixTime = 0; // If you wont use GTP timer to run RTC clock (see R4SwRTC arduino library)
static volatile bool pinState = false;
static FspTimer servo_timer;
void setup() {
Serial.begin(9600);
delay(2000);
Serial.println("GPT test program");
pinMode(7, OUTPUT);
uint8_t timer_type = 0;
int8_t channel = FspTimer::get_available_timer(timer_type);
Serial.print("\nTimer_config: timer_type:");
Serial.print(timer_type, DEC);
Serial.print(" Channel: ");
Serial.println(channel, DEC);
// lets initially configure the GPT timer
if (!servo_timer.begin(TIMER_MODE_PERIODIC, timer_type, channel,
TMR_FREQ_HZ, 0.0f, timer_callback, nullptr)) {
Serial.println("Timer failed to start");
}
// First pass assume GPT timer
servo_timer.setup_overflow_irq();
servo_timer.open();
servo_timer.start();
Serial.print("Raw Period: ");
Serial.println(servo_timer.get_period_raw(), DEC);
}
void loop() {
}
void timer_callback(timer_callback_args_t *args) {
(void)args; // remove warning
timerCount++;
if ( timerCount >= CNT_CMPR ) {
//unixTime++; // Use this counter if use clock with GTP timer (like R4SwRTC library)
timerCount = 0;
}
pinState? *pinD7 = OFF : *pinD7 = ON; // Change D7 pin state ... 0x04 set output LOW, 0x05 HIGH (to use oscilloscope on pin D7)
pinState = !pinState;
Bene fin qui ci sono, tutto funziona ... volevo adesso provare ad utilizzare il timer GPT utilizzando direttamente i registri, senza usare l' FSP, per questo volevo vedere la tua soluzione nella sezione in inglese ...
Ti segnalo che, nella sezione in lingua Inglese, si può scrivere solo in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato.
Eccomi. Premetto che sono un novizio sia nei confronti di Arduino che del C. Tuttavia ho fatto un po' di esperienza sui registri dei vari timer, sugli event-link e sulla gestione degli interrupt. Non ho usato librerie. Non so esattamente quali risultati vuoi raggiungere, ad ogni modo ti posto qualche pezzetto dello sketch a cui sto lavorando, poi mi dirai se ti può servire , e in tal caso magari riesco a darti qualche dritta in più.
//SETUP REGISTRI TIMER GENERICI
R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD2_Pos); //Pag. 177: Cancella Stop State AGT1
R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD3_Pos); //Cancella Stop State AGT0
R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD5_Pos); //Cancella Stop State GPT320 e 321
R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD6_Pos); //Cancella Stop State GPT16x
R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD14_Pos); //Come sopra, per abilitare POEG
R_MSTP->MSTPCRC &= ~(1<<R_MSTP_MSTPCRC_MSTPC14_Pos); // Enable Event Link Controller in Master Stop Register
//SETUP GPT0: generate doubled frequency
R_GPT0->GTWP = 0xA500; //Pag. 397: A500h Time register write enable
R_GPT0->GTUDDTYC = 0x00000001; //Pag. 418: Count UP
R_GPT0->GTCR = 0x00000; //Pag. 417: Clock 48 MHz, saw
R_GPT0->GTPR=9600000; //Pag. 431: Max count = 960000 = 0,2 second.
R_GPT0->GTCNT = 0; //Pag. 430: Initial value counter
R_GPT0->GTIOR = 0b100011001; //Pag. 420: GTIOC0A out, high @ cycle end, high @ stop, low @ compare match GTCCRA, Out enabled 0b100011001
R_GPT0->GTCCR[0] = 480000; //Pag. 430: Compare A = 480000 = 10 mS
R_GPT0->GTSSR = 0x10000; //Pag. 399: Start counter da ELC Compare B (GPT1_GTCCR[1]) Non so perchè vuole 10000 invece che 20000
R_GPT0->GTCSR = 0x10000; //Pag. 404: Clear counter da ELC Compare B
//SETUP GPT1: Ha il compito di misurare il periodo del RP. Il valore in conteggi è in "R_GPT1->GTCCR[0]"
R_GPT1->GTWP = 0xA500; //Pag. 397: A500h Abilita la scrittura dei registri timer
R_GPT1->GTUDDTYC = 0x00000001; //Pag. 418: Count UP
R_GPT1->GTCR = 0x00000000; //Pag. 417: Clock 48 MHz
R_GPT1->GTPR=24000000; //Pag. 431: Massimo conteggio = 48.000.000 * 0.5 = 24000000
R_GPT1->GTCNT = 0; //Pag. 430: Valore iniziale contatore
R_GPT1->GTCCR[0] = 5760000; //Compare A: Questo lo usiamo per la cattura del periodo
R_GPT1->GTCCR[1] = 768000; //Compare B: 48000000 / 3840000 = 16 mS. Impostazione ritardo. Al Compare match, ELC resetta e avvia GPT0
R_GPT1->GTICASR = 2; //Pag. 411: Cattura Compare A su falling edge di GTETRGA
R_GPT1->GTCR = 0x00000001; //Pag. 417: Timer Start. Free run, Clear by GTETRGA
R_GPT1->GTCSR = 2; //Pag. 404: Clear counter da GTETRGA su falling edge 1: l'impulso parte da rising, 2 parte da falling
R_MSTP->MSTPCRC &= ~(1<<R_MSTP_MSTPCRC_MSTPC14_Pos); // Enable Event Link Controller in Master Stop Register
R_ELC->ELSR[0].HA = 0x60; //GPT1 Compare A -> GPT0. Start e clear di GPT0 Destinazione: 0 = GPT0
R_ELC->ELCR = (1 << R_ELC_ELCR_ELCON_Pos); // enable ELC
//SETUP GPT7: Genera un clock a 100 x frequenza rotore principale (= 580 / 60 * 100 = 966,66 Hz = 1034,5 uS) per pilotare il filtro attivo della 2 x giro
//Il timer è da 16 bit. 517 uS / 65535 =
R_GPT7->GTWP = 0xA500; //Pag. 397: A500h Abilita la scrittura dei registri timer
R_GPT7->GTUDDTYC = 0x00000001; //Pag. 418: Count UP
R_GPT7->GTCR = 0x0000000; //Pag. 417: Clock 48 MHz = 0,0208333 uS x 65536 = 1.365 mS ciclo. Per 967 Hz fermare a 46400 conteggi
R_GPT7->GTPR=46400; //Pag. 431: Massimo conteggio = 46400. Viene aggiornato dal tach RP
R_GPT7->GTCNT = 0; //Pag. 430: Valore iniziale contatore
R_GPT7->GTCCR[0] = 23200; //Compare A: Duty cycle 50%. Viene aggiornato dal tach RP
R_GPT7->GTIOR = 0b100011001; //Pag. 420: GTIOCA out, high @ cycle end, high @ stop, low @ compare match GTCCRA, Out enabled 0b100011001
R_GPT7->GTCR = 0x00000001; //Pag. 417: Timer Start. Free run
//SETUP GPT5: Genera un clock a 100 x frequenza rotore coda (= 3000 / 60 * 100 = 5000 Hz = 200 uS) per pilotare il filtro attivo passa banda
//Il timer è da 16 bit. 517 uS / 65535 =
R_GPT5->GTWP = 0xA500; //Pag. 397: A500h Abilita la scrittura dei registri timer
R_GPT5->GTUDDTYC = 0x00000001; //Pag. 418: Count UP
R_GPT5->GTCR = 0x0000000; //Pag. 417: Clock 48 MHz = 0,0208333 uS x 65536 = 1.365 mS ciclo. Per 5000 Hz fermare a 9600 conteggi
R_GPT5->GTPR=9600; //Pag. 431: Massimo conteggio = 46400. Viene aggiornato dal tach RP
R_GPT5->GTCNT = 0; //Pag. 430: Valore iniziale contatore
R_GPT5->GTCCR[0] = 4800; //Compare A: Duty cycle 50%. Viene aggiornato dal tach RP
R_GPT5->GTIOR = 0b100011001; //Pag. 420: GTIOCA out, high @ cycle end, high @ stop, low @ compare match GTCCRA, Out enabled 0b100011001
R_GPT5->GTCR = 0x00000001; //Pag. 417: Timer Start. Free run
@jo_berry: Buongiorno e benvenuto nella sezione Italiana del forum,
... cortesemente, come prima cosa, leggi attentamente il REGOLAMENTOdi detta sezione, (... e, per evitare future possibili discussioni/incomprensioni, prestando molta attenzione al punto 15), dopo di che, come da suddetto regolamento (punto 16.7), fai la tua presentazioneNELL'APPOSITA DISCUSSIONE (... quello che vedi in blu è un link, fai click su di esso per raggiungere la discussione) spiegando bene quali esperienze hai in elettronica e programmazione, affinché noi possiamo conoscere la tua esperienza ed esprimerci con termini adeguati.
Grazie 1000 @jo_berry , al momento sto giusto prendendo confidenza con il nuovo Arduino Uno R4 ... L'esempio dell'elicottero mi ha subito fatto venire in mente un vecchio progetto per regolare l'anticipo di accensione di un motore a scoppio, dove in ingresso c'era il segnale a bassa tensione della bobina che porta la scintilla alla candela e in uscita un flash che si usa per la macchina fotografica che ad ogni scoppio della scintilla faceva luce sull'albero motore opportunamente segnato ... Il segnale del flash illumminava l'albero (su cui era stato fatto un riferimento) sempre nello stesso istante in modo che si potessesse anticipare o ritardare l'angolo dell'albero motore rispetto alla scintilla della candela!
Ovviamente il primo passo è quello di avere confidenza con i timer e gli interrupt in modo da poter giocare con i segnali di Arduino ...
Buon giorno anche a te, Guglielmo. Chiedo venia, ma ero convinto che, avendo già fatto la mia presentazione nella sezione inglese, fosse sufficiente. No problem, provvedo subito a mettermi in regola. Ciao.