Send one bit out per clock pulse received using direct port manipulation? I want to send one bit of a byte out per 'rising edge' received to an Arduino digital input. I am addressing the outputs using direct port manipulation (to achieve maximum speed), and I would like to do the same for input. 

So I'm calling a function called bitBang in my main loop, sending the ready line high before moving into the function: 

//Send control
PORTB |= _BV(PORTB2);
bitBang(controlByte);
PORTB &amp;= ~_BV(PORTB2);


What I would like to do upon entering the function is listen for a rising edge to appear on the digital input port using the direct port syntax and iterate through the byte setting the data line high or low depending on the bit's value.

How can I achieve this in the most efficient way possible?
Example bit-banged SPI using port manipulation:



bitBangedSPIfast.h :

#include &lt;Arduino.h&gt;

class bitBangedSPIfast
  {
  // addresses of output ports - NULL if not applicable
  volatile byte * const mosiPort_;
  volatile byte * const misoPin_;
  volatile byte * const sckPort_;

  // bit masks for above
  const byte mosiBit_;
  const byte misoBit_;
  const byte sckBit_;

  // addresses of data direction register ports
  volatile byte * const mosiDDR_;
  volatile byte * const misoDDR_;
  volatile byte * const sckDDR_;

  // bit masks for above
  const byte mosiDDRBit_;
  const byte misoDDRBit_;
  const byte sckDDRBit_;

  // delay for clock being high
  unsigned long delayUs_;

  public:
    // constructor
    bitBangedSPIfast (
          // output ports
          volatile byte &amp; mosiPort, 
          const    byte mosiBit,
          volatile byte &amp; misoPin, 
          const    byte misoBit,
          volatile byte &amp; sckPort,
          const    byte sckBit,

          // data direction register ports
          volatile byte &amp; mosiDDR, 
          const    byte mosiDDRBit,
          volatile byte &amp; misoDDR, 
          const    byte misoDDRBit,
          volatile byte &amp; sckDDR,
          const    byte sckDDRBit,

          const unsigned long delayUs = 1)
       : 
         mosiPort_ (&amp;mosiPort), 
         mosiBit_  (1 &lt;&lt; mosiBit),
         misoPin_  (&amp;misoPin), 
         misoBit_  (1 &lt;&lt; misoBit), 
         sckPort_  (&amp;sckPort), 
         sckBit_   (1 &lt;&lt; sckBit), 

         mosiDDR_     (&amp;mosiDDR), 
         mosiDDRBit_  (1 &lt;&lt; mosiDDRBit),
         misoDDR_     (&amp;misoDDR), 
         misoDDRBit_  (1 &lt;&lt; misoDDRBit), 
         sckDDR_      (&amp;sckDDR), 
         sckDDRBit_   (1 &lt;&lt; sckDDRBit), 

        delayUs_ (delayUs) { }

    void begin ();
    byte transfer (byte input);

  };  // end of bitBangedSPIfast




bitBangedSPIfast.cpp :

#include &lt;bitBangedSPIfast.h&gt;

void bitBangedSPIfast::begin ()
  {
  if (mosiPort_)
    *mosiDDR_ |= mosiDDRBit_;    // output
  if (misoPin_)
    *misoDDR_ &amp;= ~misoDDRBit_;   // input
  *sckDDR_ |= sckDDRBit_;        // output
  }   // end of bitBangedSPIfast::begin


// Bit Banged SPI transfer
byte bitBangedSPIfast::transfer (byte c)
{       
  // loop for each bit  
  for (byte bit = 0; bit &lt; 8; bit++) 
    {
    // set up MOSI on falling edge of previous SCK (sampled on rising edge)
    if (mosiPort_)
      {
      if (c &amp; 0x80)
        *mosiPort_ |= mosiBit_;
      else
        *mosiPort_ &amp;= ~mosiBit_;
      }

    // finished with MS bit, get read to receive next bit      
    c &lt;&lt;= 1;

    // read MISO
    if (misoPin_)
      c |= (*misoPin_ &amp; misoBit_) != 0;

    // clock high
    *sckPort_ |= sckBit_;

    // delay between rise and fall of clock
    delayMicroseconds (delayUs_);

    // clock low
    *sckPort_ &amp;= ~sckBit_;

    // delay between rise and fall of clock
    delayMicroseconds (delayUs_);
    }  // end of for loop, for each bit

  return c;
  }  // end of bitBangedSPIfast::transfer  




Example usage:

#include &lt;bitBangedSPIfast.h&gt;

bitBangedSPIfast bbSPI (PORTD,  5, PIND,  6, PORTD, 7,    // MOSI port (D5), MISO pin (D6), SCK port (D7)
                        DDRD,   5, DDRD,  6, DDRD,  7);   // MOSI ddr  (D5), MISO ddr (D6), SCK ddr  (D7)
const byte mySS =  8;  // slave select

void setup (void)
  {
  bbSPI.begin ();
  pinMode (mySS, OUTPUT);
  }  // end of setup

void loop (void)
  {
  char c;

  // enable Slave Select
  digitalWrite(mySS, LOW); 

  // send test string
  for (const char * p = "Hello, world!" ; c = *p; p++)
    bbSPI.transfer (c);

  // disable Slave Select
  digitalWrite(mySS, HIGH);

  delay (100); 
  }  // end of loop




Reference

SPI - Serial Peripheral Interface - for Arduino