Sending a PWM signal to any digital output pin

Hello fellow orangutan users,

I’m trying to get a pwm signal from a digital output pin.
I see many examples using the Arduino library call analogWrite(pin, pwm) function. Is there an easy pololu equivalent?
All help greatly appreciated.

Cheers,

Jay

Hello.

The only way to generate a PWM output on an arbitrary digital pin is in software (on the Arduino, I believe the analogWrite() function is limited only to the six pins that are hardware PWM outputs), but you can use a timer interrupt to accomplish this with minimal processor overhead. What model Orangutan do you have and what PWM frequency and duty cycle resolution do you need?

- Ben

set_servo_target_b give sends a pwm signal to any output pin, I kind of just want an extension of that that says analogWrite() instead.

i have a baby orangutan b 328. need a duty cycle resolution of 0-255, 8 bit is plenty. pwm must be generated through the hardware timer1 as I am running motors on timer0 and timer2. the processor runs the control algorithm for the motors.

i’m ultimately trying to control the speed of two extra motors off the last remaining timer if possible.

cheers.

Jay

pwm frequency is not extremely critical i don’t think. say 1 kHz?

Ah i’ve just discovered that pins PB1 and PB2 are the timer1 pwm outputs. I think i might have found my problem. i was trying to get a pwm signal out of PB0.

cheers,

Jay

If you can use timer1’s two hardware PWM outputs (pins PB1 and PB2), the code will be simpler and higher performance. Using a PWM frequency of 20 kHz or above allows for quieter motor operation since it is ultrasonic, but not all motor drivers can handle frequencies that high. Do you know what the limit of your driver is? Also, your last post makes it sound like you might now know how to do this yourself; do you still need help with the code?

- Ben

thank you for all your help ben.

I would like some help with the code. I’m not so sure about initializing the pwm signal.

So far i’ve got:

// set PB1 as the pwm pin
	DDRB|=(1<<PB1);

	//enable the pwm signal
	//COM1A10 = 0;
	//COM1A11 = 1;
	TCCR1A = 0xA1;

	//set a 50% duty cycle
	OCR1A = 128;

	//set prescaler	
	TCCR1A = 0x05;

but this doesn’t generate the pwm signal. can yo ufind any problems or refer me to any examples to generating a pwm signal using timer1 on the baby o?

cheers,

jay

code update.

I’ve tried the following:

#include <avr/io.h>
#define F_CPU 20000000UL	// F_CPU tells util/delay.h our clock frequency - Baby-O. = 20MHz
#include <util/delay.h>
#include <avr/io.h>
#include <pololu/orangutan.h>

void InitPWM()
{
   /*
   TCCR1 - Timer Counter Control Register (TIMER1)
   -----------------------------------------------
   BITS DESCRIPTION
   

   NO:   NAME   DESCRIPTION
   --------------------------
   BIT 7 : FOC1   Force Output Compare [Not used]
   BIT 6 : WGM10  Wave form generartion mode [SET to 1]
   BIT 5 : COM11  Compare Output Mode        [SET to 1]
   BIT 4 : COM10  Compare Output Mode        [SET to 0]

   BIT 3 : WGM11  Wave form generation mode  [SET to 1]
   BIT 2 : CS12   Clock Select               [SET to 0]
   BIT 1 : CS11   Clock Select               [SET to 0]
   BIT 0 : CS10   Clock Select               [SET to 1]

   The above settings are for
   --------------------------

   Timer Clock = CPU Clock (No Prescalling)
   Mode        = Fast PWM
   PWM Output  = Non Inverted

   */

   TCCR1A|=(1<<WGM10)|(1<<WGM11)|(1<<COM1A1)|(1<<CS10);

   //Set OCR1 PIN as output. It is  PB1 on ATmega328
   DDRB|=(1<<PB1);
}

/******************************************************************
Sets the duty cycle of output. 

Arguments
---------
duty: Between 0 - 255

0= 0%

255= 100%

The Function sets the duty cycle of pwm output generated on OC0 PIN
The average voltage on this output pin will be

         duty
 Vout=  ------ x 5v
         255 

This can be used to control the brightness of LED or Speed of Motor.
*********************************************************************/

void SetPWMOutput(uint8_t duty)
{
   OCR1A=duty;
}


int main()
{
   uint8_t brightness=128; //brightness range = [0,255] 

   //Initialize PWM Channel 0
   InitPWM();
  
   //Do this forever
   while(1)
   {

         SetPWMOutput(brightness);
		 delay_ms(100);
		 red_led(TOGGLE);

   }
   return 0;
}

the red LED blinks but there’s no visible pwm from PB1.

Cheers,

Jay

You’re not actually turning on timer 1. To do that, you need to set the clock selection bits in the TCCR1B register:

TCCR1B = 1; // set timer clock to system clock (timer ticks at 20 MHz)

I also suggest you use a phase-correct PWM, which lets you achieve glitch-free 0% and 100% duty cycles. If you use a 9-bit phase-correct PWM, your PWM frequency will be approximately 19.6 kHz (you still haven’t told me if your driver can handle ultrasonic PWM):

DDRB |= (1 << PB1) | (1 << PB2);  // or set_digital_output(IO_B1, LOW); set_digital_output(IO_B2, LOW);
// COM1 bits set to clear OC1A/OC1B on Compare Match when upcounting and
// set OC1A/OC1B on Compare Match when downcounting.
// WGM11:10 set for 9-bit phase-correct PWM
TCCR1A = 0xA2;
OCR1A = 384;  // 75% duty cycle on OC1A (PB1)
OCR1B = 128;  // 25% duty cycle on OC1B (PB2)
TCCR1B = 1;  // Timer1 clock = 20 MHz

I think this code will work for you, but I haven’t tested it. Please let me know if you have any problems or questions.

- Ben