Introduction to Interrupts for PSoC 4 Hardware Blocks | Cypress Semiconductor
Introduction to Interrupts for PSoC 4 Hardware Blocks
July 01, 2013
With PSoC 4, new blocks in the device handle interrupts a bit differently than before with PSoC 3 and 5LP. The main difference is the usage of the Write-One-To-Clear methodology.
I'll use the TCPWM as an example of how this type of interrupt is used and controlled. The following are the APIs that are applicable to interrupts for the TCPWM:
void SetInterruptMode(uint32 interruptMask)
Used to control which interrupt sources are able to generate an interrupt. There are defined values for each of the sources. For the TCPWM an interrupt can be generated based on a terminal count or based on either a compare value or a capture. This function doesn't need to be called if the interrupt sources are configured using the component customizer. This function modifies the INTR_MASK register for the block.
This is the function that you want to call when the interrupt fires. It allows the interrupt routine to determine which interrupt source caused the interrupt. The same defined values are used to indicate which source caused the interrupt. This function returns the value of the INTR_MASKED register for the block.
Similar to the GetInterruptSourceMasked() function except it doesn't take into account which mask bits are enabled or disabled. This function is useful when polling for the condition to occur instead of being triggered by an interrupt. This function returns the value of the INTR register for the block.
void ClearInterrupt(uint32 interruptMask)
Once the condition has occured, the interrupt bit will stay set until the bit is cleared. This function is used to clear the specified bits. This is implemented by writing a one bit to the INTR register.
void SetInterrupt(uint32 interruptMask)
With this function the interrupt can be forced to occur without requiring the actual hardware condition to occur. It will cause the interrupt condition to be seen by the hardware and software in the same way as it would be if the actual hardware interrupt had occurred. This is useful to test out the operation of the interrupt code. This function writes to the INTR_SET register for the block.
To try this out I'm going to use the TCPWM configured as a PWM and configured to generate an interrupt at each terminal count. Note that in the customizer I've configured the PWM to generate an interrupt "On terminal count" so the SetInterruptMode() function doesn't need to be called.
To use the interrupt an Interrupt Service Routine (ISR) needs to be created. There are two options. Either a function can be created and tied to the interrupt using the StartEx() function from the interrupt component, or the provided interrupt routine that is provided with the interrupt component can be edited in the merge region. I recommend that you use the StartEx() implementation because it allows you to separate your code from the generated code.
I want to monitor when the ISR code is executing so I've created a software controlled pin (PWM_isr_active) that will be high during the execution of the interrupt.
Here's the first attempt at an ISR, but it is flawed:
Looking at the waveform that is generated for the PWM_isr_active signal in yellow and the PWM_out signal in blue, you can see that the interrupt is executing more rapidly than the PWM:
The problem is that the interrupt is not being cleared, so it executes as fast as it can over and over.
Here's a second attempt at an ISR and this one clears the interrupt source before returning from the interrupt:
The waveform now is exactly as expected. The ISR is triggered at the terminal count and shortly after that the pin has been written to indicate that the ISR is active. Then the interrupt completes and isn't called again until the next PWM period.:
If I wanted to debug the operation of my interrupt routine I could have also just triggered the interrupt without running the PWM. In this case however I do need to set the interrupt source since I'm not calling the PWM Start() function which sets the interrupt source based on the customizer setting:
The output from this test looks very similar, except that the PWM isn't running:
There are other variations that can also be used with this PWM example. A polled implementation could be done using GetInterruptSource(). If this function had been called instead of GetInterruptSourceMasked() then the value returned would have shown both bits set, since the compare and the terminal count happen during each PWM period and the interrupt mask is not used for this function.