Go Down

Topic: Changing Arduino Zero PWM Frequency (Read 32203 times) previous topic - next topic

glovisol

Hi MartinL

From my tests right before the crash I found the following, that might be interesting:

With all the unmodified set-ups of your sketch, on this version of Arduino M0 & 1.7.8 IDE, yesterday evening I got 17.5 KHz.

When I started moving constants, nothing happened, save for Prescaler = 64, that brought me down to 1.25 KHz.

I use Picotech PC scope 2000 series, with Picoscope software which reads frequency, Duty Cycle, and many other parameters, so I am pretty sure of freq. readings, apart from seeing the waveform on the display.

Also I noticed that reading on pin 2 kept at 175.4 Khz, while the 17.5 Khz came on pin 4, thus these pins are used differently on the two IDES & Boards.

Same applies to the controls:

Timer TCC must be another one here.
The PER register command does not operate, so another must be used.
The only one that works here is PRESCALER, where DIV8 and DIV64 make the difference.

I am reading Section 6 of the SAMD21 to get a better ida of the works.

Today I have ordered an original Genuino Zero, coming from UK, then it will be possible to tabulate the differences between Boards, IDEs. etc. It will be an interesting exercise.

Unfortunately the "double click" reset trick does not work in my board, which stays recognized no longer by the USB.

Kind regards,

glovisol


MartinL

#31
Mar 10, 2016, 12:46 pm Last Edit: Mar 10, 2016, 01:42 pm by MartinL
My apologies, I now see the problem. It's to do with the fact that in the loop() section of your code you're calling the analogWrite() function. (I commented this section of code out when I ran the test that outputs 6Hz).

analogWrite() also uses the TCC timers. So if you happen to use an analogWrite() pin that also uses the TCC0 timer, it will conflict with the register manipulation. That's why we're getting different results and has probably caused your M0 to crash.

I imagine the reason your USB port isn't working, is probably due to the fact that the sketch has crashed. Normally on the native USB port the sketch looks for the port to be opened at 1200bps to enter bootloader mode, but if the sketch has crashed it can't do this. This happened to my Zero once, while messing around with some critical registers. I got it working again by pressing reset button between the compile and upload phases, although it took quite a number of goes to get the timing right and it working again.

glovisol

Thanks for your message! You are right I should have been more careful before re-using the analogWrite!


Anyway I realized that, when connected to the PC via USB, the LED "L" is pulsating: I measured with the scope and found a 0,35 V squarewave across it with a freq. of 26.9Hz: this meant that the goddam thing was probably working!!

So I connected back the pot, put the scope on pin 2 and saw the PWM changing with input voltage!! So it is working with the last DEMO I uploaded yesterday. I placed the pot at 1.25V to inputs
A0 - A5 and measurements are as follows.

OUT PWM PINS 0 & 1: 0V.
OUT PWM PIN 2, 3,6 &7: Square Wave 3.3 Vpp (of course!) - Freq. 1.27 KHz - Duty Cycle: 37.7%
OUT PWM PIN 4&5: Square Wave 3.3Vpp - Freq. 161.4 KHz - Duty Cycle 37.7%
OUT PWM PIN 8,9,10,11 & 12: 0V
OUT PWM PIN 13: Square wave 3.3Vpp - Freq. 26.92 Hz - Duty Cycle: 67% (reciprocal of 37%).

So, to sumarize, the sketch did not crash, as it is still working now, but the sketch does not allow communications thru USB!

Now I am going to make you laugh: two hours ago I got the message that the UK supplier had sent the payment back to me "because  they cannot ship to Italy due to legal reasons..." Will we have smugglers now to smuggle Arduinos together with cocaine? What a mad world.

I will run the reset button to death now...

Have a nice evening,

glovisol

MartinL

Quote
Now I am going to make you laugh: two hours ago I got the message that the UK supplier had sent the payment back to me "because  they cannot ship to Italy due to legal reasons..." Will we have smugglers now to smuggle Arduinos together with cocaine? What a mad world.
I've seen the UK supplier's website saying they won't ship to Italy. It might be worth querying it, since you can easily find Italian distributors selling Genuino products in Italy.

glovisol

Hi there,

I am back in business. I pulsed the RESET input with an NE555 pulser outputting 0.5 mS wide pulses @ 200Hz approx. (amplitude 2.5 V). USB disconnected & M0 fed with 8 V on Vin. I let it fry for 5 minutes. As soon as I connected to USB it was recognized again and I again pushed RESET manually to make sure I had removed the offending sketch.

Back to work: I am reading the book, but it takes time. My first question: the SAMD21 has several oscillators. If I used the OSC 32K (32.768 KHz) I would end up with a PWM frequency of 32768/282 = 116 Hz without touching anything else and playing it safe with analogWrite.... Why use a syncro Phaselock @ 48 MHz, if I need low freq. PWM?

Cheers,

glovisol

glovisol

#35
Mar 10, 2016, 04:32 pm Last Edit: Mar 10, 2016, 06:13 pm by glovisol
OK, I tried....I understand now there is only ONE oscillator, e.g. the 8 MHz oscillator here.

I am taking no chances now and am only writing on Pin 7. No more crash problems.

But I see that the prescaler GLK_TCC (now at 64) can also do 256 and 1024. Since with 64 I am at 1.5 Khz already, with 1024 I could go down to 80 Hz approx., not bad... Fact is the prescaler really takes 6a as maximum and does not respond to the higher ratios, so I think the mode of operation is wrong.

glovisol

glovisol

 OK, solved it.

Now the prescaler is at 1024 and PWM is down to 92 Hz. It has been a long day.

Now we must discover why the REG_TCC0_PER do not work.

Thanks a lot for your continuing assistance: you really set me up in business!

Kind regards,

glovisol

MartinL

#37
Mar 10, 2016, 04:54 pm Last Edit: Mar 10, 2016, 04:54 pm by MartinL
Glad to hear you got it working again.

The timer's prescaler gives you the following divisors: 1, 2, 4, 8, 16, 64, 256 and 1024. It's also possible to take the GCLK lower with the GCLK divisor in the REG_GCLK_GENDIV register.

The generic clock can be taken from a number of sources. In my example code it's sourced from the 48MHz DPLL.

What PWM frequency are you looking for on D7?

glovisol

Hi MartinL,

In reality I tried all of the mentioned oscillators, but on the Arduino Board is used a micro where only the mask of the 8MHz oscillator is enclosed, whick locks the 48 MHz clock. This is the only clock we have on board.

 At present I am using the N=256 prescaler and I get 367.6 Hz, but with N=1024 I can go down  to 82 Hz.

I have prepared the enclosed WORD file with all sketch entries , showing what is working and what is not working: have a look. I have yet to figure out how I get the 367.6 Hz.

Of course the sketch shows very coarse frequency control for now, but I expect we can improve a lot!

In any case this fills the bill for my application, because even the cheapest optocoupler will easily work at 370 hz.

Have a nice evening, kind regards,

glovisol




glovisol

Did not let me load the Word File. I try again.

Cheers,

glovisol

MartinL

#40
Mar 10, 2016, 11:52 pm Last Edit: Mar 10, 2016, 11:54 pm by MartinL
The following code will output 370Hz on pin D7 with an 11-bit resolution:

Code: [Select]
// Output 370Hz PWM on timer TCC0 (11-bit resolution) on D7
void setup()
{
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(3) |          // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
                    GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                     GCLK_GENCTRL_GENEN |         // Enable GCLK4
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                     GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Enable the port multiplexer for the 1 PWM channel: timer TCC0 output
  const uint8_t CHANNELS = 1;
  const uint8_t pwmPins[] = { 7 };
  for (uint8_t i = 0; i < CHANNELS; i++)
  {
     PORT->Group[g_APinDescription[pwmPins[i]].ulPort].PINCFG[g_APinDescription[pwmPins[i]].ulPin].bit.PMUXEN = 1;
  }
  // Connect the TCC0 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
  // F & E specify the timers: TCC0, TCC1 and TCC2
 
  PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F;

  // Feed GCLK4 to TCC0 and TCC1
  /*REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1*/
  GCLK->CLKCTRL.reg = 0x441A;                     // Added for compilation problem with Arduino M0
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Dual slope PWM operation: timers countinuously count up to PER register value then down 0
  REG_TCC0_WAVE |= TCC_WAVE_POL(0xF) |         // Reverse the output polarity on all TCC0 outputs
                    TCC_WAVE_WAVEGEN_DSBOTTOM;    // Setup dual slope PWM on TCC0
  while (TCC0->SYNCBUSY.bit.WAVE);               // Wait for synchronization

  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation:
  // 20000 = 50Hz, 10000 = 100Hz, 2500  = 400Hz, 2702 = 370Hz
  REG_TCC0_PER = 2702;      // Set the frequency of the PWM on TCC0 to 370Hz
  while(TCC0->SYNCBUSY.bit.PER);

  // The CCBx register value corresponds to the pulsewidth in microseconds (us)
  REG_TCC0_CCB3 = 1500;       // TCC0 CCB3 - center the servo on D7
  while(TCC0->SYNCBUSY.bit.CCB3);

  // Divide the 16MHz signal by 8 giving 2MHz (0.5us) TCC0 timer tick and enable the outputs
  REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 |    // Divide GCLK4 by 8
                    TCC_CTRLA_ENABLE;             // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization
}

void loop() { }

Here the timer is being clocked with a 2MHz signal (48MHz/3 = 16MHz, 16MHz/8 = 2MHz), or in other words each tick has a period of 0.5uS (1/2MHz). We're using dual slope PWM, in this scenario the timer counts up to the PER register value then back down to 0 and so on. So the PER register determines how long the timer takes to cycle counting up and then back down or in other words it determines the PWM's frequency.

This is given by the formula for dual slope PWM: PWM frequency = timer frequency / (2 * PER).

If we know the PWM frequency this formula can be rewritten PER = timer frequency / (2 * PWM frequency).

Therefore PER = 2MHz / (2 * 370) = 2702. That's the value of our PER register for 370Hz.

The CCBx registers determine the duty cycle. They can be any value between 0 and PER. In this case a value of 1351 (2702/2) will give a 50% duty cycle.

The resolution of this signal is given by the formula: resolution = log(PER + 1)/log(2). For a PER register value of 2702 this gives a resolution of 11-bits.

glovisol

Dear Martin,

Thanks a lot for the ad hoc sketch!! Just up (7.30 AM here). Will test right away.I am enclosing a PICT. showing the 370 Hz , the PWM D.C. and the mean D.C. recovered @ 10 bit.

Will post results later today.

glovisol

glovisol

Dear Martin,

I got a big fright! Sorry to disappoint you. I uploaded the sketch and it compiled first time. Near the end of uploading  IT LOST THE COMM PORT. Again the message "Device not recognized".

I unplugged Arduino instantly from  the USB cable, re-started the PC, checked "Devices" and re-plugged the M0. This time Windows recognized it and I could reload  Blink".

I carefully inspected your script and checked it with the working one (the Word stencilled script) found nothing wrong and did a second test. Again it lost the COMM Port before completing the upload.

I recovered M0nagain and re-loaded yesterday's sketch which is quietly working now....I believe there are gross differences between the US Zero and the Italian M0 in MUX settings.

I intend to get an US Zero with twin USB's as soon as possible, so that we have a common testing ground and not work with the constant fear of losing the Micro.

Kind regards,

glovisol

MartinL

The one of the main differences between the M0/M0 Pro and the Zero is that the digital pins D2 and D4 are swapped.

So, on the M0 the TCC0 will output on D4, D5, D6 and D7, while the Zero will output on D2, D5, D6 and D7. Apart from that, the MUX settings should be the same.

glovisol

#44
Mar 11, 2016, 10:10 am Last Edit: Mar 11, 2016, 10:16 am by glovisol
The MUX settings should be the same, but are not because these last settings freezed my M0 twice. What do you suggest?

Also you did not comment on the observations on the stencilled Word doc., where you can see that some parts of the sketch are not operative: this should surely point to relevant differences. I have located Zeros in France and hope to be operative by mid next week.

Furthermore pin 7 is for system testing only. I really need 6 output pins with 200 to 400 Hz PWM ouputs & Duty Cycle variable 0 to 100%, so a pin plan must be carefully laid out, in order not to have analogWrite interferences.

Go Up