digitalWriteFast and compiler optimization

I'm trying to create a high speed clock ( sub-us) line that I'm manually toggling high and low.

I'd like to use something like the following code to utilized digitialWriteFast and have flexibility to change the pins being used by changing a constant.

digitialWriteFast(clk,HIGH);
asm("nop \n\tnop \n\t");
digitialWriteFast(clk,LOW);

Unfortunately the compiler is optimizing the 2 writes out of the code. Call delayMicroseconds(1) instead of the asm nop's the digitalWrites aren't optimized out.
Does anyone know of a way to prevent the compiler from optimizing out the digitialWriteFast calls so that the resulting code looks like

asm("sbi 0x05, 1 ");
asm("nop \n\tnop \n\t");
asm("cbi 0x05, 1 ");

Does this work...

digitialWriteFast(clk,HIGH);
asm volatile ("nop \n\tnop \n\t");
digitialWriteFast(clk,LOW);

no, it doesn't.

it still just produces

digitalWriteFast(sclk, HIGH);
12c6: 85 b1 in r24, 0x05 ; 5
12c8: 82 60 ori r24, 0x02 ; 2
asm volatile("nop \n\tnop \n\t");
12ca: 00 00 nop
12cc: 00 00 nop
digitalWriteFast(sclk, LOW);
12ce: 8d 7f andi r24, 0xFD ; 253
12d0: 85 b9 out 0x05, r24 ; 5

which isn't setting the digital out pins which I'd expect to look something like this
asm("sbi 0x05, 1 ");
1276: 29 9a sbi 0x05, 1 ; 5
asm volatile("nop \n\tnop \n\t");
1278: 00 00 nop
127a: 00 00 nop
asm("cbi 0x05, 1 ");
127c: 29 98 cbi 0x05, 1 ; 5

Which board are you using?

Which digitialWriteFast variation are you using?

mega 2560 with the arduino v022 sdk
I'm using the latest version of the digitalWriteFast library from November which is interrupt safe.

How is clk defined?

sclk is just defined as
#define sclk 52

OK, I figured out the issue. There is a bug in the digitWriteFast code. Basically the first parameter to bitWrite needed to have a volatile cast on it which is missing. I determined this by looking at the wiring and avr/sfr_defs code.

I've changed the atomicWrite to add the volatile uint8_t cast and removed the uint8_t cast from the fast macro. Everything is happy now :slight_smile:

#define atomicWrite(A,P,V)
if ( (int)(A) < 0x40) { bitWrite(((volatile uint8_t) A), __digitalPinToBit(P), (V) );}
else {
uint8_t register saveSreg = SREG;
cli();
bitWrite(((volatile uint8_t)A), __digitalPinToBit(P), (V) );
SREG=saveSreg;
}

attached is the modified header file.

digitalWriteFast.h (5.79 KB)

Thank you for the follow-up and thank you for adding an issue.

Thanks for the explanation and updated code. I stumbled across this issue yesterday and was worrying how to address it. Lots of time saved.

Thanks, Ian.