<?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>NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/7863/nrf51-sine-wave-with-pwm-and-timer</link><description>Hi, 
 I want to generate a sine wave using the nrf pwm library and a timer CC instead of a delay that is used in the sine example here to get better accuracy. 
 It basically works but I keep getting strange &amp;quot;jumps&amp;quot; in the signal. Here is an image of</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Mon, 29 Jun 2015 12:07:27 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/7863/nrf51-sine-wave-with-pwm-and-timer" /><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28032?ContentTypeID=1</link><pubDate>Mon, 29 Jun 2015 12:07:27 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8bbdffa4-ec78-487f-81a6-7ce89cf811d6</guid><dc:creator>gammarui</dc:creator><description>&lt;p&gt;I tried to generate a sine with the same method as before but without sd and it works, sometimes. When I set NRF_TIMER1-&amp;gt;CC[0] = X, most values for X generates the same inverted pwm problem I got with the softdevice. However, the glitches come in a predictable pattern and it seems like it is caused by some wrap around problem. I tested a few values on X and it seems 98, 107, 118, 150 works but I cant find any least common denominator that makes any sense. Any idea what could cause this?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28037?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 16:01:29 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:f7bb8891-3405-428b-b79b-0041bb741ffa</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;One other thing. In your code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Configure GPIOTE channel 0 and 1 to change pin state
  nrf_gpiote_task_config(0, pin, NRF_GPIOTE_POLARITY_LOTOHI,
      NRF_GPIOTE_INITIAL_VALUE_LOW);

  nrf_gpiote_task_config(1, pin, NRF_GPIOTE_POLARITY_HITOLO,
      NRF_GPIOTE_INITIAL_VALUE_LOW);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;it looks like you are trying to use two GPIOTE task that target the same pin. You can&amp;#39;t do that. You have to use the toggle function. That&amp;#39;s why there are so many PWM problem questions. It would be a much better system if you could SET and CLEAR the same pin via PPI/GPIOTE, but I guess the silicon designers have to make compromises. I believe the new nRF52 has proper PWM hardware.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28036?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 14:53:31 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:4cf103ce-f4bb-4201-a1e3-5db9f112a564</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;Some of the formatting has been screwed up in the copy and paste. Sorry.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28035?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 14:49:58 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:1e00a20e-683d-4f9d-9fd7-d02dddd185c9</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;OK Here is my code. Bear in mind that I am generating two sine waves, and I am using a fractional accumulator method(or whatever it&amp;#39;s called)
This is completely self contained, i.e. all the setting up and clearing up is in this function.
As I said, I do not have the SD running at this point, but if I were you I&amp;#39;d get it working without first, then see if you can make it work with the SD.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;quot;dtmf.h&amp;quot;
#include &amp;quot;nrf_gpiote.h&amp;quot;
#include &amp;quot;nrf.h&amp;quot;
#include &amp;quot;nrf51_bitfields.h&amp;quot;
#include &amp;quot;nrf_soc.h&amp;quot;
#include &amp;quot;nrf_gpio.h&amp;quot;


#define	DIGIT_LEN	100000/20		// 100 mS, PWM max is 20uS
#define	GAP_LEN		100000/20		// 100 mS

#define GPIOTE_CHAN_FOR_PWM_TASK	3	//The GPIOTE Channel used for PWM
#define DTMF_TIMER	NRF_TIMER1		// Timer used


enum
{
DTMF_1, DTMF_2, DTMF_3, DTMF_A,
DTMF_4, DTMF_5, DTMF_6, DTMF_B,
DTMF_7, DTMF_8, DTMF_9, DTMF_C,
DTMF_STAR, DTMF_0, DTMF_HASH, DTMF_D
};

#define HF1663	(1663 * 32678 + 20000) / 40000
#define HF1477	(1477 * 32678 + 20000) / 40000
#define HF1336	(1336 * 32678 + 20000) / 40000
#define HF1209	(1209 * 32678 + 20000) / 40000

#define LF941	(941 * 32678 + 20000) / 40000
#define LF852	(852 * 32678 + 20000) / 40000
#define LF770	(770 * 32678 + 20000) / 40000
#define LF697	(697 * 32678 + 20000) / 40000

const uint16_t HighGroup [4] =
	{
	HF1209,
	HF1336,
	HF1477,
	HF1663
	};
const uint16_t LowGroup [4] =
	{
	LF697,
	LF770,
	LF852,
	LF941
	};

const uint8_t SineTable [128] = {
	0,0,0,0,1,1,2,3,
	4,6,7,9,10,12,14,16,
	18,21,23,25,28,31,33,36,
	39,42,45,48,51,54,57,60,
	64,67,70,73,76,79,82,85,
	88,91,94,96,99,102,104,106,
	109,111,113,115,117,118,120,121,
	123,124,125,126,126,127,127,127,
	127,127,127,127,126,126,125,124,
	123,121,120,118,117,115,113,111,
	109,106,104,102,99,96,94,91,
	88,85,82,79,76,73,70,67,
	64,60,57,54,51,48,45,42,
	39,36,33,31,28,25,23,21,
	18,16,14,12,10,9,7,6,
	4,3,2,1,1,0,0,0
	};

void SendDTMF(uint8_t code)
{
uint16_t StepLo = 0;
uint16_t StepHi = 0;
uint16_t SineIndexLo = 0;
uint16_t SineIndexHi = 0;
uint16_t pwm_value = 1;
uint8_t temph;
uint8_t templ;
uint16_t duration;
nrf_gpio_cfg_output(PWM_OUT);
nrf_gpio_cfg_output(DTMF_LED);

// Set up the PPI
// PPI channel 0 event is Timer1 compare 2
NRF_PPI-&amp;gt;CH[0].EEP = (uint32_t) &amp;amp;DTMF_TIMER-&amp;gt;EVENTS_COMPARE[2];

// PPI channel 0 task is GPIOTE task 3(toggle output)
NRF_PPI-&amp;gt;CH[0].TEP = (uint32_t) &amp;amp;NRF_GPIOTE-&amp;gt;TASKS_OUT[3];

// PPI chan 1 event is Timer n compare 0
NRF_PPI-&amp;gt;CH[1].EEP = (uint32_t) &amp;amp;DTMF_TIMER-&amp;gt;EVENTS_COMPARE[0];

// PPI chan 1 task is GPIOTE task 3(toggle output)
NRF_PPI-&amp;gt;CH[1].TEP = (uint32_t) &amp;amp;NRF_GPIOTE-&amp;gt;TASKS_OUT[3];

// Enable PPI chan 0
NRF_PPI-&amp;gt;CHENSET = (1 &amp;lt;&amp;lt; 0);

// Enable PPI chan 1
NRF_PPI-&amp;gt;CHENSET = (1 &amp;lt;&amp;lt; 1);

DTMF_TIMER-&amp;gt;MODE = TIMER_MODE_MODE_Timer;    // Set the timer in Timer Mode.
DTMF_TIMER-&amp;gt;PRESCALER = 0; // Prescaler 0 produces 16mHz Hz timer frequency =&amp;gt; 1 tick = 62.5nS.
DTMF_TIMER-&amp;gt;BITMODE = TIMER_BITMODE_BITMODE_16Bit;  // 16 bit mode.
DTMF_TIMER-&amp;gt;TASKS_CLEAR = 1; // clear the task first to be usable for later.

DTMF_TIMER-&amp;gt;CC[0] = 1;		// cc 0 is the end of the PWM ON period, avoid zero
DTMF_TIMER-&amp;gt;CC[1] = 255;	// cc 1 is the point where we update the period (cc0)
DTMF_TIMER-&amp;gt;CC[2] = 399;	//319;	// cc 2 is the point where we clear the counter and set the PWM out high
// cc2 clears the counter
DTMF_TIMER-&amp;gt;SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Msk;

// Configure the GPIOTE Task to toggle the PWM output.
nrf_gpiote_task_config(GPIOTE_CHAN_FOR_PWM_TASK,
                           PWM_OUT,
                           NRF_GPIOTE_POLARITY_TOGGLE,
                           NRF_GPIOTE_INITIAL_VALUE_HIGH);

StepLo = LowGroup[code &amp;gt;&amp;gt; 2 &amp;amp; 3];
StepHi = HighGroup[code &amp;amp; 3];

duration = DIGIT_LEN + GAP_LEN;
DTMF_TIMER-&amp;gt;TASKS_START = 1;  // Start timer.

nrf_gpio_pin_set(DTMF_LED);

// Because my app was doing nothing else I polled the timer compare
// but it should work as an IRQ
while(duration)
    {
    if(DTMF_TIMER-&amp;gt;EVENTS_COMPARE[1])
	{
	DTMF_TIMER-&amp;gt;CC[0] = pwm_value;
	DTMF_TIMER-&amp;gt;EVENTS_COMPARE[1] = 0;
	// Now calculate value for next time time.
	// Move pointers a step width ahead
	SineIndexHi += StepHi;
	SineIndexLo += StepLo;
	temph = SineTable[SineIndexHi &amp;gt;&amp;gt; 8 &amp;amp; 127];
	templ = SineTable[SineIndexLo &amp;gt;&amp;gt; 8 &amp;amp; 127];
	templ -= (templ &amp;gt;&amp;gt; 2);		// Low * 0.75
	temph += templ;
	// Avoid a zero value. I can do this safely as the sine table only goes up to 127
	// and the lower of the two tones has been multiplied by 0.75 abave
	temph += 1;
	pwm_value = (uint16_t)temph;

	if(duration == GAP_LEN)
	    {
	    nrf_gpio_pin_clear(DTMF_LED);	// This turns off the LED after 50mS or so
	    }
	if(duration &amp;lt; GAP_LEN)
		{
		if(temph == 1)			// This is because I want to turn the tones off when the output is close to 0V
			{
			StepHi = 0;
			StepLo = 0;
			nrf_gpiote_unconfig(GPIOTE_CHAN_FOR_PWM_TASK);
		        nrf_gpio_pin_write(PWM_OUT, 0);
			}
		}
	if(duration)
		{
		duration--;
		}
	}
    }// ends while(duration)

// Dismantle everything
DTMF_TIMER-&amp;gt;TASKS_STOP = 1;  // Stop timer.
DTMF_TIMER-&amp;gt;TASKS_CLEAR = 1;  // Clear timer.
DTMF_TIMER-&amp;gt;SHORTS = 0x00;
DTMF_TIMER-&amp;gt;EVENTS_COMPARE[0] = 0;
DTMF_TIMER-&amp;gt;EVENTS_COMPARE[1] = 0;
DTMF_TIMER-&amp;gt;EVENTS_COMPARE[2] = 0;

// Disable PPI chan 0
NRF_PPI-&amp;gt;CHENCLR = (1 &amp;lt;&amp;lt; 0);
// Disable PPI chan 1
NRF_PPI-&amp;gt;CHENCLR = (1 &amp;lt;&amp;lt; 1);
}
&lt;/code&gt;&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28034?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 14:00:00 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ea7de20f-ff9e-40b3-9b13-b1292ab13b06</guid><dc:creator>gammarui</dc:creator><description>&lt;p&gt;Hi John, Thanks for your workaround. I tried to implement it but I am not sure if I understand you correctly, is it something like this you mean:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace {

uint8_t phase = 1;

bool active = false;

const uint8_t sine26[] = {0, 4, 16, 35, 59, 88, 120, 152, 182, 210, 232, 247,
    255, 255, 247, 232, 210, 182, 152, 120, 88, 59, 35, 16, 4, 0};

}
void initSimplePWM(uint8_t pin);

extern &amp;quot;C&amp;quot; {

void TIMER2_IRQHandler(void) {
  NRF_TIMER2-&amp;gt;CC[0] = sine26[phase];
  if (phase &amp;lt; 26) {
    phase++;
  } else {
    phase = 1;
  }
}

} // end of extern C

int main() {
  setupLEDPins();

  pinOutput(PIEZO_PWM_PIN);

// Init softdevice
  BluetoothPeripheral::instance().initialize();

  initSimplePWM(PIEZO_PWM_PIN);
  NRF_TIMER2-&amp;gt;TASKS_START = 1;               // Start timer.

  while (1) {
    delayMs(100);
    pinToggle(LED_RED);
  }
  
  return 0;
}

void initSimplePWM(uint8_t pin) {
  // Configure GPIOTE channel 0 and 1 to change pin state
  nrf_gpiote_task_config(0, pin, NRF_GPIOTE_POLARITY_LOTOHI,
      NRF_GPIOTE_INITIAL_VALUE_LOW);

  nrf_gpiote_task_config(1, pin, NRF_GPIOTE_POLARITY_HITOLO,
      NRF_GPIOTE_INITIAL_VALUE_LOW);

  // Configure PPI channel 0 to toggle PWM_OUTPUT_PIN on every TIMER2 COMPARE[0] match.
  NRF_PPI-&amp;gt;CH[0].EEP = (uint32_t)&amp;amp;NRF_TIMER2-&amp;gt;EVENTS_COMPARE[0];
  NRF_PPI-&amp;gt;CH[0].TEP = (uint32_t)&amp;amp;NRF_GPIOTE-&amp;gt;TASKS_OUT[0];
  NRF_PPI-&amp;gt;CH[1].EEP = (uint32_t)&amp;amp;NRF_TIMER2-&amp;gt;EVENTS_COMPARE[1];
  NRF_PPI-&amp;gt;CH[1].TEP = (uint32_t)&amp;amp;NRF_GPIOTE-&amp;gt;TASKS_OUT[1];

  // Enable PPI channel 0.
  NRF_PPI-&amp;gt;CHEN = (PPI_CHEN_CH0_Enabled &amp;lt;&amp;lt; PPI_CHEN_CH0_Pos |
  PPI_CHEN_CH1_Enabled &amp;lt;&amp;lt; PPI_CHEN_CH1_Pos);
  //sd_ppi_channel_enable_set(1 &amp;lt;&amp;lt; 0);

  // Init TIMER2 for 10kHz PWM
  NRF_TIMER2-&amp;gt;MODE = TIMER_MODE_MODE_Timer;     // Set the timer in Counter Mode
  NRF_TIMER2-&amp;gt;TASKS_CLEAR = 1;   // Clear the tasks first to be usable for later
  NRF_TIMER2-&amp;gt;PRESCALER = 4; // 2^PRESCALER (values authorized 1 to 9) 4 : 16MHz / 16 = 1MHz
  NRF_TIMER2-&amp;gt;BITMODE = TIMER_BITMODE_BITMODE_16Bit; //Set counter to 16 bit resolution
  NRF_TIMER2-&amp;gt;CC[0] = phase; //1Mhz timer with prescaler 4
  NRF_TIMER2-&amp;gt;CC[1] = 400; //1Mhz timer with prescaler 4
  NRF_TIMER2-&amp;gt;CC[2] = 256; //1Mhz timer with prescaler 4
  NRF_TIMER2-&amp;gt;SHORTS = (TIMER_SHORTS_COMPARE1_CLEAR_Enabled
      &amp;lt;&amp;lt; TIMER_SHORTS_COMPARE1_CLEAR_Pos);

  NRF_TIMER2-&amp;gt;INTENSET = (TIMER_INTENSET_COMPARE2_Enabled
      &amp;lt;&amp;lt; TIMER_INTENSET_COMPARE2_Pos);
  sd_nvic_SetPriority(TIMER2_IRQn, 3);
  sd_nvic_EnableIRQ(TIMER2_IRQn);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code does not work but if this is what you meant and you got it to work I will continue on this path as there does not seem to be any other way to generate a sine wave output with the nrf51 device.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28033?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 11:48:40 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a0b39771-5be8-402a-b1a9-b93dab095c2a</guid><dc:creator>JohnBrown</dc:creator><description>&lt;p&gt;The way I got round this in order to generate DTMF was to set the maximum count to 400, but limit the on-time to 256. This way I was able to set the next duty cycle in the dead time between 256 and 399. The only IRQ was the one at the 256 count, when I set the compare for the off-time and then looked up the value for next time
The downside:&lt;/p&gt;
&lt;p&gt;a) I had to avoid the value of zero for the on-time(I used 1 to 256 rather than 0 to 255)&lt;/p&gt;
&lt;p&gt;b) The resulting voltage levels were not 0 to Vdd(didn&amp;#39;t matter in my app.)&lt;/p&gt;
&lt;p&gt;So one compare register is set at 400. This clears the timer(via SHORTS) and toggles the output to ON.&lt;/p&gt;
&lt;p&gt;Another compare register is set to the duty, this toggles the output to OFF.&lt;/p&gt;
&lt;p&gt;A third compare is set to 256, this generates an IRQ in which I update the duty compare with the value I calculated last time, then calc the value for next time.&lt;/p&gt;
&lt;p&gt;Admittedly, I was not running the SD during this, but I reckon that if you can cope with a lower amplitude sine wave, this could still work, you might need to increase the 400 to something higher...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28031?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 11:47:40 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:c64a1219-0ad4-4a20-8c8e-3305b7ab4fa5</guid><dc:creator>gammarui</dc:creator><description>&lt;p&gt;Thanks for your quick reply. Yes, I am using S110.&lt;/p&gt;
&lt;p&gt;Looking forward to a fix in future releases!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: NRF51 sine wave with pwm and timer</title><link>https://devzone.nordicsemi.com/thread/28030?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2015 11:34:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8f6a9a8b-9c49-4ed1-bad6-35159809aaa3</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;If you are using softdevice, then it is a known issue
&lt;a href="https://devzone.nordicsemi.com/questions/sort:relevance-desc/query:pwm%20reverse/"&gt;devzone.nordicsemi.com/.../&lt;/a&gt;
This issue is currently under investigation and we unfortunately  have to wait until further information is available.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>