Bitbang PWM on non-PWM pins

eriknyquist:
If you want more I/O, get the Mega- if you want speed, get the chipKit!

You aren't really comparing apples with apples here.

Any code that has delays in it will be slow, by design. analogRead is known to take 104 uS per read. Doing digitalWrite is known to be slower than port manipulation, however there is a digitalWriteFast library that speeds that up for ports that are known at compile time (not variables).

The entire approach of doing software PWM, when hardware PWM is available, is hardly using the chip to its best advantage.

I see from a quick browse that the ChipKit runs at 80 MHz. So you should really be comparing the Due to it, not the Uno.

eriknyquist:
FYI, I tried it with the chipKitUNO32 and it's way faster- 15us to return to the beginning of loop, compared to Arduino at 130us.

It's still not a fair comparison. If the chipKit ran at 16 MHz it would take longer too:

15 * 80 / 16 = 75

That's faster than 130 uS, but the ADC converter may well run faster as well.

I think I understand what you're saying, but keep in mind I'm not timing how long the loop takes to execute (and I'm also not using the same code I posted above)

void setup(){
pinMode(0, OUTPUT);
}
void loop(){
  digitalWrite(0, HIGH);
  delay(1);
  digitalWrite(0, LOW);
}

so with this code, with an LED connected to pin 0, to the naked eye the LED is constantly on. Of course there is a small gap when the LED is off, while the program returns to the beginning of the loop- this is what I have been measuring using the code above. I was under the belief that nothing inside the loop (i.e. wether or not a delay function is used) will have an effect on the time taken to return to the beginning of the loop (though I do understand that the loop itself will take longer because the delay is a NOP so the program has to wait for the delay to finish before it can do anything else, if that is what you mean). Is this correct?
P.S. the Due is also 15us. I realise this information may be useless but I like measuring stuff! :slight_smile: :slight_smile:

sorry AWOL, just accidentally hit post before I was finished :stuck_out_tongue:

so with this code, with an LED connected to pin 0, to the naked eye the LED is constantly on.

To the naked eye or a Hadland high-speed camera, the LED is constantly on.

. Of course there is a small gap when the LED is off,

No, there isn't.

12.5 not 15. OK so it doesn't actually have enough time to reach zero....effectively off though.
Also AWOL, yes you're right the LED would never be off because my head is in the clouds and I wrote it wrong. I have updated it, what is there now is what I actually had running. So, that delay we can see- is that the time that it takes to switch off and on a GPIO, or is that the time it takes to return to the beginning of the loop? or both?

This thread is hard to follow with code being corrected in earlier posts, but whatever.

In the Arduino world, loop is called repeatedly by main, plus tests if it needs to call serialEventRun.

main looks like this:

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

Instruction cycle counts (in brackets):

        for (;;) {
                loop();
 416:   0e 94 80 00     call    0x100   ; 0x100 <loop>   (4)
                if (serialEventRun) serialEventRun();
 41a:   20 97           sbiw    r28, 0x00       ; 0   (2)
 41c:   e1 f3           breq    .-8             ; 0x416 <main+0x10>   (1/2)
 41e:   0e 94 00 00     call    0       ; 0x0 <__vectors>   (4)
 422:   f9 cf           rjmp    .-14            ; 0x416 <main+0x10>   (2)

loop looks like this:

void loop(){
  digitalWrite(0, HIGH);
  delay(1);
  digitalWrite(0, LOW);
}

Cycle counts:

00000100 <loop>:
 100:   80 e0           ldi     r24, 0x00       ; 0   (1)
 102:   61 e0           ldi     r22, 0x01       ; 1   (1)
 104:   0e 94 af 01     call    0x35e   ; 0x35e <digitalWrite>   (4)
 108:   61 e0           ldi     r22, 0x01       ; 1   (1)
 10a:   70 e0           ldi     r23, 0x00       ; 0   (1)
 10c:   80 e0           ldi     r24, 0x00       ; 0   (1)
 10e:   90 e0           ldi     r25, 0x00       ; 0   (1)
 110:   0e 94 dc 00     call    0x1b8   ; 0x1b8 <delay>   (4)
 114:   80 e0           ldi     r24, 0x00       ; 0   (1)
 116:   60 e0           ldi     r22, 0x00       ; 0   (1)
 118:   0e 94 af 01     call    0x35e   ; 0x35e <digitalWrite>   (4)
 11c:   08 95           ret   (4)

Assuming the branch at 0x41c is taken I count 10 cycles in (this part of) main. Plus 6 up to when the first digitalWrite is called, and 4 after the second digitalWrite, adding up to 20 cycles.

20 * 62.5 nS = 1.250 uS

That is what you measured.

So you could probably say that loop will cost you 14 clock cycles on its own. The 10 inside main, plus the 4 to return from loop.