PWM interrupt on edge of IP

Is there any way for the Interrupt Pending (IP) bits of the PWM block to respond to changes (edges) of their trigger states, not only the levels?

In case of the GPIO block, there are the four registers GPIO_RISE_IP (0x1C), GPIO_FALL_IP (0x24), GPIO_HIGH_IP (0x2C), and GPIO_LOW_IP (0x34) It would be very nice if this functionality exists in the PWM block as well.

Using a 16 MHz clock (hfx), the PWM is set up like this:

  pwm1_cfg = 0;  // 0x10025000
  pwm1_count = 0;  // 0x10025008
  pwm1_scount = 0;  // 0x10025010
  pwm1_cmp0 =  3999;  // 0x10025020
  pwm1_cmp3 =  2000;  // 0x1002502C. 50% duty cycle
  pwm1_cfg = (PWM_CFG_ENALWAYS | PWM_CFG_DEGLITCH | PWM_CFG_ZEROCMP | 0);  // scale 0..15

External (PLIC) interrupt is set up like this:

  # enable external interrupt source
  lui t0, %hi(PLIC_ENA)  # 0x0C002000
  addi t0, t0, %lo(PLIC_ENA)
  addi t1, zero, 15  # 15 = 47 mod 32
  sw t1, 4(t0)       # 4 = (47 div 32) * 4
  # prioritize external interrupt source
  lui t0, %hi(PLIC_PRIO)  # 0x0C000000
  addi t0, t0, %lo(PLIC_PRIO)
  addi t1, zero, 188  # 188 = 47 * 4
  add t0, t0, t1
  addi t2, zero, 7  # 7 = highest prio
  sw t2, 0(t0)
  # define external interrupt threshold level
  lui t0, %hi(PLIC_THRESHOLD)  # 0C200000
  addi t0, t0, %lo(PLIC_THRESHOLD)
  addi t1, zero, 0  # 0=permit-all-nonzero-prio
  sw t1, 0(t0)
  # clear external interrupt pending bit
  lui t0, %hi(CSR_MIP_MEIP)  # bit [11] 0x00000800
  addi t0, t0, %lo(CSR_MIP_MEIP)
  csrrc zero, mip, t0
  # enable external interrupt source
  lui t0, %hi(CSR_MIE_MEIE)  # bit [11] 0x00000800
  addi t0, t0, %lo(CSR_MIE_MEIE)
  csrrs zero, mie, t0
  # enable interrupts
  csrrsi zero, mstatus, CSR_MSTATUS_MIE  # bit [3] 0x00000008

The claim/complete process is invoked by mtvec and is being performed as usual:

  lui t0, %hi(PLIC_CLAIM)    # 0x0C2000004
  addi t0, t0, %lo(PLIC_CLAIM)
  lw t1, 0(t0)               # act of reading clears pending bit
  addi sp, sp, -16   # alloc stack frame
  sw ra, 12(sp)      # save return addr
  sw t1, 8(sp)       # save int source id
  sw t0, 4(sp)       # save claim/complete reg
  jal plic_pwm1_3
  lw t0, 4(sp)       # restore claim/complete reg
  lw t1, 8(sp)       # restore int source id
  lw ra, 12(sp)      # restore return addr
  addi sp, sp, 16    # dealloc stack frame
  sw t1, 0(t0)               # signal claim complete

It seems to make no difference whether or not the PWM IP bit is cleared down when servicing the interrupt – the interrupt repeatedly triggers for as long as the comparator output is high.

plic_pwm1_3:  # plic source id 47
  # this does not stop re-trigger of interrupt
  lui t0, %hi(PWM1_BASE)  # 0x10025000
  lw t1, PWM_CFG(t0)  # 0x00
  lui t2, %hi(~PWM_CFG_CMP3IP)  # bit [31] 0x80000000
  addi t2, t2, %lo(~PWM_CFG_CMP3IP)
  and t1, t1, t2
  sw t1, PWM_CFG(t0)  # clear
  # marker pulse, for easy oscilloscope visualization
  lui t0, %hi(GPIO_BASE)
  lw t1, GPIO_OUT_VAL(t0)
  xori t1, t1, MARKER_BIT
  sw t1, GPIO_OUT_VAL(t0)
  xori t1, t1,DEMO_BIT
  sw t1, GPIO_OUT_VAL(t0)

Any suggestions, @mwachs5 or others? I can only think of using another PWM comparator, arranged to generate a narrow (non-50% duty cycle) pulse.

A picture of the “marker pulse” and its unwanted re-triggers is shown below. In this picture, PWM1_1 is set for 50% duty cycle with its pwm1_cmp1 value as 2000, and pwm1_cmp3 set for a small pulse (small duty cycle) with pwm1_cmp3 = (pwm1_cmp0 + 1) - 300. Shown in the picture PWM1_1 has been inverted using GPIO register OUT_XOR=1.