/* Bit-banging serial output routine for shift registers like the 74HC595
 * Matt Sarnoff (www.msarnoff.org)
 *
 * Note that setting or clearing a bit in an I/O register (SBI/CBI instructions)
 * takes two cycles, but loading an I/O register (OUT instruction)
 * only takes one.
 */

#define set_bit(v,b)        v |= _BV(b)
#define clear_bit(v,b)      v &= ~_BV(b)
#define pulse_bit(v,b)      do { set_bit(v,b); clear_bit(v,b); } while(0)
#define pulse_bit_low(v,b)  do { clear_bit(v,b); set_bit(v,b); } while(0)

#define CLK    6
#define DATA   7
#define STROBE 1

void serialout16(unsigned int c)
{
  register uint8_t port = PORTD;
  register uint8_t portdata = port | _BV(DATA);

  if (c & _BV(15))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(14))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(13))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(12))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(11))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(10))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(9))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(8))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(7))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(6))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(5))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(4))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(3))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(2))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(1))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;
  if (c & _BV(0))
    PORTD = portdata;
  set_bit(PORTD, CLK);
  PORTD = port;

  pulse_bit(PORTB, STROBE);
}


