// #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;
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
--- /dev/null
+/*\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