CH32V003 fast interrupt (PFIC) features - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 20, 2023, 10:12:38 pm
content: I've been trying to understand the CH32V003's fast interrupt feature, particularly the hardware prologue/epilogue (HPE) feature. It's a bit difficult because of the poor language used in the reference manual. I want to confirm I'm understanding things correctly.As I understand it, HPE is a feature that will, when an interrupt occurs, automatically (in hardware) save a certain set of 10 registers to the stack, and restore them again afterwards, so that the ISR doesn't have to do this with code in a function prologue and epilogue. This reduces interrupt latency, because saving/restoring 10 registers takes a certain amount of time, right?HPE appears to be a hardware feature that isn't enabled by default, and you have to turn it on by setting the HWSTKEN bit of the INTSYSCR register. For a while I couldn't figure out why none of the example code from WCH does this, nor why any of the peripheral or core headers even mention this register. However, I realised that it is the startup assembly code that actually enables HPE, along with interrupt nesting (INESTEN):Code:li t0, 0x3csrw 0x804, t0(0x804 is the address of the INTSYSCR register. I presume it is referred to by address and not by name as the register is a non-standard CSR, and thus has no assembler mnemonic. HWSTKEN and INESTEN are bits 0 and 1 of the register.)Asbrucehoult mentioned in my other recent thread, when using mainstream GCC, apparently I can take advantage of HPE by declaring an ISR as__attribute__((naked))to avoid the usual compiler-generated prologue/epilogue, so long as I manually include the appropriatemretinstruction to return from the function. I presume this what the customised GCC from MounRiver IDE automatically does when specifying__attribute__((interrupt("WCH-Interrupt-fast")))on an ISR? Or is it doing something different or additional?If Ididn'twant to use HPE (although I do), could I just comment-out the aforementioned lines in the startup assembly code, and then simply declare my ISRs with just__attribute__((interrupt()))alone?Also, on a related note, am I correct in understanding that the vector-table-free (VTF) feature allows for even lower interrupt latency by bypassing the interrupt vector table when an interrupt occurs, because it will look at a VTF register for the address to jump to instead? It appears that the CH32V003 supports assigning up to two IRQs to the VTF feature. You do so by writing the IRQ number to one register, and the ISR address (plus enable flag in LSb) to another register. Something like the following perhaps?Code:uint32_t func_addr = &SysTick_Handler;PFIC->VTFIDR = SysTicK_IRQn;PFIC->VTFADDR = (func_addr & 0xFFFFFFFE) | 0x1;

author: newbrain
author_rank: Super Contributor
timestamp: February 21, 2023, 12:25:10 pm
content: From your description, I would imagine the hardware stacking and vector table free functionalities to be very similar to the ones of the ch32v307.Seethis post of minefor some tests I had done on that MCU.HTH

author: uliano
author_rank: Regular Contributor
timestamp: February 21, 2023, 04:25:30 pm
content: I'm trying to follow you and learn something.I'm not proficient in using naked toochain on these chips so I'm sticking to Mounriver Studio, at leas for the moment, so the following is with gcc8.2 from WCH.the interrupt is translated in this wayCode:void EXTI7_0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));void EXTI7_0_IRQHandler(void){GPIOD->BSHR = GPIO_Pin_4;GPIOD->BCR = GPIO_Pin_4;EXTI_ClearITPendingBit(EXTI_Line0);}00000222 <EXTI7_0_IRQHandler>:222:400117b7luia5,0x40011226:4741lia4,16228:40e7a823swa4,1040(a5) # 40011410 <__global_pointer$+0x20010be8>22c:40e7aa23swa4,1044(a5)230:4505lia0,1232:2425jal45a <EXTI_ClearITPendingBit>234:30200073mretand with HWSTKEN enabled (as per their startup.S) I get 416 ns or 20 clock cycles to the rising edge of pin D4.Then things start getting foggy to me. I commented out the __attribute__ and got this translationCode:00000222 <EXTI7_0_IRQHandler>:222:e7fff2efjalt0,a0 <__riscv_save_0>226:400117b7luia5,0x4001122a:4741lia4,1622c:40e7a823swa4,1040(a5) # 40011410 <__global_pointer$+0x20010be8>230:40e7aa23swa4,1044(a5)234:4505lia0,1236:241djal45c <EXTI_ClearITPendingBit>238:bd8djaa <__riscv_restore_0>000000a0 <__riscv_save_0>:a0:1151addisp,sp,-12a2:c026sws1,0(sp)a4:c222sws0,4(sp)a6:c406swra,8(sp)a8:8282jrt0000000aa <__riscv_restore_0>:aa:4482lws1,0(sp)ac:4412lws0,4(sp)ae:40a2lwra,8(sp)b0:0131addisp,sp,12b2:8082retand set the HWSTKEN to 0 but, unfortunately, now it doesn't run as expected (I get only one pulse and then the interrupt isn't triggered anymore). For the record the first interrupt is after 729 ns or 35 clock cycles.To add fog over fog if I compile with __attrubute__ and HWSTKEN=0 it unexpectedly runs, timing 374 ns or 18 clock cycles. Here I have an hypothesis: the program may be so simple that failing to save the register doesn't affect it.

author: jnk0le
author_rank: Regular Contributor
timestamp: February 21, 2023, 06:32:47 pm
content: They released processor manual for the one in v003http://www.wch-ic.com/downloads/QingKeV2_Processor_Manual_PDF.htmlV2 HW stacker is pushing similarly to cortex-m. The rest are doing some kind of shadow registers like ARM FIQ.Quote`mret` is missing, so no more interrupts and a bogus return.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 21, 2023, 07:15:43 pm
content: Quote from: newbrain on February 21, 2023, 12:25:10 pmThat explains a lot, thank you. Yes, seems very similar.Quote from: uliano on February 21, 2023, 04:25:30 pmThat's probably to be expected, because you aren't telling the compiler that the function is an ISR any more, so it doesn't know it needs to insert the proper prologue/epilogue code to save/restore the set of caller-saved registers, so your ISR code is probably clobbering values in registers that were expected not to have changed when the ISR returns. The compiler is just adding a regular prologue/epilogue to save/restore callee-saved registers.And yes, as jnk0le said, there is also no proper return - 'ret' is not appropriate for returning from an ISR.I'm still unclear as to why specifically 'mret' is used for returning from ISRs. Something to do with returning to or from execution in 'machine' mode? But given the CH32V003 always operates only in machine mode...Quote from: uliano on February 21, 2023, 04:25:30 pmYou were compiling with -msave-restore, yes? I presume having this is the result of that option that uses "smaller but slower prologue and epilogue code that uses library function calls".

author: uliano
author_rank: Regular Contributor
timestamp: February 23, 2023, 07:02:58 am
content: I did some homework and got some progress. For some reason I thought that theEXTI7_0_IRQHandlerwas already defined as interrupt somewhere in the headers and so I commented out the line with__attribute__((interrupt("WCH-Interrupt-fast")))obtaining a standard function. Once understood that, by using__attribute__((interrupt()))I got a regular interrupt with the 10 register pushed in the stack and could measure the following:withWCH-Interrupt-fastand HWSTKEN=1 -> 20 clock cycles;withoutWCH-Interrupt-fastand HWSTKEN=0 -> 39 clock cycles;withoutWCH-Interrupt-fastand HWSTKEN=1 -> 41 clock cycles.This means 2 cycles for the fast saving versus the 21 cycles for the standard register push code. So far so good.Then I tried to activate VTF (Vector Table Free) interrupt (in combination with WCH-Interrupt-fast) with this code:Code:PFIC->VTFIDR = EXTI7_0_IRQn;PFIC->VTFADDR = ((uint32_t)&EXTI7_0_IRQHandler) | 1;but, alas, nothing happens: I still measure the same 20 cyclesAny suggestion?

author: BadeBhaiya
author_rank: Regular Contributor
timestamp: February 23, 2023, 07:17:08 am
content: Sorry to butt into the thread.Just curious what is the programming/flashing hardware like? I read the datasheet and it mentions a single-wire debug interface. Is it logic level UART or have their rolled out something of their own?

author: uliano
author_rank: Regular Contributor
timestamp: February 23, 2023, 07:28:44 am
content: Quote from: BadeBhaiya on February 23, 2023, 07:17:08 amhttps://it.aliexpress.com/item/1005004881582037.htmlfor ch32v003 only GND, VDD and SWDIO are needed.Here you can find more detailshttps://github.com/openwch/ch32v003/blob/main/RISC-V%20QingKeV2%20Microprocessor%20Debug%20Manual.pdf

author: Sacodepatatas
author_rank: Regular Contributor
timestamp: February 24, 2023, 11:00:50 pm
content: It seems to me that the 1-wire debug WCH interface has "borrowed" some ideas from the stm8s SWIM interface.https://www.st.com/resource/en/user_manual/cd00173911-stm8-swim-communication-protocol-and-debug-module-stmicroelectronics.pdf