-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
After spending a couple of days chasing this down, I've discovered that attempting to use hw_set_bits (or hw_clear_bits, or hw_xor_bits) with the DMA INTS0/INTS1 interrupt flag register causes ALL of the active channel interrupts to be cleared, not just the ones in the bitmask. This happens even when an empty bitmask is used.
The correct behavior is obtained by simply assigning a bitmask to the register, e.g. dma_hw->ints0 = 1 << channel_num
. Unfortunately the current implementation of dma_irqn_acknowledge_channel uses hw_set_bits.
Discussion: https://forums.raspberrypi.com/viewtopic.php?p=2029939
Minimal reproduction: https://github.com/NomiChirps/missed_interrupt
The DMA INTS0/INTS1 register is marked as "WC" type in the RP2040 datasheet:
WC
This is a single bit that is typically set by a piece of hardware and then written to by the processor to clear the bit. The
bit is cleared by writing a 1, using either a normal write or the clear alias. See Section 2.1.2 for more information about
the clear alias.
So it's advertised that hw_clear_bits() should work with this register, and not clear that hw_set_bits() does anything well-defined. My testing has found that none of the hw_*_bits() aliases function as advertised here, though; they all clear the entire register no matter what bitmask is used.
In conclusion...
- I'd be happy to author a pull request to correct dma_irqn_acknowledge_channel, if you'd like.
- I think it might be worth checking to make sure no other "WC"-typed registers are accidentally misused(?) this way by the SDK.
- It's a mystery why hw_clear_bits() doesn't work with this register, although the data sheet seems to advertise that it should.
Thanks for reading :)