Created Fri, 16 Aug 2013 17:54:23 +0000 by Pentium
Fri, 16 Aug 2013 17:54:23 +0000
Hi there, I would like to generate two different pwm signals, at two different frequecies so one will be 6 times more than the other. I' ve seen a great page in the wiki so I discovered about timer2 and 3. I' ve written a analogWrite2 function which works pretty nice using the other output comparator and timer3. Here the code:
//*********************************************************************
void analogWrite2(uint8_t pin, int val, unsigned int timerPeriod, unsigned short preScaler)
{
uint16_t timer;
uint8_t pwm_mask;
p32_oc * ocp;
/* Check if pin number is in valid range.
*/
if (pin >= NUM_DIGITAL_PINS_EXTENDED)
{
return 0;
}
#if (OPT_BOARD_ANALOG_WRITE != 0)
/* Peform any board specific processing.
*/
int _board_analogWrite(uint8_t pin, int val);
if (_board_analogWrite(pin, val) != 0)
{
return;
}
#endif // OPT_BOARD_ANALOG_WRITE
/* Determine if this is actually a PWM capable pin or not.
** The value in timer will be the output compare number associated with
** the pin, or NOT_ON_TIMER if no OC is connected to the pin.
** The values 0 or >=255 have the side effect of turning off PWM on
** pins that are PWM capable.
*/
timer = digitalPinToTimerOC(pin) >> _BN_TIMER_OC;
if ((timer == NOT_ON_TIMER) || (val == 0) || (val >= 110000))
{
/* We're going to be setting the pin to a steady state.
** Make sure it is set as a digital output. And then set
** it LOW or HIGH depending on the value requested to be
** written. The digitalWrite function has the side effect
** of turning off PWM on the pin if it happens to be a
** PWM capable pin.
*/
pinMode(pin, OUTPUT);
if (val < 128)
{
digitalWrite(pin, LOW);
}
else
{
digitalWrite(pin, HIGH);
}
}
else
{
/* It's a PWM capable pin. Timer 3 is used for the time base
** for analog output, so if no PWM are currently active then
** Timer 3 needs to be initialized
*/
if (pwm_active2 == 0)
{
switch(preScaler)
{
case 1:
T3CON = TBCON_PS_1;
break;
case 2:
T3CON = TBCON_PS_2;
break;
case 4:
T3CON = TBCON_PS_4;
break;
case 8:
T3CON = TBCON_PS_8;
break;
case 16:
T3CON = TBCON_PS_16;
break;
case 32:
T3CON = TBCON_PS_32;
break;
case 64:
T3CON = TBCON_PS_64;
break;
case 256:
T3CON = TBCON_PS_256;
break;
default:
T3CON = TBCON_PS_256;
break;
}
TMR3 = 0;
PR3 = timerPeriod;
T3CONSET = TBCON_ON;
}
/* Generate bit mask for this output compare.
*/
pwm_mask = (1 << (timer - (_TIMER_OC2 >> _BN_TIMER_OC)));
/* Obtain a pointer to the output compare being being used
** NOTE: as of 11/15/2011 All existing PIC32 devices
** (PIC32MX1XX/2XX/3XX/4XX/5XX/6XX/7XX) have the output compares
** in consecutive locations. The base address is _OCMP1_BASE_ADDRESS
** and the distance between their addresses is 0x200.
*/
ocp = (p32_oc *)(_OCMP2_BASE_ADDRESS + (0x200 * (timer - (_TIMER_OC2 >> _BN_TIMER_OC))));
/* If the requested PWM isn't active, init its output compare. Enabling
** the output compare takes over control of pin direction and forces the
** pin to be an output.
*/
int dutyDiv= pow(2, (int)log2(timerPeriod));
if ((pwm_active2 & 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));
#endif
ocp->ocxR.reg = ((timerPeriod*val)/dutyDiv);
ocp->ocxCon.reg = OCCON_SRC_TIMER3 | OCCON_PWM_FAULT_DISABLE;
ocp->ocxCon.set = OCCON_ON;
pwm_active2 |= pwm_mask;
}
/* Set the duty cycle register for the requested output compare
*/
ocp->ocxRs.reg = ((timerPeriod*val)/dutyDiv);
}
}
Basicly I put the pwm timer period arg (which is cpuclock/prescaler/desidered frequency) and the prescaler (for timer 2 are 1 8 16 32 64 128 256) and I get a pretty clean pwm signal with a dutyDiv resolution. So for example...
FQR: 10 kHz with 1:1 prescaler I think should be 12-bit resolution.
I' m trying to generate two phased PWM, one is generated by my function (and it works fine, with my scope I can see it' s stable) the other one doesn' t! I tried to use both tone (which uses timer1) and standard analogwrite (editing the PR2 period) but they won' t at all to be phased. Can anyone help me? Thank you, regards
p.s. if you find some errors in my code please comments!