R4 Minima Timer GPT, double frequency with delay

Hi everyone. This is my first post, so if I happen to break the rules, I ask for forgiveness in advance.
And since I'm also a novice with C and Arduino, I come to my request for help.
With the Arduino R4 Minima, I receive an input signal that needs to be doubled in frequency and at which a delay of programmable value must be added. In detail:


Input signal (red) with period of approximately 100 mS (variable) on D2, connected to GTERGA, configured for GPT0 Timer Start. GPT0 exits on GTIOC0A (D7) with PWM signal, pulse with fixed duration of 10 mS.
The red signal is also received by GPT1, which captures its period, in the register R_GPT1-GTCCR[0].
The same signal also generates an IRQ, which is intercepted by "void P_irq": the routine reads the
captured period, divides it by 2 and writes it to the End of Cycle register of GPT0 (R_GPT0->GTPR).
The result I get is the blue signal. First pulse on Falling edge synchronous to input, and second pulse at 180° from the first. So far everything is smooth.
The second goal to achieve (I'm not sure how) is to delay this signal by a minimum of 1 mS to a maximum of approximately 50 mS (it would be the green one).
The idea was to produce a variable duty cycle with GPT1, working on Compare B, and link the event of end pulse at GPT0 start.
But the link doesn't work. Anyone have any suggestions? it would be very welcome.
Thanks in advance. Giorgio

long periodo;
long semi_periodo;

void setup() {

    Serial.begin(250000);

//PIN USCITA Test ritardo GPT1 su porta P106
    //Pag. 361: setta P106 / D6,  PDR a 1 = Output), PMR a 1 = Usata per periferica,  PSEL a 3 = uscita su GTIOC0B per test PW£M GPT1
    R_PFS->PORT[1].PIN[6].PmnPFS = (1 << R_PFS_PORT_PIN_PmnPFS_PDR_Pos) | (1 << R_PFS_PORT_PIN_PmnPFS_PMR_Pos) | (3 << R_PFS_PORT_PIN_PmnPFS_PSEL_Pos);   

//PIN USCITA TRIGGER TELECAMERA GPT0 su porta P107

    //Pag. 361: setta P107 / D7,  PDR a 1 = Output), PMR a 1 = Usata per periferica,  PSEL a 3 = uscita su GTIOC0A per trigger telecamera
    R_PFS->PORT[1].PIN[7].PmnPFS = (1 << R_PFS_PORT_PIN_PmnPFS_PDR_Pos) | (1 << R_PFS_PORT_PIN_PmnPFS_PMR_Pos) | (3 << R_PFS_PORT_PIN_PmnPFS_PSEL_Pos);   

//PIN INGRESSO TACH RP   (diretto a timer)    Le 2 istruzioni seguenti servono per usare il vecchio sistema con P_IRQ. Puo essere usato in parallelo a GTETRGA                          
    pinMode(5, INPUT_PULLUP);                                 //pin 2 interrupt Ingresso sensore giri RP
    attachInterrupt(digitalPinToInterrupt(2), P_IRQ,FALLING);  

    //Pag. 361:     
    R_PFS->PORT[1].PIN[5].PmnPFS = 0b00010000000010110010000010000;   //Pag. 362: Periferica = GTETRGA, Usato per periferica, Non analogico, Usa IRQ, Falling edge, Input pull-up, Input era 5

//SETUP REGISTRI VARI

  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


//SETUP GPT0: Ha il compito di generare la 2 x giro

  R_GPT0->GTWP = 0xA500;                                  //Pag. 397: A500h Abilita la scrittura dei registri timer
  R_GPT0->GTUDDTYC = 0x00000001;                          //Pag. 418: Count UP
  R_GPT0->GTCR = 0x00000;                                 //Pag. 417: Clock 48 MHz, triangolare                                                                                                                                                                      
  R_GPT0->GTPR=9600000;                                   //Pag. 431: Massimo conteggio = 48.000.000 * 0.2 = 9600000 = 0,2 secondi. Viene poi settato da P_IRQ a semi_periodo
  R_GPT0->GTCNT = 0;                                      //Pag. 430: Valore iniziale contatore
  R_GPT0->GTIOR = 0b100011001;                            //Pag. 420: Uscita GTIOCA alta a fine ciclo, alta allo stop, bassa al compare match di GTCCRA, Uscita abilitata 0b100011001
  R_GPT0->GTCCR[0] = 480000;                              //Pag. 430: Initial Compare A = 480000 = 10 mS. It will be set by GPT1 Capture A   
  R_GPT0->GTSSR = 2;                                      //Pag. 399: Start counter da GTETRGA su falling edge    1 o 2 sembra non cambiare niente
  R_GPT0->GTCSR = 2;                                      //Pag. 404: Clear counter da GTETRGA su falling edge    1: il trigger camera parte da rising, 2 parte da falling                                                                                                                                                             


//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=9600000;                                   //Pag. 431: Massimo conteggio = 48.000.000 * 0.2 = 9600000 = 0,2 secondi, per vedere qualcosa all'oscilloscopio
  R_GPT1->GTCNT = 0;                                      //Pag. 430: Valore iniziale contatore
  R_GPT1->GTIOR = 0b0000001000011110000000000000000;      //Pag. 420: Uscita GTIOCB alta a fine ciclo, alta allo stop, bassa al compare match di GTCCRB, Uscita abilitata 0b100011001
  R_GPT1->GTCCR[1] = 1000000;                              //Compare B: 48000000/1000000 = variabile delay on GPT0 counter start (correzione dell'angolo di tracking) via ELC
  R_GPT1->GTICASR = 2;                                    //Pag. 411: Cattura su falling edge di GTETRGA
  R_GPT1->GTSSR = 2;                                      //Pag. 399: Start counter da GTETRGA su falling edge    1 o 2 sembra non cambiare niente
  R_GPT1->GTCSR = 2;                                      //Pag. 404: Clear counter da GTETRGA su falling edge    1: l'impulso parte da rising, 2 parte da falling  

  R_ELC->ELSR[0].HA = 0x60;                               //Pag. 347 Attivo ELC Event Link Controller per linkare Compare B GPT1 GTCCR1 (60h) a Start GPT0 (0h)
  R_ELC->ELCR = 128;                                      //ELC enable

}

void loop() {

}

void P_IRQ() {                                            //irq RP su pin P105 / D2 / IRQ0

periodo = R_GPT1->GTCCR[0];
semi_periodo = periodo / 2;

R_GPT0->GTPR = semi_periodo;                              //setta fine ciclo di GPT0 a circa 50 mS

}

Maybe hiding in the word salad is some key information.

What is the minimum and maximum frequency of the original signal?

Is the doubled signal to also vary with variations in the pulse length of the high portion of the input?

How fast and in what ways might the input frequency change, how accurately does the doubling need to be? It might be hard to follow, say, an increasing input frequency attempting to continuously adjust the output waveform synthesis.

Maybe if you said something about the why are you needing to do this part it woukd make it easier to help.

a7

In the meantime, thanks for the quick replies. I will try to compress the problem as much as possible.
It is a system for verifying the tracking of a helicopter, i.e. correct alignment of the 2 blades of the main rotor, both on the horizontal plane (a higher blade, one lower) than on rotation (one blade advances, the other backwards).
An optical sensor placed in front of the shaft produces the signal of 1 pulse per revolution (red signal).
The frequency is 580 RPM (9.7 Hz), rather precise because it is electronically regulated, and stable also thanks to the notable inertia of the rotor itself.
But for particular checks, we can also force the system to speed +/- 10%.
The sensor signal will become the trigger of a camera that must photograph both blades when they are in front of the vehicle, i.e. in the direction of flight.
And here the first function becomes necessary, that is, producing the second pulse at 180°, to also immortalize the second blade.
The second part of the problem (the one still to be solved) arises from the fact that the sensor is not
necessarily installed at the correct angle to photograph the blades from the front.
In the worst case scenario, the camera could take the photo with a few degrees of delay:
in this case I would have to wait almost 1/2 turn to find the next blade in the right place.
Hence the need to delay both pulses from a minimum of say 0° to a maximum of 180°.
As for the relationship between the output signal and the length of the input pulse, the answer is no.
In the sense that our reference is the "falling edge". The pulse could be longer or shorter.
Typically it could be around 5/10 mS. It depends on the size of the reflective sticker that
it was glued.

Thank you again. Giorgio

Yes, it's exactly the solution I imagined. In fact, if you look at the sketch I attached, in the lines before the "Loop" you see the instructions relating to ELC.
But I probably made a mistake or overlooked some detail and it doesn't work. GPT0 does not start.
Currently it only works if I run it directly from GTETRGA, so without delay.
As for precision: the error between the two pulses should be contained within a maximum of 10 / 20 uS.
With the 32-bit 48 MHz timer we have more than enough.
The delay could be in 5° steps, which at 580 RPM is about 1.4 mS
Clock accuracy: I don't think it's a problem. We don't need absolute time; the relative one is sufficient; T2 = T/2.
GPT0 and GPT1 use the same clock, so no problem.

I hope I understood what you meant correctly.
The last line (Counter Clear) is useless.
This is the sketch that works, directed by GTETRGA, without delay

   R_GPT0->GTWP = 0xA500;          //A500h register write enable
   R_GPT0->GTUDDTYC = 1;           //Count UP
   R_GPT0->GTCR = 0x00000;         //Clock 48 MHz, saw                                                                                                                                                                      
   R_GPT0->GTPR = 9600000;         //Max count = 48.000.000 * 0.2 = 9600000 = 0,2 secondi.
 				                   //	 P_irq set it at period / 2
   R_GPT0->GTCNT = 0;              //Initial count
   R_GPT0->GTIOR = 0b100011001;    //GTIOCA out, high at cycle end, high at stop, low at compare match GTCCRA, Out enabled
   R_GPT0->GTCCR[0] = 480000;      //Initial Compare A = 480000 = 10 mS. It will be set by GPT1 Capture A   
   R_GPT0->GTSSR = 2;              //Start counter from GTETRGA on falling edge 
 //  R_GPT0->GTCSR = 2;              //Clear counter from GTETRGA on falling edge

The following is the one linked to GPT1 GTCCRB, which doesn't work

  R_GPT0->GTWP = 0xA500;          //A500h register write enable
  R_GPT0->GTUDDTYC = 0x00000001;  //Count UP
  R_GPT0->GTCR = 0x00000;         //Clock 48 MHz, saw                                                                                                                                                                      
  R_GPT0->GTPR = 9600000;         //Max count = 48.000.000 * 0.2 = 9600000 = 0,2 secondi.
	                              //		        P_irq set it at period / 2
  R_GPT0->GTCNT = 0;              //Initial count
  R_GPT0->GTIOR = 0b100011001;    //GTIOCA out, high at cycle end, high at stop, low at compare match GTCCRA, Out enabled
  R_GPT0->GTCCR[0] = 480000;      //Initial Compare A = 480000 = 10 mS. It will be set by GPT1 Capture A   
  R_GPT0->GTSSR = 0x20000;        //Counter start enabled at the ELC_GPTB event input
//  R_GPT0->GTCSR = 2;              //Clear counter from GTETRGA on falling edge

So the mid pulse you output. I assume this measured time value will be delayed by one pulse, seeing that you need to measure each incoming for length. Correct?

-jim lee

From what I understand this should do it..

I had to slow it down a bunch so you can see it working on the simulator.

But, if the whole point was to learn the fancy new processor, then this'll not be of any help.

I agree with you. Pre-packaged things that work without knowing how have always scared me. But thank you very much anyway, and I will try it as soon as possible

For greater clarity I cleaned it all up and put the comments in English

long periodo;
long semi_periodo;

void setup() {

    Serial.begin(250000);

//Output: GPT1 Delay PWM Test on D6 (P106)
    //Set P106 / D6,  PDR = 1 = Output), PMR = 1 = Used for peripheral,  PSEL =3 3 = out on GTIOC0B
    R_PFS->PORT[1].PIN[6].PmnPFS = (1 << R_PFS_PORT_PIN_PmnPFS_PDR_Pos) | (1 << R_PFS_PORT_PIN_PmnPFS_PMR_Pos) | (3 << R_PFS_PORT_PIN_PmnPFS_PSEL_Pos);   

//Output: Camera trigger GPT0 on D7 (P107)
    //Set P107 / D7,  PDR = 1 = Output), PMR = 1 = Used for peripheral,  PSEL =3 3 = out on GTIOC0A 
    R_PFS->PORT[1].PIN[7].PmnPFS = (1 << R_PFS_PORT_PIN_PmnPFS_PDR_Pos) | (1 << R_PFS_PORT_PIN_PmnPFS_PMR_Pos) | (3 << R_PFS_PORT_PIN_PmnPFS_PSEL_Pos);   

//Input: Optical sensor. This is to use interrupt (Void P_irq)
    pinMode(5, INPUT_PULLUP);                   //
    attachInterrupt(digitalPinToInterrupt(2), P_IRQ,FALLING);  

//Input: Optical sensor. This is to use GTERGA on GPT0 & GPT1
    //Set D2 (P105): Peripheral = GTETRGA, Used for peripheral, No analogic, Use IRQ, Falling edge, Input pull-up, Input
    R_PFS->PORT[1].PIN[5].PmnPFS = 0b00010000000010110010000010000;  

//SETUP VARIOUS REGISTERS

  R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD2_Pos);     //Cancel Stop State AGT1
  R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD3_Pos);     //Cancel Stop State AGT0
  R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD5_Pos);     //Cancel Stop State GPT320 e 321
  R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD6_Pos);     //Cancel Stop State GPT16x
  R_MSTP->MSTPCRD &= ~(1 << R_MSTP_MSTPCRD_MSTPD14_Pos);    //POEG enable


//SETUP GPT0: produces the doubled frequency

  R_GPT0->GTWP = 0xA500;          //A500h register write enable
  R_GPT0->GTUDDTYC = 0x00000001;  //Count UP
  R_GPT0->GTCR = 0x00000;         //Clock 48 MHz, saw                                                                                                                                                                      
  R_GPT0->GTPR = 9600000;         //Max count = 48.000.000 * 0.2 = 9600000 = 0,2 secondi.                                  
                                  //"void P_irq" set it at period / 2
  R_GPT0->GTCNT = 0;              //Initial count
  R_GPT0->GTIOR = 0b100011001;    //GTIOCA out, high @ cycle end, high @ stop, low @ compare match GTCCRA, Out enabled
  R_GPT0->GTCCR[0] = 480000;      //Compare A = 480000 = pulse 10 mS.   
  R_GPT0->GTSSR = 0x2;            //GTSSR=0x2 = Counter start enabled from GTERGA (D2 / P105) falling edge:  WORKING
//          or  = 0x20000 = Counter start enabled at the ELC_GPTB event input:  NOT WORKING


//SETUP GPT1: Period measure

  R_GPT1->GTWP = 0xA500;          //A500h register write enable 
  R_GPT1->GTUDDTYC = 0x00000001;  //Count UP
  R_GPT1->GTCR = 0x00000000;      //Clock 48 MHz, saw                                                                                                                                                                 
  R_GPT1->GTPR=9600000;           //Max count = 48.000.000 * 0.2 = 9600000 = 0,2 secondi.
  R_GPT1->GTCNT = 0;              //Initial count
  //GTIOCB Output @ cycle end High, High @ stop, Low at GTCCRB Compare Match, Output enabled 
  R_GPT1->GTIOR = 0b0000001000011110000000000000000; 
  R_GPT1->GTCCR[1] = 720000;      //Compare B: 48000000/720000 = 15 mS delay on GPT0 timer start (tracking angle correction) via ELC
  R_GPT1->GTICASR = 2;            //Period Capture on GTETRGA falling edge 
  R_GPT1->GTSSR = 2;              //Counter Start from falling edge GTETRGA
  R_GPT1->GTCSR = 2;              //Counter Clear from falling edge GTETRGA  (1=rising, 2=falling)


//ELC SETUP

  R_ELC->ELSR[0].HA = 0x60;       //ELC Event Link Controller to link GPT1 Compare B GTCCR1 (60h) to GPT0 Start (0h)
  R_ELC->ELCR = 128;              //ELC enable

}

void loop() {

}

void P_IRQ() {                    //irq RP on pin P105 / D2 / IRQ0

periodo = R_GPT1->GTCCR[0];       //get gaptured period (100 mS)
semi_periodo = periodo / 2;       //division / 2
R_GPT0->GTPR = semi_periodo;      //GPT0 End Cycle setting at 50 mS

}

Good evening guys, I have partially solved my problem. The mistake (stupid me) was to use the same pin both as a generic pin and as a peripheral pin. Obviously this is not allowed, and it created a conflict when I tried to use Event Link Controller. Here the mistake:

//TACH RP INPUT interrupt -> "void P_irq". Port P105 (D2) 
    pinMode(2, INPUT_PULLUP);    //pin 2, Optical sensor input / interrupt
    attachInterrupt(digitalPinToInterrupt(2), P_IRQ,RISING);  

//Peripheral = GTETRGA, Used for peripheral, No analogic, Use IRQ, Falling edge, Input pull-up,     
    R_PFS->PORT[1].PIN[5].PmnPFS = 0b00010000000010110010000010000;

Now I have one last thing left to do: I generated the vector_data.h file with E2Studio, containing the necessary callback.

/* generated vector header file - do not edit */
#ifndef VECTOR_DATA_H
#define VECTOR_DATA_H
#ifdef __cplusplus
        extern "C" {
        #endif
/* Number of interrupts allocated */
#ifndef VECTOR_DATA_IRQ_COUNT
#define VECTOR_DATA_IRQ_COUNT    (1)
#endif
/* ISR prototypes */
void gpt_capture_a_isr(void);

#if __has_include("r_ioport.h")
        /* Vector table allocations */
        #define VECTOR_NUMBER_GPT1_CAPTURE_COMPARE_A ((IRQn_Type) 0) /* GPT1 CAPTURE COMPARE A (Compare match A) */
        #define GPT1_CAPTURE_COMPARE_A_IRQn          ((IRQn_Type) 0) /* GPT1 CAPTURE COMPARE A (Compare match A) */
        #endif

#ifdef __cplusplus
        }
        #endif
#endif /* VECTOR_DATA_H */

But I don't know how to insert it inside the Arduino IDE. Any suggestions?

Ok, I did this.
And in the sketch I inserted these instructions...

void gpt_capture_a_isr(){
Serial.println ("IRQ");
}

to verify the operation, but the callback does not arrive. What is missing?

Ok, I'll keep trying. And I look forward to your miraculous intervention!!! Good night

Good morning everyone. I solved my problem brilliantly by taking inspiration from Susan Parker's magnificent work on interrupt handling (M4_Minima_Test_Code_Fast-PWM_SPI_IRQ_ADC_DAC_SCI/README.md at main · TriodeGirl/M4_Minima_Test_Code_Fast-PWM_SPI_IRQ_ADC_DAC_SCI · GitHub).
Thank you all for your cooperation and, above all, Thank you Susan. You will be in my dreams!!!
Giorgio

Hello @jo_berry can you show me how to solve problem using GPT timer with direct register operations? I'm studying GPT timers ... I understood ho to use FSP but I newer use GPT timer with direct register operations ...

Thanks
Luigi Conte

Hello. From your name I'd say you're Italian. How about continuing in our language?

OK, i move my question in this post.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.