When I was looking into the sample codes of ch32v103 on the git hub as written in my previous post, I noticed that the sample codes are using a non-standard function attribute __attribute__
((interrupt("WCH-Interrupt-fast")))
for the interrupt routines. This unsupported attribute resulted in the following warning message during the build.
warning: argument to 'interrupt' attribute is not "user", "supervisor", or "machine" [-Wattributes]
To find out how to handle the interrupt routine with the toolchain that I built, this time, I picked up an interrupt example in the ch32v103/EVT/EXAM/EXTI/EXTI0
(GitHub).
git clone https://github.com/openwch/ch32v103.git<br>cd ch32v103/EVT/EXAM/EXTI/EXTI0/User
Then I created a Makefile in the ch32v103/EVT/EXAM/EXTI/EXTI0/User
directory in the same way as before. Without modifying the ch32v10x_it.c
(GitHub), the compiler gave me the warning message I mentioned and generated the following assembly code for EXTI0_IRQHandler()
– one of the interrupt routines in the ch32v10x_it.c
(Snipped from this exiti0.lst).
000018d8 <EXTI0_IRQHandler>:
18d8: 1141 addi sp,sp,-16
18da: 4505 li a0,1
18dc: c606 sw ra,12(sp)
18de: 2c3d jal 1b1c <EXTI_GetITStatus>
18e0: c911 beqz a0,18f4 <EXTI0_IRQHandler+0x1c>
18e2: 6509 lui a0,0x2
18e4: fe450513 addi a0,a0,-28 # 1fe4 <__sf_fake_stdin+0xa4>
18e8: 94ffe0ef jal ra,236 <puts>
18ec: 40b2 lw ra,12(sp)
18ee: 4505 li a0,1
18f0: 0141 addi sp,sp,16
18f2: a491 j 1b36 <EXTI_ClearITPendingBit>
18f4: 40b2 lw ra,12(sp)
18f6: 0141 addi sp,sp,16
18f8: 8082 ret
18fa: a001 j 18fa <EXTI0_IRQHandler+0x22>
18fc: a001 j 18fc <EXTI0_IRQHandler+0x24>
This code will not work correctly since the compiler puts ret
at the end of the interrupt function. The following is the output from the compiler that came with the MounRiver Studio for the same EXTI0_IRQHandler()
with the non-standard function attribute __
attribute__
((interrupt("WCH-Interrupt-fast")))
(Snipped from this exiti0.lst).
000001ee <EXTI0_IRQHandler>:
1ee: 4505 li a0,1
1f0: 2629 jal 4fa <EXTI_GetITStatus>
1f2: c909 beqz a0,204 <EXTI0_IRQHandler+0x16>
1f4: 00002537 lui a0,0x2
1f8: c0850513 addi a0,a0,-1016 # 1c08 <_read+0xc>
1fc: 105000ef jal ra,b00 <puts>
200: 4505 li a0,1
202: 2e19 jal 518 <EXTI_ClearITPendingBit>
204: 30200073 mret
To get a similar result, I modified the function attribute for the three functions in the ch32v10x_it.c
.
// [original]
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void EXTI0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// [modified]
void NMI_Handler(void) __attribute__((interrupt("machine")));
void HardFault_Handler(void) __attribute__((interrupt("machine")));
void EXTI0_IRQHandler(void) __attribute__((interrupt("machine")));
I got the following output with this change (Snipped from this exiti0.lst).
000018da <EXTI0_IRQHandler>:
18da: 7139 addi sp,sp,-64
18dc: d62a sw a0,44(sp)
18de: 4505 li a0,1
18e0: de06 sw ra,60(sp)
18e2: dc16 sw t0,56(sp)
18e4: da1a sw t1,52(sp)
18e6: d81e sw t2,48(sp)
18e8: d42e sw a1,40(sp)
18ea: d232 sw a2,36(sp)
18ec: d036 sw a3,32(sp)
18ee: ce3a sw a4,28(sp)
18f0: cc3e sw a5,24(sp)
18f2: ca42 sw a6,20(sp)
18f4: c846 sw a7,16(sp)
18f6: c672 sw t3,12(sp)
18f8: c476 sw t4,8(sp)
18fa: c27a sw t5,4(sp)
18fc: c07e sw t6,0(sp)
18fe: 2ca9 jal 1b58 <EXTI_GetITStatus>
1900: c901 beqz a0,1910 <EXTI0_IRQHandler+0x36>
1902: 6509 lui a0,0x2
1904: 02050513 addi a0,a0,32 # 2020 <__sf_fake_stdin+0xa4>
1908: 92ffe0ef jal ra,236 <puts>
190c: 4505 li a0,1
190e: 2495 jal 1b72 <EXTI_ClearITPendingBit>
1910: 50f2 lw ra,60(sp)
1912: 52e2 lw t0,56(sp)
1914: 5352 lw t1,52(sp)
1916: 53c2 lw t2,48(sp)
1918: 5532 lw a0,44(sp)
191a: 55a2 lw a1,40(sp)
191c: 5612 lw a2,36(sp)
191e: 5682 lw a3,32(sp)
1920: 4772 lw a4,28(sp)
1922: 47e2 lw a5,24(sp)
1924: 4852 lw a6,20(sp)
1926: 48c2 lw a7,16(sp)
1928: 4e32 lw t3,12(sp)
192a: 4ea2 lw t4,8(sp)
192c: 4f12 lw t5,4(sp)
192e: 4f82 lw t6,0(sp)
1930: 6121 addi sp,sp,64
1932: 30200073 mret
1936: a001 j 1936 <EXTI0_IRQHandler+0x5c>
1938: a001 j 1938 <EXTI0_IRQHandler+0x5e>
I tested the outputted hex file with the CH32V103R Mini Evaluation board. I wired up a push switch to the GPIO PA0 pin as follows.
While the loop in the main()
function outputted Run at main
periodically to the UART output, the interrupt routine EXTI0_IRQHandler()
outputted Run at EXTI
whenever I pressed and released the button that I added.
In this way, I was able to make the interrupt routine work by applying the standard function attribute __
attribute__
((interrupt("machine")))
. It also increased the object size slightly compared with the object generated by MounRiver’s modified GCC (92bytes vs. 26bytes. @.text section).
I tried a combination of a function attribute __
attribute__
((naked()))
that will not generate prologue/epilogue codes to a specified function and an inline assembly routine to remove the instructions for pushing and popping registers to the stack and confirmed that it worked also. We should use the naked attribute carefully, as written here, though.
[Added on 2022-05-07]
I noticed that WCH explained their interrupt mechanism in the below YouTube video (The explanation starts from around 11min). It appears that they call it the “HPE mode.”
The Research of RISC-V for Embedded MCUs. – YouTube
[Added on 2022-06-24]
The following page might be also very useful to understand the interrupt of the CH32V series.
FreeRTOS on CH32V307 (imi.moe)