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)
nop
nop
nop
nop
nop
xori t1, t1,DEMO_BIT
sw t1, GPIO_OUT_VAL(t0)
#
ret
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.