DeqingSun / ch55xduino

An Arduino-like programming API for the CH55X
GNU Lesser General Public License v2.1
433 stars 85 forks source link

Timer3 Interrupts on the CH558 not working (with suggested fix) #165

Open dirkx opened 3 months ago

dirkx commented 3 months ago

Interrupts for Timer3 (see demo program below) appeared not to work (timer 2 is fine).

Applying below makes this work.

diff --git a/ch55xduino/ch55x/cores/ch55xduino/main.c b/ch55xduino/ch55x/cores/ch55xduino/main.c
index 58a5483..76a2d60 100644
--- a/ch55xduino/ch55x/cores/ch55xduino/main.c
+++ b/ch55xduino/ch55x/cores/ch55xduino/main.c
@@ -24,6 +24,10 @@
 void USBInterrupt(void);
 // Timer2Interrupt NEEDs to saves the context
 void Timer2Interrupt(void) __interrupt(INT_NO_TMR2);
+#if defined(CH559)  || defined(CH558)
+void Timer3Interrupt(void) __interrupt(INT_NO_TMR3);
+#endif
+

But not quite understanding why. Test/sample code below flashes the led nicely as expected once above is patched in (though USB Serial sometimes acts funny):

#include <Serial.h>
#define LED (40)

static unsigned int flag = 0;
void Timer3Interrupt(void) __interrupt(INT_NO_TMR3) __using(1) {
  // clear count-passed endpoint interupt.
  T3_STAT |= bT3_IF_END;

  flag++;
  digitalWrite(LED, flag & 1);
}

void setup() {
    digitalWrite(LED, LOW);
    pinMode(LED, OUTPUT);

  // give the Arduino IDE some time to switch.
  delay(3000);
  USBSerial_println(__FILE__);
  USBSerial_println("Gotta get going...");
  USBSerial_println(__DATE__);
  USBSerial_println(__TIME__);

#define PERIOD (200)            /* milli seconds */
#define DIV (F_CPU / 10 / 1000) /* Result is a 10 Khz counter  */
#define ENDCOUNT (10 * PERIOD)  /* count to 10k */

  // set divisor
  T3_SETUP |= bT3_EN_CK_SE;  //  Enable to accessing divisor setting register.
  T3_CK_SE_L = DIV & 0xff;
  T3_CK_SE_H = (DIV >> 8) & 0xff;
  T3_SETUP &= ~bT3_EN_CK_SE;  // clear access again.

  T3_CTRL |= bT3_CLR_ALL;   // Force clear FIFO and count of timer3.
  T3_CTRL &= ~bT3_CLR_ALL;  // And go back to reset by software
  T3_SETUP |= bT3_IE_END;   // Enable interruts
  T3_CTRL &= ~bT3_MOD_CAP;  // Timer or PWM mode

  T3_STAT |= bT3_IF_END;  // Interrupt when we pass ENDCOUNT

  T3_END_L = ENDCOUNT & 0xff;
  T3_END_H = (ENDCOUNT >> 8) & 0xff;

  T3_CTRL |= bT3_CNT_EN;  // start timer

  IE_TMR3 = 1;  // Timer3 interrupt is enabled.
  EA = 1;       // Global interrupt enable control bit
}

void loop() {
  {
    static uint32_t last;
    if (millis() - last > 2500) {
      last = millis();
      USBSerial_println("Tock");
    }
  }
  {
    static uint32_t last = 0;
    if (last != flag) {
      last = flag;
      USBSerial_print("IRQ seen:");
      USBSerial_println(flag);
      delay(100);
    }
  }
}
DeqingSun commented 3 months ago

That is a compiler limitation.

SDCC need the interrupt handler at least have a prototype in main.c

You can open the main.c to check how to do it.