|
|
View previous topic :: View next topic |
Author |
Message |
anestho
Joined: 27 Dec 2006 Posts: 28
|
maximum frequency for software PWM? |
Posted: Thu Dec 28, 2006 7:02 pm |
|
|
Hi,
What would be a reasonable fastest frequency for a software generated PWM using a 12F683 and internal 8 Mhz osc.
For 255 steps and 4 PWM outputs? PWM needs to have a selectable duty cycle from 0% to 100%, constant period.
looking to drive brushed motors. What would be the lowest frequency that a motor can be driven off of?
The only other thing the PIC would be doing would be polling one of the pins for input for a byte. software rs232, or I may use int_EXT to measure a pulse, which ever is faster. |
|
|
Ttelmah Guest
|
|
Posted: Fri Dec 29, 2006 4:08 am |
|
|
The problem here, is your 'only other thing'.
You can generate four PWM, by sitting in a loop, and using four counters, changing the output as each reaches zero. To get an accurate time, have the loop wait till a change on perhaps the fourth bit of the timer0 counter. This would give a potential synchronised PWM, at about 4KHz. The problem though is that this is going to stop as soon as a serial character is seen, resulting in an extended on or off pulse, and the same would apply to using an interrupt to input a byte (the fastest method would be to poll for the byte at the start of the PWM loop). Since the PIC concerned does not have enough pins spare to perform a parallel transfer of the incoming byte, there will still be a massive degradation on speed....
You can operate off a low PWM frequency, by integrating the output (inductor/capacitor filter), but realistically, this is going to be a poorly performing circuit, and will give problems. Also since you are controlling four PWM's, presumably four bytes will be needed, making this worse....
Best Wishes |
|
|
anestho
Joined: 27 Dec 2006 Posts: 28
|
|
Posted: Fri Dec 29, 2006 8:03 am |
|
|
What if I slow down the PWM to < 1KHz and reduce the steps to say 64?
I don;t need the PWM too fast, just fast enough to give the motor an analog voltage. wHen I tried to do this with an interrupt timer, the square ware generated had a fairly high period (20ms) and ws too slow to drive the motor. I figure that is because of the interrupt overhead on entry and exit. I did read the thread on < 100 Hz, but I think that may be too slow, but not sure.
How much time is spend getting a byte from rs232. Both 12f783 chips would be at 8 mhz. I don't know if its better to send a string of 4 bytes then decode it into the duty cycle for each channel, or do it one at a time. Not really sure how to time how long routines take, or a set of instructions. |
|
|
Ttelmah Guest
|
|
Posted: Fri Dec 29, 2006 10:09 am |
|
|
At heart, the problem is going to remain. For software serial, there is a balancing act. If you use a 'slow' rate, so the code can be started by an interrupt, the character time goes up. At a faster rate, you will take less time to receive the character, but then have to be polling the input at least twice in each bit time.
Realistically, you would be much better off using a chip like the 16F648, and use it's hardware serial to receive the characters. You also have to provide some method of synchronising the transfer, otherwise if a character is lost, the wrong data wll go to the wrong PWM...
Best Wishes |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Fri Dec 29, 2006 10:18 am |
|
|
anestho wrote: |
How much time is spend getting a byte from rs232. |
It depends on the baud rate. For example at 9600 baud N 8 1:
10 bits / 9600baud = 1.04ms
Though actually the software UART will return when it sees the start of the Stop bit so it is really only about 950us per byte. With the CCS routines the CPU is totally consumed by the receive function. If you service an interrupt you will corrupt the incomming byte. I have heard of people writing receive routines for low baud rates that allow quick interrupts during each bit,but that can be tricky. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
anestho
Joined: 27 Dec 2006 Posts: 28
|
|
Posted: Fri Dec 29, 2006 1:45 pm |
|
|
Thanks to both of you for the help! I didt think this would be easy.. but then again I didn't figure this to be that hard either.
It seems that rs232 serial will be too long of a delay for running PWM. WHat about just sending a short pulse from the 1st pic. The width would be proportional to the byte value. It could certainly be less than 1000 us to do all 4 pulses. I'm not sure if I am beating a dead horse here. I don't know much assembler, so I'm stuck.
There is a program written by Andy Burkett which is written in CC5X C compiler. He has a do_PWM routine that he states completes in 35 us. I don't know how since there are if-then in the routine, so variable instruction time.
He uses this routine to time the input pulse train. He also calls this PWM routine after each statement, and inside if-then. Each call to the routine advances the counter by 1 step, so ideally if the routine takes 35 us to complete each time, he uses 20 steps before resetting the frame (35 x 20) = 700 us period.
Here is my version of the PWM routine. I am using 8 Mhz, so I call the routine after every 2 statements (about 1 us).
In the main code, I decode the pulse train and divide it so that it falls within the 0-19 range. nmotorcoount and nruddercount get these values. It is averaged over 2 frames to lessen the jitter. At the end of the main, I update the status bits nMainMotorStatus & nTailMotorStatus with the new status of on or off (0 or 1).
Code: |
VOID do_PWM()
{
if (nFrameCount == MAX_FRAME_COUNT) //0-19
{
nFrameCount = 0;
output_bit(pin_A0,nMainMotorStatus);
output_bit(pin_A1,nTailMotorStatus);
}
else
{
nFrameCount ++;
if (nFrameCount == nMotorCount)
output_low(pin_A0);
if (nFrameCount == nRudderCount)
output_low(pin_A1);
}
}
|
I also use the INT_EXT to read in the pulse train. Unfortunately, I can't call the PWM routine during the servicing of this interrupt.
[code]
#int_EXT
INT_isr()
{
// Read timer 1 - on 1 us
setup_timer_1(T1_DISABLED|T1_DIV_BY_2); // Stop timer1
temp_timer1 = get_timer1(); // Read timer1
if (ch_index <4> TX_GAP) // If time > 2.5ms => begin of a new pulse train
ch_index = 0;
set_timer1(0); // Clear timer1
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
}
code] |
|
|
C Turner
Joined: 10 Nov 2003 Posts: 40 Location: Utah
|
|
Posted: Fri Dec 29, 2006 6:34 pm |
|
|
Although it depends heavily on exactly what your required speed might be - and which PIC (and hardware timers) you may have available, one technique that I've used very successfully is an ISR-timed software UART.
If your code is reasonably efficient, an ISR of at least 10-12 kHz is easily managable with an 8 MHz clock rate - and the trick would be to make this ISR an exact integer multiple of your expected baud rate. (You would want the ISR rate to be at least 3 times the serial input rate - which is the limiting speed of this scheme.)
For instance, assume that your serial input is 2400 baud. Running an ISR at 4 times this rate (9600 Hz) you can do 4-times oversampling on your serial input.
Now, suppose that your PWM requirements were modest - say 6 bits of resolultion (64 counts) so that would mean that the PWM rate would be 150 Hz.
FWIW, I've measured PWM frequencies on control valves and solenoids on automobile engines to be in the range of 300-1500 Hz - and a DC motor really won't mind anything in this range too much - and 150 Hz probably isn't too outrageous a departure. For R/C servos, I don't know what the typical PWM rates might be, but I'd expected it to be somewhere in the above range.
An ISR would consists of two parts - the first one being the most time-critical PWM update portion:
- ISR starts
- Increment each of the 4 PWM counters.
- AND each counter to limit the maximum count to be appropriate to your desired number of bits (timing resolution)
- Compare each of the 4 PWM counters with its respective PWM output value: If it's above this value, set the respective output high, and if not, set it low.
(This could neatly be done with simple inline assembly code.)
The second part of the ISR would be the UART:
- If you haven't found it already, look for a start bit on your serial input.
-Once you've found your serial start bit, you would then set a flag to indicate that you've started receiving a character.
- You would also know that you can expect a new serial bit every 4 ISRs from that point on and a simple counter would let you know when every 4th ISR occurred, at which time you can, once again, "look" for a new serial data bit.
- Simply "read" each new bit anytime a new one was expected until you have all bits in this character read, and indicate that you've a new byte ready and are looking for a start bit again.
***
One advantage of such an oversampled software UART - especially when used with a PIC running an internal clock - is that you can actually keep track of the timing of the serial bit transitions: If you have anough RAM, you can simply "record" an oversampled version of your serial input and then "process" it later. In this way, you could note the time of the start bit, the times of each of the transitions of other data bits - especially that final stop bit.
Knowing these timings, you can, in many cases, "adjust" the windowing of the received data - or, if you are brave, even tweak the PIC's internal oscillator to more-closely match the received baud rate.
Another simple method is to provide some simple "fast/slow" bits by the ISR that indicate of the new bit is arriving a bit early/late so the PIC's clock's timing can be tweaked outside the ISR, where it will not excessively burden the ISR itself.
Best of luck,
CT |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|