<?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>Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/7824/random-pwm-dutycycle-inversion-in-softdevice-8-0</link><description>I am using the PWM library in this repository for a nRF51822. I write the following code to generate a ~ 30% dutycycle 500 kHz PWM output: 
 #define V_CLK 5

static void v_clock_start(void)
{ 
 // Init PWM
 nrf_pwm_config_t pwm_config = PWM_DEFAULT_CONFIG;</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Thu, 03 Sep 2015 10:54:53 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/7824/random-pwm-dutycycle-inversion-in-softdevice-8-0" /><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27874?ContentTypeID=1</link><pubDate>Thu, 03 Sep 2015 10:54:53 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:80734abe-c78e-4775-899b-1cac3f1dbc86</guid><dc:creator>Stefan Birnir Sverrisson</dc:creator><description>&lt;p&gt;You are correct, there is no direct call to PWM_IRQHandler() from nrf_pwm_set_value(). The nrf_pwm_set_value() only sets the new duty cycle value into a variable. The actual duty cycle is updated when a timeslot starts, and that is where it is safe to update the duty cycle.&lt;/p&gt;
&lt;p&gt;However, by implementing the new nrf_pwm_set_value_directly() function, we will not have to wait for the timeslot to call the PWM_IRQHandler() and update the PWM duty cycle, we will just call the PWM_IRQHandler() function directly. That should be safe since we did not start the PWM yet.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27873?ContentTypeID=1</link><pubDate>Wed, 02 Sep 2015 23:50:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:852b1443-4779-4996-9935-c5f5f35c8a5d</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;Hi Stefan,  in the code nrf_pwm.c, there is a function called PWM_IRQHandler(). May I know under what circumstances is it called? I will assume if I set a new PWM parameter such as calling nrf_pwm_set_value() to set PWM duty cycle, it will be called to update the PWM configuration. But I do not see a direct function call of PWM_IRQHandler() in nrf_pwm_set_value().&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27872?ContentTypeID=1</link><pubDate>Tue, 07 Jul 2015 16:43:55 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ce235e16-d2f1-41e6-a775-aec73b633be4</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;Thanks for your detailed explanation!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27871?ContentTypeID=1</link><pubDate>Sat, 04 Jul 2015 00:07:30 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:01bb51c1-7874-4bec-b01a-7417ae9f494b</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;Hi Stefan, your advice works. Thanks. Just curious, could you please explain the &amp;quot;extra stuff&amp;quot; in &lt;a href="https://github.com/NordicSemiconductor/nrf51-pwm-library/blob/master/nrf_pwm.c"&gt;nrf_pwm.c&lt;/a&gt;, such as using two timers when channel number&amp;gt;2, function apply_pan73_workaround(), safe_margins_present() and the part containing nrf_radio_signal_callback when SoftDevice is enabled?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27870?ContentTypeID=1</link><pubDate>Wed, 01 Jul 2015 09:54:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:3bf9dfce-5a1a-4e59-93c2-59c2a3bfa789</guid><dc:creator>Stefan Birnir Sverrisson</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;In theory, we have estimated 62.5kHz to be the safe boundary of the PWM frequency. We have not tested with higher frequencies. The library has worked fine in the tests that we have performed so far, which are within the PWM frequency limit mentioned above. I expect that the PWM occasionally flips when you set the duty cycle with after configuring, am I correct?&lt;/p&gt;
&lt;p&gt;I have a suggestion. In your code you call nrf_pwm_init which configures and starts the PWM, and then you set the duty cycle with nrf_pwm_set_value after it has started, which is not recommended with &amp;gt;62.5kHz. Since you intend to use a fixed PWM, you can set the duty cycle before starting the PWM which should be safe. Then you can avoid updating the duty cycle after the PWM is started. For this purpose add the following function in nrf_pwm.c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void nrf_pwm_set_value_directly(uint32_t pwm_channel, uint32_t pwm_value)
{
		pwm_next_value[pwm_channel] = pwm_value;
		pwm_modified[pwm_channel] = true;
		PWM_IRQHandler();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then call this function just before you start the PWM in the nrf_pwm_init function, i.e.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...    
#if(USE_WITH_SOFTDEVICE == 1)
		sd_radio_session_open(nrf_radio_signal_callback);
#else
		NVIC_SetPriority(PWM_IRQn, 0);
		NVIC_EnableIRQ(PWM_IRQn);
#endif
		
		nrf_pwm_set_value_directly(0, 10);
		
		apply_pan73_workaround(PWM_TIMER, true);
		PWM_TIMER-&amp;gt;TASKS_START = 1;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then remove your call to your nrf_pwm_set_value function in v_clock_start&lt;/p&gt;
&lt;p&gt;Let me know if that solves the issue&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 6.7.2015&lt;/strong&gt;
A little bit about how the PWM library works.&lt;/p&gt;
&lt;p&gt;Each TIMER peripheral has 4 CC capture/compare registers. One of those register (I think CC[2]) is used to toggle the PWM in one direction (low to high), and one CC register (e.g. CC[0]) is used to toggle in the other direction (high to low). The value of CC[0] is changed in order to change the duty cycle of the PWM channel. If you need another PWM channel, CC[2] is also used for that one to toggle from low to high (the value of CC[2] is fixed), but e.g. CC[1] is used to toggle from high to low. The conclusion is that you can use one TIMER peripheral for 3 PWM channels. If you want more channels, you will have to use another timer peripheral as well.&lt;/p&gt;
&lt;p&gt;The  apply_pan73_workaround() is implementation for the anomaly #73 workaround stated in the &lt;a href="https://www.nordicsemi.com/eng/nordic/Products/nRF51822/PAN-nRF51822/24634"&gt;nRF51822-PAN v3.0 document&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When updating the PWM duty cycle, it is critical, for safe operation, that it is updated in the correct moment, i.e. not close to the moments when the signal is to be toggled from high to low, or from low to high. If the duty cycle is updated when the signal is about to be toggled, the PWM signal might flip, as you have found out by experience. There are defined safe margins, which is the minimum time from the instant that you are updating the duty cycle until the signal will toggle. If updating the PWM duty cycle inside a safe margin, then the strategy is simply to wait a few us until we are outside the safe margin, and then do the PWM duty cycle update. When the PWM frequency is too high however, there is not enough time outside the safe margins to perform the PWM duty cycle update, and the duty cycle update might result in a PWM signal flip.&lt;/p&gt;
&lt;p&gt;Since TIMER, PPI, GPIOTE is used to produce the PWM signal, no CPU is needed. However, when updating the PWM duty cycle (the value of e.g. CC[0] register), the CPU is needed. But there might also be other peripherals that need the CPU at the same time. Since the PWM duty cycle update is very time critical operation in order to work correctly, we must ensure that the PWM duty cycle update operation is not interrupted once it is started. This is why the PWM library uses timeslots API to do the PWM duty cycle update. The nrf_radio_signal_callback event is received when the radio finishes its scheduled BLE radio activity and grants the CPU to the application for a certain period of time. This ensures that the BLE softdevice will not interrupt the PWM duty cycle update procedure.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27878?ContentTypeID=1</link><pubDate>Tue, 30 Jun 2015 17:49:56 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a47fcf35-52ab-45da-b900-160204f9d13b</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;@stefanbirnir Yes, I am using a higher PWM frequency (500kHz) than 62.5kHz. Unfortunately, 62.5 kHz is a little low for my application right now. I actually don&amp;#39;t need to change the PWM duty cycle. The reason I constantly turn on (using nrf_pwm_set_value) and off (using nrf_pwm_enabled) PWM is to save power since I only need those PWM signals once every few minutes. And I only use 1 channel for this particular case. Given those conditions, is there a workaround?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27869?ContentTypeID=1</link><pubDate>Tue, 30 Jun 2015 15:06:31 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:dbb37c52-e674-4004-8baa-d124be0941a6</guid><dc:creator>Stefan Birnir Sverrisson</dc:creator><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;We have seen this problem before and there are several possible causes. We think however that the problem is related to the update of the PWM duty cycle when PWM frequency is high, i.e. when nrf_pwm_set_value is called. Are you calling this method, or are you maintaining a fixed duty cycle PWM?&lt;/p&gt;
&lt;p&gt;If the frequency of the PWM is too high, the PWM might flip when the duty cycle is updated. I think the library implements the PWM_MODE_BUZZER_255 mode which is 62.5kHz and that is max frequency in order to do this safely. Is that frequency too low for your scenario? Can you try to lower the frequency in order to see if that is the actual issue.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27868?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 08:34:34 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:442927f9-cba1-48d4-8c09-da0e9ff76536</guid><dc:creator>JohnBrown</dc:creator><description>&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Does it work properly if you don&amp;#39;t have the SD running?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What is the range of duty cycle you wish to produce?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you are only using one channel, and you don&amp;#39;t need to change duty cycle on the fly, I still believe you&amp;#39;d be better off writing your own PWM functions. If you don&amp;#39;t need to use the IRQs, then since it&amp;#39;s all hardware(timer compare events, GPIOTE tasks) it should work perfectly fine even with the SD running.&lt;/p&gt;
&lt;p&gt;On the other hand, I don&amp;#39;t know what exactly you are trying to achieve.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27867?ContentTypeID=1</link><pubDate>Thu, 25 Jun 2015 23:13:46 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a6dfa272-bafd-4a43-8c0e-760780946399</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;I had similar feeling but I saw a line in nrf_pwm.c in &lt;a href="https://github.com/NordicSemiconductor/nrf51-pwm-library"&gt;that repository&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; nrf_gpiote_task_config(pwm_gpiote_channel[i], pwm_io_ch[i], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;when it started GPIOTE task with setting initial pin state high. If that was the case, the PWM waveform shouldn&amp;#39;t change in a bistate manner. I don&amp;#39;t know what I am missing here...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27877?ContentTypeID=1</link><pubDate>Thu, 25 Jun 2015 22:43:09 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:bdb0ef04-6823-4db8-a691-580b141abfb3</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;Well my guess would be that you are stopping the PWM in an entirely unsychronized fashion, and not dismantling the PPI/GPIOTE stuff, and since the PWM has to use the toggle function, anything can happen.
In my opinion, the PWM capability of the nRF51 is flawed, but if you are not using ISRs you should be able to write something using PPI and GPIOTE that works. If I were you I would ignore the PWM library and write my own functions. A quick search on PWM might persuade you...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27876?ContentTypeID=1</link><pubDate>Thu, 25 Jun 2015 17:02:50 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:617e1929-c8ef-498e-ade9-8e4723ee4d44</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;I used the v_clock_start() function in my question description to re-enable PWM.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27866?ContentTypeID=1</link><pubDate>Thu, 25 Jun 2015 16:54:13 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:bdb27015-6afc-4975-8697-ebbf9c7ce50e</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;You say that you&amp;#39;re using&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nrf_pwm_set_enabled(false);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to disable the PWM, what are you using to re-enable it?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27875?ContentTypeID=1</link><pubDate>Thu, 25 Jun 2015 16:32:49 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:bd98a89d-f2f1-4854-b683-17212cd0b2a3</guid><dc:creator>diode</dc:creator><description>&lt;p&gt;When PWM is active, the duty cycle doesn&amp;#39;t change. But the duty cycle can be different if I enable PWM at different time. Yes, I am running PWM with SoftDevice. By saying &amp;quot;regularly&amp;quot;, I mean the I can see the duty cycle inversion from time to time. By saying &amp;quot;randomly&amp;quot;, I mean I don&amp;#39;t see a periodic pattern of such behavior --- I can not predict its appearance.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Random PWM dutycycle inversion in SoftDevice 8.0</title><link>https://devzone.nordicsemi.com/thread/27865?ContentTypeID=1</link><pubDate>Thu, 25 Jun 2015 11:00:45 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:3f1cf234-87ed-4df3-8bac-5badb4bd8673</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;If you start the PWM and leave it running, i.e. DON&amp;#39;T enable and disable periodically, is the PWM stable?
Also, are you running a soft device while making these observations?&lt;/p&gt;
&lt;p&gt;BTW, what do you mean by &amp;quot;regularly and randomly&amp;quot;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>