]> jspc29.x-matter.uni-frankfurt.de Git - avr.git/commitdiff
add I2C to stepmotor
authorJan Michel <michel@physik.uni-frankfurt.de>
Fri, 16 Oct 2026 10:03:58 +0000 (12:03 +0200)
committerJan Michel <michel@physik.uni-frankfurt.de>
Fri, 16 Oct 2026 10:04:21 +0000 (12:04 +0200)
atmega32u4/stepmotorcontroller/Makefile
atmega32u4/stepmotorcontroller/main.c
atmega32u4/stepmotorcontroller/twi.c [new file with mode: 0644]
atmega32u4/stepmotorcontroller/twi.h [new file with mode: 0644]

index 88b803436b506d2d620d167c3524c330d5461576..b2ba0f70af42746ebff4b2c65eee57d8347b6c57 100644 (file)
@@ -8,7 +8,7 @@
 MCU = atmega32u4
 FORMAT = ihex
 TARGET = main
-SRC = $(TARGET).c usb_serial.c lcdlib/lcd-color-graphic.c lcdlib/font.c \
+SRC = $(TARGET).c usb_serial.c lcdlib/lcd-color-graphic.c lcdlib/font.c twi.c \
       lcdlib/Fonts/digits_24px.c lcdlib/Fonts/digits_32px.c lcdlib/Fonts/font_proportional_16px.c lcdlib/Fonts/font_fixed_16px.c lcdlib/Fonts/font_proportional_8px.c lcdlib/Fonts/symbols_16px.c
 ASRC = 
 OPT = 2
index 1327f0b3fdc34adbae76da558b47e6adba9db108..5aff4af498df2d3358d25cc66b37e3b8a3ec0043 100644 (file)
@@ -1,71 +1,74 @@
 
 
 // #include <avr/eeprom.h>
+#include "lcdlib/font.h"
+#include "lcdlib/lcd-color-graphic.h"
+#include "twi.h"
 #include <avr/interrupt.h>
 #include <avr/io.h>
 #include <string.h>
 #include <usb_serial.h>
 #include <util/delay.h>
-#include "lcdlib/lcd-color-graphic.h"
-#include "lcdlib/font.h"
-
 
 void getdata(uint8_t buf);
 
-
 #define FIRMWARE_VERSION 0x001
 
-#define KP_C1_OFF()   PORTD |=  (1 << PD7)
-#define KP_C1_ON()  PORTD &= ~(1 << PD7)
-#define KP_C2_OFF()   PORTC |=  (1 << PC6)
-#define KP_C2_ON()  PORTC &= ~(1 << PC6)
-#define KP_C3_OFF()   PORTC |=  (1 << PC7)
-#define KP_C3_ON()  PORTC &= ~(1 << PC7)
-#define KP_C4_OFF()   PORTE |=  (1 << PE2)
-#define KP_C4_ON()  PORTE &= ~(1 << PE2)
+#define KP_C1_OFF() PORTD |= (1 << PD7)
+#define KP_C1_ON() PORTD &= ~(1 << PD7)
+#define KP_C2_OFF() PORTC |= (1 << PC6)
+#define KP_C2_ON() PORTC &= ~(1 << PC6)
+#define KP_C3_OFF() PORTC |= (1 << PC7)
+#define KP_C3_ON() PORTC &= ~(1 << PC7)
+#define KP_C4_OFF() PORTE |= (1 << PE2)
+#define KP_C4_ON() PORTE &= ~(1 << PE2)
+
+#define KP_R1() ((PIND & (1 << PD3)) ? 0 : 1)
+#define KP_R2() ((PIND & (1 << PD5)) ? 0 : 1)
+#define KP_R3() ((PIND & (1 << PD6)) ? 0 : 1)
+#define KP_R4() ((PIND & (1 << PD4)) ? 0 : 1)
 
-#define KP_R1() ((PIND & (1<<PD3))?0:1)
-#define KP_R2() ((PIND & (1<<PD5))?0:1)
-#define KP_R3() ((PIND & (1<<PD6))?0:1)
-#define KP_R4() ((PIND & (1<<PD4))?0:1)
+#define ENABLE_POWER() PORTD |= (1 << PD2)
+#define DISABLE_POWER() PORTD &= ~(1 << PD2)
 
-#define DISABLE_M2()  PORTF |=  (1 << PF0)
-#define ENABLE_M2()   PORTF &= ~(1 << PF0)
+#define DISABLE_M2() PORTF |= (1 << PF0)
+#define ENABLE_M2() PORTF &= ~(1 << PF0)
 
-#define DISABLE_M1()  PORTF |=  (1 << PF7)
-#define ENABLE_M1()   PORTF &= ~(1 << PF7)
+#define DISABLE_M1() PORTF |= (1 << PF7)
+#define ENABLE_M1() PORTF &= ~(1 << PF7)
 
-#define PULSE_HIGH_M2()  PORTF |=  (1 << PF4)
-#define PULSE_LOW_M2()   PORTF &= ~(1 << PF4)
+#define PULSE_HIGH_M2() PORTF |= (1 << PF4)
+#define PULSE_LOW_M2() PORTF &= ~(1 << PF4)
 
-#define PULSE_HIGH_M1()  PORTF |=  (1 << PF5)
-#define PULSE_LOW_M1()   PORTF &= ~(1 << PF5)
+#define PULSE_HIGH_M1() PORTF |= (1 << PF5)
+#define PULSE_LOW_M1() PORTF &= ~(1 << PF5)
 
-#define DIRECTION_FORWARD_M2()   PORTF |=  (1 << PF1)
-#define DIRECTION_BACKWARD_M2()  PORTF &= ~(1 << PF1)
+#define DIRECTION_FORWARD_M2() PORTF |= (1 << PF1)
+#define DIRECTION_BACKWARD_M2() PORTF &= ~(1 << PF1)
 
-#define DIRECTION_BACKWARD_M1()   PORTF |=  (1 << PF6)
-#define DIRECTION_FORWARD_M1()  PORTF &= ~(1 << PF6)
+#define DIRECTION_BACKWARD_M1() PORTF |= (1 << PF6)
+#define DIRECTION_FORWARD_M1() PORTF &= ~(1 << PF6)
 
 uint8_t motor_active = 0;
-volatile uint32_t  M1_STEPS = 0;
-volatile uint32_t  M2_STEPS = 0;
-volatile uint8_t  halfstep = 0;
-volatile uint8_t  M1_DIR = 0;
-volatile uint8_t  M2_DIR = 0;
-
-volatile uint8_t  M1_SWITCH_LOW = 0;
-volatile uint8_t  M2_SWITCH_LOW = 0;
-volatile uint8_t  M1_SWITCH_HIGH = 0;
-volatile uint8_t  M2_SWITCH_HIGH = 0;
-volatile uint8_t  switch_changed = 0;
+volatile uint32_t M1_STEPS = 0;
+volatile uint32_t M2_STEPS = 0;
+volatile uint8_t halfstep = 0;
+volatile uint8_t M1_DIR = 0;
+volatile uint8_t M2_DIR = 0;
+
+volatile uint8_t M1_SWITCH_LOW = 0;
+volatile uint8_t M2_SWITCH_LOW = 0;
+volatile uint8_t M1_SWITCH_HIGH = 0;
+volatile uint8_t M2_SWITCH_HIGH = 0;
+volatile uint8_t switch_changed = 0;
 
 volatile int32_t M1_position = 100000;
 volatile int32_t M2_position = 100000;
-uint32_t stepsize = 32;
-int32_t  inputbuffer = 0;
+uint32_t stepsize = 100;
+uint32_t stored_stepsize = 0;
+int32_t inputbuffer = 0;
 uint32_t last_inputbuffer = 1;
-uint8_t  negativeinput = 0;
+uint8_t negativeinput = 0;
 
 uint16_t time;
 uint8_t rxcnt = 0, txpoint = 0;
@@ -73,569 +76,730 @@ uint8_t rxbuf[15];
 uint8_t txbuf[15];
 color_t colors[16];
 color_t topback;
-volatile uint8_t keypad[16] = {0};
+volatile uint8_t keypad[16] = { 0 };
 volatile uint16_t keystate = 0;
 uint8_t numlock = 0;
 uint8_t speed = 4;
 
-uint8_t speeds[8] = {128,64,48,32,16,8,4,2};
-  //0  128 0.25k
-  //1  64 0.5k
-  //2  48 0.66k
-  //3  32 1k
-  //4  16 1.95k
-  //5  8 3.9k
-  //6  4  7.8k
-  //7  2  15.6k
+uint8_t speeds[8] = { 128, 64, 48, 32, 16, 8, 4, 2 };
+// 0  128 0.25k
+// 1  64 0.5k
+// 2  48 0.66k
+// 3  32 1k
+// 4  16 1.95k
+// 5  8 3.9k
+// 6  4  7.8k
+// 7  2  15.6k
+
+uint8_t i2cTx[4];
+uint8_t i2cStatus;
+uint8_t i2cRx[8];
 
 /*****************************************************************
  * Command Handling
  *****************************************************************/
 
 // convert integer or nibbles into hex value
-uint8_t nib_to_hex(uint32_t in, uint8_t nib) {
-  uint8_t t = (in >> (nib * 4)) & 0xF;
-  if (t <= 9) {
-    return t + 0x30;
+uint8_t nib_to_hex(uint32_t in, uint8_t nib)
+{
+    uint8_t t = (in >> (nib * 4)) & 0xF;
+    if (t <= 9) {
+        return t + 0x30;
     }
-  return t - 10 + 0x61;
-  }
+    return t - 10 + 0x61;
+}
 
 // convert hex value to integer,  assumes valid number
-uint8_t hex_to_int(uint8_t h) {
-  if (h < 0x40) return h - 0x30;
-  if (h < 0x50) return h - 0x41 + 10;
-                return h - 0x61 + 10;
-  }
-
-
-uint32_t hex_to_int32(uint8_t * buf) {
-  uint32_t value = 0;
-  for(uint8_t i = 0;i < 8; i++) {
-    value <<= 4;
-    value += hex_to_int(*buf);
-    buf++;
+uint8_t hex_to_int(uint8_t h)
+{
+    if (h < 0x40)
+        return h - 0x30;
+    if (h < 0x50)
+        return h - 0x41 + 10;
+    return h - 0x61 + 10;
+}
+
+uint32_t hex_to_int32(uint8_t* buf)
+{
+    uint32_t value = 0;
+    for (uint8_t i = 0; i < 8; i++) {
+        value <<= 4;
+        value += hex_to_int(*buf);
+        buf++;
     }
-  return value;
-  }
-
-void send_answer_buf(uint8_t *b) { UCSR1B |= (1 << UDRIE1); }
-  // activate transmit interupt "ISR(USART1_UDRE_vect)"
-
-//compose response string
-void send_answer_hex(uint8_t *rxbuf, uint32_t v) {
-  txbuf[0] = 'A';
-  txbuf[1] = rxbuf[1];
-  txbuf[2] = rxbuf[2];
-  txbuf[3] = nib_to_hex(v, 7);
-  txbuf[4] = nib_to_hex(v, 6);
-  txbuf[5] = nib_to_hex(v, 5);
-  txbuf[6] = nib_to_hex(v, 4);
-  txbuf[7] = nib_to_hex(v, 3);
-  txbuf[8] = nib_to_hex(v, 2);
-  txbuf[9] = nib_to_hex(v, 1);
-  txbuf[10] =nib_to_hex(v, 0);
-  txbuf[11] = '\n';
-  txbuf[12] = 0;
-  usb_serial_write(txbuf, 12);
-  usb_serial_flush_output();  
-  // send_answer_buf(txbuf);
-  }
-
-//R0100000000
- /*****************************************************************
+    return value;
+}
+
+void send_answer_buf(uint8_t* b) { UCSR1B |= (1 << UDRIE1); }
+// activate transmit interupt "ISR(USART1_UDRE_vect)"
+
+// compose response string
+void send_answer_hex(uint8_t* rxbuf, uint32_t v)
+{
+    txbuf[0] = 'A';
+    txbuf[1] = rxbuf[1];
+    txbuf[2] = rxbuf[2];
+    txbuf[3] = nib_to_hex(v, 7);
+    txbuf[4] = nib_to_hex(v, 6);
+    txbuf[5] = nib_to_hex(v, 5);
+    txbuf[6] = nib_to_hex(v, 4);
+    txbuf[7] = nib_to_hex(v, 3);
+    txbuf[8] = nib_to_hex(v, 2);
+    txbuf[9] = nib_to_hex(v, 1);
+    txbuf[10] = nib_to_hex(v, 0);
+    txbuf[11] = '\n';
+    txbuf[12] = 0;
+    usb_serial_write(txbuf, 12);
+    usb_serial_flush_output();
+    // send_answer_buf(txbuf);
+}
+
+// R0100000000
+/*****************************************************************
  * Setting functions
  *****************************************************************/
 
-
 // uint16_t keystate_old = 0;
 uint8_t keyupdate = 0;
- /*****************************************************************
+/*****************************************************************
  * Interrupts
  *****************************************************************/
-ISR(TIMER0_COMPA_vect) {
-  // interupt for time, watchdog, keypad
-  time++;
-  asm volatile("wdr");
-  
-  KP_C1_ON(); asm volatile("nop");
-  uint16_t tmp_keystate = 0;
-  if ( KP_R1()) tmp_keystate |= (1 << 0);
-  if ( KP_R2()) tmp_keystate |= (1 << 1);
-  if ( KP_R3()) tmp_keystate |= (1 << 2);
-  if ( KP_R4()) tmp_keystate |= (1 << 3);
-  
-  KP_C1_OFF();
-  KP_C2_ON(); asm volatile("nop");
-  if ( KP_R1()) tmp_keystate |= (1 << 4);
-  if ( KP_R2()) tmp_keystate |= (1 << 5);
-  if ( KP_R3()) tmp_keystate |= (1 << 6);
-  if ( KP_R4()) tmp_keystate |= (1 << 7);
-  KP_C2_OFF();
-  KP_C3_ON(); asm volatile("nop");
-  if ( KP_R1()) tmp_keystate |= (1 << 8);
-  if ( KP_R2()) tmp_keystate |= (1 << 9);
-  if ( KP_R3()) tmp_keystate |= (1 << 10);
-  if ( KP_R4()) tmp_keystate |= (1 << 11);
-  KP_C3_OFF();
-  KP_C4_ON(); asm volatile("nop");
-  if ( KP_R1()) tmp_keystate |= (1 << 12);
-  if ( KP_R2()) tmp_keystate |= (1 << 13);
-  if ( KP_R3()) tmp_keystate |= (1 << 14);
-  if ( KP_R4()) tmp_keystate |= (1 << 15);
-  KP_C4_OFF();
-  
-  // keystate_old = keystate;
-  keystate = tmp_keystate;
-  keyupdate = 1;
-  uint8_t j = 0;
-  for(uint16_t i = 1; i != 0 ; i <<= 1) {
-    if(tmp_keystate & i) {
-      if (keypad[j] < 200)
-        keypad[j]++;
-    }
-    else if (keypad[j] == 255) {
-        keypad[j] = 0;
+ISR(TIMER0_COMPA_vect)
+{
+    // interupt for time, watchdog, keypad
+    time++;
+    asm volatile("wdr");
+
+    KP_C1_ON();
+    asm volatile("nop");
+    uint16_t tmp_keystate = 0;
+    if (KP_R1())
+        tmp_keystate |= (1 << 0);
+    if (KP_R2())
+        tmp_keystate |= (1 << 1);
+    if (KP_R3())
+        tmp_keystate |= (1 << 2);
+    if (KP_R4())
+        tmp_keystate |= (1 << 3);
+
+    KP_C1_OFF();
+    KP_C2_ON();
+    asm volatile("nop");
+    if (KP_R1())
+        tmp_keystate |= (1 << 4);
+    if (KP_R2())
+        tmp_keystate |= (1 << 5);
+    if (KP_R3())
+        tmp_keystate |= (1 << 6);
+    if (KP_R4())
+        tmp_keystate |= (1 << 7);
+    KP_C2_OFF();
+    KP_C3_ON();
+    asm volatile("nop");
+    if (KP_R1())
+        tmp_keystate |= (1 << 8);
+    if (KP_R2())
+        tmp_keystate |= (1 << 9);
+    if (KP_R3())
+        tmp_keystate |= (1 << 10);
+    if (KP_R4())
+        tmp_keystate |= (1 << 11);
+    KP_C3_OFF();
+    KP_C4_ON();
+    asm volatile("nop");
+    if (KP_R1())
+        tmp_keystate |= (1 << 12);
+    if (KP_R2())
+        tmp_keystate |= (1 << 13);
+    if (KP_R3())
+        tmp_keystate |= (1 << 14);
+    if (KP_R4())
+        tmp_keystate |= (1 << 15);
+    KP_C4_OFF();
+
+    // keystate_old = keystate;
+    keystate = tmp_keystate;
+    keyupdate = 1;
+    uint8_t j = 0;
+    for (uint16_t i = 1; i != 0; i <<= 1) {
+        if (tmp_keystate & i) {
+            if (keypad[j] < 200)
+                keypad[j]++;
+        } else if (keypad[j] == 255) {
+            keypad[j] = 0;
+        }
+        j++;
     }
-    j++;
-  }
-
 }
 
+ISR(TIMER1_COMPA_vect)
+{
 
-ISR(TIMER1_COMPA_vect) {
-  
-  // if (M1_STEPS > 0) {
+    // if (M1_STEPS > 0) {
     if (halfstep) {
-      if (M1_DIR) {
-        // DIRECTION_FORWARD_M1();
-        if (M1_SWITCH_HIGH)
-          M1_STEPS = 0;
-      }
-      else {
-        // DIRECTION_BACKWARD_M1();
-        if (M1_SWITCH_LOW)
-          M1_STEPS = 0;
-      }
-      // if (!motor_active) M1_STEPS = 0;
-      if (M1_STEPS > 0) {
-        M1_STEPS--;
-        M1_position += 2*M1_DIR-1;
-        PULSE_HIGH_M1();
-      }
-    }
-    else {
-      PULSE_LOW_M1();      
+        if (M1_DIR) {
+            // DIRECTION_FORWARD_M1();
+            if (M1_SWITCH_HIGH)
+                M1_STEPS = 0;
+        } else {
+            // DIRECTION_BACKWARD_M1();
+            if (M1_SWITCH_LOW)
+                M1_STEPS = 0;
+        }
+        // if (!motor_active) M1_STEPS = 0;
+        if (M1_STEPS > 0) {
+            M1_STEPS--;
+            M1_position += 2 * M1_DIR - 1;
+            PULSE_HIGH_M1();
+        }
+    } else {
+        PULSE_LOW_M1();
     }
-  // }
+    // }
 
-  // if (M2_STEPS > 0) {
+    // if (M2_STEPS > 0) {
     if (halfstep) {
-      if (M2_DIR) {
-        // DIRECTION_FORWARD_M2();
-        if (M2_SWITCH_HIGH)
-          M2_STEPS = 0;
-      }
-      else {
-        // DIRECTION_BACKWARD_M2();
-        if (M2_SWITCH_LOW)
-          M2_STEPS = 0;
-      }
-      // if (!motor_active) M2_STEPS = 0;
-      if (M2_STEPS > 0) {
-        M2_STEPS--;
-        M2_position += 2*M2_DIR-1;
-        PULSE_HIGH_M2();
-      }
-    }
-    else {
-      PULSE_LOW_M2();      
+        if (M2_DIR) {
+            // DIRECTION_FORWARD_M2();
+            if (M2_SWITCH_HIGH)
+                M2_STEPS = 0;
+        } else {
+            // DIRECTION_BACKWARD_M2();
+            if (M2_SWITCH_LOW)
+                M2_STEPS = 0;
+        }
+        // if (!motor_active) M2_STEPS = 0;
+        if (M2_STEPS > 0) {
+            M2_STEPS--;
+            M2_position += 2 * M2_DIR - 1;
+            PULSE_HIGH_M2();
+        }
+    } else {
+        PULSE_LOW_M2();
     }
-  // }
-  
-  halfstep = 1 - halfstep;  
-}
+    // }
 
-ISR(PCINT0_vect) {
-  // interupt for switches
-  M1_SWITCH_LOW  = (PINB & (1<<PB5))? 0 : 1;
-  M1_SWITCH_HIGH = (PINB & (1<<PB6))? 0 : 1;
-  M2_SWITCH_LOW  = (PINB & (1<<PB4))? 0 : 1;
-  M2_SWITCH_HIGH = (PINB & (1<<PB7))? 0 : 1;
-  switch_changed = 1;
+    halfstep = 1 - halfstep;
 }
 
+ISR(PCINT0_vect)
+{
+    // interupt for switches
+    M1_SWITCH_LOW = (PINB & (1 << PB5)) ? 1 : 0;
+    M1_SWITCH_HIGH = (PINB & (1 << PB6)) ? 1 : 0;
+    M2_SWITCH_LOW = (PINB & (1 << PB4)) ? 1 : 0;
+    M2_SWITCH_HIGH = (PINB & (1 << PB7)) ? 1 : 0;
+    switch_changed = 1;
+}
 
-
-void init_spi_lcd() {
+void init_spi_lcd()
+{
 }
 
- /*****************************************************************
+/*****************************************************************
  * Communication
  *****************************************************************/
-void getdata(uint8_t buf) {
+void getdata(uint8_t buf)
+{
 
-  if (rxcnt != 0 || (buf == 'W' || buf == 'R')) {
-    rxbuf[rxcnt++] = buf;
+    if (rxcnt != 0 || (buf == 'W' || buf == 'R')) {
+        rxbuf[rxcnt++] = buf;
     }
-  if (buf == '\n' || buf == '\r') { // End of Command
-    if (rxcnt == 12) {
-      uint8_t regnumber = hex_to_int(rxbuf[2]) + hex_to_int(rxbuf[1])*16;
-
-      if (rxbuf[0] == 'R') {
-        if (regnumber == 1) {        //Register 1: PIN
-          send_answer_hex(&rxbuf[0], 0xabcd1234);
-          }
-
-      }
-      if (rxbuf[0] == 'W') {
-        uint32_t value = hex_to_int32(&rxbuf[3]);
-        if (regnumber == 0) {
-          send_answer_hex(&rxbuf[0], value);
-          }
+    if (buf == '\n' || buf == '\r') { // End of Command
+        if (rxcnt == 12) {
+            uint8_t regnumber = hex_to_int(rxbuf[2]) + hex_to_int(rxbuf[1]) * 16;
+
+            if (rxbuf[0] == 'R') {
+                if (regnumber == 1) { // Register 1: PIN
+                    send_answer_hex(&rxbuf[0], 0xabcd1234);
+                }
+            }
+            if (rxbuf[0] == 'W') {
+                uint32_t value = hex_to_int32(&rxbuf[3]);
+                if (regnumber == 0) {
+                    send_answer_hex(&rxbuf[0], value);
+                }
+            }
         }
-      }
     }
 
-  if (rxcnt >= 12 || buf == '\n' || buf == '\r') {
-    rxcnt = 0;
+    if (rxcnt >= 12 || buf == '\n' || buf == '\r') {
+        rxcnt = 0;
     }
-  }
+}
 
 // R0000000000
- /*****************************************************************
+/*****************************************************************
  * Main function
  *****************************************************************/
 
-__attribute__((naked)) void main(void) {
-  // initialize the board
-
-  CLKPR = (1 << CLKPCE); // prescaler 2 = 8 MHz
-  CLKPR = (1 << CLKPS0); // prescaler 2
-
-  // Configure ports
-
-  MCUCR |= (1 << JTD);
-  MCUCR |= (1 << JTD); // yes, twice
-
-  //--------------------------------------------------------//
-  // DDRx  : 0 = Input; 1 = Output
-  // PORTx : Input  ->  0: no PullUp    1: Pullup
-  //        Output ->  0: LOW          1: HIGH
-
-  PORTB = 0b11110000;
-  DDRB  = 0b00001111;
-
-  PORTC = 0b00000000;
-  DDRC  = 0b11000000;
-
-  PORTD = 0b01111100;
-  DDRD  = 0b10000100;
-
-  PORTE = 0b00000000;
-  DDRE  = 0b01000100;
-
-  PORTF = 0b10000001;
-  DDRF  = 0b11110011;
-
-  // Timer0 at 50 Hz CTC
-  TCCR0A = (2 << WGM00);  // CTC mode
-  TCCR0B = (5 << CS00); //1024 prescaler
-  OCR0A  = 160;
-  TIMSK0 = (1 << OCIE0A); // Overflow interrupt
-
-  //SPI for display
-  SPCR = 0 << SPIE | 1 << SPE | 0 << DORD | 1 << MSTR | 1 << CPOL | 1 << CPHA | 0 << SPR1 | 0 << SPR0;
-  SPSR = 1 << SPI2X;
-  SPDR = LCD_NOP; //Do not use 0 here, only LCD_NOP is allowed!
-
-  //Interrupt for switches
-  PCICR = (1 << PCIE0);
-  PCMSK0 = 0xf0;
-
-  //Timer for motor Controller
-  TCCR1A = 0;
-  TCCR1B = (4 << CS00) | (1 << WGM12); //256 prescaler, CTC mode
-  OCR1A = 16; //1.95 kHz
-  TIMSK1 = (1 << OCIE1A); //overflow interrupt
-  
-
-  
-  //I2C for current monitor
-
-  usb_init();
-  _delay_ms(200);
-  lcd_init();  
-  lcd_set_color(colors+0,0x1f,0x3f,0x0e); //yellow 1st
-  lcd_set_color(colors+1,0x1f,0x3f,0x0e); //yellow 2nd
-  lcd_set_color(colors+2,0x1f,0x3f,0x1f); //second curve
-  lcd_set_color(colors+3,0x0e,0x3f,0x0f); //green
-  lcd_set_color(colors+4,0x0e,0x1f,0x1f); //blue cool
-  lcd_set_color(colors+5,0x1f,0x0f,0x05); //red heat
-  lcd_set_color(colors+6,0,0,0);          //black
-  
-  lcd_set_color(&topback,0x03,0x04,0x05);
-
-  lcd_command_1(LCD_MIRROR, LCD_BGR | LCD_FLIP_XY);
-  lcd_command(LCD_ON);
-  lcd_use_background(colors[6]);
-  lcd_use_foreground(colors[0]);
-  lcd_set_area_xy(0, 0x13F, 0, 0xEF);
-  lcd_set_font(FONT_PROP_16,SPACING);
-  lcd_putstr_xy_P(PSTR("Step Motor Controller"),2,0);
-  lcd_putstr_xy_P(PSTR("X"),72,2);
-  lcd_putstr_xy_P(PSTR("Y"),112,2);
-  lcd_putstr_xy_P(PSTR("S"),208,2);
-  lcd_use_foreground(colors[5]);
-  lcd_putstr_xy_P(PSTR("off"),16,280);  
-  lcd_use_foreground(colors[0]);
-  lcd_putstr_xy_P(PSTR("<-->"),32,280);
-  lcd_putstr_xy_P(PSTR("Sp 4"),48,280);
-  lcd_set_font(FONT_DIGITS_32,SPACING);  
-  LCD_MOVE_TO(200,46);
-  lcd_put_long(stepsize);
-  lcd_set_font(FONT_PROP_16,SPACING);
-
-
-  uint16_t lasttime = 0;
-
-  for (uint8_t i = 0; i < 16; i++) keypad[i] = 0;
-  
-  while (1) {
-    int n = usb_serial_getchar();
-    if (n >= 0) {
-      getdata(n);
-    }
-
-    if ((time != lasttime)) {
-      if(switch_changed) {
-        switch_changed = 0;
-        lcd_set_font(FONT_PROP_16,SPACING);
-        lcd_use_foreground(colors[5]);        
-        if(M1_SWITCH_LOW) lcd_putstr_xy_P(PSTR("min"),72,240);
-        if(M1_SWITCH_HIGH) lcd_putstr_xy_P(PSTR("max"),72,240);
-        if(M2_SWITCH_LOW) lcd_putstr_xy_P(PSTR("min"),112,240);
-        if(M2_SWITCH_HIGH) lcd_putstr_xy_P(PSTR("max"),112,240);
-        if(!M1_SWITCH_LOW && !M1_SWITCH_HIGH) lcd_set_area_xy(240, 280, 72, 88);
-        if(!M2_SWITCH_LOW && !M2_SWITCH_HIGH) lcd_set_area_xy(240, 280, 112, 128);
-        lcd_use_foreground(colors[0]);
-        }
-        
-//ABCD
-      if(keyupdate) {
-        keyupdate = 0;
-        
-        lcd_set_font(FONT_PROP_16,SPACING);
-        if(keypad[12] && keypad[12] != 255) { //A
-          if (motor_active) {
-            motor_active = 0;
-            DISABLE_M1();
-            DISABLE_M2();
-            M1_STEPS = 0;
-            M2_STEPS = 0;
-            lcd_use_foreground(colors[5]);
-            lcd_putstr_xy_P(PSTR("off"),16,280);
-            lcd_use_foreground(colors[0]);
-            }
-          else {
-            motor_active = 1;
-            ENABLE_M1();
-            ENABLE_M2();
-            lcd_use_foreground(colors[3]);
-            lcd_putstr_xy_P(PSTR("ON "),16,280);
-            lcd_use_foreground(colors[0]);
-          }
-          keypad[12] = 255;  
+__attribute__((naked)) void main(void)
+{
+    // initialize the board
+
+    CLKPR = (1 << CLKPCE); // prescaler 2 = 8 MHz
+    CLKPR = (1 << CLKPS0); // prescaler 2
+
+    // Configure ports
+
+    MCUCR |= (1 << JTD);
+    MCUCR |= (1 << JTD); // yes, twice
+
+    //--------------------------------------------------------//
+    // DDRx  : 0 = Input; 1 = Output
+    // PORTx : Input  ->  0: no PullUp    1: Pullup
+    //        Output ->  0: LOW          1: HIGH
+
+    PORTB = 0b11110000;
+    DDRB = 0b00001111;
+
+    PORTC = 0b00000000;
+    DDRC = 0b11000000;
+
+    PORTD = 0b01111100;
+    DDRD = 0b10000100;
+
+    PORTE = 0b00000000;
+    DDRE = 0b01000100;
+
+    PORTF = 0b10000001;
+    DDRF = 0b11110011;
+
+    // Timer0 at 50 Hz CTC
+    TCCR0A = (2 << WGM00); // CTC mode
+    TCCR0B = (5 << CS00); // 1024 prescaler
+    OCR0A = 160;
+    TIMSK0 = (1 << OCIE0A); // Overflow interrupt
+
+    // SPI for display
+    SPCR = 0 << SPIE | 1 << SPE | 0 << DORD | 1 << MSTR | 1 << CPOL | 1 << CPHA | 0 << SPR1 | 0 << SPR0;
+    SPSR = 1 << SPI2X;
+    SPDR = LCD_NOP; // Do not use 0 here, only LCD_NOP is allowed!
+
+    // Interrupt for switches
+    PCICR = (1 << PCIE0);
+    PCMSK0 = 0xf0;
+
+    // Timer for motor Controller
+    TCCR1A = 0;
+    TCCR1B = (4 << CS00) | (1 << WGM12); // 256 prescaler, CTC mode
+    OCR1A = 16; // 1.95 kHz
+    TIMSK1 = (1 << OCIE1A); // overflow interrupt
+
+    // // I2C for current monitor
+    // // 47
+    // // 0 config1_descriptor 0b0000_0111_0111_0111 = 0x066f
+    // // 1 shunt voltage
+    // // 2 bus voltage
+    // // 3 power
+    // // 4 current
+    // // 5 calib 29789 -> 1/8mA
+    // twi_init();
+    // i2cTx[0] = 0;
+    // i2cTx[1] = 0x07;
+    // i2cTx[2] = 0x7f; // config register
+    // twi_writeTo(0x47, i2cTx, 3, 1, 1);
+    // i2cTx[0] = 5;
+    // i2cTx[1] = 29789 >> 8;
+    // i2cTx[2] = 29789; // calib register
+    // twi_writeTo(0x47, i2cTx, 3, 1, 1);
+    // i2cTx[0] = 1; // switch to voltage register
+    // twi_writeTo(0x47, i2cTx, 1, 1, 1);
+
+    usb_init();
+    _delay_ms(200);
+    lcd_init();
+    lcd_set_color(colors + 0, 0x1f, 0x3f, 0x0e); // yellow 1st
+    lcd_set_color(colors + 1, 0x1f, 0x3f, 0x0e); // yellow 2nd
+    lcd_set_color(colors + 2, 0x1f, 0x3f, 0x1f); // second curve
+    lcd_set_color(colors + 3, 0x0e, 0x3f, 0x0f); // green
+    lcd_set_color(colors + 4, 0x0e, 0x1f, 0x1f); // blue cool
+    lcd_set_color(colors + 5, 0x1f, 0x0f, 0x05); // red heat
+    lcd_set_color(colors + 6, 0, 0, 0); // black
+
+    lcd_set_color(&topback, 0x03, 0x04, 0x05);
+
+    lcd_command_1(LCD_MIRROR, LCD_BGR | LCD_FLIP_XY);
+    lcd_command(LCD_ON);
+    lcd_use_background(colors[6]);
+    lcd_use_foreground(colors[0]);
+    lcd_set_area_xy(0, 0x13F, 0, 0xEF);
+    lcd_set_font(FONT_PROP_16, SPACING);
+    lcd_putstr_xy_P(PSTR("Step Motor Controller"), 2, 0);
+    lcd_putstr_xy_P(PSTR("X"), 72, 2);
+    lcd_putstr_xy_P(PSTR("Y"), 112, 2);
+    lcd_putstr_xy_P(PSTR("S"), 208, 2);
+    lcd_use_foreground(colors[5]);
+    lcd_putstr_xy_P(PSTR("off"), 16, 280);
+    lcd_use_foreground(colors[0]);
+    lcd_putstr_xy_P(PSTR("<-->"), 32, 280);
+    lcd_putstr_xy_P(PSTR("Sp 4"), 48, 280);
+    lcd_set_font(FONT_DIGITS_32, SPACING);
+    LCD_MOVE_TO(200, 46);
+    lcd_put_long(stepsize);
+    lcd_set_font(FONT_PROP_16, SPACING);
+
+    uint16_t lasttime = 0;
+
+    for (uint8_t i = 0; i < 16; i++)
+        keypad[i] = 0;
+
+    while (1) {
+        int n = usb_serial_getchar();
+        if (n >= 0) {
+            getdata(n);
         }
-        if(keypad[13] && keypad[13] != 255) { //B
-          numlock = 1 - numlock;
-          if (numlock) {
-            lcd_set_area_xy(280,320,32,48);
-            lcd_putstr_xy_P(PSTR("NUM"),32,280);
-          }
-          else {
-            lcd_set_area_xy(280,320,32,48);
-            lcd_putstr_xy_P(PSTR("<-->"),32,280);
-            lcd_set_area_xy(240,320,224,240);
-            inputbuffer = 0;
-            negativeinput = 0;
-          }
-          keypad[13] = 255;  
-        }
-//Cursor Keys        
-        if(!numlock) {
-          if(keypad[14] && keypad[14] != 255) { //C
-            cli();
-            M1_position = 0;
-            M2_position = 0;
-            sei();
-            keypad[14] = 255;  
-          }      
-          if(keypad[15] && keypad[15] != 255) { //D
-            cli();
-            M1_STEPS = 0;
-            M2_STEPS = 0;
-            sei();
-            keypad[14] = 255;  
-          }       
-          
-          if(keypad[4]) { //2
-            if (keypad[4] < 20 || keypad[4] > 40) {
-              if(M2_STEPS == 0 && motor_active) {
-                DIRECTION_FORWARD_M2();
-                M2_DIR = 1;
-                M2_STEPS = stepsize;
-              }
-            }
-            if(keypad[4] < 20)        keypad[4] = 20;
-            if (!(keystate & (1<<4))) keypad[4] = 255;
-          }
-        
-          if(keypad[6]) { //8
-            if (keypad[6] < 20 || keypad[6] > 40) {
-              if(M2_STEPS == 0 && motor_active) {
-                DIRECTION_BACKWARD_M2();
-                M2_DIR = 0;
-                M2_STEPS = stepsize;
-              }
-            }
-            if(keypad[6] < 20)        keypad[6] = 20;
-            if (!(keystate & (1<<6))) keypad[6] = 255;
-          }
-          
-          if(keypad[1]) { //4
-            if (keypad[1] < 20 || keypad[1] > 40) {
-              if(M1_STEPS == 0 && motor_active) {
-                DIRECTION_BACKWARD_M1();
-                M1_DIR = 0;
-                M1_STEPS = stepsize;
-              }
-            }
-            if(keypad[1] < 20)        keypad[1] = 20;
-            if (!(keystate & (1<<1))) keypad[1] = 255;
-          }
-        
-          if(keypad[9]) { //6
-            if (keypad[9] < 20 || keypad[9] > 40) {
-              if(M1_STEPS == 0 && motor_active) {
-                DIRECTION_FORWARD_M1();
-                M1_DIR = 1;
-                M1_STEPS = stepsize;
-              }
-            }
-            if(keypad[9] < 20)        keypad[9] = 20;
-            if (!(keystate & (1<<9))) keypad[9] = 255;
-          }
-        inputbuffer = 0;
-        }
-//Number input
-        else {
-          if( keypad[0]  && keypad[0] != 255) { inputbuffer *= 10; inputbuffer += 1; keypad[0] = 255; }
-          if( keypad[1]  && keypad[1] != 255) { inputbuffer *= 10; inputbuffer += 4; keypad[1] = 255; }
-          if( keypad[2]  && keypad[2] != 255) { inputbuffer *= 10; inputbuffer += 7; keypad[2] = 255; }
-          if( keypad[4]  && keypad[4] != 255) { inputbuffer *= 10; inputbuffer += 2; keypad[4] = 255; }
-          if( keypad[5]  && keypad[5] != 255) { inputbuffer *= 10; inputbuffer += 5; keypad[5] = 255; }
-          if( keypad[6]  && keypad[6] != 255) { inputbuffer *= 10; inputbuffer += 8; keypad[6] = 255; }
-          if( keypad[7]  && keypad[7] != 255) { 
-            if (inputbuffer != 0) {inputbuffer *= 10; inputbuffer += 0; keypad[7] = 255; }
-            if (inputbuffer == 0) {negativeinput = 1 - negativeinput; keypad[7] = 255;}
-          }
-          if( keypad[8]  && keypad[8] != 255) { inputbuffer *= 10; inputbuffer += 3; keypad[8] = 255; }
-          if( keypad[9]  && keypad[9] != 255) { inputbuffer *= 10; inputbuffer += 6; keypad[9] = 255; }
-          if( keypad[10] && keypad[10] != 255) { inputbuffer *= 10; inputbuffer += 9; keypad[10] = 255; }
-          if( keypad[11] && keypad[11] != 255) {  // #
-            stepsize = inputbuffer;
-            inputbuffer = 0; negativeinput=0;
-            if (stepsize > 100000) stepsize = 100000;
-            keypad[11] = 255;
-            lcd_set_font(FONT_DIGITS_32,SPACING);  
-            LCD_MOVE_TO(200,16);
-            lcd_set_area_xy(16,240,200,232);            
-            lcd_put_long_align32_7(stepsize);
-            lcd_set_font(FONT_PROP_16,SPACING);
-          } 
-          if(keypad[3] && keypad[3] != 255) {  // *
-            speed = inputbuffer & 0x7;
-            inputbuffer = 0; negativeinput = 0;        
-            cli();
-            OCR1A = speeds[speed];
-            TCNT1 = 0;
-            sei();
-            keypad[3] = 255;
-            lcd_set_font(FONT_PROP_16,SPACING);
-            lcd_set_area_xy(280,320,48,64);
-            LCD_MOVE_TO(48,280);
-            lcd_putstr_P(PSTR("Sp "));
-            lcd_put_short(speed);
-          }
-          if(keypad[14] && keypad[14] != 255) { //C
-            if (motor_active) {
-              cli();
-              M1_STEPS = 0;
-              if (negativeinput) inputbuffer *= -1;
-              if(M1_position < inputbuffer) {
-                DIRECTION_FORWARD_M1();
-                M1_DIR = 1;
-                M1_STEPS = inputbuffer-M1_position;
-              } else {
-                DIRECTION_BACKWARD_M1();
-                M1_DIR = 0;
-                M1_STEPS = M1_position-inputbuffer;
-              }
-              inputbuffer = 0; negativeinput = 0;
-              sei();
+
+        if ((time != lasttime)) {
+            if (switch_changed) {
+                switch_changed = 0;
+                lcd_set_font(FONT_PROP_16, SPACING);
+                lcd_use_foreground(colors[5]);
+                if (M1_SWITCH_LOW)
+                    lcd_putstr_xy_P(PSTR("min"), 72, 240);
+                if (M1_SWITCH_HIGH)
+                    lcd_putstr_xy_P(PSTR("max"), 72, 240);
+                if (M2_SWITCH_LOW)
+                    lcd_putstr_xy_P(PSTR("min"), 112, 240);
+                if (M2_SWITCH_HIGH)
+                    lcd_putstr_xy_P(PSTR("max"), 112, 240);
+                if (!M1_SWITCH_LOW && !M1_SWITCH_HIGH)
+                    lcd_set_area_xy(240, 280, 72, 88);
+                if (!M2_SWITCH_LOW && !M2_SWITCH_HIGH)
+                    lcd_set_area_xy(240, 280, 112, 128);
+                lcd_use_foreground(colors[0]);
             }
-            keypad[14] = 255;  
-          }        
-          if(keypad[15] && keypad[15] != 255) { //D
-            if (motor_active) {            
-              cli();
-              M2_STEPS = 0;
-              if (negativeinput) inputbuffer *= -1;
-              if(M2_position < inputbuffer) {
-                DIRECTION_FORWARD_M2();
-                M2_DIR = 1;
-                M2_STEPS = inputbuffer-M2_position;
-              } else {
-                DIRECTION_BACKWARD_M2();
-                M2_DIR = 0;
-                M2_STEPS = M2_position-inputbuffer;
-              }
-              inputbuffer = 0; negativeinput = 0;
-              sei();
+
+            // ABCD
+            if (keyupdate) {
+                keyupdate = 0;
+
+                lcd_set_font(FONT_PROP_16, SPACING);
+                if (keypad[12] && keypad[12] != 255) { // A
+                    if (motor_active) {
+                        motor_active = 0;
+                        DISABLE_M1();
+                        DISABLE_M2();
+                        DISABLE_POWER();
+                        M1_STEPS = 0;
+                        M2_STEPS = 0;
+                        lcd_use_foreground(colors[5]);
+                        lcd_putstr_xy_P(PSTR("off"), 16, 280);
+                        lcd_use_foreground(colors[0]);
+                    } else {
+                        motor_active = 1;
+                        ENABLE_M1();
+                        ENABLE_M2();
+                        ENABLE_POWER();
+                        lcd_use_foreground(colors[3]);
+                        lcd_putstr_xy_P(PSTR("ON "), 16, 280);
+                        lcd_use_foreground(colors[0]);
+                    }
+                    keypad[12] = 255;
+                }
+                if (keypad[13] && keypad[13] != 255) { // B
+                    numlock = 1 - numlock;
+                    if (numlock) {
+                        lcd_set_area_xy(280, 320, 32, 48);
+                        lcd_putstr_xy_P(PSTR("NUM"), 32, 280);
+                    } else {
+                        lcd_set_area_xy(280, 320, 32, 48);
+                        lcd_putstr_xy_P(PSTR("<-->"), 32, 280);
+                        lcd_set_area_xy(240, 320, 224, 240);
+                        inputbuffer = 0;
+                        negativeinput = 0;
+                    }
+                    keypad[13] = 255;
+                }
+                // Cursor Keys
+                if (!numlock) {
+                    if (keypad[14] && keypad[14] != 255) { // C
+                        cli();
+                        M1_position = 0;
+                        M2_position = 0;
+                        sei();
+                        keypad[14] = 255;
+                    }
+                    if (keypad[15] && keypad[15] != 255) { // D
+                        cli();
+                        M1_STEPS = 0;
+                        M2_STEPS = 0;
+                        sei();
+                        keypad[14] = 255;
+                    }
+
+                    if (keypad[4]) { // 2
+                        if (keypad[4] < 20 || keypad[4] > 40) {
+                            cli();
+                            if (M2_STEPS == 0 && motor_active) {
+                                DIRECTION_FORWARD_M2();
+                                M2_DIR = 1;
+                                M2_STEPS = stepsize;
+                            }
+                            sei();
+                        }
+                        if (keypad[4] < 20)
+                            keypad[4] = 20;
+                        if (!(keystate & (1 << 4)))
+                            keypad[4] = 255;
+                    }
+                    if (keypad[5]) { // 5, toggle single step mode
+                        cli();
+                        if(stepsize != 1) {
+                          stored_stepsize = stepsize;
+                          stepsize = 1;
+                          }
+                        else {
+                          stepsize = stored_stepsize;
+                          }
+                        sei();
+
+                        lcd_set_font(FONT_DIGITS_32, SPACING);
+                        LCD_MOVE_TO(200, 16);
+                        lcd_set_area_xy(16, 240, 200, 232);
+                        lcd_put_long_align32_7(stepsize);
+                        lcd_set_font(FONT_PROP_16, SPACING);
+                        
+                        keypad[5] = 255;
+                    }
+                    if (keypad[6]) { // 8
+                        if (keypad[6] < 20 || keypad[6] > 40) {
+                            cli();
+                            if (M2_STEPS == 0 && motor_active) {
+                                DIRECTION_BACKWARD_M2();
+                                M2_DIR = 0;
+                                M2_STEPS = stepsize;
+                            }
+                            sei();
+                        }
+                        if (keypad[6] < 20)
+                            keypad[6] = 20;
+                        if (!(keystate & (1 << 6)))
+                            keypad[6] = 255;
+                    }
+
+                    if (keypad[1]) { // 4
+                        if (keypad[1] < 20 || keypad[1] > 40) {
+                            cli();
+                            if (M1_STEPS == 0 && motor_active) {
+                                DIRECTION_BACKWARD_M1();
+                                M1_DIR = 0;
+                                M1_STEPS = stepsize;
+                            }
+                            sei();
+                        }
+                        if (keypad[1] < 20)
+                            keypad[1] = 20;
+                        if (!(keystate & (1 << 1)))
+                            keypad[1] = 255;
+                    }
+
+                    if (keypad[9]) { // 6
+                        if (keypad[9] < 20 || keypad[9] > 40) {
+                            cli();
+                            if (M1_STEPS == 0 && motor_active) {
+                                DIRECTION_FORWARD_M1();
+                                M1_DIR = 1;
+                                M1_STEPS = stepsize;
+                            }
+                            sei();
+                        }
+                        if (keypad[9] < 20)
+                            keypad[9] = 20;
+                        if (!(keystate & (1 << 9)))
+                            keypad[9] = 255;
+                    }
+                    inputbuffer = 0;
+                }
+                // Number input
+                else {
+                    if (keypad[0] && keypad[0] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 1;
+                        keypad[0] = 255;
+                    }
+                    if (keypad[1] && keypad[1] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 4;
+                        keypad[1] = 255;
+                    }
+                    if (keypad[2] && keypad[2] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 7;
+                        keypad[2] = 255;
+                    }
+                    if (keypad[4] && keypad[4] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 2;
+                        keypad[4] = 255;
+                    }
+                    if (keypad[5] && keypad[5] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 5;
+                        keypad[5] = 255;
+                    }
+                    if (keypad[6] && keypad[6] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 8;
+                        keypad[6] = 255;
+                    }
+                    if (keypad[7] && keypad[7] != 255) {
+                        if (inputbuffer != 0) {
+                            inputbuffer *= 10;
+                            inputbuffer += 0;
+                            keypad[7] = 255;
+                        }
+                        if (inputbuffer == 0) {
+                            negativeinput = 1 - negativeinput;
+                            keypad[7] = 255;
+                        }
+                    }
+                    if (keypad[8] && keypad[8] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 3;
+                        keypad[8] = 255;
+                    }
+                    if (keypad[9] && keypad[9] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 6;
+                        keypad[9] = 255;
+                    }
+                    if (keypad[10] && keypad[10] != 255) {
+                        inputbuffer *= 10;
+                        inputbuffer += 9;
+                        keypad[10] = 255;
+                    }
+                    if (keypad[11] && keypad[11] != 255) { // #
+                        stepsize = inputbuffer;
+                        inputbuffer = 0;
+                        negativeinput = 0;
+                        if (stepsize > 100000)
+                            stepsize = 100000;
+                        keypad[11] = 255;
+                        lcd_set_font(FONT_DIGITS_32, SPACING);
+                        LCD_MOVE_TO(200, 16);
+                        lcd_set_area_xy(16, 240, 200, 232);
+                        lcd_put_long_align32_7(stepsize);
+                        lcd_set_font(FONT_PROP_16, SPACING);
+                    }
+                    if (keypad[3] && keypad[3] != 255) { // *
+                        speed = inputbuffer & 0x7;
+                        inputbuffer = 0;
+                        negativeinput = 0;
+                        cli();
+                        OCR1A = speeds[speed];
+                        TCNT1 = 0;
+                        sei();
+                        keypad[3] = 255;
+                        lcd_set_font(FONT_PROP_16, SPACING);
+                        lcd_set_area_xy(280, 320, 48, 64);
+                        LCD_MOVE_TO(48, 280);
+                        lcd_putstr_P(PSTR("Sp "));
+                        lcd_put_short(speed);
+                    }
+                    if (keypad[14] && keypad[14] != 255) { // C
+                        if (motor_active) {
+                            cli();
+                            M1_STEPS = 0;
+                            if (negativeinput)
+                                inputbuffer *= -1;
+                            if (M1_position < inputbuffer) {
+                                DIRECTION_FORWARD_M1();
+                                M1_DIR = 1;
+                                M1_STEPS = inputbuffer - M1_position;
+                            } else {
+                                DIRECTION_BACKWARD_M1();
+                                M1_DIR = 0;
+                                M1_STEPS = M1_position - inputbuffer;
+                            }
+                            inputbuffer = 0;
+                            negativeinput = 0;
+                            sei();
+                        }
+                        keypad[14] = 255;
+                    }
+                    if (keypad[15] && keypad[15] != 255) { // D
+                        if (motor_active) {
+                            cli();
+                            M2_STEPS = 0;
+                            if (negativeinput)
+                                inputbuffer *= -1;
+                            if (M2_position < inputbuffer) {
+                                DIRECTION_FORWARD_M2();
+                                M2_DIR = 1;
+                                M2_STEPS = inputbuffer - M2_position;
+                            } else {
+                                DIRECTION_BACKWARD_M2();
+                                M2_DIR = 0;
+                                M2_STEPS = M2_position - inputbuffer;
+                            }
+                            inputbuffer = 0;
+                            negativeinput = 0;
+                            sei();
+                        }
+                        keypad[15] = 255;
+                    }
+                    if (inputbuffer > 1000000)
+                        inputbuffer = 0;
+                    if (inputbuffer != last_inputbuffer) {
+                        lcd_set_font(FONT_PROP_16, SPACING);
+                        lcd_set_area_xy(240, 320, 224, 240);
+                        LCD_MOVE_TO(224, 240);
+                        if (negativeinput)
+                            lcd_put_long(-inputbuffer);
+                        else
+                            lcd_put_long(inputbuffer);
+                    }
+                    last_inputbuffer = inputbuffer;
+                }
             }
-            keypad[15] = 255;  
-          }           
-          if (inputbuffer > 1000000) inputbuffer = 0;
-          if(inputbuffer != last_inputbuffer) {
-            lcd_set_font(FONT_PROP_16,SPACING);
-            lcd_set_area_xy(240,320,224,240);
-            LCD_MOVE_TO(224,240);
-            if (negativeinput)  lcd_put_long(-inputbuffer); 
-            else                lcd_put_long(inputbuffer);
-            
+
+            // output position
+            if ((time & 0xf) == 0) {
+                lcd_set_font(FONT_DIGITS_32, SPACING);
+                // lcd_use_background(topback);
+
+                LCD_MOVE_TO(64, 16);
+                // lcd_set_area_xy(16,180,64,96);
+                lcd_put_long_align32_7(M1_position);
+
+                LCD_MOVE_TO(104, 16);
+                // lcd_set_area_xy(16,180,104,136);
+                lcd_put_long_align32_7(M2_position);
+
+                lcd_set_font(FONT_PROP_16, SPACING);
+                LCD_MOVE_TO(24, 0);
+
+                // i2cTx[0]=1; //switch to voltage register
+                // twi_writeTo(0x47, i2cTx, 1, 1, 1);
+                // twi_readFrom(0x47, i2cRx, 2, 1);
+                // lcd_put_int((i2cRx[0]<<8)+i2cRx[1]);
+                // lcd_putc(' ');
+                //
+                // i2cTx[0]=2; //switch to bus voltage register
+                // twi_writeTo(0x47, i2cTx, 1, 1, 1);
+                // twi_readFrom(0x47, i2cRx, 2, 1);
+                // lcd_put_int((((i2cRx[0]<<8)+i2cRx[1])>>3)*4);
+                // lcd_putc(' ');
+                //
+                // i2cTx[0]=3; //switch to power register
+                // twi_writeTo(0x47, i2cTx, 1, 1, 1);
+                // twi_readFrom(0x47, i2cRx, 2, 1);
+                // lcd_put_int(((i2cRx[0]<<8)+i2cRx[1])/8*20);
+                // lcd_putc(' ');
+                //
+                // i2cTx[0]=4; //switch to current register
+                // twi_writeTo(0x47, i2cTx, 1, 1, 1);
+                // twi_readFrom(0x47, i2cRx, 2, 1);
+                // lcd_put_int(((i2cRx[0]<<8)+i2cRx[1])/8);
             }
-          last_inputbuffer = inputbuffer;
         }
-      }  
-        
-      //output position
-      if( (time & 0xf) == 0) {
-        lcd_set_font(FONT_DIGITS_32,SPACING);  
-        // lcd_use_background(topback);
-
-        LCD_MOVE_TO(64,16);
-        // lcd_set_area_xy(16,180,64,96);
-        lcd_put_long_align32_7(M1_position);
-
-        LCD_MOVE_TO(104,16);
-        // lcd_set_area_xy(16,180,104,136);       
-        lcd_put_long_align32_7(M2_position);
-
-      }
-    }
-
 
-    lasttime = time;
-  }
+        lasttime = time;
+    }
 }
+// 1 shunt voltage
+// 2 bus voltage
+// 3 power
+// 4 current
+// 5 calib 29789 -> 1/8mA
diff --git a/atmega32u4/stepmotorcontroller/twi.c b/atmega32u4/stepmotorcontroller/twi.c
new file mode 100644 (file)
index 0000000..6bc2c66
--- /dev/null
@@ -0,0 +1,571 @@
+/*\r
+  twi.c - TWI/I2C library for Atmega32U4\r
+\r
+  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.\r
+\r
+  This library is free software; you can redistribute it and/or\r
+  modify it under the terms of the GNU Lesser General Public\r
+  License as published by the Free Software Foundation; either\r
+  version 2.1 of the License, or (at your option) any later version.\r
+\r
+  This library is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+  Lesser General Public License for more details.\r
+\r
+  You should have received a copy of the GNU Lesser General Public\r
+  License along with this library; if not, write to the Free Software\r
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
+\r
+  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts\r
+\r
+  Modified 2017 by Adrian Weber to use I2C without Arduino librarys\r
+*/\r
+\r
+#include <math.h>\r
+#include <stdlib.h>\r
+#include <inttypes.h>\r
+#include <avr/io.h>\r
+#include <avr/interrupt.h>\r
+#include <compat/twi.h>\r
+#include <stdbool.h>\r
+\r
+#ifndef cbi\r
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))\r
+#endif\r
+\r
+#ifndef sbi\r
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))\r
+#endif\r
+#include "twi.h"\r
+\r
+static volatile uint8_t twi_state;\r
+static volatile uint8_t twi_slarw;\r
+static volatile uint8_t twi_sendStop;                  // should the transaction end with a stop\r
+static volatile uint8_t twi_inRepStart;                        // in the middle of a repeated start\r
+\r
+static void (*twi_onSlaveTransmit)(void);\r
+static void (*twi_onSlaveReceive)(uint8_t*, int);\r
+\r
+static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];\r
+static volatile uint8_t twi_masterBufferIndex;\r
+static volatile uint8_t twi_masterBufferLength;\r
+\r
+static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];\r
+static volatile uint8_t twi_txBufferIndex;\r
+static volatile uint8_t twi_txBufferLength;\r
+\r
+static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];\r
+static volatile uint8_t twi_rxBufferIndex;\r
+\r
+static volatile uint8_t twi_error;\r
+\r
+\r
+/* \r
+ * Function twi_init\r
+ * Desc     readys twi pins and sets twi bitrate\r
+ * Input    none\r
+ * Output   none\r
+ */\r
+void twi_init(void)\r
+{\r
+  // initialize state\r
+  twi_state = TWI_READY;\r
+  twi_sendStop = true;         // default value\r
+  twi_inRepStart = false;\r
+  \r
+  // activate internal pullups for twi.\r
+  // DDRD |= (1 << PC4);\r
+  // DDRD |= (1 << PC5);\r
+  // PORTD |= (1 << PC4);\r
+  // PORTD |= (1 << PC5);\r
+\r
+  // initialize twi prescaler and bit rate\r
+  cbi(TWSR, TWPS0);\r
+  cbi(TWSR, TWPS1);\r
+  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;\r
+\r
+  sei();\r
+\r
+  /* twi bit rate formula from atmega128 manual pg 204\r
+  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))\r
+  note: TWBR should be 10 or higher for master mode\r
+  It is 72 for a 16mhz Wiring board with 100kHz TWI */\r
+\r
+  // enable twi module, acks, and twi interrupt\r
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);\r
+}\r
+\r
+/* \r
+ * Function twi_disable\r
+ * Desc     disables twi pins\r
+ * Input    none\r
+ * Output   none\r
+ */\r
+void twi_disable(void)\r
+{\r
+  // disable twi module, acks, and twi interrupt\r
+  TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));\r
+\r
+  // deactivate internal pullups for twi.\r
+  // DDRD |= (1 << PC4);\r
+  // DDRD |= (1 << PC5);\r
+  // PORTD |= (1 << PC4);\r
+  // PORTD |= (1 << PC5);\r
+\r
+}\r
+\r
+/* \r
+ * Function twi_slaveInit\r
+ * Desc     sets slave address and enables interrupt\r
+ * Input    none\r
+ * Output   none\r
+ */\r
+void twi_setAddress(uint8_t address)\r
+{\r
+  // set twi slave address (skip over TWGCE bit)\r
+  TWAR = address << 1;\r
+}\r
+\r
+/* \r
+ * Function twi_setClock\r
+ * Desc     sets twi bit rate\r
+ * Input    Clock Frequency\r
+ * Output   none\r
+ */\r
+void twi_setFrequency(uint32_t frequency)\r
+{\r
+  TWBR = ((F_CPU / frequency) - 16) / 2;\r
+  \r
+  /* twi bit rate formula from atmega128 manual pg 204\r
+  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))\r
+  note: TWBR should be 10 or higher for master mode\r
+  It is 72 for a 16mhz Wiring board with 100kHz TWI */\r
+}\r
+\r
+/* \r
+ * Function twi_readFrom\r
+ * Desc     attempts to become twi bus master and read a\r
+ *          series of bytes from a device on the bus\r
+ * Input    address: 7bit i2c device address\r
+ *          data: pointer to byte array\r
+ *          length: number of bytes to read into array\r
+ *          sendStop: Boolean indicating whether to send a stop at the end\r
+ * Output   number of bytes read\r
+ */\r
+uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)\r
+{\r
+  uint8_t i;\r
+\r
+  // ensure data will fit into buffer\r
+  if(TWI_BUFFER_LENGTH < length){\r
+    return 0;\r
+  }\r
+  // wait until twi is ready, become master receiver\r
+  while(TWI_READY != twi_state){\r
+    continue;\r
+  } \r
+  twi_state = TWI_MRX;\r
+  twi_sendStop = sendStop;\r
+  // reset error state (0xFF.. no error occured)\r
+  twi_error = 0xFF;\r
+\r
+  // initialize buffer iteration vars\r
+  twi_masterBufferIndex = 0;\r
+  twi_masterBufferLength = length-1;  // This is not intuitive, read on...\r
+  // On receive, the previously configured ACK/NACK setting is transmitted in\r
+  // response to the received byte before the interrupt is signalled. \r
+  // Therefor we must actually set NACK when the _next_ to last byte is\r
+  // received, causing that NACK to be sent in response to receiving the last\r
+  // expected byte of data.\r
+\r
+  // build sla+w, slave device address + w bit\r
+  twi_slarw = TW_READ;\r
+  twi_slarw |= address << 1;\r
+\r
+  if (true == twi_inRepStart) {\r
+    // if we're in the repeated start state, then we've already sent the start,\r
+    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.\r
+    // We need to remove ourselves from the repeated start state before we enable interrupts,\r
+    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning\r
+    // up. Also, don't enable the START interrupt. There may be one pending from the \r
+    // repeated start that we sent ourselves, and that would really confuse things.\r
+    twi_inRepStart = false;                    // remember, we're dealing with an ASYNC ISR\r
+    do {\r
+      TWDR = twi_slarw;\r
+    } while(TWCR & _BV(TWWC));\r
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);     // enable INTs, but not START\r
+  }\r
+  else\r
+    // send start condition\r
+    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);\r
+\r
+  // wait for read operation to complete\r
+  while(TWI_MRX == twi_state){\r
+    continue;\r
+  }\r
+\r
+  if (twi_masterBufferIndex < length)\r
+    length = twi_masterBufferIndex;\r
+\r
+  // copy twi buffer to data\r
+  for(i = 0; i < length; ++i){\r
+    data[i] = twi_masterBuffer[i];\r
+  }\r
+       \r
+  return length;\r
+}\r
+\r
+/* \r
+ * Function twi_writeTo\r
+ * Desc     attempts to become twi bus master and write a\r
+ *          series of bytes to a device on the bus\r
+ * Input    address: 7bit i2c device address\r
+ *          data: pointer to byte array\r
+ *          length: number of bytes in array\r
+ *          wait: boolean indicating to wait for write or not\r
+ *          sendStop: boolean indicating whether or not to send a stop at the end\r
+ * Output   0 .. success\r
+ *          1 .. length to long for buffer\r
+ *          2 .. address send, NACK received\r
+ *          3 .. data send, NACK received\r
+ *          4 .. other twi error (lost bus arbitration, bus error, ..)\r
+ */\r
+uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)\r
+{\r
+  uint8_t i;\r
+\r
+  // ensure data will fit into buffer\r
+  if(TWI_BUFFER_LENGTH < length){\r
+    return 1;\r
+  }\r
+\r
+  // wait until twi is ready, become master transmitter\r
+  while(TWI_READY != twi_state){\r
+    continue;\r
+  }\r
+  twi_state = TWI_MTX;\r
+  twi_sendStop = sendStop;\r
+  // reset error state (0xFF.. no error occured)\r
+  twi_error = 0xFF;\r
+\r
+  // initialize buffer iteration vars\r
+  twi_masterBufferIndex = 0;\r
+  twi_masterBufferLength = length;\r
+  \r
+  // copy data to twi buffer\r
+  for(i = 0; i < length; ++i){\r
+    twi_masterBuffer[i] = data[i];\r
+  }\r
+  \r
+  // build sla+w, slave device address + w bit\r
+  twi_slarw = TW_WRITE;\r
+  twi_slarw |= address << 1;\r
+  \r
+\r
+  // if we're in a repeated start, then we've already sent the START\r
+  // in the ISR. Don't do it again.\r
+  //\r
+  if (true == twi_inRepStart) {\r
+    // if we're in the repeated start state, then we've already sent the start,\r
+    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.\r
+    // We need to remove ourselves from the repeated start state before we enable interrupts,\r
+    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning\r
+    // up. Also, don't enable the START interrupt. There may be one pending from the \r
+    // repeated start that we sent outselves, and that would really confuse things.\r
+    twi_inRepStart = false;                    // remember, we're dealing with an ASYNC ISR\r
+    do {\r
+      TWDR = twi_slarw;                                \r
+    } while(TWCR & _BV(TWWC));\r
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);     // enable INTs, but not START\r
+  }\r
+  else\r
+    // send start condition\r
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);        // enable INTs\r
+\r
+\r
+  // wait for write operation to complete\r
+  while(wait && (TWI_MTX == twi_state)){\r
+    continue;\r
+  }\r
+\r
+  if (twi_error == 0xFF)\r
+    return 0;  // success\r
+  else if (twi_error == TW_MT_SLA_NACK)\r
+    return 2;  // error: address send, nack received\r
+  else if (twi_error == TW_MT_DATA_NACK)\r
+    return 3;  // error: data send, nack received\r
+  else\r
+    return 4;  // other twi error\r
+}\r
+\r
+/* \r
+ * Function twi_transmit\r
+ * Desc     fills slave tx buffer with data\r
+ *          must be called in slave tx event callback\r
+ * Input    data: pointer to byte array\r
+ *          length: number of bytes in array\r
+ * Output   1 length too long for buffer\r
+ *          2 not slave transmitter\r
+ *          0 ok\r
+ */\r
+uint8_t twi_transmit(const uint8_t* data, uint8_t length)\r
+{\r
+  uint8_t i;\r
+\r
+  // ensure data will fit into buffer\r
+  if(TWI_BUFFER_LENGTH < length){\r
+    return 1;\r
+  }\r
+  \r
+  // ensure we are currently a slave transmitter\r
+  if(TWI_STX != twi_state){\r
+    return 2;\r
+  }\r
+  \r
+  // set length and copy data into tx buffer\r
+  twi_txBufferLength = length;\r
+  for(i = 0; i < length; ++i){\r
+    twi_txBuffer[i] = data[i];\r
+  }\r
+  \r
+  return 0;\r
+}\r
+\r
+/* \r
+ * Function twi_attachSlaveRxEvent\r
+ * Desc     sets function called before a slave read operation\r
+ * Input    function: callback function to use\r
+ * Output   none\r
+ */\r
+void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )\r
+{\r
+  twi_onSlaveReceive = function;\r
+}\r
+\r
+/* \r
+ * Function twi_attachSlaveTxEvent\r
+ * Desc     sets function called before a slave write operation\r
+ * Input    function: callback function to use\r
+ * Output   none\r
+ */\r
+void twi_attachSlaveTxEvent( void (*function)(void) )\r
+{\r
+  twi_onSlaveTransmit = function;\r
+}\r
+\r
+/* \r
+ * Function twi_reply\r
+ * Desc     sends byte or readys receive line\r
+ * Input    ack: byte indicating to ack or to nack\r
+ * Output   none\r
+ */\r
+void twi_reply(uint8_t ack)\r
+{\r
+  // transmit master read ready signal, with or without ack\r
+  if(ack){\r
+    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);\r
+  }else{\r
+         TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);\r
+  }\r
+}\r
+\r
+/* \r
+ * Function twi_stop\r
+ * Desc     relinquishes bus master status\r
+ * Input    none\r
+ * Output   none\r
+ */\r
+void twi_stop(void)\r
+{\r
+  // send stop condition\r
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);\r
+\r
+  // wait for stop condition to be exectued on bus\r
+  // TWINT is not set after a stop condition!\r
+  while(TWCR & _BV(TWSTO)){\r
+    continue;\r
+  }\r
+\r
+  // update twi state\r
+  twi_state = TWI_READY;\r
+}\r
+\r
+/* \r
+ * Function twi_releaseBus\r
+ * Desc     releases bus control\r
+ * Input    none\r
+ * Output   none\r
+ */\r
+void twi_releaseBus(void)\r
+{\r
+  // release bus\r
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);\r
+\r
+  // update twi state\r
+  twi_state = TWI_READY;\r
+}\r
+\r
+ISR(TWI_vect)\r
+{\r
+  switch(TW_STATUS){\r
+    // All Master\r
+    case TW_START:     // sent start condition\r
+    case TW_REP_START: // sent repeated start condition\r
+      // copy device address and r/w bit to output register and ack\r
+      TWDR = twi_slarw;\r
+      twi_reply(1);\r
+      break;\r
+\r
+    // Master Transmitter\r
+    case TW_MT_SLA_ACK:  // slave receiver acked address\r
+    case TW_MT_DATA_ACK: // slave receiver acked data\r
+      // if there is data to send, send it, otherwise stop \r
+      if(twi_masterBufferIndex < twi_masterBufferLength){\r
+        // copy data to output register and ack\r
+        TWDR = twi_masterBuffer[twi_masterBufferIndex++];\r
+        twi_reply(1);\r
+      }else{\r
+       if (twi_sendStop)\r
+          twi_stop();\r
+       else {\r
+         twi_inRepStart = true;        // we're gonna send the START\r
+         // don't enable the interrupt. We'll generate the start, but we \r
+         // avoid handling the interrupt until we're in the next transaction,\r
+         // at the point where we would normally issue the start.\r
+         TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;\r
+         twi_state = TWI_READY;\r
+       }\r
+      }\r
+      break;\r
+    case TW_MT_SLA_NACK:  // address sent, nack received\r
+      twi_error = TW_MT_SLA_NACK;\r
+      twi_stop();\r
+      break;\r
+    case TW_MT_DATA_NACK: // data sent, nack received\r
+      twi_error = TW_MT_DATA_NACK;\r
+      twi_stop();\r
+      break;\r
+    case TW_MT_ARB_LOST: // lost bus arbitration\r
+      twi_error = TW_MT_ARB_LOST;\r
+      twi_releaseBus();\r
+      break;\r
+\r
+    // Master Receiver\r
+    case TW_MR_DATA_ACK: // data received, ack sent\r
+      // put byte into buffer\r
+      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;\r
+    case TW_MR_SLA_ACK:  // address sent, ack received\r
+      // ack if more bytes are expected, otherwise nack\r
+      if(twi_masterBufferIndex < twi_masterBufferLength){\r
+        twi_reply(1);\r
+      }else{\r
+        twi_reply(0);\r
+      }\r
+      break;\r
+    case TW_MR_DATA_NACK: // data received, nack sent\r
+      // put final byte into buffer\r
+      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;\r
+       if (twi_sendStop)\r
+          twi_stop();\r
+       else {\r
+         twi_inRepStart = true;        // we're gonna send the START\r
+         // don't enable the interrupt. We'll generate the start, but we \r
+         // avoid handling the interrupt until we're in the next transaction,\r
+         // at the point where we would normally issue the start.\r
+         TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;\r
+         twi_state = TWI_READY;\r
+       }    \r
+       break;\r
+    case TW_MR_SLA_NACK: // address sent, nack received\r
+      twi_stop();\r
+      break;\r
+    // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case\r
+\r
+    // Slave Receiver\r
+    case TW_SR_SLA_ACK:   // addressed, returned ack\r
+    case TW_SR_GCALL_ACK: // addressed generally, returned ack\r
+    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack\r
+    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack\r
+      // enter slave receiver mode\r
+      twi_state = TWI_SRX;\r
+      // indicate that rx buffer can be overwritten and ack\r
+      twi_rxBufferIndex = 0;\r
+      twi_reply(1);\r
+      break;\r
+    case TW_SR_DATA_ACK:       // data received, returned ack\r
+    case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack\r
+      // if there is still room in the rx buffer\r
+      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){\r
+        // put byte in buffer and ack\r
+        twi_rxBuffer[twi_rxBufferIndex++] = TWDR;\r
+        twi_reply(1);\r
+      }else{\r
+        // otherwise nack\r
+        twi_reply(0);\r
+      }\r
+      break;\r
+    case TW_SR_STOP: // stop or repeated start condition received\r
+      // ack future responses and leave slave receiver state\r
+      twi_releaseBus();\r
+      // put a null char after data if there's room\r
+      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){\r
+        twi_rxBuffer[twi_rxBufferIndex] = '\0';\r
+      }\r
+      // callback to user defined callback\r
+      twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);\r
+      // since we submit rx buffer to "wire" library, we can reset it\r
+      twi_rxBufferIndex = 0;\r
+      break;\r
+    case TW_SR_DATA_NACK:       // data received, returned nack\r
+    case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack\r
+      // nack back at master\r
+      twi_reply(0);\r
+      break;\r
+    \r
+    // Slave Transmitter\r
+    case TW_ST_SLA_ACK:          // addressed, returned ack\r
+    case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack\r
+      // enter slave transmitter mode\r
+      twi_state = TWI_STX;\r
+      // ready the tx buffer index for iteration\r
+      twi_txBufferIndex = 0;\r
+      // set tx buffer length to be zero, to verify if user changes it\r
+      twi_txBufferLength = 0;\r
+      // request for txBuffer to be filled and length to be set\r
+      // note: user must call twi_transmit(bytes, length) to do this\r
+      twi_onSlaveTransmit();\r
+      // if they didn't change buffer & length, initialize it\r
+      if(0 == twi_txBufferLength){\r
+        twi_txBufferLength = 1;\r
+        twi_txBuffer[0] = 0x00;\r
+      }\r
+      // transmit first byte from buffer, fall\r
+    case TW_ST_DATA_ACK: // byte sent, ack returned\r
+      // copy data to output register\r
+      TWDR = twi_txBuffer[twi_txBufferIndex++];\r
+      // if there is more to send, ack, otherwise nack\r
+      if(twi_txBufferIndex < twi_txBufferLength){\r
+        twi_reply(1);\r
+      }else{\r
+        twi_reply(0);\r
+      }\r
+      break;\r
+    case TW_ST_DATA_NACK: // received nack, we are done \r
+    case TW_ST_LAST_DATA: // received ack, but we are done already!\r
+      // ack future responses\r
+      twi_reply(1);\r
+      // leave slave receiver state\r
+      twi_state = TWI_READY;\r
+      break;\r
+\r
+    // All\r
+    case TW_NO_INFO:   // no state information\r
+      break;\r
+    case TW_BUS_ERROR: // bus error, illegal stop/start\r
+      twi_error = TW_BUS_ERROR;\r
+      twi_stop();\r
+      break;\r
+  }\r
+}\r
+\r
diff --git a/atmega32u4/stepmotorcontroller/twi.h b/atmega32u4/stepmotorcontroller/twi.h
new file mode 100644 (file)
index 0000000..2380ecb
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  twi.h - TWI/I2C library for Wiring & Arduino
+  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef twi_h
+#define twi_h
+  #include <inttypes.h>
+
+  #ifndef TWI_FREQ
+  #define TWI_FREQ 400000L
+  #endif
+
+  #ifndef TWI_BUFFER_LENGTH
+  #define TWI_BUFFER_LENGTH 32
+  #endif
+
+  #define TWI_READY 0
+  #define TWI_MRX   1
+  #define TWI_MTX   2
+  #define TWI_SRX   3
+  #define TWI_STX   4
+  
+  void twi_init(void);
+  void twi_disable(void);
+  void twi_setAddress(uint8_t);
+  void twi_setFrequency(uint32_t);
+  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
+  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
+  uint8_t twi_transmit(const uint8_t*, uint8_t);
+  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
+  void twi_attachSlaveTxEvent( void (*)(void) );
+  void twi_reply(uint8_t);
+  void twi_stop(void);
+  void twi_releaseBus(void);
+
+#endif
+