<?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>Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/89209/clarification-on-how-to-generate-a-10khz-sine-wave-with-pwm-and-dma</link><description>I&amp;#39;m struggling when using PWM and DMA to generate a sine wave. I&amp;#39;m sure I&amp;#39;m not interpreting the documentation right, and I hope someone can point me in the right direction 
 I tried the following code 
 
 If I understand correctly how PWM works, with</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Thu, 23 Jun 2022 16:29:35 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/89209/clarification-on-how-to-generate-a-10khz-sine-wave-with-pwm-and-dma" /><item><title>RE: Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/thread/374014?ContentTypeID=1</link><pubDate>Thu, 23 Jun 2022 16:29:35 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:97d9de02-626e-4091-a5a8-e9b849918951</guid><dc:creator>robca</dc:creator><description>&lt;p&gt;Perfect, thanks for the explanation and additional code. Now it all makes sense again &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: Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/thread/373806?ContentTypeID=1</link><pubDate>Thu, 23 Jun 2022 03:44:49 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0ce11dad-5f2d-409d-b40b-8cc602c41e95</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;You are correct, I was being misleading. I&amp;#39;ve attached a simple snippet of low-level code which generates a short burst, though not at the frequency you are looking for. There is also the possibility to use multiple PWMs out-of-phase to generate&amp;nbsp;additional steps if you need to generate a cleaner sine wave.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#define PWM_PIN (PIN_FEATHER_D6)
#define PWM_STEPS 800
uint16_t buf[PWM_STEPS];
void TestPWM(void)
{
  // Build (say) ramp - Ramp up/Down
  for (uint32_t i=0; i&amp;lt;PWM_STEPS/2; i++)
  {
     buf[i] = 0x8000 | 2*i;
     buf[PWM_STEPS-i-1] = 0x8000 | 2*i;
  }
  // Start crystal HFCLK
  NRF_CLOCK-&amp;gt;TASKS_HFCLKSTART = 1;
  while (NRF_CLOCK-&amp;gt;EVENTS_HFCLKSTARTED == 0) ;
  NRF_CLOCK-&amp;gt;EVENTS_HFCLKSTARTED = 0;
  // Configure PWM_PIN as output, drive low
  NRF_GPIO-&amp;gt;DIRSET = (1 &amp;lt;&amp;lt; PWM_PIN);
  NRF_GPIO-&amp;gt;OUTCLR = (1 &amp;lt;&amp;lt; PWM_PIN);
  NRF_PWM0-&amp;gt;PRESCALER   = PWM_PRESCALER_PRESCALER_DIV_1; // 16 MHz clock
  NRF_PWM0-&amp;gt;PSEL.OUT[0] = PWM_PIN;
  NRF_PWM0-&amp;gt;MODE        = (PWM_MODE_UPDOWN_UpAndDown &amp;lt;&amp;lt; PWM_MODE_UPDOWN_Pos);
  NRF_PWM0-&amp;gt;DECODER     = (PWM_DECODER_LOAD_Common &amp;lt;&amp;lt; PWM_DECODER_LOAD_Pos) | (PWM_DECODER_MODE_RefreshCount &amp;lt;&amp;lt; PWM_DECODER_MODE_Pos);
  NRF_PWM0-&amp;gt;LOOP        = 100;
  NRF_PWM0-&amp;gt;COUNTERTOP = PWM_STEPS;
  NRF_PWM0-&amp;gt;SEQ[0].CNT = ((sizeof(buf) / sizeof(uint16_t)) &amp;lt;&amp;lt; PWM_SEQ_CNT_CNT_Pos);
  NRF_PWM0-&amp;gt;SEQ[0].ENDDELAY = 0;
  NRF_PWM0-&amp;gt;SEQ[0].PTR = (uint32_t)&amp;amp;buf[0];
  NRF_PWM0-&amp;gt;SEQ[0].REFRESH = 0;
  NRF_PWM0-&amp;gt;SEQ[1].CNT = ((sizeof(buf) / sizeof(uint16_t)) &amp;lt;&amp;lt; PWM_SEQ_CNT_CNT_Pos);
  NRF_PWM0-&amp;gt;SEQ[1].ENDDELAY = 0;
  NRF_PWM0-&amp;gt;SEQ[1].PTR = (uint32_t)&amp;amp;buf[0];
  NRF_PWM0-&amp;gt;SEQ[1].REFRESH = 0;
  // Stop after burst
  NRF_PWM0-&amp;gt;SHORTS = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
  NRF_PWM0-&amp;gt;ENABLE = 1;
  NRF_PWM0-&amp;gt;TASKS_SEQSTART[0] = 1;
}&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/thread/373798?ContentTypeID=1</link><pubDate>Thu, 23 Jun 2022 00:08:30 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:eec9a663-db3a-45de-a1d9-f5db3b5f76a9</guid><dc:creator>robca</dc:creator><description>&lt;p&gt;Yes, thanks. I understand how the prescalers relate to the clock and PWM frequency.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s use 16MHz clock and 40 COUNTERTOP, as in your example. That means that each single PWM pulse is at 16MHz, and I need 40 of those to represent every possible number from 0 to 40. So I have only 400kHz &amp;quot;values&amp;quot; with which to form a sine wave. Let&amp;#39;s call COUNTERTOP the vertical resolution of the XY sine graph. So I have 40 Y values to play with.&lt;/p&gt;
&lt;p&gt;Now I need enough X values to represent a sine. Given that I need a 10kHz sine wave, I can use 40 X values to represent one period of my sine. So now my frequency is 400kHZ/40=10kHZ. My sine has a resolution, so to speak, of 40x40 pixels.&lt;/p&gt;
&lt;p&gt;If I were to use, say, 80 values for X, the frequency of my sine would be only 5kHz, 400kHz/80.&lt;/p&gt;
&lt;p&gt;In the following oscilloscope screenshot, I&amp;#39;m using prescaler 1, 16MHz clock, 40 COUNTERTOP and sending the value 1, a single pulse. The overall frequency is 400kHz (my scope is picking up a slightly different one, I think it&amp;#39;s noise, I just hacked things together badly)&lt;/p&gt;
&lt;p&gt;&lt;img style="max-height:240px;max-width:320px;" alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/640x480/__key/communityserver-discussions-components-files/4/DS2302A_5F00_22_2D00_06_2D00_2022_5F00_16_2D00_36_2D00_15.4.png" /&gt;&lt;/p&gt;
&lt;p&gt;So far, so good: each pulse is at 16MHz, and I need 40 to represent a PWM value (&amp;quot;cycle&amp;quot;)&lt;/p&gt;
&lt;p&gt;Now I use a table with 40 values, forming a LUT for a sine (the one in my code above), and I see, as expected, a 10kHz sine wave. Badly filtered because I only had around the wrong RC values, but the overall frequency won&amp;#39;t change, just how clean the sine looks&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img style="max-height:240px;max-width:320px;" alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/640x480/__key/communityserver-discussions-components-files/4/DS2302A_5F00_22_2D00_06_2D00_2022_5F00_16_2D00_40_2D00_06.9.png" /&gt;&lt;/p&gt;
&lt;p&gt;So now I ask again: what am I missing? How can I use more entries in the LUT without either reducing too much the vertical resolution or changing frequency? 40 and 40 is all I can do to make things work, and I don&amp;#39;t understand how to program the nRF52840 any different. I could do 20 and 80, but it would be a worse compromise&lt;/p&gt;
&lt;p&gt;If I needed a 1kHz sine wave, then, yes, I could use higher countertop and more table entries...&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/thread/373787?ContentTypeID=1</link><pubDate>Wed, 22 Jun 2022 19:27:13 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:375cae28-64ab-4538-a0d4-e4b1439a4fdd</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;The PWM choices are dictated by the prescaler used, divide 16MHz by 1 , 2, 4, 8 etc;, This might be clearer:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// PWM frequency input with prescale /1: 16MHz
//
// COUNTERTOP   Steps  Resolution in % Output Frequency          Memory (bytes)
// ==========   =====  =============== ========================= ==============
//    1600       1600  1/1600 = .0625  16,000,000/1,600 =  10kHz 1600*2=3200
//      40         40  1/  40 = 2.5    16,000,000/   40 = 400kHz   40*2=  80


// PWM frequency input with prescale /8:  2MHz
//
// COUNTERTOP   Steps  Resolution in % Output Frequency          Memory (bytes)
// ==========   =====  =============== ========================= ==============
//     200        200  1/ 200 = 0.5     2,000,000/  200 =  10kHz  200*2= 400
//      40         40  1/  40 = 2.5     2,000,000/   40 =  50kHz   40*2=  80&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/thread/373772?ContentTypeID=1</link><pubDate>Wed, 22 Jun 2022 17:19:31 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a1554bee-3514-4ab7-bc50-97f3d6295d9e</guid><dc:creator>robca</dc:creator><description>[quote userid="65515" url="~/f/nordic-q-a/89209/clarification-on-how-to-generate-a-10khz-sine-wave-with-pwm-and-dma/373555"]Why only 40 steps, by the way? More steps and a faster net clock would give a better (cleaner) output unless you are very short of memory. 1600 steps (3200 bytes) is an option is it not ..[/quote]
&lt;p&gt;Thanks for your answer, but either I misunderstand you or my understanding of the way a PWM works is wrong... or both &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;We start from a 16MHz clock. The first decision is how many steps of that 16MHz clock our PWM period uses. That is what Nordic calls counter top, and defines the resolution of the PWM. I landed on 40, to strike the best possible balance between sine points and resolution. So each PWM period has 40 steps, and each step is 2.5% duty cycle.&lt;/p&gt;
&lt;p&gt;That results in a PWM frequency of 400kHz (16MHz/40). In order to generate a 10kHz sine, I can only use 40 points to define a single sine. I could use more points for the sine, but I would have fewer steps for the resolution. I chose 40 and 40 as a compromise between the competing requirements of the vertical and horizontal resolution. If the main clock were higher (some processors can use up to 256MHz clocks), I could increase both&lt;/p&gt;
&lt;p&gt;What am I doing wrong?&lt;/p&gt;
&lt;p&gt;I will try your Common-vs-waveform mode comment, I think I understand what you mean. But it would not change the resolution/frequency, which is the main concern now. I&amp;#39;m not sure that a 40 point.40 values sine would be anywhere near good enough to measure a phase shift from what I see on my scope, but maybe I can use a better output filter. I&amp;#39;m also not sure if the pin I used is properly configured, need to check&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Clarification on how to generate a 10kHz sine wave with PWM and DMA</title><link>https://devzone.nordicsemi.com/thread/373555?ContentTypeID=1</link><pubDate>Wed, 22 Jun 2022 01:49:09 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b65d0843-c7fd-4f24-aaa6-038eaecff6d2</guid><dc:creator>hmolesworth</dc:creator><description>&lt;p&gt;Since in PWM mode here COUNTERTOP is a fixed number, there is no need for waveform mode, instead use Common mode and a single pin connected. That requires a single 16-bit number for each step (instead of 4 numbers per step in waveform mode). Up/Down might give a better sine curve (instead of Up, but it doesn&amp;#39;t matter other than maybe halving the memory requirement).&lt;/p&gt;
&lt;p&gt;The CR filter is just that, a resistor feeding a capacitor to Gnd with the output at the CR junction. -3dB frequency set to (say) 10kHz gives 50% of available signal at the CR junction output. f=1/2pieCR, but very high values of R will be a problem depending on the impedance of the connected circuit being driven. Avoid polarised Tants, instead use ceramics for the capacitor.&amp;nbsp;&lt;span&gt;Maybe try 150R 100nF for 10kHz -3dB. Need to set PWM output pin to H0H1 drive levels, by the way, since driving a capacitive load&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;PDM mode might be a better option if there is too much distortion when you test this PWM; note PDM mode would require using PWM Waveform with a corresponding larger (more complex) table.&lt;/p&gt;
&lt;p&gt;Why only 40 steps, by the way? More steps and a faster net clock would give a better (cleaner) output unless you are very short of memory. 1600 steps (3200 bytes) is an option is it not ..&lt;/p&gt;
&lt;p&gt;Edit: I should add that the CR introduces a phase shift so the known zero-crossing position isn&amp;#39;t; This can be allowed for, preferably with a ratiometric measurement using a fixed phase shift via (say) a calibrated CR network. The frequency step must be &amp;quot;smooth&amp;quot; between end-of-table and start-of-table to avoid a discontinuity in the measurement (in audio terms an annoying &amp;quot;click&amp;quot;). This is best handled by choosing&amp;nbsp; a frequency very close to 10kHz which has an integral number of steps where the exact 10kHz sample might not otherwise be integral. Another reason for lots of steps&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>