dbuezas / lgt8fx

Board Package for Logic Green LGT8F328P LGT8F328D and LGT8F88D
369 stars 88 forks source link

issues with timer3 in lgt8f328p #245

Closed manhabc closed 1 year ago

manhabc commented 1 year ago

Hello it's me again with new issues in using timer3, I'm doing project and Timer1, Timer2 already used, so I'm using the Web timer edit to setup. But the output of the timer3 is supper weird, with the value OCR3A = 20000, what I saw on my oscilloscope is the D9 go LOW every 0.5mS (with my calculation, it should be 20mS). More interesting, when I changed to 0-65535, I got the same results. I also tried to use 8MHz or 16MHz, internal or 8MHz external (my project use 8mhz external) system clk, it's the same

Do you have any idea what is going on with my setup? Many thanks!

ps: I edited for being more clearly. So sorry for my English

Here is the code I check with timer3

`

include

include <avr/interrupt.h>

include <avr/io.h>

void setup(){ pinMode(D9,OUTPUT); noInterrupts(); TCCR3B = 1 << CS31; TIMSK3 = 1 << OCIE3A; OCR3A = 20000; interrupts(); }

ISR(TIMER3_vect) { if (TIFR3 & (1 << OCF3A)) { TIFR3 = 1 << OCF3A; digitalWrite(D9,LOW);

}

}

void loop(){ digitalWrite(D9, HIGH); } `

dbuezas commented 1 year ago

Please paste the full output code of the tool, including the deep link back to the preconfigured tool.

manhabc commented 1 year ago

Absolutely, here is my code with the link back to config website.

void setup(){ / https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&timerMode=Normal&clockPrescalerOrSource=8&FCPU_UI=8Mhz&interruptA=on&OCR3A=20000 / noInterrupts(); TCCR3B = 1 << CS31; TIMSK3 = 1 << OCIE3A; OCR3A = 20000; interrupts(); }

ISR(TIMER3_vect) { if (TIFR3 & (1 << OCF3A)) { TIFR3 = 1 << OCF3A; digitalWrite(D9,LOW); }

void loop(){ digitalWrite(D9, HIGH); }

}

LaZsolt commented 1 year ago
void loop(){
digitalWrite(D9, HIGH);
}

This code snippet set continuously D9 to high. It is no coincidence that the pulse is short.

manhabc commented 1 year ago
void loop(){
digitalWrite(D9, HIGH);
}

This code snippet set continuously D9 to high. It is no coincidence that the pulse is short.

But I do see D9 pul down for abt 0.25mS, monitoring on my oscilloscope.

LaZsolt commented 1 year ago

But I do see D9 pul down for abt 0.25mS, monitoring on my oscilloscope.

Yes, that time when the interrupt set this output low, then the digitalWrite() inside the loop() sets back to high.

manhabc commented 1 year ago

But I do see D9 pul down for abt 0.25mS, monitoring on my oscilloscope.

Yes, that time when the interrupt set this output low, then the digitalWrite() inside the loop() sets back to high.

But what I concern is the timing, with 0cr3a = 20000 it should be almost 20mS but I got only 0.5mS. I Change value but it is the same.

Time for D9 go L is only 25uS not 0.25mS (my bad on converting)

LaZsolt commented 1 year ago

The timer3 controls only the interrupt, which sets the output low. But the digitalWrite(D9, HIGH) inside the loop() not controlled by any Timer, so the output will going to high as soon as could.

dbuezas commented 1 year ago

To expand on what @LaZsolt said, those 25uS are the time between an interrupt and the next time the loop runs, which can be anything depending on what else you have in the loop or what other interrupts do. So not what you want.

Here's a potential solution for what you want to achieve: If you want to generate a pwm in a pin which is not an output of the timer, (D9 in your case), you could use the interrupts of two outputs. One to write the pin HIGH and the other to write it LOW.

Like this but add digitalWrite(D9, HIGH) and digitalWrite(D9, LOW) inside each of the if statements of the interrupt.

dbuezas commented 1 year ago

Closing the issue as it is a question, but feel free to continue the discussion below :)

manhabc commented 1 year ago

Maybe you misunderstand my concern, since English is not my mother language. Im not asking why the 25uS D9 pul low , (I did it for marking purpose only). I’m asking about the time from x1 to x2, 8mhz sys clk , prescale 1:8 which is 1uS for 1 count. Then with ocr3a change from 0-65535 the time from x1 to x2 is not change, it’s stable at 0.5mS. That is my problem now. If you are not going with me, I will try to make another example for more details

manhabc commented 1 year ago

BAECB5D9-00D0-4516-975D-BFF31BB1B6AF

LaZsolt commented 1 year ago

Okay. Try this code:

https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&CompareOutputModeA=disconnect&timerMode=CTC&interruptA=on&OCR3A=20000&clockPrescalerOrSource=8&FCPU_UI=8Mhz

manhabc commented 1 year ago

Okay. Try this code:

https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&CompareOutputModeA=disconnect&timerMode=CTC&interruptA=on&OCR3A=20000&clockPrescalerOrSource=8&FCPU_UI=8Mhz

The same as previous, I also reset TCNT3 each time it reach Ocr3a but no different. Am I got the fake one? Timer1 and 2 are exactly as in my setting

dbuezas commented 1 year ago

Oh, I see. You mean that timers 1 and 2 work as you expect but timer 3 doesn't?

dbuezas commented 1 year ago

Mmm I think you found a bug in the app. Nothing sets the TCCR3A register

LaZsolt commented 1 year ago

Mmm I think you found a bug in the app. Nothing sets the TCCR3A register

I think in this example WGM30 ad WGM31 bits are 0, that's why your app not generating code to set TCRR3A register. (In this timer 3 configuration all bits of TCCR3A register are 0.)

manhabc commented 1 year ago

Oh, I see. You mean that timers 1 and 2 work as you expect but timer 3 doesn't?

Yes, It drive me crazy till I narrow down my code to timer3 set up

@ LaZsoft I think so but how to manually turn on all the bits?

LaZsolt commented 1 year ago

If you could use D6 Arduino pin instead of D9 here is an idea. In this setup the timer generate the short pulses without use of any interrupt. ICR3 sets the lengt of time between pulses and OCR3A must be less than ICR3.

void setup(){
  /* https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&CompareOutputModeA=clear-on-match%2C+set-at-max&FCPU_UI=8Mhz&clockPrescalerOrSource=8&topValue=ICR3&ICR3=20000&OCR3A=19950&OCnA_OutputPort=AC0P%28D6%29 */
  noInterrupts();
  TCCR3A = 
    1 << COM3A1;
  TCCR3B = 
    1 << WGM33 |
    1 << CS31;
  PMX0 = 
    1 << WCE;
  PMX1 = 
    1 << C3AC;
  OCR3A = 19950;
  ICR3 = 20000;
  interrupts();
}

https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&CompareOutputModeA=clear-on-match%2C+set-at-max&FCPU_UI=8Mhz&clockPrescalerOrSource=8&topValue=ICR3&ICR3=20000&OCR3A=19950&OCnA_OutputPort=AC0P%28D6%29

(In the case of using Timer 3 compare B output the pulses came out on D2 Arduino pin.)

dbuezas commented 1 year ago

I think in this example WGM30 ad WGM31 bits are 0, that's why your app not generating code to set TCRR3A register. (In this timer 3 configuration all bits of TCCR3A register are 0.)

But is that correct? the other timers look very different

manhabc commented 1 year ago

If you could use D6 Arduino pin instead of D9 here is an idea. In this setup the timer generate the short pulses without use of any interrupt. ICR3 sets the lengt of time between pulses and OCR3A must be less than ICR3.

void setup(){
  /* https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&CompareOutputModeA=clear-on-match%2C+set-at-max&FCPU_UI=8Mhz&clockPrescalerOrSource=8&topValue=ICR3&ICR3=20000&OCR3A=19950&OCnA_OutputPort=AC0P%28D6%29 */
  noInterrupts();
  TCCR3A = 
    1 << COM3A1;
  TCCR3B = 
    1 << WGM33 |
    1 << CS31;
  PMX0 = 
    1 << WCE;
  PMX1 = 
    1 << C3AC;
  OCR3A = 19950;
  ICR3 = 20000;
  interrupts();
}

https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&CompareOutputModeA=clear-on-match%2C+set-at-max&FCPU_UI=8Mhz&clockPrescalerOrSource=8&topValue=ICR3&ICR3=20000&OCR3A=19950&OCnA_OutputPort=AC0P%28D6%29

(In the case of using Timer 3 compare B output the pulses came out on D2 Arduino pin.)

I’m using timer3 to create a pulse from 1-100mS, just when buttons was pressed, it will make D9 H for setting time (1-100mS) then it’s done I’m thinking of using timer0 but it’s affecting the millis function. I will try this way t = millis D9 H While ( millis - t < timeset*1000)

D9 L

it might not accurate but hope it works well. Many thanks and I really appreciate your help

LaZsolt commented 1 year ago

But is that correct? the other timers look very different

Yes, looks different, because WGM bits are in one register. Timer 3 WGM bits are in two different registers.

dbuezas commented 1 year ago

Then I guess the question remains, why @manhabc is getting the wrong period

LaZsolt commented 1 year ago

Remains a mystery.

manhabc commented 1 year ago

Remains a mystery.

So how can I check the version of IC? Maybe they reduce some func to lower the price?

LaZsolt commented 1 year ago

I made a test, but the behaviour is really strange.

void setup(){
  pinMode(LED_BUILTIN,OUTPUT);
  noInterrupts();
  TCCR3B =
  1 << CS31;
  TIMSK3 =
  1 << OCIE3A;
  OCR3A = 20000;
  interrupts();
}

ISR(TIMER3_vect) {
  if (TIFR3 & (1 << OCF3A)) {
    TIFR3 = 1 << OCF3A;
    digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
    }
}

void loop(){
  OCR3A = 20000;
  delay(5000);
  OCR3A = 15000;
  delay(5000);
  OCR3A = 10000;
  delay(5000);
  OCR3A = 5000;
  delay(5000);
}

The Timer 3 behaviour not as what we expect according arduino-web-timers. I'll keep testing.

LaZsolt commented 1 year ago

I started the Timer 3 test with the setup above. Then in arduino-web-timer I turned off the normal mode, and after this I turned on the ICR3 box. I get this result: kép

LaZsolt commented 1 year ago

The Timer 3 behaviour not as what we expect according arduino-web-timers. I'll keep testing.

I think the settings TCCR3B = 1 << CS31; TIMSK3 = 1 << OCIE3A; not the normal mode. I'll keep testing.

LaZsolt commented 1 year ago

Okay. I think I found the reason: If the compare output not enabled, the timer behavior is not that then you expected. So @dbuezas, if no behaviour selected on Timer 3 any compare outputs there in no predictable behaviour. Not even interrupt.

LaZsolt commented 1 year ago

@manhabc

Here is the code for you:

Does not need include lgt328p.h, interrupt.h, io.h

void setup(){
  pinMode(D9,OUTPUT);
  noInterrupts();
  TCCR3A = 
    1 << COM3A0;
  TCCR3B =
   1 << WGM32 |
   1 << CS31;
  TIMSK3 =
    1 << OCIE3A;
  PMX0 = 
    1 << WCE;
  PMX1 = 
    1 << C3AC;    // Set compare output to D2 arduino pin (LQFP32 package)
  OCR3A = 20000;  // You can control the time between low pulses
  interrupts();
}

ISR(TIMER3_vect) {
  if (TIFR3 & (1 << OCF3A)) {
    TIFR3 = 1 << OCF3A;
    digitalWrite(D9, LOW);
  }
}

void loop(){
  digitalWrite(D9, HIGH);
}

You are unable to use D2 arduino pin as general IO. https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&clockPrescalerOrSource=8&FCPU_UI=8Mhz&interruptA=on&OCR3A=20000&CompareOutputModeA=toggle&topValue=OCR3A&OCnA_OutputPort=AC0P%28D6%29

dbuezas commented 1 year ago

if no behaviour selected on Timer 3 any compare outputs there in no predictable behaviour

Oh wow. This is specific to Timer 3, right? Maybe one could use Output C, the F3 pin is not even exposed in the QFP32 and SSOP20 packages.

LaZsolt commented 1 year ago

Maybe one could use Output C

Yes, good idea. The modified and tested source:

//Does not need include lgt328p.h, interrupt.h, io.h

void setup(){
  pinMode(D9,OUTPUT);
  noInterrupts();
  TCCR3A = 
    1 << COM3C0;
  TCCR3B =
   1 << WGM32 |
   1 << CS31;
  TIMSK3 =
    1 << OCIE3C;
  OCR3A = 20000;  // You can control the time between low pulses
  OCR3C = 1;      // Compare C interrupt at 1 
  interrupts();
}

ISR(TIMER3_vect) {
  if (TIFR3 & (1 << OCF3C)) {
    TIFR3 = 1 << OCF3C;
    digitalWrite(D9, LOW);
  }
}

void loop(){
  digitalWrite(D9, HIGH);
}
dbuezas commented 1 year ago

This is specific to Timer 3, right? I mean, Timer0 for example is more than happy running keeping track of millis without any output. I could add a constraint that forbids that all outputs are disconnected if an interrupt is used on Timer3

LaZsolt commented 1 year ago

I tried to search in the databook a mention about this behavior, but nothing found. @manhabc wrote that when tested Timer 1 and 2 they do what he want, but Timer 3 not. I made a test on Timer 3 which ended up to turn out this behavior.

So add a constraint that forbids using Timer 3 interrupts if no output connected.

dbuezas commented 1 year ago

So, no interrupts on an output if if is disconnected. I assume this happens independently on each channel.

dbuezas commented 1 year ago

Btw @manhabc you could also use the overflow and capture interrupts.

LaZsolt commented 1 year ago

So, no interrupts on an output if if is disconnected. I assume this happens independently on each channel.

When I tested the interrupts there was interrupts, but the behaviour was not as what we expected. The interrupt behaviour became good after I turned on an output (eg. toggle).

dbuezas commented 1 year ago

These are now fixed:

Note: you need to clear the cache to get the latest version. In Chrome, cmd+shift+r in Mac, ctrl+f5 in Windows and Linux.

I can't test on an LGT at the moment, but another alternative is to use ICR3 as top value and use the interrupt on input capture (it triggers on match too) or/and the overflow interrupt. See here for the example.

manhabc commented 1 year ago

Thank you so much! I will test and tell you later.

One more comment on web timer, could you please add option to change the values of OCRXA or ICR …. Using mouse to slide the bar from 0-65535 for exact value is the most painful things in my life. I have to create an excel file for reference

hmeijdam commented 1 year ago

As a workaround, you can enter/modify the value directly in the URL. No mouse sliding required.

Here you can see I set OCR1A to 64999 https://dbuezas.github.io/arduino-web-timers/#mcu=ATMEGA328P&timer=1&timerMode=PCPWM&topValue=OCR1A&OCR1A=64999

manhabc commented 1 year ago

As a workaround, you can enter/modify the value directly in the URL. No mouse sliding required.

Here you can see I set OCR1A to 64999 https://dbuezas.github.io/arduino-web-timers/#mcu=ATMEGA328P&timer=1&timerMode=PCPWM&topValue=OCR1A&OCR1A=64999

Ah ha, it’s ok now. Thanks!

LaZsolt commented 1 year ago

I can't test on an LGT at the moment, but another alternative is to use ICR3 as top value and use the interrupt on input capture (it triggers on match too) or/and the overflow interrupt.

I did the test with OCR3A and Interrupt on Timer overflow at TOP. In this case not need to enable any compare outputs. Working. :)

https://dbuezas.github.io/arduino-web-timers/#mcu=LGT8F328P&timer=3&InterruptOnInputCapture=off&topValue=OCR3A&InterruptOnTimerOverflow=on&setTovMoment=TOP&OCR3A=20000&clockPrescalerOrSource=1

// Timer 3 OCR3A interrupt on overflow test

void setup() {
  pinMode(LED_BUILTIN,OUTPUT);
  digitalWrite(LED_BUILTIN,HIGH);
  delay(3000);             // Wait 3 seconds after reset for reprogramming

  noInterrupts();
  TCCR3A = 
    1 << WGM31 |
    1 << WGM30;
  TCCR3B = 
    1 << WGM33 |
    1 << WGM32 |
    1 << CS32;
  TIMSK3 = 
    1 << TOIE3;
  OCR3A = 20000;
  interrupts();
} // end setup()

ISR(TIMER3_vect) {
  if (TIFR3 & (1 << TOV3)) {
      TIFR3 = 1 << TOV3;
      digitalToggle(LED_BUILTIN);
  }
} // end Timer3 ISR

void loop() {

  delay(5000);
  noInterrupts();
  OCR3A = 10000;
  interrupts();

  delay(5000);
  noInterrupts();
  OCR3A = 5000;
  interrupts();

  delay(5000);
  noInterrupts();
  OCR3A = 20000;
  interrupts();

} // end loop()
dbuezas commented 1 year ago

@manhabc you can now edit the values with the keyboard too

image