CH32V003 interrupt nesting - Page 1
Forum section: electronics / general

author: Stan6314
author_rank: Newbie
timestamp: February 10, 2025, 07:51:29 pm
content: I have a problem with a nested interrupt on the CH32V003. I use MounRiver Studio II.I need to generate 2 signals in the processor in exact time sequence.Timer TIM1 runs with a set period of 1500 pulses in CH32V003. Compare/Capture OC1 is connected to timer TIM1, which creates a PWM 100 pulses wide. I would need to be able to perform another program action during the PWM, for example, at time 500. I connected OC2 to generate an interrupt. This works fine.The problem is that the moment the interrupt is triggered fluctuates slightly. Unfortunately, RISC-V processor instructions do not last the same amount of time. So it occurred to me that, for example, using OC3, I would trigger another interrupt at time 490 consisting only of a series of NOP instructions. The interrupt from OC2, which arrives at time 500, will then hit one of the NOP instructions and the fluctuation will disappear.I can't implement this function and I haven't found a similar example. Could someone please help me with a similar example where nested interrupts are created using a timer and, for example, its OC2 and OC3 modules. The first one only has a synchronization function and the nested second one then performs the appropriate action.Thanks for your help.

author: brucehoult
author_rank: Super Contributor
timestamp: February 11, 2025, 01:59:14 am
content: Seems like a funny way to do it.If you're prepared to take an interrupt a little early (e.g. at 490 as you suggest) with possible jitter, why not then simply grab the current timer value, subtract it from 500 minus a couple, and JR into a series of NOPs so that you execute the instruction after the last NOP precisely at time 500?

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 11, 2025, 10:32:41 am
content: What amount of jitter are you experiencing? Like, how tight do you need the timing to be? Are we talking hundreds, tens, single-digit nanoseconds?What clock source are you running the MCU from? Internal HSI or external crystal? Have you tried running the CPU at 48 MHz? Faster clock speed will obviously result in quicker execution of instructions, so any jitter caused by having to wait for completion of an arbitrary instruction before interrupt should be minimised at the maximum clock speed. Also note that the CPU runs from HCLK, so if you have your RCC HPRE divider at an unexpected value, it may be running slower than you think (default is /3).Regarding interrupts, have you tried VTF for your OC2 interrupt? You configure a special register with the interrupt number and ISR address, which then enables it to skip the vector table lookup when that interrupt occurs. This minimises ISR execution latency. It doesn't make enough difference for regular use to be worth it, but may help in your situation.I think the problem with your OC2/OC3 interrupt idea is possibly that because the IRQ is the same for both (TIM1_CC_IRQn, 37), you can't get execution of one to pre-empt or take priority over the other, because they're both instances of the same interrupt, just occurring at different times. At least, that's my understanding of the PFIC interrupt priority system. I might be wrong.

author: Stan6314
author_rank: Newbie
timestamp: February 12, 2025, 08:44:55 pm
content: Thank you very much for the help from both of you. The idea of ​​using the "jr" instruction seemed to me to be a simple and ingenious solution to my problem. Unfortunately, it turned out that in this case the problem is more complicated.I am trying to output data to a VGA monitor from a CH32V003. I thought I would proceed as follows:1) The processor runs at a frequency of 48 MHz.2) I will start the TIM1 timer with a period of about 1500 pulses without a prescaler.3) Using CC1, I will make a PWM output for automatic generation of a horizontal synchro pulse.4) In the TIM1_UP interrupt, the lines will be counted and after 525 lines a software vertical pulse will be made.5) Using CC2, which will generate the TIM_IT_CC2 interrupt, I will start a DMA transfer at the right moment during the line.6) The DMA channel will fulfill the SPI, which will make a video signal on the MOSI output. The SPI frequency is divided by 4 (12 MHz).I managed to get everything up and running fine, but I noticed that some lines on the screen were slightly shifted to the right (about 1 pixel). Since I had an empty main loop, I assumed it was a longer jump instruction that always had to be completed. I tried adding different numbers of NOPs to the main loop. The shifted lines really changed based on this.Unfortunately, I found out that the problem is more complicated. The CPHA and CPOL settings also affect the line shift. The divider in SPI is probably always running. It depends on the moment when data is written to the data register. Then the clock phase for sending data must come. I probably can't reset the divider, so the moment of data insertion and data output from MOSI may be slightly out of sync. I probably won't fix this.Anyway, thanks again for your help.

author: brucehoult
author_rank: Super Contributor
timestamp: February 13, 2025, 12:51:16 am
content: VGA, eh?CH32V003 doesn't have anywhere near enough RAM for even a b&w 640x480 frame buffer (37.5k) or even 320x240 (9.375). So I assume you're using a character generation approach, and probably no more than 320x240 resolution too.Just like the Olimex RVPC.https://github.com/OLIMEX/RVPC/blob/main/SOFTWARE/Demo-VGA/src/vga.c

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 13, 2025, 01:01:02 am
content: Yes, at best character/sprite-based generation. Not necessarily ultra useful, but possibly a fun challenge.

author: brucehoult
author_rank: Super Contributor
timestamp: February 13, 2025, 01:39:21 am
content: I don't know if you're aware of the RVPC, a €1.00 kit for self-soldering containing an 8 pin CH32V003 as the only  active component.It implements both PS/2 keyboard support and bit-banged VGA output, not even using SPI as that's not exposed on the 8 pin package. almost ... there's a transistor to drive the piezo speaker

author: Stan6314
author_rank: Newbie
timestamp: February 16, 2025, 08:37:01 pm
content: Thanks for all the advice. I know RVPC and I have one with me. But in RVPC the VGA signal generation is using software.Fortunately, I think I have already found a solution to my problem. I am still working on it, but when it is possible to publish it (that is, I will not be ashamed of the source code), I will definitely introduce it to you.

author: bson
author_rank: Unknown
timestamp: February 26, 2025, 06:54:53 pm
content: Quote from: brucehoult on February 11, 2025, 01:59:14 amOr just busy wait, polling the timer.

author: Stan6314
author_rank: Newbie
timestamp: July 20, 2025, 11:20:57 am
content: As I promised, I would like to show the solution I came up with. For a stable VGA image, it turned out to be the easiest to keep the SPI output running permanently and "feed" the SPI module constantly using DMA in circular mode.The buffer for DMA is 43 bytes. 32 bytes are a useful signal and 11 bytes are empty characters 0x00 for darkening the sides of the image.Everything was solved by appropriate settings of 3 peripherals - SPI, DMA and TIM1. SPI and DMA continue to run after the settings without program intervention.The entire VGA display operation is performed in a small function TIM1_UP_IRQHandler, where data is prepared for display every even line. 25 character lines (8*8 characters) are displayed, spread out into 400 lines on the screen. Vertical synchronization is done in software in this interrupt.Horizontal synchronization is created by a PWM module linked to TIM1. The only thing that needs to be ensured is the correct timing of the start of TIM1 and the DMA module. The time difference between their starts will determine the horizontal position of the image on the screen.Not only the VGA interface and the PS2 keyboard have been included in the memory, but also the Tiny BASIC interpreter, which processes the program stored in the serial EEPROM on I2C.The project is here:https://github.com/Stan6314/TinyBasRVHopefully this will be useful to someone.

author: voltsandjolts
author_rank: Unknown
timestamp: July 20, 2025, 01:04:45 pm
content: TIM1_UP_IRQHandler