<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/96200/pwm-interrupts-interrupt-priority-levels</link><description>Zephyr 3.2.99 - nRF Connect 2.2.0 
 
 We have a 4 digit 7 segment display that we use on one of our products. Instead of using something like timers to keep the display updated we designed it to use PWM interrupts instead. So every time an interrupt happens</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Tue, 26 Sep 2023 11:53:42 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/96200/pwm-interrupts-interrupt-priority-levels" /><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447700?ContentTypeID=1</link><pubDate>Tue, 26 Sep 2023 11:53:42 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:173757cf-979a-470c-b64d-d34adc8a7150</guid><dc:creator>ovrebekk</dc:creator><description>&lt;p&gt;My hat of to you Hugh, that is a much better solution. I will make sure to keep it in mind it for future reference&amp;nbsp;&lt;span class="emoticon" data-url="https://devzone.nordicsemi.com/cfs-file/__key/system/emoji/1f642.svg" title="Slight smile"&gt;&amp;#x1f642;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Best of luck James, hope you get this working nicely!&lt;/p&gt;
&lt;p&gt;Regards&lt;br /&gt;Torbjørn&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447696?ContentTypeID=1</link><pubDate>Tue, 26 Sep 2023 11:44:47 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:19652b83-4b13-4707-8f39-9513782ec03f</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Thank you all for the help and thank you hmolesworth for really explaining it and providing example code. Between you and&amp;nbsp;&lt;span&gt;Torbj&amp;oslash;rn I&amp;#39;m sure I&amp;#39;ll have enough to get it working properly. Kudos on the nice ascii art too, that looks like and must have taken a while. I appreciate it.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447693?ContentTypeID=1</link><pubDate>Tue, 26 Sep 2023 11:32:59 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:c67897fd-c734-46e4-8145-a5c0e259e43f</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;I edited the waveform notes to show active-low digit&amp;nbsp; selects which the sample code uses; the dead band prefixes the digit select. Making dead band wider is a useful way of dimming the display&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447603?ContentTypeID=1</link><pubDate>Tue, 26 Sep 2023 02:58:16 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0e237244-6225-4423-be50-e726e895e501</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;The dead band is actually free, just adjust the active time &amp;quot;on&amp;quot; for the digit selects slightly shorter than you were doing. Brightness control works exactly the same way; constant refresh frequency with less active digit time gives lower brightness. Here is a working example for the 4 digits; I just do a burst so the levels are easy to see on a &amp;#39;scope&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// These settings give active-low digit selects which remain high if the sequence stops
#define T_TOP_COUNT     4095            // 12-bit
#define DEAD_BAND_WIDTH  400
#define T_DEAD         (DEAD_BAND_WIDTH)
#define T_OFF         ((T_TOP_COUNT+1) | 0x8000)
#define T_DIGIT       (DEAD_BAND_WIDTH | 0x8000)
#define T_SEGMENT     ((DEAD_BAND_WIDTH/2) | 0x8000)
#define T_PERIODS       16

#include &amp;quot;nrf_drv_pwm.h&amp;quot;
#include &amp;quot;nrf_delay.h&amp;quot;

static nrf_pwm_values_individual_t PWM_DigitTable[] = {
    //   Index     DIGIT 1    DIGIT 2    DIGIT 3    DIGIT 4
    //   =====     ========== ========== ========== =========
    { /*   0  */   (T_DIGIT), (T_OFF),   (T_OFF),   (T_OFF)   },
    { /*   1  */   (T_OFF),   (T_DIGIT), (T_OFF),   (T_OFF)   },
    { /*   2  */   (T_OFF),   (T_OFF),   (T_DIGIT), (T_OFF)   },
    { /*   3  */   (T_OFF),   (T_OFF),   (T_OFF),   (T_DIGIT) },
};
// +--------+--------+-------+---------+
// |H       |E       |L       |P       |
// |.BC.EFG.|A..DEFG.|...DEF..|AB..EFGP|
// +--------+--------+-------+---------+
static nrf_pwm_values_individual_t PWM_SegmentTableABCD[] = {
    //   Index     Segment A    Segment B    Segment C    Segment D
    //   =====     ============ ============ ============ ============
    { /*   0  */   (T_OFF),     (T_SEGMENT), (T_SEGMENT), (T_OFF)     }, // &amp;#39;H&amp;#39;
    { /*   1  */   (T_SEGMENT), (T_OFF),     (T_OFF),     (T_SEGMENT) }, // &amp;#39;E&amp;#39;
    { /*   2  */   (T_OFF),     (T_OFF),     (T_OFF),     (T_SEGMENT) }, // &amp;#39;L&amp;#39;
    { /*   3  */   (T_SEGMENT), (T_SEGMENT), (T_OFF),     (T_OFF)     }, // &amp;#39;P&amp;#39;
};
static nrf_pwm_values_individual_t PWM_SegmentTableEFGP[] = {
    //   Index     Segment E    Segment F    Segment G    Segment P
    //   =====     ============ ============ ============ ============
    { /*   0  */   (T_SEGMENT), (T_SEGMENT), (T_SEGMENT), (T_OFF)     }, // &amp;#39;H&amp;#39;
    { /*   1  */   (T_SEGMENT), (T_SEGMENT), (T_SEGMENT), (T_OFF)     }, // &amp;#39;E&amp;#39;
    { /*   2  */   (T_SEGMENT), (T_SEGMENT), (T_OFF),     (T_OFF)     }, // &amp;#39;L&amp;#39;
    { /*   3  */   (T_SEGMENT), (T_SEGMENT), (T_SEGMENT), (T_SEGMENT) }, // &amp;#39;P&amp;#39;
};
#define NUM_PWM_ITERATIONS_DIGIT  ( sizeof(PWM_DigitTable)/sizeof(PWM_DigitTable[0].channel_0) )
#define NUM_PWM_ITERATIONS_7SEG   ( sizeof(PWM_SegmentTableABCD)/sizeof(PWM_SegmentTableABCD[0].channel_0) )

#define PIN_DIGIT_1 17  // LED1 Red
#define PIN_DIGIT_2 18  // LED2 Red
#define PIN_DIGIT_3 19  // LED3 Green
#define PIN_DIGIT_4 20  // LED4 Green

NRF_PWM_Type * const pNRF_PWM = NRF_PWM1;
#define PWM_IRQn PWM1_IRQn
static volatile bool mSequenceComplete = false;
static volatile uint32_t mPwmInterruptCounter = 0;

void PWM1_IRQHandler(void)
{
   // All enabled interrupts MUST be handled to avoid thrashing
   if (pNRF_PWM-&amp;gt;EVENTS_STOPPED)
   {
      pNRF_PWM-&amp;gt;EVENTS_STOPPED = 0;
   }
   if (pNRF_PWM-&amp;gt;EVENTS_SEQEND[0])
   {
      pNRF_PWM-&amp;gt;EVENTS_SEQEND[0] = 0;
      // Set flag to update brightness or 7-segment values in sequence 0
   }
   if (pNRF_PWM-&amp;gt;EVENTS_SEQEND[1])
   {
      pNRF_PWM-&amp;gt;EVENTS_SEQEND[1] = 0;
      // Set flag to update brightness or 7-segment values in sequence 1
   }
   if (pNRF_PWM-&amp;gt;EVENTS_LOOPSDONE)
   {
     pNRF_PWM-&amp;gt;EVENTS_LOOPSDONE = 0;
   }
   // Clear pending hardware register bus operations - Cortex-M4 issue
   __DSB();
   mSequenceComplete = true;
   mPwmInterruptCounter++;
}

void stuff(void)
{
   // If PWM is alive, disable it after stopping first before changing parameters
   if (pNRF_PWM-&amp;gt;ENABLE)
   {
      NVIC_DisableIRQ(PWM_IRQn);
      pNRF_PWM-&amp;gt;TASKS_STOP;
      // Clear pending hardware register bus operations - Cortex-M4 issue
      __DSB();
      // Using only sequence 0; as long as at least sequence is stopped proceed
      while ((pNRF_PWM-&amp;gt;EVENTS_STOPPED == 0) &amp;amp;&amp;amp; (pNRF_PWM-&amp;gt;EVENTS_SEQEND[0] == 0))
         ;
      pNRF_PWM-&amp;gt;ENABLE = 0;
   }

   // Configure PWM pins as High-Drive outputs, and set to 0
   nrf_gpio_pin_set(PIN_DIGIT_1);
   nrf_gpio_pin_set(PIN_DIGIT_2);
   nrf_gpio_pin_set(PIN_DIGIT_3);
   nrf_gpio_pin_set(PIN_DIGIT_4);
   nrf_gpio_cfg(PIN_DIGIT_1,  NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
   nrf_gpio_cfg(PIN_DIGIT_2,  NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
   nrf_gpio_cfg(PIN_DIGIT_3,  NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
   nrf_gpio_cfg(PIN_DIGIT_4,  NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
   // Wait to get clean signal for oscilloscope
   nrf_delay_ms(10);

   pNRF_PWM-&amp;gt;PRESCALER = 2; // Prescaler - Base clock frequenc: 0 == /1, 2 == /4 so 16MHz/4 -&amp;gt; 4MHz
   pNRF_PWM-&amp;gt;PSEL.OUT[0] = PIN_DIGIT_1;
   pNRF_PWM-&amp;gt;PSEL.OUT[1] = PIN_DIGIT_2;
   pNRF_PWM-&amp;gt;PSEL.OUT[2] = PIN_DIGIT_3;
   pNRF_PWM-&amp;gt;PSEL.OUT[3] = PIN_DIGIT_4;
   pNRF_PWM-&amp;gt;MODE = PWM_MODE_UPDOWN_Up;
   pNRF_PWM-&amp;gt;DECODER = PWM_DECODER_LOAD_Individual | (PWM_DECODER_MODE_RefreshCount &amp;lt;&amp;lt; PWM_DECODER_MODE_Pos);
   pNRF_PWM-&amp;gt;LOOP = T_PERIODS;
   pNRF_PWM-&amp;gt;COUNTERTOP = T_TOP_COUNT; // 16-bit Value up to which the pulse generator counter counts: 3-32767, Not used in waveform mode
   // Sequence 0:
   pNRF_PWM-&amp;gt;SEQ[0].CNT = NUM_PWM_ITERATIONS_DIGIT;
   pNRF_PWM-&amp;gt;SEQ[0].ENDDELAY = 0; // 24-bit
   pNRF_PWM-&amp;gt;SEQ[0].PTR = (uint32_t)PWM_DigitTable;
   pNRF_PWM-&amp;gt;SEQ[0].REFRESH = 0;
   // Sequence 1 (not used):
   pNRF_PWM-&amp;gt;SEQ[1].CNT = NUM_PWM_ITERATIONS_DIGIT;
   pNRF_PWM-&amp;gt;SEQ[1].ENDDELAY = 0;                // 24-bit
   pNRF_PWM-&amp;gt;SEQ[1].PTR = (uint32_t)&amp;amp;PWM_DigitTable[0];
   pNRF_PWM-&amp;gt;SEQ[1].REFRESH = 0;
   // Loop throgh digit cycle table T_PERIODS times then stop
   pNRF_PWM-&amp;gt;SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk;
   pNRF_PWM-&amp;gt;EVENTS_STOPPED = 0;                   // Response to STOP task, emitted when PWM pulses are no longer generated
                                                   // pNRF_PWM-&amp;gt;EVENTS_SEQSTARTED[0] = (0.0); // First PWM period started on sequence 0, 1
   pNRF_PWM-&amp;gt;EVENTS_SEQEND[0] = 0;                 // Emitted at end of every sequence 0, 1, when last value from RAM has been applied to wave counter
   pNRF_PWM-&amp;gt;EVENTS_SEQEND[1] = 0;
   pNRF_PWM-&amp;gt;EVENTS_SEQSTARTED[0] = 0;
   pNRF_PWM-&amp;gt;EVENTS_SEQSTARTED[1] = 0;
   pNRF_PWM-&amp;gt;EVENTS_PWMPERIODEND = 0; // Emitted at the end of each PWM period
   pNRF_PWM-&amp;gt;EVENTS_LOOPSDONE = 0;    // Concatenated sequences have been played the amount of times defined in LOOP.CNT
   // Disable all interrupts
   pNRF_PWM-&amp;gt;INTENCLR = 0x000000FEul;
   // Enable selected interrupts - best to SHORT the TASKS_STOP command and only interrupt on EVENTS_STOPPED
   pNRF_PWM-&amp;gt;INTENSET = PWM_INTEN_STOPPED_Msk; // EVENTS_STOPPED and EVENTS_SEQEND[0] and EVENTS_SEQEND[1]
   // Set interrupt priority and enable interrupt
   NVIC_SetPriority(PWM_IRQn, 6);
   NVIC_ClearPendingIRQ(PWM_IRQn);
   NVIC_EnableIRQ(PWM_IRQn);
   Start a burst of cycles
   pNRF_PWM-&amp;gt;ENABLE = 1;
   pNRF_PWM-&amp;gt;TASKS_SEQSTART[0] = 1;
   while(1)
      ;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The digit and segment sequence is as noted before; not sure if the segment is active low or active high so this sequence shows digit select active low and segment select active high; the example code uses active-low digit drives&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;//                        .BC.EFG.   A..DEFG.  ...DEF..  AB..EFGP                        +--- Optional blanking interval, change segment data here
//                       +-- START                                                       |
//                 !     |&amp;lt;------------------- Display Cycle 1 ---------------------&amp;gt;|   |   |&amp;lt;------------------- Display Cycle 2 ---------------------&amp;gt;|
//                 !     |                                            Optional blank |&amp;lt;-/~/-&amp;gt;|                                            Optional blank |&amp;lt;-/~
//                 !     |                                                           |       |                                                           |
//                 !     |&amp;lt;---- C1 ----&amp;gt;|&amp;lt;---- C2 ----&amp;gt;|&amp;lt;---- C3 ----&amp;gt;|&amp;lt;---- C4 ----&amp;gt;|       |&amp;lt;---- C1 ----&amp;gt;|&amp;lt;---- C2 ----&amp;gt;|&amp;lt;---- C3 ----&amp;gt;|&amp;lt;---- C4 ----&amp;gt;|
//                 !     |              |              |              |              |       |              |              |              |              |
//                 !     |              |              |              |              |       |              |              |              |              |
//                 !     | |&amp;lt;--- D1 ---&amp;gt;| |&amp;lt;--- D2 ---&amp;gt;| |&amp;lt;--- D3 ---&amp;gt;| |&amp;lt;--- D4 ---&amp;gt;|       | |&amp;lt;--- D1 ---&amp;gt;| |&amp;lt;--- D2 ---&amp;gt;| |&amp;lt;--- D3 ---&amp;gt;| |&amp;lt;--- D4 ---&amp;gt;|
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//   Dead Bands &amp;gt;  !  --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--         |    --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--         | &amp;lt; Dead Bands
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !       |              |            | |            | |            |         |              |            | |            | |            |
// ================/~/=====+            +===============================================/~/====+            +===============================================/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-1         !     | |     D1     | |            | |            | |            |       | |    D1      | |            | |            | |            |
//                 !     | +============+ |            | |            | |            |       | +============+ |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            |                |            | |            |       | |            |                |            | |            |
// ================/~/====================+            +================================/~/===================+            +================================/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-2         !     | |            | |     D2     | |            | |            |       | |            | |     D2     | |            | |            |
//                 !     | |            | +============+ |            | |            |       | |            | +============+ |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            |                |            |       | |            | |            |                |            |
// ================/~/===================================+            +=================/~/==================================+            +=================/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-3         !     | |            | |            | |     D3     | |            |       | |            | |            | |     D3     | |            |
//                 !     | |            | |            | +============+ |            |       | |            | |            | +============+ |            |
//                 ^     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            |                      | |            | |            | |            |
// ================/~/==================================================+            +==/~/=================================================+            +==/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-4         !     | |            | |            | |            | |    D4      |       | |            | |            | |            | |     D4     |
//                 !     | |            | |            | |            | +============+       | |            | |            | |            | +============+
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// Display &amp;quot;HELP&amp;quot;  !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//  &amp;#39;X&amp;#39;=DON&amp;#39;T CARE |     X+             X+=============X|            |X+=============XXXXXXXXX|            |X+=============X|            |X+=============X|
//                 !     X|    &amp;#39;H&amp;#39;      X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      XXXXXXXXX|    &amp;#39;H&amp;#39;     |X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      X|
// SEGMENT-A0      !     X|             X|             X|            |X|             XXXXXXXXX|            |X|             X|            |X|             X|
// ================/~/===X+=============X+             X==============X+             XXXX/~/XX==============X+             X==============X+             X==/~
//                 !      |              |            | |            | |            | |       |            | |            | |            | |            | |
//                 !      |              |            | |            | |            | |       |            | |            | |            | |            | |
//                 !     X+=============X+=============X|            |X+=============XXXXXXXXX+=============X+=============X|            |X+=============X|
//                 !     X|    &amp;#39;H&amp;#39;      X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      XXXXXXXXX|    &amp;#39;H&amp;#39;      X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      X|
// SEGMENT-G0      !     X|             X|             X|            |X|             XXXXXXXXX|             X|             X|            |X|             X|
// ================/~/===X+             X+             X==============X+             XXXX/~/XX+             X+             X==============X+             X==/~&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447423?ContentTypeID=1</link><pubDate>Mon, 25 Sep 2023 09:57:22 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:9fdc0312-ca19-4de5-9b97-6fa35cddd3c2</guid><dc:creator>ovrebekk</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;I believe the issue with offset between the channels occur because you are not starting the channels at exactly the same time. I would recommend changing the EGU setup a little to remedy this.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Essentially you can use two PPI channels to connect one of the EGU events to all three PWM start tasks, and then you just have to activate the corresponding EGU task to have all three PWM modules start in perfect sync.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;It might be you have to follow Hugh&amp;#39;s advice about a dead band as well. There is no simple mechanism in the PWM module to implement this unfortunately, but a couple of solutions exist:&lt;/p&gt;
&lt;p&gt;a) You can increase the size of the PWM buffers by a factor of X, and&amp;nbsp;increase&amp;nbsp;the playback speed by the same amount. Then you can use the last value of each group to implement a dead band. The drawback of this method is that you need quite large buffers if you want a small dead band. As an example if you want a dead band of 2% you would need to select an X value of 50, leading to higher memory consumption and a bit more CPU time to update the buffers.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;b) To avoid having to increase the buffers significantly you can use a timer to step the PWM modules manually, in an uneven manner. Now you just need to double the size of the buffers (adding an additional &amp;#39;dead band&amp;#39; value for each&amp;nbsp;LED on value), and set a timer to generate first a long interval, which is the LED on value, and then a short interval for the dead band.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The drawback of this method is that you need to use an additional hardware timer.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Best regards&lt;br /&gt;Torbjørn&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447327?ContentTypeID=1</link><pubDate>Mon, 25 Sep 2023 03:24:16 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5b0d96d9-74fc-40b1-8db7-1f5e091cc90c</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;Not had time to do any test code,&amp;nbsp; but here are notes on using a dead band to avoid ghosting (Edited to show active-low digit selects)&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// 7-Segment Display (Right-hand Decimal Point)
// ============================================
//
//                        =================== &amp;quot;HELP&amp;quot; ==============
//          A            [.BC.EFG.] [A..DEFG.] [...DEF..] [AB..EFGP]
//       ------                       ------                ------ 
//      |      |          |      |   |          |          |      |
//    F |      | B        |      |   |          |          |      | 
//      |   G  |          |      |   |          |          |      |
//       ------            ------     ------    |           ------ 
//      |      |          |      |   |          |          |       
//    E |      | C        |      |   |          |          |        
//      |      |          |      |   |          |          |       
//       ------ o DP                  -----      -----            o 
//         D
//                        .BC.EFG.   A..DEFG.  ...DEF..  AB..EFGP                        +--- Optional blanking interval, change segment data here
//                       +-- START                                                       |
//                 !     |&amp;lt;------------------- Display Cycle 1 ---------------------&amp;gt;|   |   |&amp;lt;------------------- Display Cycle 2 ---------------------&amp;gt;|
//                 !     |                                            Optional blank |&amp;lt;-/~/-&amp;gt;|                                            Optional blank |&amp;lt;-/~
//                 !     |                                                           |       |                                                           |
//                 !     |&amp;lt;---- C1 ----&amp;gt;|&amp;lt;---- C2 ----&amp;gt;|&amp;lt;---- C3 ----&amp;gt;|&amp;lt;---- C4 ----&amp;gt;|       |&amp;lt;---- C1 ----&amp;gt;|&amp;lt;---- C2 ----&amp;gt;|&amp;lt;---- C3 ----&amp;gt;|&amp;lt;---- C4 ----&amp;gt;|
//                 !     |              |              |              |              |       |              |              |              |              |
//                 !     |              |              |              |              |       |              |              |              |              |
//                 !     | |&amp;lt;--- D1 ---&amp;gt;| |&amp;lt;--- D2 ---&amp;gt;| |&amp;lt;--- D3 ---&amp;gt;| |&amp;lt;--- D4 ---&amp;gt;|       | |&amp;lt;--- D1 ---&amp;gt;| |&amp;lt;--- D2 ---&amp;gt;| |&amp;lt;--- D3 ---&amp;gt;| |&amp;lt;--- D4 ---&amp;gt;|
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//   Dead Bands &amp;gt;  !  --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--         |    --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--      --&amp;gt;| |&amp;lt;--         | &amp;lt; Dead Bands
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !       |              |            | |            | |            |         |              |            | |            | |            |
// ================/~/=====+            +===============================================/~/====+            +===============================================/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-1         !     | |     D1     | |            | |            | |            |       | |    D1      | |            | |            | |            |
//                 !     | +============+ |            | |            | |            |       | +============+ |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            |                |            | |            |       | |            |                |            | |            |
// ================/~/====================+            +================================/~/===================+            +================================/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-2         !     | |            | |     D2     | |            | |            |       | |            | |     D2     | |            | |            |
//                 !     | |            | +============+ |            | |            |       | |            | +============+ |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            |                |            |       | |            | |            |                |            |
// ================/~/===================================+            +=================/~/==================================+            +=================/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-3         !     | |            | |            | |     D3     | |            |       | |            | |            | |     D3     | |            |
//                 !     | |            | |            | +============+ |            |       | |            | |            | +============+ |            |
//                 ^     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            |                      | |            | |            | |            |
// ================/~/==================================================+            +==/~/=================================================+            +==/~
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// DIGIT-4         !     | |            | |            | |            | |    D4      |       | |            | |            | |            | |     D4     |
//                 !     | |            | |            | |            | +============+       | |            | |            | |            | +============+
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
// Display &amp;quot;HELP&amp;quot;  !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//                 !     | |            | |            | |            | |            |       | |            | |            | |            | |            |
//  &amp;#39;X&amp;#39;=DON&amp;#39;T CARE |     X+             X+=============X|            |X+=============XXXXXXXXX|            |X+=============X|            |X+=============X|
//                 !     X|    &amp;#39;H&amp;#39;      X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      XXXXXXXXX|    &amp;#39;H&amp;#39;     |X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      X|
// SEGMENT-A0      !     X|             X|             X|            |X|             XXXXXXXXX|            |X|             X|            |X|             X|
// ================/~/===X+=============X+             X==============X+             XXXX/~/XX==============X+             X==============X+             X==/~
//                 !      |              |            | |            | |            | |       |            | |            | |            | |            | |
//                 !      |              |            | |            | |            | |       |            | |            | |            | |            | |
//                 !     X+=============X+=============X|            |X+=============XXXXXXXXX+=============X+=============X|            |X+=============X|
//                 !     X|    &amp;#39;H&amp;#39;      X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      XXXXXXXXX|    &amp;#39;H&amp;#39;      X|    &amp;#39;E&amp;#39;      X|    &amp;#39;L&amp;#39;     |X|    &amp;#39;P&amp;#39;      X|
// SEGMENT-G0      !     X|             X|             X|            |X|             XXXXXXXXX|             X|             X|            |X|             X|
// ================/~/===X+             X+             X==============X+             XXXX/~/XX+             X+             X==============X+             X==/~&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The digit time&amp;nbsp;&lt;em&gt;T_DIGIT&lt;/em&gt; is constant, unless using the digit &amp;quot;on&amp;quot; time to control brightness in which case it would be changed each time the brightness is changed, typically using a logarithmic look-up table. Using both PWM Sequence 0 and 1 allows much longer to change segment values and digit brightness, but it can be done with a single sequence.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// 16MHz clock with /1 prescaler and 4096 TOPCOUNT and 4 digits gives ((16000000/4094)/4)=977Hz or about 1mSec display refresh
// 60Hz refresh would be 240Hz repeat so use (say) 4mSecs digit with 16MHz clock so set prescaler to /4
// Using two buffers gives 2 x 4mSec time to do 7-segment or brightness refresh
// Display brightness can be changed digit by digit by reducing turn-on time while keeping constant refresh rate

// Edited to use Active-low digit drive, active-high segment drive
#define T_TOP_COUNT     4095            // 12-bit
#define DEAD_BAND_WIDTH  400
#define T_DEAD         (DEAD_BAND_WIDTH)
#define T_OFF         ((T_TOP_COUNT+1) | 0x8000)
#define T_DIGIT       (DEAD_BAND_WIDTH | 0x8000)
#define T_SEGMENT     ((DEAD_BAND_WIDTH/2) | 0x8000)
#define T_PERIODS       16
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;If I get time I&amp;#39;ll put together some test code to verify this, but meanwhile maybe it will help&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static nrf_pwm_values_individual_t PWM_DigitTable[] = {
    //   Index     DIGIT 1    DIGIT 2    DIGIT 3    DIGIT 4
    //   =====     ========== ========== ========== =========
    { /*   0  */   (T_DIGIT), (T_OFF),   (T_OFF),   (T_OFF)   },
    { /*   1  */   (T_OFF),   (T_DIGIT), (T_OFF),   (T_OFF)   },
    { /*   2  */   (T_OFF),   (T_OFF),   (T_DIGIT), (T_OFF)   },
    { /*   3  */   (T_OFF),   (T_OFF),   (T_OFF),   (T_DIGIT) }
};
// +--------+--------+-------+---------+
// |H       |E       |L       |P       |
// |.BC.EF..|A..DEFG.|...DEF..|AB..EFGP|
// +--------+--------+-------+---------+
static nrf_pwm_values_individual_t PWM_SegmentTableABCD[] = {
    //   Index     Segment A    Segment B    Segment C    Segment D
    //   =====     ============ ============ ============ ============
    { /*   0  */   (T_OFF),     (T_SEGMENT), (T_SEGMENT), (T_OFF)     }, // &amp;#39;H&amp;#39;
    { /*   1  */   (T_SEGMENT), (T_OFF),     (T_OFF),     (T_SEGMENT) }, // &amp;#39;E&amp;#39;
    { /*   2  */   (T_OFF),     (T_OFF),     (T_OFF),     (T_SEGMENT) }, // &amp;#39;L&amp;#39;
    { /*   3  */   (T_SEGMENT), (T_SEGMENT), (T_OFF),     (T_OFF)     }, // &amp;#39;P&amp;#39;
};
static nrf_pwm_values_individual_t PWM_SegmentTableEFGP[] = {
    //   Index     Segment E    Segment F    Segment G    Segment P
    //   =====     ============ ============ ============ ============
    { /*   0  */   (T_SEGMENT), (T_SEGMENT), (T_SEGMENT), (T_OFF)     }, // &amp;#39;H&amp;#39;
    { /*   1  */   (T_SEGMENT), (T_SEGMENT), (T_SEGMENT), (T_OFF)     }, // &amp;#39;E&amp;#39;
    { /*   2  */   (T_SEGMENT), (T_SEGMENT), (T_OFF),     (T_OFF)     }, // &amp;#39;L&amp;#39;
    { /*   3  */   (T_SEGMENT), (T_SEGMENT), (T_SEGMENT), (T_SEGMENT) }, // &amp;#39;P&amp;#39;
};
#define NUM_PWM_ITERATIONS_DIGIT  ( sizeof(PWM_DigitTable)/sizeof(PWM_DigitTable[0].channel_0) )
#define NUM_PWM_TABLE_LINES_DIGIT ( sizeof(PWM_DigitTable)/sizeof(PWM_DigitTable[0]) )
#define NUM_PWM_ITERATIONS_7SEG   ( sizeof(PWM_SegmentTableABCD)/sizeof(PWM_SegmentTableABCD[0].channel_0) )
#define NUM_PWM_TABLE_LINES_7SEG  ( sizeof(PWM_SegmentTableABCD)/sizeof(PWM_SegmentTableABCD[0]) )&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447277?ContentTypeID=1</link><pubDate>Fri, 22 Sep 2023 15:24:38 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2f4a96fd-233a-4c1e-8d6f-c75a8cdd6a49</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;You are missing using a dead band, which is traditional for driving H-bridges and things like display digits. Transitioning edges simultaneously never works in the real world as the slanting edges will overlap with external loads with (in some cases, such as an H-bridge) disastrous effect. Adding a dead-band puts a small gap between the active portion of the digit drives, say 2%. I&amp;#39;ll add some notes on how to do this when I get time later.&lt;/p&gt;
&lt;p&gt;As an aside, using a logic analyser to display the waveform hides this effect as it gives an unreal look to the signals. Better to use an oscilloscope which shows that the signal drive edges are never vertical but always slant and hence cross each other and cause ghosting (or short-circuit of heavy duty power supplies in the case of the H-bridge)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/447270?ContentTypeID=1</link><pubDate>Fri, 22 Sep 2023 14:37:48 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:67296bdf-c573-4c70-a7ae-a9c6b00d72c9</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;Hope your week is going well. I had a chance to play with this and it&amp;#39;s almost there. I feel like I&amp;#39;m on the right track, but missing something. I&amp;#39;m not 100% versed in EGU and PPI, so I&amp;#39;m most likely missing something. I got it playing back and it&amp;#39;s almost perfectly synced, but it&amp;#39;s off enough that there is still a slight bleed. Here is how I am setting everything up (I took out error check to make it easier to read, but it&amp;#39;s there):&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static uint16_t mPwm1Seq[4] = { 0U, 0U, 0U, 0U };
static uint16_t mPwm2Seq[4] = { 0U, 0U, 0U, 0U };
static uint16_t mPwm3Seq[4] = { 0U, 0U, 0U, 0U };

static const nrfx_egu_t mEgu0 = NRFX_EGU_INSTANCE(0);
static const nrfx_pwm_t mPwm1 = NRFX_PWM_INSTANCE(1); // Display Digits 1, 2, 3, 4
static const nrfx_pwm_t mPwm2 = NRFX_PWM_INSTANCE(2); // Display LED Segments A, B, C, D
static const nrfx_pwm_t mPwm3 = NRFX_PWM_INSTANCE(3); // Display LED Segments E, F, G, DP (Decimal Points / Colon)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;EGU&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static bool configure_egu(void)
{
    IRQ_DIRECT_CONNECT(SWI0_EGU0_IRQn, 0, nrfx_egu_0_irq_handler, 0);

    nrfx_egu_init(&amp;amp;mEgu0, 0, egu_callback, NULL);
    nrfx_egu_int_enable(&amp;amp;mEgu0, EGU_CHANNEL_MASK);

    return true;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;PPI&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static bool configure_ppi(void)
{
    for (int i = 0; i &amp;lt; ARRAY_SIZE(mPpiChannels); i++)
    {
        nrfx_ppi_channel_alloc(&amp;amp;mPpiChannels[i]);
    }

    nrfx_ppi_channel_assign(
        mPpiChannels[0],
        nrfx_pwm_event_address_get(&amp;amp;mPwm1, NRF_PWM_EVENT_PWMPERIODEND),
        nrfx_pwm_task_address_get(&amp;amp;mPwm1, NRF_PWM_TASK_SEQSTART0)
    );

    nrfx_ppi_channel_fork_assign(
        mPpiChannels[0],
        nrf_egu_task_address_get(NRF_EGU0, NRF_EGU_TASK_TRIGGER0)
    );

    nrfx_ppi_channel_assign(
        mPpiChannels[1],
        nrfx_pwm_event_address_get(&amp;amp;mPwm1, NRF_PWM_EVENT_PWMPERIODEND),
        nrfx_pwm_task_address_get(&amp;amp;mPwm2, NRF_PWM_TASK_SEQSTART0)
    );

    nrfx_ppi_channel_fork_assign(
        mPpiChannels[1],
        nrfx_pwm_task_address_get(&amp;amp;mPwm3, NRF_PWM_TASK_SEQSTART0)
    );

    for (int i = 0; i &amp;lt; ARRAY_SIZE(mPpiChannels); i++)
    {
        nrfx_ppi_channel_enable(mPpiChannels[i]);
    }

    return true;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Then in the EGU callback I&amp;#39;m updating the sequences like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static void egu_callback(uint8_t event_idx, void * p_context)
{
    // Increment current display digit and wrap back to the first digit when needed
    mCurrentDigit = WRAP(++mCurrentDigit, dd_1, dd_4);

    mPwm1Seq[0] = 0U; // Set digit 0 sequence value here
    mPwm1Seq[1] = 0U; // Set digit 1 sequence value here
    mPwm1Seq[2] = 0U; // Set digit 2 sequence value here
    mPwm1Seq[3] = 0U; // Set digit 3 sequence value here
    mPwm2Seq[0] = 0U; // Set segment A sequence value here
    mPwm2Seq[1] = 0U; // Set segment B sequence value here
    mPwm2Seq[2] = 0U; // Set segment C sequence value here
    mPwm2Seq[3] = 0U; // Set segment D sequence value here
    mPwm3Seq[0] = 0U; // Set segment E sequence value here
    mPwm3Seq[1] = 0U; // Set segment F sequence value here
    mPwm3Seq[2] = 0U; // Set segment G sequence value here
    mPwm3Seq[3] = 0U; // Set segment DP sequence value here
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This works, however, there is still a slight bleeding, like I mentioned before. Here is a logic view of what&amp;#39;s happening:&lt;/p&gt;
&lt;p&gt;&lt;img style="max-height:837px;max-width:1040px;" alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/2080x1674/__key/communityserver-discussions-components-files/4/Display01.png" /&gt;&lt;/p&gt;
&lt;p&gt;You can see that everything looks in sync and correct. However, when zoomed in you can see they are off just a little. This is causing the digits to stay on slightly too long and bleeding on the next digit. The part that&amp;#39;s zoom in is the first rising edge you see on PWM2 SA and PWM3 SE:&lt;/p&gt;
&lt;p&gt;&lt;img style="max-height:827px;max-width:630px;" alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/1260x1654/__key/communityserver-discussions-components-files/4/Display02.png" /&gt;&lt;/p&gt;
&lt;p&gt;Here is the little bit of bleeding that I&amp;#39;m seeing. It&amp;#39;s a little hard to tell from the picture, but you can see it a little bit on D1 since D4 is bleeding into D1 (look at the outer segments how they&amp;#39;re lit, but not the middle one - D4 is a zero).&lt;/p&gt;
&lt;p&gt;&lt;img style="max-height:784px;max-width:1040px;" alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/2080x1568/__key/communityserver-discussions-components-files/4/Display-Digits.png" /&gt;&lt;/p&gt;
&lt;p&gt;Here are how the segments are defined just so those are clear:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;/**
 *  ┌──A──┐
 *  F     B
 *  ├──G──┤
 *  E     C
 *  └──D──┘
 */&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Appreciate any tips on this. Hope you all have a great weekend.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446677?ContentTypeID=1</link><pubDate>Tue, 19 Sep 2023 13:25:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:e51ca3e6-f4a6-48d4-ae27-f21795240ac6</guid><dc:creator>ovrebekk</dc:creator><description>&lt;p&gt;Good luck! If you have more questions just let us know &lt;span class="emoticon" data-url="https://devzone.nordicsemi.com/cfs-file/__key/system/emoji/1f642.svg" title="Slight smile"&gt;&amp;#x1f642;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446665?ContentTypeID=1</link><pubDate>Tue, 19 Sep 2023 12:37:06 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:155bc68a-f682-4434-8a7f-ab351eb1c8d2</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Thank you all, that&amp;#39;s a great idea! I will look into it more this week and get back to you.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446617?ContentTypeID=1</link><pubDate>Tue, 19 Sep 2023 09:42:33 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8dbe3307-72c4-4149-8e1c-2f179ef3f4d4</guid><dc:creator>ovrebekk</dc:creator><description>&lt;p&gt;Hi&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Susheel is currently unavailable, and I will help out in the mean time.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I agree that using PWM3 to drive the digit select pins make a lot of sense.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As mentioned earlier it is possible to synchronize all the PWM modules by using the EGU and PPI controller, allowing you to start them all in parallel. Doing this you can prepare separate buffers for each PWM controller and have them played back in sync.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Then you should be able to define at minimum a&amp;nbsp;four element buffer for each PWM, setting one digit select pin high for each value, and ensuring that PWM1 and PWM2 get set to the right values for each element depending on the output of PWM3.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Then all you have to do is to update the buffers assigned to PWM1 and PWM2 when you want to change the display state.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I am pretty sure you will need to bypass the Zephyr driver and use the nrfx_pwm driver directly to do this though, as the Zephyr driver has no concept of Nordic specific concepts such as tasks and events.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Best regards&lt;br /&gt;Torbjørn&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446566?ContentTypeID=1</link><pubDate>Tue, 19 Sep 2023 06:48:25 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2ee6b068-7d26-443c-8a32-8da512bf1440</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;I think it is possible to use PWM3 to drive the GPIO pins to drive the 4 digits. Ill ask the PWM expert on how to synchronize them. That is PWM3&amp;#39;s next sequence should start after we have&amp;nbsp;&lt;span&gt;NRFX_PWM_EVT_FINISHED from the PWM2.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;I am guessing the second tip from Hugh would behave the same as in the callback from the event&amp;nbsp;NRFX_PWM_EVT_FINISHED (just less interrupt post processing overhead when using EGU). Will make it little faster but I am not sure if it makes huge difference in terms of power consumption.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446496?ContentTypeID=1</link><pubDate>Mon, 18 Sep 2023 15:45:05 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2a61fbba-6ac0-4525-9831-5f253797fa67</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;How about using PWM3 to drive the 4 digit select pins? Hardware solution, no delays&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Edit:&lt;/p&gt;
&lt;p&gt;Second tip, when an interrupt is not available, such as when a PWM interrupt is hogged by the irritating OS, try using PPI to trigger a spare EGU interrupt from the PWM hardware event.&lt;/p&gt;
&lt;p&gt;Moving a slow piece of code out of an interrupt which has to be kept very fast can also be done by not setting a flag or starting a task but by simply triggering a software interrupt using a spare EGU channel at a lower priority, which also generates a wakeup to handle the software interrupt.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446482?ContentTypeID=1</link><pubDate>Mon, 18 Sep 2023 14:20:22 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:be64b2b3-5ff5-4039-85a0-9a27237a0374</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Hey Susheel,&lt;/p&gt;
&lt;p&gt;I put some thought into this and I do not think it will work with Zephyr&amp;#39;s GPIO API. Let me explain in a high-level overview of what I would like to ideally achieve.&lt;/p&gt;
&lt;p&gt;I currently have 4 GPIO pins configured, one for each digit on the display. When I want a certain digit to display something, I enable that GPIO pin and disable the other 3 pins. So, I&amp;rsquo;ll enable digit 1 and disable 2, 3, and 4. Then, I&amp;rsquo;ll enable 2 and disable 1, 3, and 4. I do this to all 4 digits and then repeat back at 1. I also have all 4 channels of PWM1 and all 4 channels of PWM2 dedicated for the LED segments on the display. I play the same sequence for both PWM1 and PWM2 so the LEDs have the same brightness (the brightness is user defined, but we also blink and fade the display at certain times as well).&lt;/p&gt;
&lt;p&gt;For switching the digits, I call nrfx_pwm_init and configure a callback for PWM2. When I play the sequence for both PWM1 and PWM2 I get notified when PWM2 has finished playing the sequence (NRFX_PWM_EVT_FINISHED). From there, I increment the display digit from 1 to 2 and replay the sequence. Then when that sequence finishes I increment the display digit again and replay the sequence over. I keep doing this and wrapping the display digit (1, 2, 3, 4, 1, 2, 3, 4, 1, 2, &amp;hellip;) forever. So, I&amp;rsquo;m relying on the event finished to switch display digits.&lt;/p&gt;
&lt;p&gt;With all of that being said, is it possible to wire up the GPIO pins that are used for the display digits to automatically increment when then the NRFX_PWM_EVT_FINISHED event fires on PWM2? If so, do you happen to know of any example or suggestions on how to achieve this?&lt;/p&gt;
&lt;p&gt;Appreciate it.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446274?ContentTypeID=1</link><pubDate>Fri, 15 Sep 2023 12:33:53 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:d370a0b8-f14a-424b-901a-6d718aebd070</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Hey Susheel,&lt;/p&gt;
&lt;p&gt;Thank you for getting back with me. No worries, you&amp;#39;re one of the few that have always been helpful and knowledgeable. Thank you for that.&lt;/p&gt;
&lt;p&gt;A few months ago I took a deep look into overall timings and everything is much better, so I have not seen this display issue in a while. However, I still know it&amp;#39;s not 100% where it needs to be either. If I can get everything working on the hardware level, then that would be ideal. This afternoon, or early Monday, I&amp;#39;ll look into this again.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m thinking if I could setup a PWM sequence in RAM that just continuously plays non-stop and then use PPI to switch the digits really fast, then it should work and be all hardware level. Of course I would have to update the sequence on the fly to account for blinking, fading, etc. as well. Do you have an example that would achieve something similar like this using Zephyr? Maybe using PWM to power LEDs and using PPI to switch between the LEDs?&lt;/p&gt;
&lt;p&gt;Appreciate it Susheel.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/446192?ContentTypeID=1</link><pubDate>Fri, 15 Sep 2023 07:56:38 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:fce0d989-eb5d-45ee-857d-50e9cbf8d545</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;Hi James,&lt;/p&gt;
&lt;p&gt;My apologies for late reply. I am not trying to ghost you, but this ticket went into idle due my mistake of seeing that there is ongoing discussion which is similar to my thoughts and the status of ticket wrongly showing the tag that made me assume that the last response was not from the author of the ticket (you).&lt;/p&gt;
&lt;p&gt;In Zephyr we have an vendor specific interface layer which connects the Zephyr API to the vendor HAL. In this case of GPIO that interface is&amp;nbsp;zephyr\drivers\gpio\gpio_nrfx.c. As you can see When enabling GPIO config in Zephyr, this file is pulled in and the IRQ is already connected here.&lt;/p&gt;
[quote user="JamesDougherty"]I also looked into the GPIOTE in order to do the digit switching. One thing I found out is that it would be required to disable the Zephyr GPIO implementation since you can&amp;#39;t have Zephyr&amp;#39;s GPIO and NRFX&amp;#39;s GPIOTE enabled at the same time.[/quote]
&lt;p&gt;This seems like an architectural limitation and very specific to GPIO and GPIOTE since the interrupt and the interrupt handler is the same for them.&lt;/p&gt;
&lt;p&gt;I do not think that any other peripheral would have such limitation which does not share the same interrupt line. Since GPIO and GPIOTE have same interrupt, it is understandable that nrf_gpiote.x-&amp;gt;ISR is plugged in either by NRF_GPIO through zephyr or using nrfx_gpiote directly.&lt;/p&gt;
&lt;p&gt;If you want to use GPIOTE/PWM,&amp;nbsp; would it not be possible to use Zephyr GPIO API instead of using directly nrfx_gpiote?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/411453?ContentTypeID=1</link><pubDate>Wed, 22 Feb 2023 15:50:37 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:52a327a7-3e97-4fe0-9f19-96d24ecdceb0</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Zephyr registers it&amp;#39;s own IRQ handler for the GPIO and GPIOTE also tries to register it&amp;#39;s own IRQ handler for the GPIO. If you leave the Zephyr GPIO enabled and then try to enable NRFX GPIO you get the following:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;FAILED: zephyr/isr_tables.c zephyr/isrList.bin
multiple registrations at table_index 6 for irq 6 (0x6)
Existing handler 0x6d09, new handler 0x6d09
Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;I tried this using the sample from /boards/nrf/nrfx&lt;/p&gt;
&lt;p&gt;The readme even states: &amp;quot;Zephyr GPIO driver is disabled to prevent it from registering its own handler for the GPIOTE interrupt&amp;quot;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/411444?ContentTypeID=1</link><pubDate>Wed, 22 Feb 2023 15:27:52 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:27d1b7f3-f6a7-4d58-8f13-7f4088fcbd47</guid><dc:creator>Emil Lenngren</dc:creator><description>&lt;p&gt;I have not used Zephyr myself, so cannot really comment on this. It seems strange if you want to use the GPIOTE/PWM manually, you will be locked out to use Zephyr for the rest of the peripherals though...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/411391?ContentTypeID=1</link><pubDate>Wed, 22 Feb 2023 13:47:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:1e4519d1-eb8b-4f97-85f0-a1b2a5b9aa2c</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Thank you for the response, Emil.&lt;/p&gt;
&lt;p&gt;I looked into this and the NRFX PWM driver, in Zephyr, is already doing this behind the scenes. When you call pwm_set_pulse_dt, pwm_set_dt, pwm_set, etc. it will setup the period and pulse cycles and then call pwm_set_cycles, which in turn calls Nordics NRFX driver&amp;#39;s pwm_nrfx_set_cycles function. In there it updates the sequence value stored in RAM for that channel and then calls nrfx_pwm_simple_playback to play the sequence back once.&lt;/p&gt;
&lt;p&gt;I also looked into the GPIOTE in order to do the digit switching. One thing I found out is that it would be required to disable the Zephyr GPIO implementation since you can&amp;#39;t have Zephyr&amp;#39;s GPIO and NRFX&amp;#39;s GPIOTE enabled at the same time. That would mean I would have to change all my code that uses the Zephyr GPIO implementation over to use NRF GPIO implementation. This would also mean that I would have to rewrite any Zephyr drivers that use the Zephyr GPIO, like the EEPROM driver as an example. I don&amp;#39;t feel like rewriting those, nor do I think the company wants me to rewrite a lot of things I have already written.&lt;/p&gt;
&lt;p&gt;Going back to the NRFX PWM, I noticed that when pwm_set_cycles gets called it&amp;#39;s updating the sequence value and calling nrfx_pwm_simple_playback for every channel... In our case, for the 4-digit 7-segment display, that&amp;#39;s 8 times per update. That&amp;#39;s highly inefficient and was causing the slowdown we were seeing. I turned off Zephyr&amp;#39;s implementation of PWM and rewrote the driver to update all 8 values in ram at once and then only call the nrfx_pwm_simple_playback once. So, to answer your question, I&amp;#39;m sure it can be done in hardware if we disable a lot of Zephyr&amp;#39;s functionality.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Do you see any problems with this or know a better way that will work with Zephyr?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/members/aryan"&gt;Susheel Nuguru&lt;/a&gt;&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/members/simonr"&gt;Simonr&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/408397?ContentTypeID=1</link><pubDate>Mon, 06 Feb 2023 22:50:24 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a6f639dc-ac48-4e06-99d9-2bd6b783c9b2</guid><dc:creator>Emil Lenngren</dc:creator><description>&lt;p&gt;Are you sure you cannot do this in hardware instead of software?&lt;/p&gt;
&lt;p&gt;The PWM p&lt;span style="font-family:inherit;"&gt;eripheral is pretty advanced (&lt;/span&gt;&lt;a style="font-family:inherit;" href="https://infocenter.nordicsemi.com/topic/ps_nrf52840/pwm.html?cp=5_0_0_5_16)"&gt;https://infocenter.nordicsemi.com/topic/ps_nrf52840/pwm.html?cp=5_0_0_5_16)&lt;/a&gt;&lt;span style="font-family:inherit;"&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You can set up sequences in RAM that it follows. To synchronise timings, you can use PPI for starting all PWMs at the exact correct time, maybe in a combination with a TIMER peripheral.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/408383?ContentTypeID=1</link><pubDate>Mon, 06 Feb 2023 19:44:58 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5302002e-0235-48a3-ab14-e06fcf8dfa7b</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Hello Susheel.&lt;/p&gt;
&lt;p&gt;Thank you for the information on the interrupts, I didn&amp;#39;t see that document. I updated the board definition to make sure those&amp;nbsp;&lt;span&gt;peripherals have the correct priorities.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;I was researching this some more and found out that it was a timing issues caused by the ADC (it appears the ADC was throwing everything off). I had the ADC configured to sample using PPI / Timer sampling 3 channels at the same time every 500us and it&amp;#39;s setup like:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static bool adc_configure(void)
{
    const nrfx_saadc_adv_config_t adv_config = {
        .oversampling = NRF_SAADC_OVERSAMPLE_4X,
        .burst = NRF_SAADC_BURST_ENABLED,
        .internal_timer_cc = 0,
        .start_on_end = false,
    };

    //... Setup channels, calibrate, etc.

    return true;
}

static void event_handler(nrfx_saadc_evt_t const *event)
{
    switch (event-&amp;gt;type)
    {
        case NRFX_SAADC_EVT_DONE:
            // ... Process Samples
            nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
            break;

        default:
            break;
    }
}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;However, this was causing&amp;nbsp;erratic behavior:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;img style="max-height:240px;max-width:320px;" src="https://devzone.nordicsemi.com/resized-image/__size/640x480/__key/communityserver-discussions-components-files/4/adc_5F00_pre.png" alt=" " /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;If I change the code to the following:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static const bool adc_configure(void)
{
    const nrfx_saadc_adv_config_t adv_config = {
        .oversampling = NRF_SAADC_OVERSAMPLE_4X,
        .burst = NRF_SAADC_BURST_ENABLED,
        .internal_timer_cc = 0,
        .start_on_end = true, // &amp;lt;---------- Change to true
    };

    //... Setup channels, calibrate, etc.

    return true;
}

static void event_handler(nrfx_saadc_evt_t const *event)
{
    switch (event-&amp;gt;type)
    {
        case NRFX_SAADC_EVT_DONE:
            // ... Process Samples
            
            // Do not trigger start task
            // nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
            break;

        default:
            break;
    }
}&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Then I get consistent / expected behavior:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;img style="max-height:240px;max-width:320px;" src="https://devzone.nordicsemi.com/resized-image/__size/640x480/__key/communityserver-discussions-components-files/4/adc_5F00_post.png" alt=" " /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;I still don&amp;#39;t get the PWM callback for ~150us, however, it has not gone over the threshold and caused the other segments to bleed either. I&amp;#39;m going to cleanup my code and flesh out the callbacks and see how everything runs.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/407946?ContentTypeID=1</link><pubDate>Fri, 03 Feb 2023 09:54:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ab74b094-cb65-4f22-a577-afe29f4156b2</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;There are limitation that the &lt;a href="https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/softdevice_controller/README.html"&gt;Softdevice Controller&lt;/a&gt;&amp;nbsp;puts on application&amp;nbsp;are inherited from the &lt;a href="https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/mpsl/README.html#mpsl"&gt;MPSL&lt;/a&gt;. The &lt;a href="https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/mpsl/doc/mpsl.html"&gt;integration notes&lt;/a&gt;&amp;nbsp;of the MSPL gives a very clear documentation of what peripherals and priorities that are allowed for the application to use. Please go through the integration notes I linked to see if it is clear about what priority you cannot use for your PWM interrupt when BLE is enabled (and hence MPSL is initialized).&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/407584?ContentTypeID=1</link><pubDate>Wed, 01 Feb 2023 14:32:56 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5fe96f2e-d77e-400a-911a-9a0a225ee883</guid><dc:creator>JamesDougherty</dc:creator><description>&lt;p&gt;Hello Simonr,&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Thank you for the quick response. Yes, this is for a Bluetooth product, so we will be relying on the Bluetooth controller. We are redesigning our current product that uses a Microchip CPU and a Fanstel BLE radio module. The new product will use the nRF52840 for both of those purposes.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Thank you,&lt;/p&gt;
&lt;p&gt;James&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: PWM Interrupts / Interrupt Priority Levels</title><link>https://devzone.nordicsemi.com/thread/407580?ContentTypeID=1</link><pubDate>Wed, 01 Feb 2023 14:17:27 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:4784d7fc-f333-49a0-befe-b06a05c7a6ad</guid><dc:creator>Simonr</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;Are you using the SoftDevice controller (radio/BLE) in your application? I&amp;#39;m not able to see any calls taking use of the SoftDevice controller in your application, and if you&amp;#39;re not using the radio, you should be free to set the PWM to whatever priority you&amp;#39;d like to avoid this. If you are, let me know and I&amp;#39;ll look into some countermeasures for you.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;/p&gt;
&lt;p&gt;Simon&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>