chipKIT® Development Platform

Inspired by Arduino™

analogWrite issues

Created Sun, 14 Jul 2013 14:54:46 +0000 by caroper


caroper

Sun, 14 Jul 2013 14:54:46 +0000

Hi,

I am not sure if this is an issue with mpide-0023-windows-20130626 or an issue with the chipKIT DP32, but I can not get analogWrite to work.

The closest I have got is this:

void setup() 
{
}
void loop() 
{
  analogWrite(10, 128);
  delay(500);
}

which gives a constant 3.27V in the above code analogWrite(10, 127); gives a few milivolts.

if I try Pin 13 which has OC4 pre mapped to it the situation is worse less than 255 gives milivolts, 255 or greater gives 3.27 Volts.

I have tried varying delays, in case the old bug had creped back in, and I have tried it in setup, without the loop.

I know I can create my own PWM, and I intend to, but for educational reasons I wanted to show the output of analogWrite verses a hand coded version.

Any suggestions welcome as I am not used to coding Arduino Style, I normally use MPLAB.

Cheers Chris


majenko

Sun, 14 Jul 2013 14:57:52 +0000

A voltmeter isn't the best way of debugging a PWM signal. Do you have access to an oscilloscope so you can see the actual waveform produced?


caroper

Sun, 14 Jul 2013 15:11:56 +0000

There is no waveform produced.

I don't have a Scope but the Logic Analyzer is showing no wave form, the LED's are Full on or Full off, and My Multimeter works perfectly showing varying levels if I use the SoftServoPWM Library. It is Just analogWrite that is not working.

So in this instance I don't think I can blame the Tools.


majenko

Sun, 14 Jul 2013 15:26:01 +0000

Not blaming the tools - just lamenting the lack of detail the tools produce ;)

Logic analyzer is good - as good as a scope in this instance.

So, no waveform - either all on or all off.

Historically, on the Arduino, if you do analogWrite on a pin that doesn't have hardware PWM it basically turns it on or off with a threshold of 127. If the analog write value is 127 or below it turns the pin off - if it's more than 127 it turns the pin on.

That could be what you are seeing there.

If the pin you are using isn't in the board definition as being a PWM pin (regardless of your mapping) it won't recognize it as PWM and will just use the on/off technique.

if ((timer == NOT_ON_TIMER) || (val == 0) || (val >= 255))
    {
        pinMode(pin, OUTPUT);

        if (val < 128)
        {
            digitalWrite(pin, LOW);
        }
        else
        {
            digitalWrite(pin, HIGH);
        }
    }

I don't have the board definition for the DP32 to hand, so I can't see what pins should be mapped to which PWM channel, but I can see from the core code:

#if defined(__PIC32MX1XX__) || defined(__PIC32MX2XX__)
            volatile uint32_t * pps;

            /* On devices with peripheral pin select, it is necessary to connect
            ** the output compare to the pin.
            */
            pps = ppsOutputRegister(timerOCtoDigitalPin(timer));
            *pps = ppsOutputSelect(timerOCtoOutputSelect(timer));
#endif
            ocp->ocxR.reg   = ((PWM_TIMER_PERIOD*val)/256);

so it should be doing the mapping for you.

Can you confim which pins should be PWM by looking in the Board_Data.c file in the DP32 variant folder for the output_compare_to_digital_pin_PGM[] array?


mikes

Sun, 14 Jul 2013 15:33:29 +0000

Pin 10 on a uno32 has a jumper that has to be set correctly for pwm to work is it? http://www.digilentinc.com/Data/Products/CHIPKIT-UNO32/chipKIT-Uno32-Jumpers.pdf


caroper

Sun, 14 Jul 2013 16:36:42 +0000

Historically, on the Arduino, if you do analogWrite on a pin that doesn't have hardware PWM it basically turns it on or off with a threshold of 127. If the analog write value is 127 or below it turns the pin off - if it's more than 127 it turns the pin on. That could be what you are seeing there.

Interesting, thanks for that, I always assumed that analogWrite worked on any PIN.

Pin 13 is meant to be PWM and it has OC4 mapped to it. I suspect this could be a PPS mapping issue then.

Thanks Will have another look and delve into the Board_Defs.c after dinner.

Cheers Chris


caroper

Sun, 14 Jul 2013 19:54:27 +0000

I think this is what you requested:

const uint8_t output_compare_to_digital_pin_PGM[] = {
	PIN_OC1,	        // A0, B3, B4, B15, B7  ; B15   RPB15R  = 5  	
	PIN_OC2,	        // A1, B5, B1, B11, B8  ; B8    RPB8R   = 5
	PIN_OC3,	        // A3, B14, B0, B10, B9 ; B9    RPB9R   = 5
	PIN_OC4,	        // A2, B6, A4, B13, B2  ; B2    RPB2R   = 5
	PIN_OC5,	        // A2, B6, A4, B13, B2	; B13   RPB13R  = 6
};

and I have specifically mapped Pin 13 to OC4 despite it being pre mapped - Still no joy.

void setup()
{
  pinMode(11, OUTPUT); // Confirms Valid PPS Mapping
  pinMode(12, OUTPUT); // Step Count
  pinMode(13, OUTPUT); // PWM Output
  
  if(mapPps(13, PPS_OUT_OC4)) digitalWrite(11, HIGH); 
}

void loop()
{
    for (int brightness = 0; brightness < 255; brightness += 15) 
    { // Tamp Up    255 / 15 = 17 Steps
      digitalWrite(12, HIGH); // Mark Step
      analogWrite(13, brightness);
      delay(1);
      digitalWrite(12, LOW); // Space Step
      delay(1);
    } // Total Duaration 2 x 17 = 34 ms = 29.4 Hz
   for (int brightness = 255; brightness >= 0; brightness -= 15) 
   { // Ramp Down  255 / 15 = 17 Steps 
      digitalWrite(12, HIGH); // Mark Step
      analogWrite(13, brightness);
      delay(1);
      digitalWrite(12, LOW); // Space Step
      delay(1);
   } // Total Duaration 2 x 17 = 34 x 2 = 68 ms
}

Measured Readings correlate with predicted values in the code comment Pin 13 continues to toggle on at 255 and off < 255

mapPps() returns True Ch 1 Step Count is correct Ch 2 Waveform not shifting Ch 3

There must be something else I am missing,

Cheers Chris


majenko

Sun, 14 Jul 2013 20:11:39 +0000

This is the code that is setting the PWM pin high or low.

if ((timer == NOT_ON_TIMER) || (val == 0) || (val &gt;= 255))
{
  pinMode(pin, OUTPUT);

  if (val &lt; 128)
  {
    digitalWrite(pin, LOW);
  } else {
    digitalWrite(pin, HIGH);
  }
}

Going by your timings it's calling that when val is 0 or 255, which is why it is 0 for the ramp up, then 1 for the ramp down. So timer==NOT_ON_TIMER will be false, as otherwise it would be switching high/low/high half way through the ramps.

Ok, so that means that it must think it's a valid PWM pin - that's good.

Next...

if (pwm_active == 0)
{
  T2CON = TBCON_PS_256;
  TMR2 = 0;  
  PR2 = PWM_TIMER_PERIOD;
  T2CONSET = TBCON_ON;
}

Can you look at T2CON and PR2 once PWM has supposedly been started to see if the timer has been configured right?


caroper

Sun, 14 Jul 2013 20:49:04 +0000

Will this do:

Modified code:

void setup()
{
  pinMode(11, OUTPUT); // Confirms Valid PPS Mapping
  pinMode(12, OUTPUT); // Step Count
  pinMode(13, OUTPUT); // PWM Output
  pinMode(17, INPUT);  // PROG BTN
  
  Serial.begin(15200);
// Give user time to open Serial Monitor
  while(!digitalRead(17)); // wait for PROG
  
  if(mapPps(13, PPS_OUT_OC4)) digitalWrite(11, HIGH); 
}

void loop()
{
    for (int brightness = 0; brightness &lt; 255; brightness += 15) 
    { // Tamp Up    255 / 15 = 17 Steps
      digitalWrite(12, HIGH); // Mark Step
      analogWrite(13, brightness);
      Serial.print(T2CON);
      Serial.print(" : ");
      Serial.println(PR2);   
      delay(1);
      digitalWrite(12, LOW); // Space Step
      delay(1);
    } // Total Duaration 2 x 17 = 34 ms = 29.4 Hz
   for (int brightness = 255; brightness &gt;= 0; brightness -= 15) 
   { // Ramp Down  255 / 15 = 17 Steps 
      digitalWrite(12, HIGH); // Mark Step
      analogWrite(13, brightness);
      delay(1);
      digitalWrite(12, LOW); // Space Step
      delay(1);
   } // Total Duaration 2 x 17 = 34 x 2 = 68 ms
}

Output first loop 17 steps:

1st loop
0 : 65535
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
32880 : 318
next loop
112 : 318

I am not sure what I should be seeing here.

Cheers Chris


majenko

Sun, 14 Jul 2013 21:05:44 +0000

32880 = 0x8070 = 1000 0000 0111 0000 bits 15, 6, 5 and 4 are set.

Those equate to: 15: on 6-4: prescaler (111 = 1:256)

Which equates exactly to what it should be, so the timer is set up right.

Ok, next... OC4CON - is that being set right?

Can you get the value of that after PWM is init?

Ta.


caroper

Sun, 14 Jul 2013 21:32:08 +0000

OC4CON = 0

Not good, but what should it be?

I know that setting a PPS Output pin assignment to 0 is equivalent of releasing it to GPIO, and unfortunately, at this stage the documentation for PPS in MPIDE is pretty much non existent.

I could dig out the datasheet and do the PPS assignments with Plib but what I was really after was confirmation that my Code was correct in terms of MPIDE and it is it a bug in the DP32 implementation or that had I made an error coding as I have never actually used analogWrite before.

I can code around it for practical applications, but as this is meant to be teaching others how to do it in MPIDE vs MPLAB I need to get it working both ways, well 3 ways as I am showing SoftPWM too, but I know that works on any pin and have already tested it.

I really appreciate your help though, and am learning a lot from it, thanks :) It is coming up for midnight here and I hate going to bed with an unresolved coding problem.

Cheers Chris

Edit just extended that last test: OC4CON pre mapPps() 0 OC4CON post mapPps() 0 OC4CON post analogWrite() 0

so it is not being changed by anything


majenko

Sun, 14 Jul 2013 21:41:19 +0000

ocp-&gt;ocxCon.reg = OCCON_SRC_TIMER2 | OCCON_PWM_FAULT_DISABLE;
ocp-&gt;ocxCon.set = OCCON_ON;

That should set OC4CON to :

OCCON_SRC_TIMER2 = 0000 0000 0000 0000 OCCON_PWM_FAULT_DISABLE = 0000 0000 0000 0111 OCCON_ON = 1000 0000 0000 0000

which equals 1000 0000 0000 0111 or 0x8007

If that's not happening, then maybe it's using a different OC than OC4? Check out OC1CON - OC5CON and see if any of those have a reasonable value?


caroper

Sun, 14 Jul 2013 21:52:45 +0000

No, all zero

OC1CON post analogWrite() 0 OC2CON post analogWrite() 0 OC3CON post analogWrite() 0 OC4CON post analogWrite() 0 OC5CON post analogWrite() 0

It is past Midnight and I am struggling to keep my eyes open, so any code I try to write now will probably have more bugs than it fixes :)

I will take a fresh look at it in the morning with all of the Datasheets and source code at hand.

At least I can create my own version, I have done it often enough in MPLAB, I will just ignore the analogWrite stuff for now and concentrate on coding the PIC32MX with PLib.

And here was I thinking "The Arduino way" was meant to be easy. Still it is easer than fighting with MPLABX and it is a better underlying compiler than the deliberately crippled XC versions, so if I can get my development work moved over to MPIDE or your own UECIDE it will be worth while.

Cheers, And thanks again for all your help today

Chris


JordanR

Mon, 15 Jul 2013 19:20:32 +0000

Hello Chris,

Looks like there are some issues with address calculations. What version of MPIDE are you using? I found this in 0609, and am checking 0626 right now. I will let you know what I find.

Best Regards,

Jordan


caroper

Mon, 15 Jul 2013 20:29:48 +0000

Thank Jordan,

I was using 0626. I will hold off debuting it further till you have completed you tests,

Cheers Chris


JordanR

Mon, 15 Jul 2013 20:47:06 +0000

Hello Chris,

As you were seeing, it did still happen in 0626, so just to let you and anyone else experiencing this issue know, we (Digilent) are taking a look into this! Thanks for bringing it to our attention.

Best Regards,

Jordan


KeithV

Fri, 19 Jul 2013 23:59:31 +0000

The problem is in Boards_Defs.h. It defines digital_pin_to_timer_PGM as a uint16_t instead of a uint8_t as in Board_Data.c. Board_Data.c did not include Board_Defs.h so the compiler did not catch the conflict. What is happening is the compiler multiplied the pin number by 2 to index into digital_pin_to_timer_PGM which over shoots the correct value.

In Boards_Defs.h in the variant directory change:

extern const uint16_t digital_pin_to_timer_PGM[];

to:

extern const uint8_t digital_pin_to_timer_PGM[];

KeithV

Mon, 22 Jul 2013 20:00:09 +0000

Correction on this.

digital_pin_to_timer_PGM should be defined as a uint16_t in both Board_Defs.h and in Board_Data.c; not uint8_t.

It does work if both are defined as uint8_t, but there is an unused feature that is currently being ignored that (would) use the upper 8 bits. If we ever use that feature, the definition would need to be an uint16_t.


caroper

Mon, 22 Jul 2013 20:29:44 +0000

Thanks Keith,

Much appreciated.

Cheers Chris