chipKIT® Development Platform

Inspired by Arduino™

PPS and OCx / analogWrite

Created Fri, 15 Nov 2013 20:16:18 +0000 by caroper


Fri, 15 Nov 2013 20:16:18 +0000

Is it possible to remap the Output Compare Modules with pps and then use analogWrite with the new pin?

I tried it on the DP32 but with no luck. I made the suggested changes to the Boards definition files noted elsewhere and analogWrite now works fine on PIN 13 but I would like to move OC2 and OC3 to pins 12 and 11 respectively.

I need access to PWM and I2C at the same time but OC2 and OC3 share the I2C pins.

I don't mind if it has to be a permanent change, i.e. in the boards files rather than PPS, but in that case could someone explain how to go about it?

Thanks Chris


Thu, 19 Dec 2013 23:43:57 +0000

The range of pins you are able to map peripherals to is quite limited. You cannot abitrarily map any peripheral to any pin.

You need to first check that the peripherals can actually be mapped to the pins you want to use. This means cross-referencing the board reference manual (to get the internal pin names) with the data sheet for the chip, which tells you which peripherals can be mapped to which pins.


Fri, 20 Dec 2013 06:42:28 +0000


I am well aware of that, and the mappings I chose are available,

My question was whether AnalogWrite will follow the mapping or is it hard coded to specific pins. In other words, I can remap the OCx Registers but AnalogWrite no longer works if I do. Would I need to change the mappings in the Board Definition Files if I need to remap the AnalogWrite functionality.

Hope that is a little clearer.

Cheers Chris


Fri, 20 Dec 2013 10:38:09 +0000

Ah, cool, gotya.

Right, let's take a look at the source to analogWrite(). I'll reduce it to just the interesting and MX1/2 bits:

timer = digitalPinToTimerOC(pin) >> _BN_TIMER_OC;

        if (pwm_active == 0)
            T2CON = TBCON_PS_256;
            TMR2 = 0;
            PR2 = PWM_TIMER_PERIOD;
            T2CONSET = TBCON_ON;
        pwm_mask = (1 << (timer - (_TIMER_OC1 >> _BN_TIMER_OC)));

        ocp = (p32_oc *)(_OCMP1_BASE_ADDRESS + (0x200 * (timer - (_TIMER_OC1 >> _BN_TIMER_OC))));

        if ((pwm_active & pwm_mask) == 0)

#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));
            ocp->ocxR.reg   = ((PWM_TIMER_PERIOD*val)/256);
            ocp->ocxCon.reg = OCCON_SRC_TIMER2 | OCCON_PWM_FAULT_DISABLE;
            ocp->ocxCon.set = OCCON_ON;

            pwm_active |= pwm_mask;

        ocp->ocxRs.reg = ((PWM_TIMER_PERIOD*val)/256);

Ok, so there's two bits of information that is important here. One is the timer variable, which gets its data from the board definition. This is keyed to the pin number. Then there's the PPS data, which is also keyed to the pin number. The PPS is only set the first time, so it should be possible to tweak that after the first analogWrite() has been called to set up the OC peripheral.

Personally though I'd create a new board definition with both the PPS and the OC timer definitions changed. As always I have to mention [url]UECIDE[/url] here (every chance I get ;) ) in which it is easier to clone and modify a board definition as it's entirely self contained (just copy the folder, edit the files, and you're good to go).