//
//
// hello.stepper.bipolar.44.full.c
//
// bipolar full stepping hello-world
//
// Neil Gershenfeld
// 11/21/12
//
// (c) Massachusetts Institute of Technology 2012
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//

#include <avr/io.h>
#include <util/delay.h>

#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set

#define bridge_port PORTA // H-bridge port
#define bridge_portA PORTA // H-bridge port
#define bridge_portB PORTB // H-bridge port
#define bridge_direction DDRA // H-bridge direction
#define A2 (1 << PA0) // H-bridge output pins
#define A1 (1 << PA1) // "
#define B2 (1 << PA3) // "
#define B1 (1 << PA4) // "
#define C2 (1 << PA7) // H-bridge output pins
#define C1 (1 << PB2) // "
#define D2 (1 << PB1) // "
#define D1 (1 << PB0) // "
#define on_delay() _delay_us(25) // PWM on time
#define off_delay() _delay_us(5) // PWM off time
#define PWM_count 100 // number of PWM cycles
#define step_count 50 // number of steps
#define cycle_delay() _delay_ms(100)

static uint8_t count;

//
// A+ B+ PWM pulse
//
void pulse_ApBp() {
  clear(bridge_port, A2);
  clear(bridge_port, B2);
  set(bridge_port, A1);
  set(bridge_port, B1);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_port, A1);
      set(bridge_port, B1);
      on_delay();
      clear(bridge_port, A1);
      clear(bridge_port, B1);
      off_delay();
      }
   }
//
// A+ B- PWM pulse
//
void pulse_ApBm() {
  clear(bridge_port, A2);
  clear(bridge_port, B1);
  set(bridge_port, A1);
  set(bridge_port, B2);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_port, A1);
      set(bridge_port, B2);
      on_delay();
      clear(bridge_port, A1);
      clear(bridge_port, B2);
      off_delay();
      }
   }
//
// A- B+ PWM pulse
//
void pulse_AmBp() {
  clear(bridge_port, A1);
  clear(bridge_port, B2);
  set(bridge_port, A2);
  set(bridge_port, B1);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_port, A2);
      set(bridge_port, B1);
      on_delay();
      clear(bridge_port, A2);
      clear(bridge_port, B1);
      off_delay();
      }
   }
//
// A- B- PWM pulse
//
void pulse_AmBm() {
  clear(bridge_port, A1);
  clear(bridge_port, B1);
  set(bridge_port, A2);
  set(bridge_port, B2);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_port, A2);
      set(bridge_port, B2);
      on_delay();
      clear(bridge_port, A2);
      clear(bridge_port, B2);
      off_delay();
      }
   }
//
// clockwise step
//
void step_cw() {
   pulse_ApBp();
   pulse_AmBp();
   pulse_AmBm();
   pulse_ApBm();
   }
//
// counter-clockwise step
//
void step_ccw() {
   pulse_ApBm();
   pulse_AmBm();
   pulse_AmBp();
   pulse_ApBp();
   }

//
// C+ D+ PWM pulse
//
void pulse_CpDp() {
  clear(bridge_portA, C2);
  clear(bridge_portB, D2);
  set(bridge_portB, C1);
  set(bridge_portB, D1);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_portB, C1);
      set(bridge_portB, D1);
      on_delay();
      clear(bridge_portB, C1);
      clear(bridge_portB, D1);
      off_delay();
      }
   }
//
// C+ D- PWM pulse
//
void pulse_CpDm() {
  clear(bridge_portA, C2);
  clear(bridge_portB, D1);
  set(bridge_portB, C1);
  set(bridge_portB, D2);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_portB, C1);
      set(bridge_portB, D2);
      on_delay();
      clear(bridge_portB, C1);
      clear(bridge_portB, D2);
      off_delay();
      }
   }
//
// C- D+ PWM pulse
//
void pulse_CmDp() {
  clear(bridge_portB, C1);
  clear(bridge_portB, D2);
  set(bridge_portA, C2);
  set(bridge_portB, D1);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_portA, C2);
      set(bridge_portB, D1);
      on_delay();
      clear(bridge_portA, C2);
      clear(bridge_portB, D1);
      off_delay();
      }
   }
//
// C- D- PWM pulse
//
void pulse_CmDm() {
  clear(bridge_portB, C1);
  clear(bridge_portB, D1);
  set(bridge_portA, C2);
  set(bridge_portB, D2);
   for (count = 0; count < PWM_count; ++count) {
      set(bridge_portA, C2);
      set(bridge_portB, D2);
      on_delay();
      clear(bridge_portA, C2);
      clear(bridge_portB, D2);
      off_delay();
      }
   }
//
// clockwise step
//
void step_cwCD() {
   pulse_CpDp();
   pulse_CmDp();
   pulse_CmDm();
   pulse_CpDm();
   }
//
// counter-clockwise step
//
void step_ccwCD() {
   pulse_CpDm();
   pulse_CmDm();
   pulse_CmDp();
   pulse_CpDp();
   }

int main(void) {
   //
   // main
   //
   static uint8_t i,j;
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize bridge pins
   //
   clear(bridge_port, A1);
   output(bridge_direction, A1);
   clear(bridge_port, A2);
   output(bridge_direction, A2);
   clear(bridge_port, B1);
   output(bridge_direction, B1);
   clear(bridge_port, B2);
   output(bridge_direction, B2);
   clear(bridge_portB, C1);
   output(bridge_direction, C1);
   clear(bridge_portA, C2);
   output(bridge_direction, C2);
   clear(bridge_portB, D1);
   output(bridge_direction, D1);
   clear(bridge_portB, D2);
   output(bridge_direction, D2);
   //
   // main loop
   //
   while (1) {
      for (i = 0; i < step_count; ++i) {
        // for (j = 0; j < i; ++j)
            step_cw();
            step_cwCD();
         //for (j = 0; j < i; ++j)
            //step_ccw();
         }
      cycle_delay();
      //for (i = step_count; i > 0; --i) {
         //for (j = 0; j < i; ++j)
            //step_cw();
         //for (j = 0; j < i; ++j)
            //step_ccw();
         //}
      }
   }
