From: Jan Michel Date: Fri, 16 Oct 2026 10:03:58 +0000 (+0200) Subject: add I2C to stepmotor X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=bc2119d9d13ff3745225d956d5e1196ef42ef53a;p=avr.git add I2C to stepmotor --- diff --git a/atmega32u4/stepmotorcontroller/Makefile b/atmega32u4/stepmotorcontroller/Makefile index 88b8034..b2ba0f7 100644 --- a/atmega32u4/stepmotorcontroller/Makefile +++ b/atmega32u4/stepmotorcontroller/Makefile @@ -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 diff --git a/atmega32u4/stepmotorcontroller/main.c b/atmega32u4/stepmotorcontroller/main.c index 1327f0b..5aff4af 100644 --- a/atmega32u4/stepmotorcontroller/main.c +++ b/atmega32u4/stepmotorcontroller/main.c @@ -1,71 +1,74 @@ // #include +#include "lcdlib/font.h" +#include "lcdlib/lcd-color-graphic.h" +#include "twi.h" #include #include #include #include #include -#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<> (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<= 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 index 0000000..6bc2c66 --- /dev/null +++ b/atmega32u4/stepmotorcontroller/twi.c @@ -0,0 +1,571 @@ +/* + twi.c - TWI/I2C library for Atmega32U4 + + 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 + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts + + Modified 2017 by Adrian Weber to use I2C without Arduino librarys +*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif + +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif +#include "twi.h" + +static volatile uint8_t twi_state; +static volatile uint8_t twi_slarw; +static volatile uint8_t twi_sendStop; // should the transaction end with a stop +static volatile uint8_t twi_inRepStart; // in the middle of a repeated start + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + +static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_masterBufferIndex; +static volatile uint8_t twi_masterBufferLength; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + +static volatile uint8_t twi_error; + + +/* + * Function twi_init + * Desc readys twi pins and sets twi bitrate + * Input none + * Output none + */ +void twi_init(void) +{ + // initialize state + twi_state = TWI_READY; + twi_sendStop = true; // default value + twi_inRepStart = false; + + // activate internal pullups for twi. + // DDRD |= (1 << PC4); + // DDRD |= (1 << PC5); + // PORTD |= (1 << PC4); + // PORTD |= (1 << PC5); + + // initialize twi prescaler and bit rate + cbi(TWSR, TWPS0); + cbi(TWSR, TWPS1); + TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; + + sei(); + + /* twi bit rate formula from atmega128 manual pg 204 + SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) + note: TWBR should be 10 or higher for master mode + It is 72 for a 16mhz Wiring board with 100kHz TWI */ + + // enable twi module, acks, and twi interrupt + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); +} + +/* + * Function twi_disable + * Desc disables twi pins + * Input none + * Output none + */ +void twi_disable(void) +{ + // disable twi module, acks, and twi interrupt + TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA)); + + // deactivate internal pullups for twi. + // DDRD |= (1 << PC4); + // DDRD |= (1 << PC5); + // PORTD |= (1 << PC4); + // PORTD |= (1 << PC5); + +} + +/* + * Function twi_slaveInit + * Desc sets slave address and enables interrupt + * Input none + * Output none + */ +void twi_setAddress(uint8_t address) +{ + // set twi slave address (skip over TWGCE bit) + TWAR = address << 1; +} + +/* + * Function twi_setClock + * Desc sets twi bit rate + * Input Clock Frequency + * Output none + */ +void twi_setFrequency(uint32_t frequency) +{ + TWBR = ((F_CPU / frequency) - 16) / 2; + + /* twi bit rate formula from atmega128 manual pg 204 + SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) + note: TWBR should be 10 or higher for master mode + It is 72 for a 16mhz Wiring board with 100kHz TWI */ +} + +/* + * Function twi_readFrom + * Desc attempts to become twi bus master and read a + * series of bytes from a device on the bus + * Input address: 7bit i2c device address + * data: pointer to byte array + * length: number of bytes to read into array + * sendStop: Boolean indicating whether to send a stop at the end + * Output number of bytes read + */ +uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 0; + } + // wait until twi is ready, become master receiver + while(TWI_READY != twi_state){ + continue; + } + twi_state = TWI_MRX; + twi_sendStop = sendStop; + // reset error state (0xFF.. no error occured) + twi_error = 0xFF; + + // initialize buffer iteration vars + twi_masterBufferIndex = 0; + twi_masterBufferLength = length-1; // This is not intuitive, read on... + // On receive, the previously configured ACK/NACK setting is transmitted in + // response to the received byte before the interrupt is signalled. + // Therefor we must actually set NACK when the _next_ to last byte is + // received, causing that NACK to be sent in response to receiving the last + // expected byte of data. + + // build sla+w, slave device address + w bit + twi_slarw = TW_READ; + twi_slarw |= address << 1; + + if (true == twi_inRepStart) { + // if we're in the repeated start state, then we've already sent the start, + // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. + // We need to remove ourselves from the repeated start state before we enable interrupts, + // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning + // up. Also, don't enable the START interrupt. There may be one pending from the + // repeated start that we sent ourselves, and that would really confuse things. + twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR + do { + TWDR = twi_slarw; + } while(TWCR & _BV(TWWC)); + TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START + } + else + // send start condition + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); + + // wait for read operation to complete + while(TWI_MRX == twi_state){ + continue; + } + + if (twi_masterBufferIndex < length) + length = twi_masterBufferIndex; + + // copy twi buffer to data + for(i = 0; i < length; ++i){ + data[i] = twi_masterBuffer[i]; + } + + return length; +} + +/* + * Function twi_writeTo + * Desc attempts to become twi bus master and write a + * series of bytes to a device on the bus + * Input address: 7bit i2c device address + * data: pointer to byte array + * length: number of bytes in array + * wait: boolean indicating to wait for write or not + * sendStop: boolean indicating whether or not to send a stop at the end + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 1; + } + + // wait until twi is ready, become master transmitter + while(TWI_READY != twi_state){ + continue; + } + twi_state = TWI_MTX; + twi_sendStop = sendStop; + // reset error state (0xFF.. no error occured) + twi_error = 0xFF; + + // initialize buffer iteration vars + twi_masterBufferIndex = 0; + twi_masterBufferLength = length; + + // copy data to twi buffer + for(i = 0; i < length; ++i){ + twi_masterBuffer[i] = data[i]; + } + + // build sla+w, slave device address + w bit + twi_slarw = TW_WRITE; + twi_slarw |= address << 1; + + + // if we're in a repeated start, then we've already sent the START + // in the ISR. Don't do it again. + // + if (true == twi_inRepStart) { + // if we're in the repeated start state, then we've already sent the start, + // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. + // We need to remove ourselves from the repeated start state before we enable interrupts, + // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning + // up. Also, don't enable the START interrupt. There may be one pending from the + // repeated start that we sent outselves, and that would really confuse things. + twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR + do { + TWDR = twi_slarw; + } while(TWCR & _BV(TWWC)); + TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START + } + else + // send start condition + TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs + + + // wait for write operation to complete + while(wait && (TWI_MTX == twi_state)){ + continue; + } + + if (twi_error == 0xFF) + return 0; // success + else if (twi_error == TW_MT_SLA_NACK) + return 2; // error: address send, nack received + else if (twi_error == TW_MT_DATA_NACK) + return 3; // error: data send, nack received + else + return 4; // other twi error +} + +/* + * Function twi_transmit + * Desc fills slave tx buffer with data + * must be called in slave tx event callback + * Input data: pointer to byte array + * length: number of bytes in array + * Output 1 length too long for buffer + * 2 not slave transmitter + * 0 ok + */ +uint8_t twi_transmit(const uint8_t* data, uint8_t length) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 1; + } + + // ensure we are currently a slave transmitter + if(TWI_STX != twi_state){ + return 2; + } + + // set length and copy data into tx buffer + twi_txBufferLength = length; + for(i = 0; i < length; ++i){ + twi_txBuffer[i] = data[i]; + } + + return 0; +} + +/* + * Function twi_attachSlaveRxEvent + * Desc sets function called before a slave read operation + * Input function: callback function to use + * Output none + */ +void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) +{ + twi_onSlaveReceive = function; +} + +/* + * Function twi_attachSlaveTxEvent + * Desc sets function called before a slave write operation + * Input function: callback function to use + * Output none + */ +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ + twi_onSlaveTransmit = function; +} + +/* + * Function twi_reply + * Desc sends byte or readys receive line + * Input ack: byte indicating to ack or to nack + * Output none + */ +void twi_reply(uint8_t ack) +{ + // transmit master read ready signal, with or without ack + if(ack){ + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + }else{ + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + } +} + +/* + * Function twi_stop + * Desc relinquishes bus master status + * Input none + * Output none + */ +void twi_stop(void) +{ + // send stop condition + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + + // wait for stop condition to be exectued on bus + // TWINT is not set after a stop condition! + while(TWCR & _BV(TWSTO)){ + continue; + } + + // update twi state + twi_state = TWI_READY; +} + +/* + * Function twi_releaseBus + * Desc releases bus control + * Input none + * Output none + */ +void twi_releaseBus(void) +{ + // release bus + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + + // update twi state + twi_state = TWI_READY; +} + +ISR(TWI_vect) +{ + switch(TW_STATUS){ + // All Master + case TW_START: // sent start condition + case TW_REP_START: // sent repeated start condition + // copy device address and r/w bit to output register and ack + TWDR = twi_slarw; + twi_reply(1); + break; + + // Master Transmitter + case TW_MT_SLA_ACK: // slave receiver acked address + case TW_MT_DATA_ACK: // slave receiver acked data + // if there is data to send, send it, otherwise stop + if(twi_masterBufferIndex < twi_masterBufferLength){ + // copy data to output register and ack + TWDR = twi_masterBuffer[twi_masterBufferIndex++]; + twi_reply(1); + }else{ + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + } + break; + case TW_MT_SLA_NACK: // address sent, nack received + twi_error = TW_MT_SLA_NACK; + twi_stop(); + break; + case TW_MT_DATA_NACK: // data sent, nack received + twi_error = TW_MT_DATA_NACK; + twi_stop(); + break; + case TW_MT_ARB_LOST: // lost bus arbitration + twi_error = TW_MT_ARB_LOST; + twi_releaseBus(); + break; + + // Master Receiver + case TW_MR_DATA_ACK: // data received, ack sent + // put byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + case TW_MR_SLA_ACK: // address sent, ack received + // ack if more bytes are expected, otherwise nack + if(twi_masterBufferIndex < twi_masterBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_MR_DATA_NACK: // data received, nack sent + // put final byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + break; + case TW_MR_SLA_NACK: // address sent, nack received + twi_stop(); + break; + // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case + + // Slave Receiver + case TW_SR_SLA_ACK: // addressed, returned ack + case TW_SR_GCALL_ACK: // addressed generally, returned ack + case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack + case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack + // enter slave receiver mode + twi_state = TWI_SRX; + // indicate that rx buffer can be overwritten and ack + twi_rxBufferIndex = 0; + twi_reply(1); + break; + case TW_SR_DATA_ACK: // data received, returned ack + case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack + // if there is still room in the rx buffer + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + // put byte in buffer and ack + twi_rxBuffer[twi_rxBufferIndex++] = TWDR; + twi_reply(1); + }else{ + // otherwise nack + twi_reply(0); + } + break; + case TW_SR_STOP: // stop or repeated start condition received + // ack future responses and leave slave receiver state + twi_releaseBus(); + // put a null char after data if there's room + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + twi_rxBuffer[twi_rxBufferIndex] = '\0'; + } + // callback to user defined callback + twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + // since we submit rx buffer to "wire" library, we can reset it + twi_rxBufferIndex = 0; + break; + case TW_SR_DATA_NACK: // data received, returned nack + case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack + // nack back at master + twi_reply(0); + break; + + // Slave Transmitter + case TW_ST_SLA_ACK: // addressed, returned ack + case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack + // enter slave transmitter mode + twi_state = TWI_STX; + // ready the tx buffer index for iteration + twi_txBufferIndex = 0; + // set tx buffer length to be zero, to verify if user changes it + twi_txBufferLength = 0; + // request for txBuffer to be filled and length to be set + // note: user must call twi_transmit(bytes, length) to do this + twi_onSlaveTransmit(); + // if they didn't change buffer & length, initialize it + if(0 == twi_txBufferLength){ + twi_txBufferLength = 1; + twi_txBuffer[0] = 0x00; + } + // transmit first byte from buffer, fall + case TW_ST_DATA_ACK: // byte sent, ack returned + // copy data to output register + TWDR = twi_txBuffer[twi_txBufferIndex++]; + // if there is more to send, ack, otherwise nack + if(twi_txBufferIndex < twi_txBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_LAST_DATA: // received ack, but we are done already! + // ack future responses + twi_reply(1); + // leave slave receiver state + twi_state = TWI_READY; + break; + + // All + case TW_NO_INFO: // no state information + break; + case TW_BUS_ERROR: // bus error, illegal stop/start + twi_error = TW_BUS_ERROR; + twi_stop(); + break; + } +} + diff --git a/atmega32u4/stepmotorcontroller/twi.h b/atmega32u4/stepmotorcontroller/twi.h new file mode 100644 index 0000000..2380ecb --- /dev/null +++ b/atmega32u4/stepmotorcontroller/twi.h @@ -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 + + #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 +