So I was messing around this morning and wondering how effective bitbanging PWM would be compared to the PWM- enabled pins. Heres my code to control a PWM signal on pin 8 using a pot;
int Ain = 0;
int del;
int pin = 8;
void setup(){
pinMode(pin, OUTPUT);
}
void loop(){
del = analogRead(Ain)*15.625;
if(del < 100){
del = 100;
}
digitalWrite(pin, HIGH);
delayMicroseconds(del);
digitalWrite(pin, LOW);
delayMicroseconds(16000 - del);
}
and, it works great, gives a nice clean fade of the LED and on the scope it looks good
so, my question is, what's the disadvantage of this over hardware PWM? is the whole processor occupied with this bitbanging task, meaning nothing else can be done? could you control a servo with this?
I also notice that it takes 700us(!!!) to return to the beginning of the loop- so that's annoying. I suppose that's one reason why hardware PWM is better.
oh yeah good point...it's 1.95 because of the 0-1024 from ADC so I'll just make the full duty cycle 2048 us instead of 2000.
Update- I measured it more accurately and it's actually a 660us delay to return to the start of the loop, and removing the floating point multiply brings it down to 640....still bleedin ages!
any other suggestions on how to reduce the time to return to the beginning of the loop? maybe its not possible....
Thanks AWOL, good idea, I have eliminated the delayMicroSeconds() functions but my new code (below) doesn't work....just turns the LED on when the pot is past a certain point
int Ain = 0;
int del;
int pin = 8;
long prevMicros = 0;
void setup(){
pinMode(pin, OUTPUT);
}
void loop(){
del = analogRead(Ain)*2;
if(del < 10){
del = 10;
}
if((micros() - prevMicros) > (2048 - del)){
prevMicros = micros();
digitalWrite(pin, HIGH);
}
if((micros() - prevMicros) > del){
prevMicros = micros();
digitalWrite(pin, LOW);
}
}
can anyone suggest what I might be doing wrong?
On the plus side, turns out I had a leftover Serial.print in there so once I took that out I'm down to about 130us. woo!
This is just a changed BlinkWithoutDelay, but it works.
Maybe you should take a look at direct port manipulation to speed things up
const int ledPin = 8; // the number of the LED pin
const int potPin = A0;
int ledState = LOW; // ledState used to set the LED
long previousMicros = 0; // will store last time LED was updated
unsigned long interval = 1023; // interval at which to blink (milliseconds)
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(potPin, INPUT);
}
void loop()
{
unsigned long currentMicros = micros();
int val=analogRead(potPin);
if((currentMicros - previousMicros) < (1023-val)){
digitalWrite(ledPin,HIGH);
}
if((currentMicros - previousMicros )> (1023-val)){
digitalWrite(ledPin, LOW);
}
if(currentMicros - previousMicros > interval) {
previousMicros = currentMicros;
}
}
Most of that is probably your analogRead - there's an easy way to get that time back.
analogRead breaks down into:
1: select input
2: start conversion
3: wait for conversion to complete
4: read result.
Eliminate 3, and you gain 100+ microseconds.
You can do asynchronous analog to digital conversions:
so, my question is, what's the disadvantage of this over hardware PWM?
A loop with a delay will only do one lot of PWM, whereas the hardware can do 6 simultaneously.
Plus, even with careful timing etc. your software bit-banging will be out slightly due to jitter introduced by servicing interrupts (if indeed, you do that). However to get timings you generally need interrupts.
You can do it, there's just not a whole lot of point. The hardware will do it better.
interestingly, the arduino MegaADK also takes 130us to return- I thought it would have been faster than the UNO. If you want more I/O, get the Mega- if you want speed, get the chipKit!
Can anyone shed any light on why this might be (why the chipKit is so much faster than the Mega)?
AWOL, the chipKit implements analogRead too- I haven't looked at the .c file but I'm sure it's a similar process on the PIC32.
Just a simple question. Is there a reason you need to leave the loop() function at all? Would it not be a tiny bit faster and more efficient to simply put a while(true) loop inside of the loop() and never leave it?