OK, so I've been trying to write more efficient code and more syntatically correct code. Up til now, I have been using pin mode and digital read/writes to setup and manipulate I/O. Most of my projects are run on ATMega328's and ATTiny85's. I have recently started dabbling in direct port manipulation (since I have a project were I need to free up programming space and needed more instruction processing speed) and trying to decipher the various examples and tutorials I have found online as well as answers to questions found here. I have come across something interesting and I would like to see if anyone can provide me with an explanation.
I found there are different ways to perform direct port manipulation so I decided to see if there was a difference in the methods (speedwise). The first thing I found was something I started using without knowing really how it worked (I don't normally like doing that, but I was in a bind and needed to get the program running). I can't remember where I got the example for this, but after reading the reference page on port manipulation (Arduino Reference - Arduino Reference), I can't help but feel I doing it wrong (but it feels so right). I have this code to send a byte to a shift register:
PIND = 0b00010000; //this is the latchpin on PD4
shiftOut(datapin, clockpin, MSBFIRST, sRegOut);
PIND = 0b00010000;
which works perfectly (the bit goes low for the shift out, then goes high again), but reading the port manipulation page PINx is a "read only" function so I'm not sure how this is working. If anyone has any insight on this and whether it is good practice or not, I would appreciate it.
After reading through the port manipulation page, I started doing a little digging and found the _BV() macro. I played around with it a little bit and found it worked just as well. I then decided to see if there was a difference in execution speed (setting bits high/low) so I set up a little experiment. I used the below code (uncommenting each group, one at a time) and checked the speed at which the pin was turned on and off. I was a little surprised by the result so I'm hoping someone can explain this as well.
void setup() {
Serial.begin(115200);
DDRD = B11111110;
PORTD = B00000000;
}
void loop() {
// digitalWrite(7, HIGH);
// digitalWrite(7, LOW);
// 132kHz - the speed comments were added after testing each group.
// PORTD = PORTD | 0x10;
// PORTD = PORTD & 0xEF;
// 842kHz
// PIND = 0b00100000;
// PIND = 0b00100000;
// 941kHz
// PORTD |= _BV(PD6);
// PORTD &= ~_BV(PD6);
// 842kHz
}
The speed listed below each group is what I was getting on the pin with my Oscope. I was really surprised by how much slower the digital read/write functions were compared to the others. I was also surprised that the _BV() macro was the same speed as the PORTx function. I thought there might be a slight delay for the macro, but I guess not. What's really surprising is what should not be working at all generates the fastest processing time by almost 100kHz. This is basically 7 times faster than using digital read/write and 11% faster than the PORTx method. The only odd thing I found was that the off (low) time was sometimes 2 to 3 times that of the on (high) time. I figure this has to do with the turn at the end of the loop when the program starts back at the top.
I hope this information helps someone else out and I'm really looking forward to the explanation of PINx though.