From 0f054e63cba8b47b4eb7d4ae4d9ce18b4ec9616a Mon Sep 17 00:00:00 2001 From: Martin Kobetic Date: Wed, 15 Apr 2026 12:49:23 -0400 Subject: [PATCH 1/2] ARM: timer interrupt --- arm/mcu/ra4m1/dict_mcu.inc | 3 ++ arm/mcu/ra4m1/readme.md | 1 + arm/mcu/ra4m1/vectors.s | 8 +---- arm/mcu/ra4m1/words/agt.s | 68 ++++++++++++++++++++++++++++++++++++++ arm/mcu/ra4m1/words/icu.s | 17 ++++++++++ 5 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 arm/mcu/ra4m1/words/agt.s create mode 100644 arm/mcu/ra4m1/words/icu.s diff --git a/arm/mcu/ra4m1/dict_mcu.inc b/arm/mcu/ra4m1/dict_mcu.inc index 21b869ef..ab433dd9 100644 --- a/arm/mcu/ra4m1/dict_mcu.inc +++ b/arm/mcu/ra4m1/dict_mcu.inc @@ -9,3 +9,6 @@ .include "words/at-usart.s" .include "words/dwt.s" + +.include "words/agt.s" +.include "words/icu.s" diff --git a/arm/mcu/ra4m1/readme.md b/arm/mcu/ra4m1/readme.md index 52fb38e1..1b5eb65d 100644 --- a/arm/mcu/ra4m1/readme.md +++ b/arm/mcu/ra4m1/readme.md @@ -95,6 +95,7 @@ Note that the only tools needed for this process are AmForth running on the targ ## UNO R4 WIFI * https://docs.arduino.cc/hardware/uno-r4-wifi/ +* https://www.renesas.com/en/products/ra4m1 * https://docs.freenove.com/projects/fnk0096/en/latest/ * https://github.com/arduino/ArduinoCore-renesas * https://www.shumatech.com/web/products/bossa diff --git a/arm/mcu/ra4m1/vectors.s b/arm/mcu/ra4m1/vectors.s index d0a394c8..5c2e589e 100644 --- a/arm/mcu/ra4m1/vectors.s +++ b/arm/mcu/ra4m1/vectors.s @@ -4,13 +4,7 @@ IRQ_VECTORS: /* RA4M1 User Manual 13.3.1 Interrupt Vector Table - - 13.2.6 ICU Event Link Setting Register n (IELSRn) - Address: 0x40006300 + 4n : - * IELS[7:0] - ICU Event Link Select ; 0 = disabled, otherwise Event Table 13.4. - * IR[16] - Interrupt Status Flag ; write 0 to clear request - * DTCE[24] - DTC Activation Enable ; activates DTC instead of NVIC - + ARM_ICTR.INTLINESNUM=0 => 32 interrupts */ .word 0 @ 16: ICU.IELSR0 diff --git a/arm/mcu/ra4m1/words/agt.s b/arm/mcu/ra4m1/words/agt.s new file mode 100644 index 00000000..70f8bcb5 --- /dev/null +++ b/arm/mcu/ra4m1/words/agt.s @@ -0,0 +1,68 @@ +/* + RA4M1 Group: User Manual: 23. Low Power Asynchronous General Purpose Timer (AGT) + */ + +.equ RA4_AGT0_AGT, 0x40084000 /* AGT0 Counter Register [15:0] R/W */ +.equ RA4_AGT1_AGT, 0x40084100 /* AGT1 Counter Register [15:0] R/W */ +.equ RA4_AGT0_AGTCMA, 0x40084002 /* AGT0 Compare Match A Register [15:0] R/W */ +.equ RA4_AGT1_AGTCMA, 0x40084102 /* AGT1 Compare Match A Register [15:0] R/W */ +.equ RA4_AGT0_AGTCMB, 0x40084004 /* AGT0 Compare Match B Register [15:0] R/W */ +.equ RA4_AGT1_AGTCMB, 0x40084104 /* AGT1 Compare Match B Register [15:0] R/W */ +.equ RA4_AGT0_AGTCR, 0x40084008 /* AGT0 Control Register */ +.equ RA4_AGT1_AGTCR, 0x40084108 /* AGT1 Control Register */ +/* + [0] TSTART Count Start R/W + [1] TCSTF Count Status Flag R + [2] TSTOP Count Forced Stop W=1 + [4] TEDGF Active Edge Judgement Flag R/(W) + [5] TUNDF Undeflow Flag R/(W) + [6] TCMAF Compare Match A Flag R/(W) + [7] TCMBF Compare Match B Flag R/(W) + (W) - only 0 can be written to clear the flag + */ + .equ RA4_AGT0_AGTMR1, 0x40084009 /* AGT0 Mode Register 1 */ + .equ RA4_AGT1_AGTMR1, 0x40084109 /* AGT1 Mode Register 1 */ + /* + [2:0] TMOD Operating mode R/W 000=Timer, 001=Pulse output, 010=Event Counter, 011=Pulse Width Msr, 100=Pulse Period Msr + [3] TEDGPL Edge Polarity R/W + [6:4] TCK Count Source 000=PCKLB, 001=PCKLB/8, 011=PCKLB/2, 100=AGTLCLK, 101=AGT0 underflow, 110=AGTSCLK + */ +.equ RA4_AGT0_AGTMR2, 0x4008400A /* AGT0 Mode Register 2 */ +.equ RA4_AGT1_AGTMR2, 0x4008410A /* AGT1 Mode Register 2 */ +/* + [2:0] CKS AGTLCLK/AGTSCLK divisor R/W n => 1/2^n + [7] LPM Low Power Mode R/W 0=normal, 1=low power + + AGTLCLK is generated by LOCO, AGTSCLCK is not available on UNO R4 (no SOSC) + */ +.equ RA4_AGTO_AGTIOC, 0x4008400C /* AGT0 I/O Control Register */ +.equ RA4_AGT1_AGTIOC, 0x4008410C /* AGT1 I/O Control Register */ +.equ RA4_AGTO_AGTISR, 0x4008400D /* AGT0 Event Pin Select Register */ +.equ RA4_AGT1_AGTISR, 0x4008410D /* AGT1 Event Pin Select Register */ +.equ RA4_AGTO_AGTCMSR, 0x4008400E /* AGT0 Compare Match Function Select Register */ +.equ RA4_AGT1_AGTCMSR, 0x4008410E /* AGT1 Compare Match Function Select Register */ +.equ RA4_AGTO_AGTIOSEL, 0x4008400F /* AGT0 Pin Select Register */ +.equ RA4_AGT1_AGTIOSEL, 0x4008410F /* AGT1 Pin Select Register */ + +CODEWORD "agt0.init", AGT0_INIT /* ( u1 u2 -- ) initialize AGT0 as millisecond counter to generate interrupt u2 every u1 ms */ + @ validate and prepare TOS as IELSR offset + cmp TOS, #32 + blo 1f @ unsigned < 32 + throw -666 +1: + lsl TOS, #2 @ multiply by 4 + ldr r0, =RA4_ICU_IELSR + ldr r1, =0x1e @ set AGT0_AGTI as event trigger for the interrupt + str r1, [r0, TOS] + ldr r0, =RA4_AGT0_AGTMR1 + ldr r1, =0x40 @ Timer mode with AGTLCLK 32kHz + strb r1, [r0] + ldr r0, =RA4_AGT0_AGTMR2 + ldr r1, =0x05 @ 1/32 clock divisor => ~ 1ms period + strb r1, [r0] + ldr r0, =RA4_AGT0_AGT + popnos r1 @ set interrupt period to u1 milliseconds + strb r1, [r0] + loadtos + NEXT +END AGT0_INIT diff --git a/arm/mcu/ra4m1/words/icu.s b/arm/mcu/ra4m1/words/icu.s new file mode 100644 index 00000000..7676ee31 --- /dev/null +++ b/arm/mcu/ra4m1/words/icu.s @@ -0,0 +1,17 @@ +/* + RA4M1 Group: User Manual: 13. Interrupt Controller Unit (ICU) + * peripheral function interrupts: 174 sources + * external pin interrupts: 15 sources IRQ0-12,14,15 + * NVIC: 32 sources + * NMI, Oscillation stop, WDT, IWDT, Voltage Monitor 1/2, VBATT + * SRAM parity/ECC, BUS slave/master error, Stack pointer Monitor + * Low Power mode return + */ + +.equ RA4_ICU_IELSR, 0x40006300 /* ICU Event Link Setting Register n (IELSRn) = IELSR + 4n */ +/* + 13.2.6 ICU Event Link Setting Register n (IELSRn) + * IELS[7:0] - ICU Event Link Selec R/W; 0 = disabled, otherwise see 13.3.2 Event Table + * IR[16] - Interrupt Status Flag R/(W); write 0 to clear request + * DTCE[24] - DTC Activation Enable R/W; activates DTC instead of NVIC +*/ \ No newline at end of file From de9fa65088477fe04ad9daeaae8a4ed5637df8ba Mon Sep 17 00:00:00 2001 From: Martin Kobetic Date: Wed, 15 Apr 2026 23:11:26 -0400 Subject: [PATCH 2/2] wip --- arm/isr.s | 34 ++++++++++++++++--------- arm/mcu/ra4m1/isr.s | 3 --- arm/mcu/ra4m1/vectors.s | 2 +- arm/mcu/ra4m1/words/agt.s | 52 ++++++++++++++++++++++++++++----------- arm/system.s | 24 +++++++++++++++--- 5 files changed, 81 insertions(+), 34 deletions(-) delete mode 100644 arm/mcu/ra4m1/isr.s diff --git a/arm/isr.s b/arm/isr.s index d857e351..de29bd68 100644 --- a/arm/isr.s +++ b/arm/isr.s @@ -1,27 +1,37 @@ +/* + ARMv7-M Architecture Reference Manual: B1.5 exception model + + Exception entry: + 1) the hardware saves eight 32-bit words to the stack (non FPU context*): + xPSR, ReturnAddress(R15), LR(R14), R12, R3, R2, R1, R0 + * non-FPU => CONTROL[2].FPCA = 0 + 2) EXC_RETURN code (0xFFFFFF??) is loaded into LR (indicates return mode, stack register, saved stack frame type) + + Exception return when EXC_RETURN is loaded into PC via (LDM/POP, LDR PC or BX), e.g. BX LR: + 1) Restores registers from the saved stack frame + 2) Resumes execution at return address (unless Preempted or Tail-chaining) + + Global enable/disable interrupts instructions (priviledged more only): + CPSID i ; Disable interrupts and configurable fault handlers (set PRIMASK) + CPSID f ; Disable interrupts and all fault handlers (set FAULTMASK) + CPSIE i ; Enable interrupts and configurable fault handlers (clear PRIMASK) + CPSIE f ; Enable interrupts and fault handlers (clear FAULTMASK) + */ + .thumb_func nullhandler: - push {lr} - push {r1} ldr r1, =#48 SEMIT r1 mrs r1, ipsr add r1, #48 @ +"0" SEMIT r1 - - pop {r1} - pop {pc} + bx lr .thumb_func faulthandler: - push {lr} - push {r1} - ldr r1, =#70 @ F SEMIT r1 mrs r1, ipsr adds r1, #48 @ +"0" SEMIT r1 - pop {r1} - pop {pc} - -.ltorg + bx lr diff --git a/arm/mcu/ra4m1/isr.s b/arm/mcu/ra4m1/isr.s deleted file mode 100644 index 9186c7e6..00000000 --- a/arm/mcu/ra4m1/isr.s +++ /dev/null @@ -1,3 +0,0 @@ -# fall back to nullhandler -.include "arm/isr.s" - diff --git a/arm/mcu/ra4m1/vectors.s b/arm/mcu/ra4m1/vectors.s index 5c2e589e..c04c2ed7 100644 --- a/arm/mcu/ra4m1/vectors.s +++ b/arm/mcu/ra4m1/vectors.s @@ -7,7 +7,7 @@ IRQ_VECTORS: ARM_ICTR.INTLINESNUM=0 => 32 interrupts */ -.word 0 @ 16: ICU.IELSR0 +.word led_handler @ 16: ICU.IELSR0 = AGT0 .word 0 @ 17: ICU.IELSR1 .word 0 @ 18: ICU.IELSR2 .word 0 @ 19: ICU.IELSR3 diff --git a/arm/mcu/ra4m1/words/agt.s b/arm/mcu/ra4m1/words/agt.s index 70f8bcb5..18e92008 100644 --- a/arm/mcu/ra4m1/words/agt.s +++ b/arm/mcu/ra4m1/words/agt.s @@ -1,7 +1,10 @@ /* - RA4M1 Group: User Manual: 23. Low Power Asynchronous General Purpose Timer (AGT) + Use AGT0 timer as an interrupt source. */ +/* + RA4M1 Group: User Manual: 23. Low Power Asynchronous General Purpose Timer (AGT) + */ .equ RA4_AGT0_AGT, 0x40084000 /* AGT0 Counter Register [15:0] R/W */ .equ RA4_AGT1_AGT, 0x40084100 /* AGT1 Counter Register [15:0] R/W */ .equ RA4_AGT0_AGTCMA, 0x40084002 /* AGT0 Compare Match A Register [15:0] R/W */ @@ -44,25 +47,46 @@ .equ RA4_AGTO_AGTIOSEL, 0x4008400F /* AGT0 Pin Select Register */ .equ RA4_AGT1_AGTIOSEL, 0x4008410F /* AGT1 Pin Select Register */ -CODEWORD "agt0.init", AGT0_INIT /* ( u1 u2 -- ) initialize AGT0 as millisecond counter to generate interrupt u2 every u1 ms */ - @ validate and prepare TOS as IELSR offset - cmp TOS, #32 - blo 1f @ unsigned < 32 - throw -666 -1: - lsl TOS, #2 @ multiply by 4 +.equ INT_AGT0, 0 @ AGT0 interrupt number + +CODEWORD "agt0.init", AGT0_INIT /* ( u -- ) initialize AGT0 as millisecond counter to generate interrupt every u ms */ + @ enable interrupt in NVIC + ldr r0, =ARM_NVIC_ISER + mov r1, 1< ~ 1ms period + mov r1, #0x05 @ 1/32 clock divisor => ~ 1ms tick strb r1, [r0] ldr r0, =RA4_AGT0_AGT - popnos r1 @ set interrupt period to u1 milliseconds - strb r1, [r0] + strb TOS, [r0] @ set interrupt period to u1 milliseconds loadtos NEXT END AGT0_INIT + +CODEWORD "agt0.start", AGT0_START /* ( -- ) start the interrupt timer */ + ldr r0, =RA4_AGT0_AGTCR + mov r1, #1 @ TSTART = 1 + str r1, [r0] + NEXT +END AGT0_START + +CODEWORD "agt0.stop", AGT0_STOP /* ( -- ) stop the interrupt timer */ + ldr r0, =RA4_AGT0_AGTCR + mov r1, #1 @ TSTART = 0 + str r1, [r0] + NEXT +END AGT0_STOP + +.thumb_func +led_handler: /* flip the LED state, assume LED is initialized as per led.s */ + ldr r0, =RA4_P102PFS + ldrb r1, [r0] @ read PODR bit + eor r1, #1 @ flip PODR bit + strb r1, [r0] + bx lr diff --git a/arm/system.s b/arm/system.s index c443d16c..b85a25b2 100644 --- a/arm/system.s +++ b/arm/system.s @@ -1,6 +1,7 @@ -/* ARMv7M System Memory Region 0xE0000000-0xFFFFFFFF - Ref: ARMv7-M Architecture Reference Manual */ - +/* + ARMv7M System Memory Region 0xE0000000-0xFFFFFFFF + Ref: ARMv7-M Architecture Reference Manual +*/ /* B3.2.2 System control and ID registers (System Control Space SCS) */ .equ ARM_CPUID, 0xE000ED00 /* CPUID Base Register */ .equ ARM_ICSR, 0xE000ED04 /* Interrupt Control Register */ @@ -12,7 +13,7 @@ .equ ARM_SHPR2, 0xE000ED1C /* System Handler Priority Register */ .equ ARM_SHPR3, 0xE000ED20 /* System Handler Priority Register */ .equ ARM_SHCSR, 0xE000ED24 /* System Handler Control and State Register */ -.equ ARM_CFSR, 0xE000ED28 /* Configurable Fault Status Register */ +.equ ARM_CFSR, 0xE000ED28 /* Configurable Fault Status Register (UFSAR, BFSR, MMFSR) */ .equ ARM_HFSR, 0xE000ED2C /* HardFault Status Register */ .equ ARM_DFSR, 0xE000ED30 /* Debug Fault Status Register */ .equ ARM_MMFAR, 0xE000ED34 /* MemManage Fault Address Register */ @@ -33,3 +34,18 @@ .equ ARM_NVIC_IABR, 0xE000E300 /* Interrupt Active Bit Registers (0-15), bit per interrupt */ .equ ARM_NVIC_IPR, 0xE000E400 /* Interrupt Priority Registers (0-123), byte per interrupt */ +CODEWORD "int+", INTPLUS /* ( -- ) enable interrupts */ + cpsie i + NEXT +END INTPLUS + +CODEWORD "int-", INTMINUS /* ( -- ) disable interrupts */ + cpsid i + NEXT +END INTPLUS + +CODEWORD "int?", INTQ /* ( -- f ) f == interrupts enabled */ + savetos + mrs TOS, PRIMASK + NEXT +END INTQ