From 2673d7fd8b6fbca6f1ac7bf8bb5596cbe5507c66 Mon Sep 17 00:00:00 2001 From: Michael Moon Date: Tue, 8 Dec 2009 14:13:24 +1100 Subject: [PATCH] Added skel and stepper --- skel/Makefile | 76 +++++ skel/arduino.h | 104 +++++++ skel/lcd.c | 595 +++++++++++++++++++++++++++++++++++++ skel/lcd.h | 263 ++++++++++++++++ skel/ringbuffer.c | 89 ++++++ skel/ringbuffer.h | 26 ++ skel/serial.c | 72 +++++ skel/serial.h | 24 ++ skel/yourprogramnamehere.c | 56 ++++ stepper/Makefile | 76 +++++ stepper/arduino.h | 104 +++++++ stepper/lcd.c | 595 +++++++++++++++++++++++++++++++++++++ stepper/lcd.h | 263 ++++++++++++++++ stepper/ringbuffer.c | 89 ++++++ stepper/ringbuffer.h | 26 ++ stepper/serial.c | 72 +++++ stepper/serial.h | 24 ++ stepper/stepper.c | 396 ++++++++++++++++++++++++ stepper/test.c | 43 +++ 19 files changed, 2993 insertions(+) create mode 100644 skel/Makefile create mode 100644 skel/arduino.h create mode 100644 skel/lcd.c create mode 100644 skel/lcd.h create mode 100644 skel/ringbuffer.c create mode 100644 skel/ringbuffer.h create mode 100644 skel/serial.c create mode 100644 skel/serial.h create mode 100644 skel/yourprogramnamehere.c create mode 100644 stepper/Makefile create mode 100644 stepper/arduino.h create mode 100644 stepper/lcd.c create mode 100644 stepper/lcd.h create mode 100644 stepper/ringbuffer.c create mode 100644 stepper/ringbuffer.h create mode 100644 stepper/serial.c create mode 100644 stepper/serial.h create mode 100644 stepper/stepper.c create mode 100755 stepper/test.c diff --git a/skel/Makefile b/skel/Makefile new file mode 100644 index 0000000..244db1d --- /dev/null +++ b/skel/Makefile @@ -0,0 +1,76 @@ +############################################################################## +# # +# AVR-GCC skeleton # +# # +# by Triffid Hunter # +# # +############################################################################## + +############################################################################## +# # +# Change these to suit your application # +# # +############################################################################## + +PROGRAM = yourprogramnamehere + +SOURCES = $(PROGRAM).c ringbuffer.c serial.c lcd.c + +############################################################################## +# # +# Change these to suit your hardware # +# # +############################################################################## + +MCU_TARGET = atmega168 +F_CPU = 16000000L + +############################################################################## +# # +# These defaults should be ok, change if you need to # +# # +############################################################################## + +ARCH = avr- +OPTIMIZE = -Os +CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(F_CPU) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -save-temps +LDFLAGS = -Wl,-u,vfprintf -lprintf_min -Wl,--as-needed -Wl,--gc-sections -finline-functions-called-once + +CC = $(ARCH)gcc +OBJDUMP = $(ARCH)objdump +OBJCOPY = $(ARCH)objcopy +AVRDUDE = avrdude -F + +PROGPORT = /dev/arduino +PROGBAUD = 19200 + +OBJ = $(patsubst %.c,%.o,${SOURCES}) + +.PHONY: all program clean +.PRECIOUS: %.o %.elf + +all: $(PROGRAM).hex $(PROGRAM).lst + +program: $(PROGRAM).hex + stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) + @stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) + $(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C/etc/avrdude.conf -U flash:w:$^ + stty -hup -echo < $(PROGPORT) + +clean: + rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al + +%.o: %.c + $(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $^ + +%.elf: $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +%.lst: %.elf + $(OBJDUMP) -h -S $< > $@ + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.bin: %.elf + $(OBJCOPY) -j .text -j .data -O binary $< $@ diff --git a/skel/arduino.h b/skel/arduino.h new file mode 100644 index 0000000..9623abc --- /dev/null +++ b/skel/arduino.h @@ -0,0 +1,104 @@ +#ifndef _ARDUINO_H +#define _ARDUINO_H + +#define PIN_DIO0 PD0 +#define RPORT_DIO0 PIND +#define WPORT_DIO0 PORTD +#define DDR_DIO0 DDRD + +#define PIN_DIO1 PD1 +#define RPORT_DIO1 PIND +#define WPORT_DIO1 PORTD +#define DDR_DIO1 DDRD + +#define PIN_DIO2 PD2 +#define RPORT_DIO2 PIND +#define WPORT_DIO2 PORTD +#define DDR_DIO2 DDRD + +#define PIN_DIO3 PD3 +#define RPORT_DIO3 PIND +#define WPORT_DIO3 PORTD +#define DDR_DIO3 DDRD + +#define PIN_DIO4 PD4 +#define RPORT_DIO4 PIND +#define WPORT_DIO4 PORTD +#define DDR_DIO4 DDRD + +#define PIN_DIO5 PD5 +#define RPORT_DIO5 PIND +#define WPORT_DIO5 PORTD +#define DDR_DIO5 DDRD + +#define PIN_DIO6 PD6 +#define RPORT_DIO6 PIND +#define WPORT_DIO6 PORTD +#define DDR_DIO6 DDRD + +#define PIN_DIO7 PD7 +#define RPORT_DIO7 PIND +#define WPORT_DIO7 PORTD +#define DDR_DIO7 DDRD + +#define PIN_DIO8 PB0 +#define RPORT_DIO8 PINB +#define WPORT_DIO8 PORTB +#define DDR_DIO8 DDRB + +#define PIN_DIO9 PB1 +#define RPORT_DIO9 PINB +#define WPORT_DIO9 PORTB +#define DDR_DIO9 DDRB + +#define PIN_DIO10 PB2 +#define RPORT_DIO10 PINB +#define WPORT_DIO10 PORTB +#define DDR_DIO10 DDRB + +#define PIN_DIO11 PB3 +#define RPORT_DIO11 PINB +#define WPORT_DIO11 PORTB +#define DDR_DIO11 DDRB + +#define PIN_DIO12 PB4 +#define RPORT_DIO12 PINB +#define WPORT_DIO12 PORTB +#define DDR_DIO12 DDRB + +#define PIN_DIO13 PB5 +#define RPORT_DIO13 PINB +#define WPORT_DIO13 PORTB +#define DDR_DIO13 DDRB + +#define PIN_AIO0 PC0 +#define RPORT_AIO0 PINC +#define WPORT_AIO0 PORTC +#define DDR_AIO0 DDRC + +#define PIN_AIO1 PC1 +#define RPORT_AIO1 PINC +#define WPORT_AIO1 PORTC +#define DDR_AIO1 DDRC + +#define PIN_AIO2 PC2 +#define RPORT_AIO2 PINC +#define WPORT_AIO2 PORTC +#define DDR_AIO2 DDRC + +#define PIN_AIO3 PC3 +#define RPORT_AIO3 PINC +#define WPORT_AIO3 PORTC +#define DDR_AIO3 DDRC + +#define PIN_AIO4 PC4 +#define RPORT_AIO4 PINC +#define WPORT_AIO4 PORTC +#define DDR_AIO4 DDRC + +#define PIN_AIO5 PC5 +#define RPORT_AIO5 PINC +#define WPORT_AIO5 PORTC +#define DDR_AIO5 DDRC + +#endif /* _ARDUINO_H */ \ No newline at end of file diff --git a/skel/lcd.c b/skel/lcd.c new file mode 100644 index 0000000..1505eff --- /dev/null +++ b/skel/lcd.c @@ -0,0 +1,595 @@ +/**************************************************************************** + Title : HD44780U LCD library + Author: Peter Fleury http://jump.to/fleury + File: $Id: lcd.c,v 1.14.2.1 2006/01/29 12:16:41 peter Exp $ + Software: AVR-GCC 3.3 + Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega + + DESCRIPTION + Basic routines for interfacing a HD44780U-based text lcd display + + Originally based on Volker Oth's lcd library, + changed lcd_init(), added additional constants for lcd_command(), + added 4-bit I/O mode, improved and optimized code. + + Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in + 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported. + + Memory mapped mode compatible with Kanda STK200, but supports also + generation of R/W signal through A8 address line. + + USAGE + See the C include lcd.h file for a description of each function + +*****************************************************************************/ +#include +#include +#include +#include "lcd.h" + + + +/* +** constants/macros +*/ +#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */ +#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */ + #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) ) +#else + #define PIN(x) (*(&x - 2)) /* address of input register of port x */ +#endif + + +#if LCD_IO_MODE + #define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" ); + #define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN); + #define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN); + #define lcd_e_toggle() toggle_e() + #define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN) + #define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN) + #define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN) + #define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN) +#endif + +#if LCD_IO_MODE + #if LCD_LINES==1 + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE + #else + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES + #endif +#else + #if LCD_LINES==1 + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE + #else + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES + #endif +#endif + +#if LCD_CONTROLLER_KS0073 + #if LCD_LINES==4 + #define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */ + #define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */ + #define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */ + #endif +#endif + +/* +** function prototypes +*/ +#if LCD_IO_MODE +static void toggle_e(void); +#endif + +/* +** local functions +*/ + + + +/************************************************************************* + delay loop for small accurate delays: 16-bit counter, 4 cycles/loop +*************************************************************************/ +static inline void _delayFourCycles(unsigned int __count) +{ + if ( __count == 0 ) + __asm__ __volatile__( "rjmp 1f\n 1:" ); // 2 cycles + else + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" + "brne 1b" // 4 cycles/loop + : "=w" (__count) + : "0" (__count) + ); +} + + +/************************************************************************* +delay for a minimum of microseconds +the number of loops is calculated at compile-time from MCU clock frequency +*************************************************************************/ +#define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 ) + + +#if LCD_IO_MODE +/* toggle Enable Pin to initiate write */ +static void toggle_e(void) +{ + lcd_e_high(); + lcd_e_delay(); + lcd_e_low(); +} +#endif + + +/************************************************************************* +Low-level function to write byte to LCD controller +Input: data byte to write to LCD + rs 1: write data + 0: write instruction +Returns: none +*************************************************************************/ +#if LCD_IO_MODE +static void lcd_write(uint8_t data,uint8_t rs) +{ + if (rs) { /* write data (RS=1, RW=0) */ + lcd_rs_high(); + } else { /* write instruction (RS=0, RW=0) */ + lcd_rs_low(); + } + lcd_rw_low(); + + if ( + (&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) + && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) + ) + { + /* configure data pins as output */ + DDR(LCD_DATA0_PORT) |= 0x0F; + + /* output high nibble first */ + LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | ((data >> 4) & 0x0F); + lcd_e_toggle(); + + /* output low nibble */ + LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | (data & 0x0F); + lcd_e_toggle(); + + /* all data pins high (inactive) */ + LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | 0x0F; + } + else + { + /* configure data pins as output */ + DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); + DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); + DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); + DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); + + /* output high nibble first */ + LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); + LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); + LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); + LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); + if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); + if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); + if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); + if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); + lcd_e_toggle(); + + /* output low nibble */ + LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); + LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); + LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); + LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); + if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); + if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); + if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); + if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); + lcd_e_toggle(); + + /* all data pins high (inactive) */ + LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); + LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); + LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); + LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); + } +} +#else +#define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d; +/* rs==0 -> write instruction to LCD_IO_FUNCTION */ +/* rs==1 -> write data to LCD_IO_DATA */ +#endif + + +/************************************************************************* +Low-level function to read byte from LCD controller +Input: rs 1: read data + 0: read busy flag / address counter +Returns: byte read from LCD controller +*************************************************************************/ +#if LCD_IO_MODE +static uint8_t lcd_read(uint8_t rs) +{ + uint8_t data; + + if (rs) + lcd_rs_high(); /* RS=1: read data */ + else + lcd_rs_low(); /* RS=0: read busy flag */ + lcd_rw_high(); /* RW=1 read mode */ + + if ( + (&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) + && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) + ) + { + DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */ + + lcd_e_high(); + lcd_e_delay(); + data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */ + lcd_e_low(); + + lcd_e_delay(); /* Enable 500ns low */ + + lcd_e_high(); + lcd_e_delay(); + data |= PIN(LCD_DATA0_PORT) & 0x0F; /* read low nibble */ + lcd_e_low(); + } + else + { + /* configure data pins as input */ + DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN); + DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN); + DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN); + DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN); + + /* read high nibble first */ + lcd_e_high(); + lcd_e_delay(); + data = 0; + if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10; + if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20; + if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40; + if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80; + lcd_e_low(); + + lcd_e_delay(); /* Enable 500ns low */ + + /* read low nibble */ + lcd_e_high(); + lcd_e_delay(); + if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01; + if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02; + if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04; + if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08; + lcd_e_low(); + } + return data; +} +#else +#define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ) +/* rs==0 -> read instruction from LCD_IO_FUNCTION */ +/* rs==1 -> read data from LCD_IO_DATA */ +#endif + + +/************************************************************************* +loops while lcd is busy, returns address counter +*************************************************************************/ +static uint8_t lcd_waitbusy(void) +{ + /* wait until busy flag is cleared */ + for (; lcd_read(0) & (1 << LCD_BUSY); ); + + /* the address counter is updated 4us after the busy flag is cleared */ + delay(2); + + /* now read the address counter */ + return (lcd_read(0)); // return address counter +}/* lcd_waitbusy */ + + +/************************************************************************* +Move cursor to the start of next line or to the first line if the cursor +is already on the last line. +*************************************************************************/ +static inline void lcd_newline(uint8_t pos) +{ + register uint8_t addressCounter; + +#if LCD_LINES==1 + addressCounter = 0; +#endif +#if LCD_LINES==2 + if ( pos < (LCD_START_LINE2) ) + addressCounter = LCD_START_LINE2; + else + addressCounter = LCD_START_LINE1; +#endif +#if LCD_LINES==4 +#if KS0073_4LINES_MODE + if ( pos < LCD_START_LINE2 ) + addressCounter = LCD_START_LINE2; + else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) ) + addressCounter = LCD_START_LINE3; + else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) ) + addressCounter = LCD_START_LINE4; + else + addressCounter = LCD_START_LINE1; +#else + if ( pos < LCD_START_LINE3 ) + addressCounter = LCD_START_LINE2; + else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) ) + addressCounter = LCD_START_LINE3; + else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) ) + addressCounter = LCD_START_LINE4; + else + addressCounter = LCD_START_LINE1; +#endif +#endif + lcd_command((1 << LCD_DDRAM) + addressCounter); + +}/* lcd_newline */ + + +/* +** PUBLIC FUNCTIONS +*/ + +/************************************************************************* +Send LCD controller instruction command +Input: instruction to send to LCD controller, see HD44780 data sheet +Returns: none +*************************************************************************/ +void lcd_command(uint8_t cmd) +{ + lcd_waitbusy(); + lcd_write(cmd,0); +} + + +/************************************************************************* +Send data byte to LCD controller +Input: data to send to LCD controller, see HD44780 data sheet +Returns: none +*************************************************************************/ +void lcd_data(uint8_t data) +{ + lcd_waitbusy(); + lcd_write(data,1); +} + + + +/************************************************************************* +Set cursor to specified position +Input: x horizontal position (0: left most position) + y vertical position (0: first line) +Returns: none +*************************************************************************/ +void lcd_gotoxy(uint8_t x, uint8_t y) +{ +#if LCD_LINES==1 + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); +#endif +#if LCD_LINES==2 + if ( y==0 ) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); + else + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); +#endif +#if LCD_LINES==4 + if ( y==0 ) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); + else if ( y==1) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); + else if ( y==2) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x); + else /* y==3 */ + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x); +#endif + +}/* lcd_gotoxy */ + + +/************************************************************************* +*************************************************************************/ +int lcd_getxy(void) +{ + return lcd_waitbusy(); +} + + +/************************************************************************* +Clear display and set cursor to home position +*************************************************************************/ +void lcd_clrscr(void) +{ + lcd_command(1 << LCD_CLR); +} + + +/************************************************************************* +Set cursor to home position +*************************************************************************/ +void lcd_home(void) +{ + lcd_command(1 << LCD_HOME); +} + + +/************************************************************************* +Display character at current cursor position +Input: character to be displayed +Returns: none +*************************************************************************/ +void lcd_putc(char c) +{ + uint8_t pos; + + pos = lcd_waitbusy(); // read busy-flag and address counter + if (c=='\n') + lcd_newline(pos); + else + { +#if LCD_WRAP_LINES==1 +#if LCD_LINES==1 + if ( pos == LCD_START_LINE1 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1,0); +#elif LCD_LINES==2 + if ( pos == LCD_START_LINE1 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2,0); + else if ( pos == LCD_START_LINE2 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1,0); +#elif LCD_LINES==4 + if ( pos == LCD_START_LINE1 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2,0); + else if ( pos == LCD_START_LINE2 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE3,0); + else if ( pos == LCD_START_LINE3 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE4,0); + else if ( pos == LCD_START_LINE4 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1,0); +#endif + lcd_waitbusy(); +#endif + lcd_write(c, 1); + } + +}/* lcd_putc */ + + +/************************************************************************* +Display string without auto linefeed +Input: string to be displayed +Returns: none +*************************************************************************/ +void lcd_puts(const char *s) +/* print string on lcd (no auto linefeed) */ +{ + register char c; + + while ( (c = *s++) ) { + lcd_putc(c); + } + +}/* lcd_puts */ + + +/************************************************************************* +Display string from program memory without auto linefeed +Input: string from program memory be be displayed +Returns: none +*************************************************************************/ +void lcd_puts_p(const char *progmem_s) +/* print string from program memory on lcd (no auto linefeed) */ +{ + register char c; + + while ( (c = pgm_read_byte(progmem_s++)) ) { + lcd_putc(c); + } + +}/* lcd_puts_p */ + + +/************************************************************************* +Initialize display and select type of cursor +Input: dispAttr LCD_DISP_OFF display off + LCD_DISP_ON display on, cursor off + LCD_DISP_ON_CURSOR display on, cursor on + LCD_DISP_CURSOR_BLINK display on, cursor on flashing +Returns: none +*************************************************************************/ +void lcd_init(uint8_t dispAttr) +{ +#if LCD_IO_MODE + /* + * Initialize LCD to 4 bit I/O mode + */ + + if ( + ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) + && ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT) + ) + { + /* configure all port bits as output (all LCD lines on same port) */ + DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN) | (1 << LCD_RS_PIN) | (1 << LCD_RW_PIN) | (1 << LCD_E_PIN); + } + else if ( + ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) + ) + { + /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */ + DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN); + DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); + DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); + DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); + } + else + { + /* configure all port bits as output (LCD data and control lines on different ports */ + DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); + DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); + DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); + DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); + DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); + DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); + DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); + } + delay(16000); /* wait 16ms or more after power-on */ + + /* initial write to lcd is 8bit */ + LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // _BV(LCD_FUNCTION)>>4; + LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4; + lcd_e_toggle(); + delay(4992); /* delay, busy flag can't be checked here */ + + /* repeat last command */ + lcd_e_toggle(); delay(64); /* delay, busy flag can't be checked here */ + + /* repeat last command a third time */ + lcd_e_toggle(); delay(64); /* delay, busy flag can't be checked here */ + + /* now configure for 4bit mode */ + LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4 + lcd_e_toggle(); + delay(64); /* some displays need this additional delay */ + + /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */ +#else + /* + * Initialize LCD to 8 bit memory mapped mode + */ + + /* enable external SRAM (memory mapped lcd) and one wait state */ + MCUCR = _BV(SRE) | _BV(SRW); + + /* reset LCD */ + delay(16000); /* wait 16ms after power-on */ + lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ + delay(4992); /* wait 5ms */ + lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ + delay(64); /* wait 64us */ + lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ + delay(64); /* wait 64us */ +#endif + +#if KS0073_4LINES_MODE + /* Display with KS0073 controller requires special commands for enabling 4 line mode */ + lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON); + lcd_command(KS0073_4LINES_MODE); + lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF); +#else + lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */ +#endif + + lcd_command(LCD_DISP_OFF); /* display off */ + lcd_clrscr(); /* display clear */ + lcd_command(LCD_MODE_DEFAULT); /* set entry mode */ + lcd_command(dispAttr); /* display/cursor control */ + +}/* lcd_init */ diff --git a/skel/lcd.h b/skel/lcd.h new file mode 100644 index 0000000..bec1cee --- /dev/null +++ b/skel/lcd.h @@ -0,0 +1,263 @@ +#ifndef LCD_H +#define LCD_H +/************************************************************************* + Title : C include file for the HD44780U LCD library (lcd.c) + Author: Peter Fleury http://jump.to/fleury + File: $Id: lcd.h,v 1.13.2.2 2006/01/30 19:51:33 peter Exp $ + Software: AVR-GCC 3.3 + Hardware: any AVR device, memory mapped mode only for AT90S4414/8515/Mega +***************************************************************************/ + +/** + @defgroup pfleury_lcd LCD library + @code #include @endcode + + @brief Basic routines for interfacing a HD44780U-based text LCD display + + Originally based on Volker Oth's LCD library, + changed lcd_init(), added additional constants for lcd_command(), + added 4-bit I/O mode, improved and optimized code. + + Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in + 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported. + + Memory mapped mode compatible with Kanda STK200, but supports also + generation of R/W signal through A8 address line. + + @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + + @see The chapter Interfacing a HD44780 Based LCD to an AVR + on my home page. + +*/ + +/*@{*/ + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 303 +#error "This library requires AVR-GCC 3.3 or later, update to newer AVR-GCC compiler !" +#endif + +#include +#include + +/** + * @name Definitions for MCU Clock Frequency + * Adapt the MCU clock frequency in Hz to your target. + */ +#define XTAL F_CPU /**< clock frequency in Hz, used to calculate delay timer */ + +/** + * @name Definition for LCD controller type + * Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller. + */ +#define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */ + +/** + * @name Definitions for Display Size + * Change these definitions to adapt setting to your display + */ +#define LCD_LINES 2 /**< number of visible lines of the display */ +#define LCD_DISP_LENGTH 16 /**< visibles characters per line of the display */ +#define LCD_LINE_LENGTH 0x40 /**< internal line length of the display */ +#define LCD_START_LINE1 0x00 /**< DDRAM address of first char of line 1 */ +#define LCD_START_LINE2 0x40 /**< DDRAM address of first char of line 2 */ +#define LCD_START_LINE3 0x14 /**< DDRAM address of first char of line 3 */ +#define LCD_START_LINE4 0x54 /**< DDRAM address of first char of line 4 */ +#define LCD_WRAP_LINES 0 /**< 0: no wrap, 1: wrap at end of visibile line */ + +#define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */ + +#if LCD_IO_MODE +/** + * @name Definitions for 4-bit IO mode + * Change LCD_PORT if you want to use a different port for the LCD pins. + * + * The four LCD data lines and the three control lines RS, RW, E can be on the + * same port or on different ports. + * Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on + * different ports. + * + * Normally the four data lines should be mapped to bit 0..3 on one port, but it + * is possible to connect these data lines in different order or even on different + * ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions. + * */ +#define LCD_PORT PORTB /**< port for the LCD lines */ +#define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */ +#define LCD_DATA1_PORT LCD_PORT /**< port for 4bit data bit 1 */ +#define LCD_DATA2_PORT LCD_PORT /**< port for 4bit data bit 2 */ +#define LCD_DATA3_PORT LCD_PORT /**< port for 4bit data bit 3 */ +#define LCD_DATA0_PIN 0 /**< pin for 4bit data bit 0 */ +#define LCD_DATA1_PIN 1 /**< pin for 4bit data bit 1 */ +#define LCD_DATA2_PIN 2 /**< pin for 4bit data bit 2 */ +#define LCD_DATA3_PIN 3 /**< pin for 4bit data bit 3 */ +#define LCD_RS_PORT PORTD /**< port for RS line */ +#define LCD_RS_PIN 2 /**< pin for RS line */ +#define LCD_RW_PORT PORTD /**< port for RW line */ +#define LCD_RW_PIN 3 /**< pin for RW line */ +#define LCD_E_PORT PORTD /**< port for Enable line */ +#define LCD_E_PIN 4 /**< pin for Enable line */ + +#elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || defined(__AVR_ATmega64__) || \ + defined(__AVR_ATmega8515__)|| defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__) || \ + defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__) +/* + * memory mapped mode is only supported when the device has an external data memory interface + */ +#define LCD_IO_DATA 0xC000 /* A15=E=1, A14=RS=1 */ +#define LCD_IO_FUNCTION 0x8000 /* A15=E=1, A14=RS=0 */ +#define LCD_IO_READ 0x0100 /* A8 =R/W=1 (R/W: 1=Read, 0=Write */ +#else +#error "external data memory interface not available for this device, use 4-bit IO port mode" + +#endif + + +/** + * @name Definitions for LCD command instructions + * The constants define the various LCD controller instructions which can be passed to the + * function lcd_command(), see HD44780 data sheet for a complete description. + */ + +/* instruction register bit positions, see HD44780U data sheet */ +#define LCD_CLR 0 /* DB0: clear display */ +#define LCD_HOME 1 /* DB1: return to home position */ +#define LCD_ENTRY_MODE 2 /* DB2: set entry mode */ +#define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */ +#define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */ +#define LCD_ON 3 /* DB3: turn lcd/cursor on */ +#define LCD_ON_DISPLAY 2 /* DB2: turn display on */ +#define LCD_ON_CURSOR 1 /* DB1: turn cursor on */ +#define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */ +#define LCD_MOVE 4 /* DB4: move cursor/display */ +#define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */ +#define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */ +#define LCD_FUNCTION 5 /* DB5: function set */ +#define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */ +#define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */ +#define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */ +#define LCD_CGRAM 6 /* DB6: set CG RAM address */ +#define LCD_DDRAM 7 /* DB7: set DD RAM address */ +#define LCD_BUSY 7 /* DB7: LCD is busy */ + +/* set entry mode: display shift on/off, dec/inc cursor move direction */ +#define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */ +#define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */ +#define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */ +#define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */ + +/* display on/off, cursor on/off, blinking char at cursor position */ +#define LCD_DISP_OFF 0x08 /* display off */ +#define LCD_DISP_ON 0x0C /* display on, cursor off */ +#define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */ +#define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */ +#define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */ + +/* move cursor/shift display */ +#define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */ +#define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */ +#define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */ +#define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */ + +/* function set: set interface data length and number of display lines */ +#define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */ +#define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */ +#define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */ +#define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */ + + +#define LCD_MODE_DEFAULT ((1<= denom; num -= denom); + return num; +} + +void ringbuffer_init(ringbuffer *buf, int bufsize) +{ + buf->read_pointer = 0; + buf->write_pointer = 0; + buf->size = bufsize - sizeof(ringbuffer); +} + +uint16_t ringbuffer_canread(ringbuffer *buf) +{ + return _rb_mod(buf->write_pointer + buf->size + buf->size - buf->read_pointer, buf->size); +} + +uint16_t ringbuffer_canwrite(ringbuffer *buf) +{ + return _rb_mod(buf->read_pointer + buf->size + buf->size - buf->write_pointer - 1, buf->size); +} + +uint8_t ringbuffer_readchar(ringbuffer *buf) +{ + uint8_t r = 0; + if (ringbuffer_canread(buf)) + { + r = buf->data[buf->read_pointer]; + buf->read_pointer = _rb_mod(buf->read_pointer + 1, buf->size); + } + return r; +} + +void ringbuffer_writechar(ringbuffer *buf, uint8_t data) +{ + if (ringbuffer_canwrite(buf)) + { + buf->data[buf->write_pointer] = data; + buf->write_pointer = _rb_mod(buf->write_pointer + 1, buf->size); + } +} + + +uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index) +{ + return buf->data[_rb_mod(buf->read_pointer + index, buf->size)]; +} + +uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size) +{ + uint16_t nc, i; + uint8_t *rp, *ms; + if ((nc = ringbuffer_canread(buf)) < size) + size = nc; + if (size) + { + for (i = 0, rp = buf->data + buf->read_pointer, ms = buf->data + buf->size; i < size; i++, rp++) + { + if (rp >= ms) + rp = buf->data; + newbuf[i] = *rp; + } + buf->read_pointer = rp - buf->data; + } + return size; +} + +uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size) +{ + uint16_t nc, i; + uint8_t *wp, *ms; + + if ((nc = ringbuffer_canwrite(buf)) < size) + size = nc; + if (size) + { + for (i = 0, wp = buf->write_pointer + buf->data, ms = buf->data + buf->size; i < size; i++, wp++) + { + if (wp >= ms) + wp = buf->data; + *wp = data[i]; + } + buf->write_pointer = wp - buf->data; + } + return size; +} diff --git a/skel/ringbuffer.h b/skel/ringbuffer.h new file mode 100644 index 0000000..c6a24f4 --- /dev/null +++ b/skel/ringbuffer.h @@ -0,0 +1,26 @@ +#ifndef _RINGBUFFER_H +#define _RINGBUFFER_H + +#include +#include + +typedef struct { + uint16_t read_pointer; + uint16_t write_pointer; + uint16_t size; + uint8_t data[]; +} ringbuffer; + +void ringbuffer_init(ringbuffer *buf, int bufsize); + +uint16_t ringbuffer_canread(ringbuffer *buf); +uint16_t ringbuffer_canwrite(ringbuffer *buf); + +uint8_t ringbuffer_readchar(ringbuffer *buf); +uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index); +uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size); + +void ringbuffer_writechar(ringbuffer *buf, uint8_t data); +uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size); + +#endif /* _RINGBUFFER_H */ diff --git a/skel/serial.c b/skel/serial.c new file mode 100644 index 0000000..3a691d6 --- /dev/null +++ b/skel/serial.c @@ -0,0 +1,72 @@ +#include "serial.h" + +#include "ringbuffer.h" + +#define BUFSIZE 64 + sizeof(ringbuffer) +#define BAUD 19200 + +volatile uint8_t _rx_buffer[BUFSIZE]; +volatile uint8_t _tx_buffer[BUFSIZE]; + +void serial_init(uint16_t baud) +{ + ringbuffer_init(rx_buffer, BUFSIZE); + ringbuffer_init(tx_buffer, BUFSIZE); + + UCSR0A = 0; + UCSR0B = (1 << RXEN0) | (1 << TXEN0); + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); + + UBRR0 = ((F_CPU / 16) / baud) - 1; + + UCSR0B |= (1 << RXCIE0) | (1 << UDRIE0); +} + +ISR(USART_RX_vect) +{ + ringbuffer_writechar(rx_buffer, UDR0); +} + +ISR(USART_UDRE_vect) +{ + if (ringbuffer_canread(tx_buffer)) + { + UDR0 = ringbuffer_readchar(tx_buffer); + } + else + { + UCSR0B &= ~(1 << UDRIE0); + } +} + +uint16_t serial_rxchars() +{ + return ringbuffer_canread(rx_buffer); +} + +uint16_t serial_txchars() +{ + return ringbuffer_canread(tx_buffer); +} + +uint8_t serial_popchar() +{ + return ringbuffer_readchar(rx_buffer); +} + +uint16_t serial_recvblock(uint8_t *block, int blocksize) +{ + return ringbuffer_readblock(rx_buffer, block, blocksize); +} + +void serial_writechar(uint8_t data) +{ + ringbuffer_writechar(tx_buffer, data); + UCSR0B |= (1 << UDRIE0); +} + +void serial_writeblock(uint8_t *data, int datalen) +{ + ringbuffer_writeblock(tx_buffer, data, datalen); + UCSR0B |= (1 << UDRIE0); +} diff --git a/skel/serial.h b/skel/serial.h new file mode 100644 index 0000000..efda9d6 --- /dev/null +++ b/skel/serial.h @@ -0,0 +1,24 @@ +#ifndef _SERIAL_H +#define _SERIAL_H + +#include +#include + +#define rx_buffer ((ringbuffer *) _rx_buffer) +#define tx_buffer ((ringbuffer *) _tx_buffer) + +extern volatile uint8_t _rx_buffer[]; +extern volatile uint8_t _tx_buffer[]; + +void serial_init(uint16_t baud); + +uint16_t serial_rxchars(void); +uint16_t serial_txchars(void); + +uint8_t serial_popchar(void); +void serial_writechar(uint8_t data); + +uint16_t serial_recvblock(uint8_t *block, int blocksize); +void serial_writeblock(uint8_t *data, int datalen); + +#endif /* _SERIAL_H */ diff --git a/skel/yourprogramnamehere.c b/skel/yourprogramnamehere.c new file mode 100644 index 0000000..c2fec0e --- /dev/null +++ b/skel/yourprogramnamehere.c @@ -0,0 +1,56 @@ +#include +#include +#include + +#include +#include + +#include "serial.h" +#include "lcd.h" + +// write to lcd function for fdev_setup_stream +static int lcd_putc_fdev(char c, FILE *stream) +{ + lcd_putc(c); + return 0; +} + +int serial_putc_fdev(char c, FILE *stream) +{ + serial_writechar((uint8_t) c); + return 0; +} + +int serial_getc_fdev(FILE *stream) +{ + for (;serial_rxchars() == 0;); + return (int) serial_popchar(); +} + +static FILE lcdo = FDEV_SETUP_STREAM(lcd_putc_fdev, NULL, _FDEV_SETUP_WRITE); +static FILE serio = FDEV_SETUP_STREAM(serial_putc_fdev, serial_getc_fdev, _FDEV_SETUP_RW); + +int main (void) +{ + // set up LCD + lcd_init(LCD_DISP_ON_CURSOR); + + lcd_puts_P("Starting..."); + + // set up STDIN/OUT/ERR + stdin = &serio; + stdout = &lcdo; + stderr = &lcdo; + + // set up serial + serial_init(19200); + + sei(); + + lcd_gotoxy(0, 0); + fprintf(&lcdo, "MyProject OK"); + + for (;;) + { + } +} diff --git a/stepper/Makefile b/stepper/Makefile new file mode 100644 index 0000000..51d5d5f --- /dev/null +++ b/stepper/Makefile @@ -0,0 +1,76 @@ +############################################################################## +# # +# AVR-GCC skeleton # +# # +# by Triffid Hunter # +# # +############################################################################## + +############################################################################## +# # +# Change these to suit your application # +# # +############################################################################## + +PROGRAM = stepper + +SOURCES = $(PROGRAM).c ringbuffer.c serial.c lcd.c + +############################################################################## +# # +# Change these to suit your hardware # +# # +############################################################################## + +MCU_TARGET = atmega168 +F_CPU = 16000000L + +############################################################################## +# # +# These defaults should be ok, change if you need to # +# # +############################################################################## + +ARCH = avr- +OPTIMIZE = -Os +CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(F_CPU) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -save-temps +LDFLAGS = -Wl,-u,vfprintf -lprintf_min -Wl,--as-needed -Wl,--gc-sections -finline-functions-called-once + +CC = $(ARCH)gcc +OBJDUMP = $(ARCH)objdump +OBJCOPY = $(ARCH)objcopy +AVRDUDE = avrdude -F + +PROGPORT = /dev/arduino +PROGBAUD = 19200 + +OBJ = $(patsubst %.c,%.o,${SOURCES}) + +.PHONY: all program clean +.PRECIOUS: %.o %.elf + +all: $(PROGRAM).hex $(PROGRAM).lst + +program: $(PROGRAM).hex + stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) + @stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) + $(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C/etc/avrdude.conf -U flash:w:$^ + stty -hup -echo < $(PROGPORT) + +clean: + rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al + +%.o: %.c + $(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $^ + +%.elf: $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +%.lst: %.elf + $(OBJDUMP) -h -S $< > $@ + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.bin: %.elf + $(OBJCOPY) -j .text -j .data -O binary $< $@ diff --git a/stepper/arduino.h b/stepper/arduino.h new file mode 100644 index 0000000..9623abc --- /dev/null +++ b/stepper/arduino.h @@ -0,0 +1,104 @@ +#ifndef _ARDUINO_H +#define _ARDUINO_H + +#define PIN_DIO0 PD0 +#define RPORT_DIO0 PIND +#define WPORT_DIO0 PORTD +#define DDR_DIO0 DDRD + +#define PIN_DIO1 PD1 +#define RPORT_DIO1 PIND +#define WPORT_DIO1 PORTD +#define DDR_DIO1 DDRD + +#define PIN_DIO2 PD2 +#define RPORT_DIO2 PIND +#define WPORT_DIO2 PORTD +#define DDR_DIO2 DDRD + +#define PIN_DIO3 PD3 +#define RPORT_DIO3 PIND +#define WPORT_DIO3 PORTD +#define DDR_DIO3 DDRD + +#define PIN_DIO4 PD4 +#define RPORT_DIO4 PIND +#define WPORT_DIO4 PORTD +#define DDR_DIO4 DDRD + +#define PIN_DIO5 PD5 +#define RPORT_DIO5 PIND +#define WPORT_DIO5 PORTD +#define DDR_DIO5 DDRD + +#define PIN_DIO6 PD6 +#define RPORT_DIO6 PIND +#define WPORT_DIO6 PORTD +#define DDR_DIO6 DDRD + +#define PIN_DIO7 PD7 +#define RPORT_DIO7 PIND +#define WPORT_DIO7 PORTD +#define DDR_DIO7 DDRD + +#define PIN_DIO8 PB0 +#define RPORT_DIO8 PINB +#define WPORT_DIO8 PORTB +#define DDR_DIO8 DDRB + +#define PIN_DIO9 PB1 +#define RPORT_DIO9 PINB +#define WPORT_DIO9 PORTB +#define DDR_DIO9 DDRB + +#define PIN_DIO10 PB2 +#define RPORT_DIO10 PINB +#define WPORT_DIO10 PORTB +#define DDR_DIO10 DDRB + +#define PIN_DIO11 PB3 +#define RPORT_DIO11 PINB +#define WPORT_DIO11 PORTB +#define DDR_DIO11 DDRB + +#define PIN_DIO12 PB4 +#define RPORT_DIO12 PINB +#define WPORT_DIO12 PORTB +#define DDR_DIO12 DDRB + +#define PIN_DIO13 PB5 +#define RPORT_DIO13 PINB +#define WPORT_DIO13 PORTB +#define DDR_DIO13 DDRB + +#define PIN_AIO0 PC0 +#define RPORT_AIO0 PINC +#define WPORT_AIO0 PORTC +#define DDR_AIO0 DDRC + +#define PIN_AIO1 PC1 +#define RPORT_AIO1 PINC +#define WPORT_AIO1 PORTC +#define DDR_AIO1 DDRC + +#define PIN_AIO2 PC2 +#define RPORT_AIO2 PINC +#define WPORT_AIO2 PORTC +#define DDR_AIO2 DDRC + +#define PIN_AIO3 PC3 +#define RPORT_AIO3 PINC +#define WPORT_AIO3 PORTC +#define DDR_AIO3 DDRC + +#define PIN_AIO4 PC4 +#define RPORT_AIO4 PINC +#define WPORT_AIO4 PORTC +#define DDR_AIO4 DDRC + +#define PIN_AIO5 PC5 +#define RPORT_AIO5 PINC +#define WPORT_AIO5 PORTC +#define DDR_AIO5 DDRC + +#endif /* _ARDUINO_H */ \ No newline at end of file diff --git a/stepper/lcd.c b/stepper/lcd.c new file mode 100644 index 0000000..1505eff --- /dev/null +++ b/stepper/lcd.c @@ -0,0 +1,595 @@ +/**************************************************************************** + Title : HD44780U LCD library + Author: Peter Fleury http://jump.to/fleury + File: $Id: lcd.c,v 1.14.2.1 2006/01/29 12:16:41 peter Exp $ + Software: AVR-GCC 3.3 + Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega + + DESCRIPTION + Basic routines for interfacing a HD44780U-based text lcd display + + Originally based on Volker Oth's lcd library, + changed lcd_init(), added additional constants for lcd_command(), + added 4-bit I/O mode, improved and optimized code. + + Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in + 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported. + + Memory mapped mode compatible with Kanda STK200, but supports also + generation of R/W signal through A8 address line. + + USAGE + See the C include lcd.h file for a description of each function + +*****************************************************************************/ +#include +#include +#include +#include "lcd.h" + + + +/* +** constants/macros +*/ +#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */ +#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */ + #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) ) +#else + #define PIN(x) (*(&x - 2)) /* address of input register of port x */ +#endif + + +#if LCD_IO_MODE + #define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" ); + #define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN); + #define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN); + #define lcd_e_toggle() toggle_e() + #define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN) + #define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN) + #define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN) + #define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN) +#endif + +#if LCD_IO_MODE + #if LCD_LINES==1 + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE + #else + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES + #endif +#else + #if LCD_LINES==1 + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE + #else + #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES + #endif +#endif + +#if LCD_CONTROLLER_KS0073 + #if LCD_LINES==4 + #define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */ + #define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */ + #define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */ + #endif +#endif + +/* +** function prototypes +*/ +#if LCD_IO_MODE +static void toggle_e(void); +#endif + +/* +** local functions +*/ + + + +/************************************************************************* + delay loop for small accurate delays: 16-bit counter, 4 cycles/loop +*************************************************************************/ +static inline void _delayFourCycles(unsigned int __count) +{ + if ( __count == 0 ) + __asm__ __volatile__( "rjmp 1f\n 1:" ); // 2 cycles + else + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" + "brne 1b" // 4 cycles/loop + : "=w" (__count) + : "0" (__count) + ); +} + + +/************************************************************************* +delay for a minimum of microseconds +the number of loops is calculated at compile-time from MCU clock frequency +*************************************************************************/ +#define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 ) + + +#if LCD_IO_MODE +/* toggle Enable Pin to initiate write */ +static void toggle_e(void) +{ + lcd_e_high(); + lcd_e_delay(); + lcd_e_low(); +} +#endif + + +/************************************************************************* +Low-level function to write byte to LCD controller +Input: data byte to write to LCD + rs 1: write data + 0: write instruction +Returns: none +*************************************************************************/ +#if LCD_IO_MODE +static void lcd_write(uint8_t data,uint8_t rs) +{ + if (rs) { /* write data (RS=1, RW=0) */ + lcd_rs_high(); + } else { /* write instruction (RS=0, RW=0) */ + lcd_rs_low(); + } + lcd_rw_low(); + + if ( + (&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) + && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) + ) + { + /* configure data pins as output */ + DDR(LCD_DATA0_PORT) |= 0x0F; + + /* output high nibble first */ + LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | ((data >> 4) & 0x0F); + lcd_e_toggle(); + + /* output low nibble */ + LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | (data & 0x0F); + lcd_e_toggle(); + + /* all data pins high (inactive) */ + LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | 0x0F; + } + else + { + /* configure data pins as output */ + DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); + DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); + DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); + DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); + + /* output high nibble first */ + LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); + LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); + LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); + LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); + if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); + if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); + if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); + if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); + lcd_e_toggle(); + + /* output low nibble */ + LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); + LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); + LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); + LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); + if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); + if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); + if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); + if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); + lcd_e_toggle(); + + /* all data pins high (inactive) */ + LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); + LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); + LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); + LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); + } +} +#else +#define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d; +/* rs==0 -> write instruction to LCD_IO_FUNCTION */ +/* rs==1 -> write data to LCD_IO_DATA */ +#endif + + +/************************************************************************* +Low-level function to read byte from LCD controller +Input: rs 1: read data + 0: read busy flag / address counter +Returns: byte read from LCD controller +*************************************************************************/ +#if LCD_IO_MODE +static uint8_t lcd_read(uint8_t rs) +{ + uint8_t data; + + if (rs) + lcd_rs_high(); /* RS=1: read data */ + else + lcd_rs_low(); /* RS=0: read busy flag */ + lcd_rw_high(); /* RW=1 read mode */ + + if ( + (&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) + && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) + ) + { + DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */ + + lcd_e_high(); + lcd_e_delay(); + data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */ + lcd_e_low(); + + lcd_e_delay(); /* Enable 500ns low */ + + lcd_e_high(); + lcd_e_delay(); + data |= PIN(LCD_DATA0_PORT) & 0x0F; /* read low nibble */ + lcd_e_low(); + } + else + { + /* configure data pins as input */ + DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN); + DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN); + DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN); + DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN); + + /* read high nibble first */ + lcd_e_high(); + lcd_e_delay(); + data = 0; + if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10; + if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20; + if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40; + if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80; + lcd_e_low(); + + lcd_e_delay(); /* Enable 500ns low */ + + /* read low nibble */ + lcd_e_high(); + lcd_e_delay(); + if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01; + if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02; + if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04; + if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08; + lcd_e_low(); + } + return data; +} +#else +#define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ) +/* rs==0 -> read instruction from LCD_IO_FUNCTION */ +/* rs==1 -> read data from LCD_IO_DATA */ +#endif + + +/************************************************************************* +loops while lcd is busy, returns address counter +*************************************************************************/ +static uint8_t lcd_waitbusy(void) +{ + /* wait until busy flag is cleared */ + for (; lcd_read(0) & (1 << LCD_BUSY); ); + + /* the address counter is updated 4us after the busy flag is cleared */ + delay(2); + + /* now read the address counter */ + return (lcd_read(0)); // return address counter +}/* lcd_waitbusy */ + + +/************************************************************************* +Move cursor to the start of next line or to the first line if the cursor +is already on the last line. +*************************************************************************/ +static inline void lcd_newline(uint8_t pos) +{ + register uint8_t addressCounter; + +#if LCD_LINES==1 + addressCounter = 0; +#endif +#if LCD_LINES==2 + if ( pos < (LCD_START_LINE2) ) + addressCounter = LCD_START_LINE2; + else + addressCounter = LCD_START_LINE1; +#endif +#if LCD_LINES==4 +#if KS0073_4LINES_MODE + if ( pos < LCD_START_LINE2 ) + addressCounter = LCD_START_LINE2; + else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) ) + addressCounter = LCD_START_LINE3; + else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) ) + addressCounter = LCD_START_LINE4; + else + addressCounter = LCD_START_LINE1; +#else + if ( pos < LCD_START_LINE3 ) + addressCounter = LCD_START_LINE2; + else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) ) + addressCounter = LCD_START_LINE3; + else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) ) + addressCounter = LCD_START_LINE4; + else + addressCounter = LCD_START_LINE1; +#endif +#endif + lcd_command((1 << LCD_DDRAM) + addressCounter); + +}/* lcd_newline */ + + +/* +** PUBLIC FUNCTIONS +*/ + +/************************************************************************* +Send LCD controller instruction command +Input: instruction to send to LCD controller, see HD44780 data sheet +Returns: none +*************************************************************************/ +void lcd_command(uint8_t cmd) +{ + lcd_waitbusy(); + lcd_write(cmd,0); +} + + +/************************************************************************* +Send data byte to LCD controller +Input: data to send to LCD controller, see HD44780 data sheet +Returns: none +*************************************************************************/ +void lcd_data(uint8_t data) +{ + lcd_waitbusy(); + lcd_write(data,1); +} + + + +/************************************************************************* +Set cursor to specified position +Input: x horizontal position (0: left most position) + y vertical position (0: first line) +Returns: none +*************************************************************************/ +void lcd_gotoxy(uint8_t x, uint8_t y) +{ +#if LCD_LINES==1 + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); +#endif +#if LCD_LINES==2 + if ( y==0 ) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); + else + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); +#endif +#if LCD_LINES==4 + if ( y==0 ) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x); + else if ( y==1) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x); + else if ( y==2) + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x); + else /* y==3 */ + lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x); +#endif + +}/* lcd_gotoxy */ + + +/************************************************************************* +*************************************************************************/ +int lcd_getxy(void) +{ + return lcd_waitbusy(); +} + + +/************************************************************************* +Clear display and set cursor to home position +*************************************************************************/ +void lcd_clrscr(void) +{ + lcd_command(1 << LCD_CLR); +} + + +/************************************************************************* +Set cursor to home position +*************************************************************************/ +void lcd_home(void) +{ + lcd_command(1 << LCD_HOME); +} + + +/************************************************************************* +Display character at current cursor position +Input: character to be displayed +Returns: none +*************************************************************************/ +void lcd_putc(char c) +{ + uint8_t pos; + + pos = lcd_waitbusy(); // read busy-flag and address counter + if (c=='\n') + lcd_newline(pos); + else + { +#if LCD_WRAP_LINES==1 +#if LCD_LINES==1 + if ( pos == LCD_START_LINE1 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1,0); +#elif LCD_LINES==2 + if ( pos == LCD_START_LINE1 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2,0); + else if ( pos == LCD_START_LINE2 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1,0); +#elif LCD_LINES==4 + if ( pos == LCD_START_LINE1 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2,0); + else if ( pos == LCD_START_LINE2 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE3,0); + else if ( pos == LCD_START_LINE3 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE4,0); + else if ( pos == LCD_START_LINE4 + LCD_DISP_LENGTH ) + lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1,0); +#endif + lcd_waitbusy(); +#endif + lcd_write(c, 1); + } + +}/* lcd_putc */ + + +/************************************************************************* +Display string without auto linefeed +Input: string to be displayed +Returns: none +*************************************************************************/ +void lcd_puts(const char *s) +/* print string on lcd (no auto linefeed) */ +{ + register char c; + + while ( (c = *s++) ) { + lcd_putc(c); + } + +}/* lcd_puts */ + + +/************************************************************************* +Display string from program memory without auto linefeed +Input: string from program memory be be displayed +Returns: none +*************************************************************************/ +void lcd_puts_p(const char *progmem_s) +/* print string from program memory on lcd (no auto linefeed) */ +{ + register char c; + + while ( (c = pgm_read_byte(progmem_s++)) ) { + lcd_putc(c); + } + +}/* lcd_puts_p */ + + +/************************************************************************* +Initialize display and select type of cursor +Input: dispAttr LCD_DISP_OFF display off + LCD_DISP_ON display on, cursor off + LCD_DISP_ON_CURSOR display on, cursor on + LCD_DISP_CURSOR_BLINK display on, cursor on flashing +Returns: none +*************************************************************************/ +void lcd_init(uint8_t dispAttr) +{ +#if LCD_IO_MODE + /* + * Initialize LCD to 4 bit I/O mode + */ + + if ( + ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) + && ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT) + ) + { + /* configure all port bits as output (all LCD lines on same port) */ + DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN) | (1 << LCD_RS_PIN) | (1 << LCD_RW_PIN) | (1 << LCD_E_PIN); + } + else if ( + ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) + ) + { + /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */ + DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN); + DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); + DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); + DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); + } + else + { + /* configure all port bits as output (LCD data and control lines on different ports */ + DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); + DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); + DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); + DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); + DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); + DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); + DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); + } + delay(16000); /* wait 16ms or more after power-on */ + + /* initial write to lcd is 8bit */ + LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // _BV(LCD_FUNCTION)>>4; + LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4; + lcd_e_toggle(); + delay(4992); /* delay, busy flag can't be checked here */ + + /* repeat last command */ + lcd_e_toggle(); delay(64); /* delay, busy flag can't be checked here */ + + /* repeat last command a third time */ + lcd_e_toggle(); delay(64); /* delay, busy flag can't be checked here */ + + /* now configure for 4bit mode */ + LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4 + lcd_e_toggle(); + delay(64); /* some displays need this additional delay */ + + /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */ +#else + /* + * Initialize LCD to 8 bit memory mapped mode + */ + + /* enable external SRAM (memory mapped lcd) and one wait state */ + MCUCR = _BV(SRE) | _BV(SRW); + + /* reset LCD */ + delay(16000); /* wait 16ms after power-on */ + lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ + delay(4992); /* wait 5ms */ + lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ + delay(64); /* wait 64us */ + lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ + delay(64); /* wait 64us */ +#endif + +#if KS0073_4LINES_MODE + /* Display with KS0073 controller requires special commands for enabling 4 line mode */ + lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON); + lcd_command(KS0073_4LINES_MODE); + lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF); +#else + lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */ +#endif + + lcd_command(LCD_DISP_OFF); /* display off */ + lcd_clrscr(); /* display clear */ + lcd_command(LCD_MODE_DEFAULT); /* set entry mode */ + lcd_command(dispAttr); /* display/cursor control */ + +}/* lcd_init */ diff --git a/stepper/lcd.h b/stepper/lcd.h new file mode 100644 index 0000000..bec1cee --- /dev/null +++ b/stepper/lcd.h @@ -0,0 +1,263 @@ +#ifndef LCD_H +#define LCD_H +/************************************************************************* + Title : C include file for the HD44780U LCD library (lcd.c) + Author: Peter Fleury http://jump.to/fleury + File: $Id: lcd.h,v 1.13.2.2 2006/01/30 19:51:33 peter Exp $ + Software: AVR-GCC 3.3 + Hardware: any AVR device, memory mapped mode only for AT90S4414/8515/Mega +***************************************************************************/ + +/** + @defgroup pfleury_lcd LCD library + @code #include @endcode + + @brief Basic routines for interfacing a HD44780U-based text LCD display + + Originally based on Volker Oth's LCD library, + changed lcd_init(), added additional constants for lcd_command(), + added 4-bit I/O mode, improved and optimized code. + + Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in + 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported. + + Memory mapped mode compatible with Kanda STK200, but supports also + generation of R/W signal through A8 address line. + + @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + + @see The chapter Interfacing a HD44780 Based LCD to an AVR + on my home page. + +*/ + +/*@{*/ + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 303 +#error "This library requires AVR-GCC 3.3 or later, update to newer AVR-GCC compiler !" +#endif + +#include +#include + +/** + * @name Definitions for MCU Clock Frequency + * Adapt the MCU clock frequency in Hz to your target. + */ +#define XTAL F_CPU /**< clock frequency in Hz, used to calculate delay timer */ + +/** + * @name Definition for LCD controller type + * Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller. + */ +#define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */ + +/** + * @name Definitions for Display Size + * Change these definitions to adapt setting to your display + */ +#define LCD_LINES 2 /**< number of visible lines of the display */ +#define LCD_DISP_LENGTH 16 /**< visibles characters per line of the display */ +#define LCD_LINE_LENGTH 0x40 /**< internal line length of the display */ +#define LCD_START_LINE1 0x00 /**< DDRAM address of first char of line 1 */ +#define LCD_START_LINE2 0x40 /**< DDRAM address of first char of line 2 */ +#define LCD_START_LINE3 0x14 /**< DDRAM address of first char of line 3 */ +#define LCD_START_LINE4 0x54 /**< DDRAM address of first char of line 4 */ +#define LCD_WRAP_LINES 0 /**< 0: no wrap, 1: wrap at end of visibile line */ + +#define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */ + +#if LCD_IO_MODE +/** + * @name Definitions for 4-bit IO mode + * Change LCD_PORT if you want to use a different port for the LCD pins. + * + * The four LCD data lines and the three control lines RS, RW, E can be on the + * same port or on different ports. + * Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on + * different ports. + * + * Normally the four data lines should be mapped to bit 0..3 on one port, but it + * is possible to connect these data lines in different order or even on different + * ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions. + * */ +#define LCD_PORT PORTB /**< port for the LCD lines */ +#define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */ +#define LCD_DATA1_PORT LCD_PORT /**< port for 4bit data bit 1 */ +#define LCD_DATA2_PORT LCD_PORT /**< port for 4bit data bit 2 */ +#define LCD_DATA3_PORT LCD_PORT /**< port for 4bit data bit 3 */ +#define LCD_DATA0_PIN 0 /**< pin for 4bit data bit 0 */ +#define LCD_DATA1_PIN 1 /**< pin for 4bit data bit 1 */ +#define LCD_DATA2_PIN 2 /**< pin for 4bit data bit 2 */ +#define LCD_DATA3_PIN 3 /**< pin for 4bit data bit 3 */ +#define LCD_RS_PORT PORTD /**< port for RS line */ +#define LCD_RS_PIN 2 /**< pin for RS line */ +#define LCD_RW_PORT PORTD /**< port for RW line */ +#define LCD_RW_PIN 3 /**< pin for RW line */ +#define LCD_E_PORT PORTD /**< port for Enable line */ +#define LCD_E_PIN 4 /**< pin for Enable line */ + +#elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || defined(__AVR_ATmega64__) || \ + defined(__AVR_ATmega8515__)|| defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__) || \ + defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__) +/* + * memory mapped mode is only supported when the device has an external data memory interface + */ +#define LCD_IO_DATA 0xC000 /* A15=E=1, A14=RS=1 */ +#define LCD_IO_FUNCTION 0x8000 /* A15=E=1, A14=RS=0 */ +#define LCD_IO_READ 0x0100 /* A8 =R/W=1 (R/W: 1=Read, 0=Write */ +#else +#error "external data memory interface not available for this device, use 4-bit IO port mode" + +#endif + + +/** + * @name Definitions for LCD command instructions + * The constants define the various LCD controller instructions which can be passed to the + * function lcd_command(), see HD44780 data sheet for a complete description. + */ + +/* instruction register bit positions, see HD44780U data sheet */ +#define LCD_CLR 0 /* DB0: clear display */ +#define LCD_HOME 1 /* DB1: return to home position */ +#define LCD_ENTRY_MODE 2 /* DB2: set entry mode */ +#define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */ +#define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */ +#define LCD_ON 3 /* DB3: turn lcd/cursor on */ +#define LCD_ON_DISPLAY 2 /* DB2: turn display on */ +#define LCD_ON_CURSOR 1 /* DB1: turn cursor on */ +#define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */ +#define LCD_MOVE 4 /* DB4: move cursor/display */ +#define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */ +#define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */ +#define LCD_FUNCTION 5 /* DB5: function set */ +#define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */ +#define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */ +#define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */ +#define LCD_CGRAM 6 /* DB6: set CG RAM address */ +#define LCD_DDRAM 7 /* DB7: set DD RAM address */ +#define LCD_BUSY 7 /* DB7: LCD is busy */ + +/* set entry mode: display shift on/off, dec/inc cursor move direction */ +#define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */ +#define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */ +#define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */ +#define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */ + +/* display on/off, cursor on/off, blinking char at cursor position */ +#define LCD_DISP_OFF 0x08 /* display off */ +#define LCD_DISP_ON 0x0C /* display on, cursor off */ +#define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */ +#define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */ +#define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */ + +/* move cursor/shift display */ +#define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */ +#define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */ +#define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */ +#define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */ + +/* function set: set interface data length and number of display lines */ +#define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */ +#define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */ +#define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */ +#define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */ + + +#define LCD_MODE_DEFAULT ((1<= denom; num -= denom); + return num; +} + +void ringbuffer_init(ringbuffer *buf, int bufsize) +{ + buf->read_pointer = 0; + buf->write_pointer = 0; + buf->size = bufsize - sizeof(ringbuffer); +} + +uint16_t ringbuffer_canread(ringbuffer *buf) +{ + return _rb_mod(buf->write_pointer + buf->size + buf->size - buf->read_pointer, buf->size); +} + +uint16_t ringbuffer_canwrite(ringbuffer *buf) +{ + return _rb_mod(buf->read_pointer + buf->size + buf->size - buf->write_pointer - 1, buf->size); +} + +uint8_t ringbuffer_readchar(ringbuffer *buf) +{ + uint8_t r = 0; + if (ringbuffer_canread(buf)) + { + r = buf->data[buf->read_pointer]; + buf->read_pointer = _rb_mod(buf->read_pointer + 1, buf->size); + } + return r; +} + +void ringbuffer_writechar(ringbuffer *buf, uint8_t data) +{ + if (ringbuffer_canwrite(buf)) + { + buf->data[buf->write_pointer] = data; + buf->write_pointer = _rb_mod(buf->write_pointer + 1, buf->size); + } +} + + +uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index) +{ + return buf->data[_rb_mod(buf->read_pointer + index, buf->size)]; +} + +uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size) +{ + uint16_t nc, i; + uint8_t *rp, *ms; + if ((nc = ringbuffer_canread(buf)) < size) + size = nc; + if (size) + { + for (i = 0, rp = buf->data + buf->read_pointer, ms = buf->data + buf->size; i < size; i++, rp++) + { + if (rp >= ms) + rp = buf->data; + newbuf[i] = *rp; + } + buf->read_pointer = rp - buf->data; + } + return size; +} + +uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size) +{ + uint16_t nc, i; + uint8_t *wp, *ms; + + if ((nc = ringbuffer_canwrite(buf)) < size) + size = nc; + if (size) + { + for (i = 0, wp = buf->write_pointer + buf->data, ms = buf->data + buf->size; i < size; i++, wp++) + { + if (wp >= ms) + wp = buf->data; + *wp = data[i]; + } + buf->write_pointer = wp - buf->data; + } + return size; +} diff --git a/stepper/ringbuffer.h b/stepper/ringbuffer.h new file mode 100644 index 0000000..c6a24f4 --- /dev/null +++ b/stepper/ringbuffer.h @@ -0,0 +1,26 @@ +#ifndef _RINGBUFFER_H +#define _RINGBUFFER_H + +#include +#include + +typedef struct { + uint16_t read_pointer; + uint16_t write_pointer; + uint16_t size; + uint8_t data[]; +} ringbuffer; + +void ringbuffer_init(ringbuffer *buf, int bufsize); + +uint16_t ringbuffer_canread(ringbuffer *buf); +uint16_t ringbuffer_canwrite(ringbuffer *buf); + +uint8_t ringbuffer_readchar(ringbuffer *buf); +uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index); +uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size); + +void ringbuffer_writechar(ringbuffer *buf, uint8_t data); +uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size); + +#endif /* _RINGBUFFER_H */ diff --git a/stepper/serial.c b/stepper/serial.c new file mode 100644 index 0000000..3a691d6 --- /dev/null +++ b/stepper/serial.c @@ -0,0 +1,72 @@ +#include "serial.h" + +#include "ringbuffer.h" + +#define BUFSIZE 64 + sizeof(ringbuffer) +#define BAUD 19200 + +volatile uint8_t _rx_buffer[BUFSIZE]; +volatile uint8_t _tx_buffer[BUFSIZE]; + +void serial_init(uint16_t baud) +{ + ringbuffer_init(rx_buffer, BUFSIZE); + ringbuffer_init(tx_buffer, BUFSIZE); + + UCSR0A = 0; + UCSR0B = (1 << RXEN0) | (1 << TXEN0); + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); + + UBRR0 = ((F_CPU / 16) / baud) - 1; + + UCSR0B |= (1 << RXCIE0) | (1 << UDRIE0); +} + +ISR(USART_RX_vect) +{ + ringbuffer_writechar(rx_buffer, UDR0); +} + +ISR(USART_UDRE_vect) +{ + if (ringbuffer_canread(tx_buffer)) + { + UDR0 = ringbuffer_readchar(tx_buffer); + } + else + { + UCSR0B &= ~(1 << UDRIE0); + } +} + +uint16_t serial_rxchars() +{ + return ringbuffer_canread(rx_buffer); +} + +uint16_t serial_txchars() +{ + return ringbuffer_canread(tx_buffer); +} + +uint8_t serial_popchar() +{ + return ringbuffer_readchar(rx_buffer); +} + +uint16_t serial_recvblock(uint8_t *block, int blocksize) +{ + return ringbuffer_readblock(rx_buffer, block, blocksize); +} + +void serial_writechar(uint8_t data) +{ + ringbuffer_writechar(tx_buffer, data); + UCSR0B |= (1 << UDRIE0); +} + +void serial_writeblock(uint8_t *data, int datalen) +{ + ringbuffer_writeblock(tx_buffer, data, datalen); + UCSR0B |= (1 << UDRIE0); +} diff --git a/stepper/serial.h b/stepper/serial.h new file mode 100644 index 0000000..efda9d6 --- /dev/null +++ b/stepper/serial.h @@ -0,0 +1,24 @@ +#ifndef _SERIAL_H +#define _SERIAL_H + +#include +#include + +#define rx_buffer ((ringbuffer *) _rx_buffer) +#define tx_buffer ((ringbuffer *) _tx_buffer) + +extern volatile uint8_t _rx_buffer[]; +extern volatile uint8_t _tx_buffer[]; + +void serial_init(uint16_t baud); + +uint16_t serial_rxchars(void); +uint16_t serial_txchars(void); + +uint8_t serial_popchar(void); +void serial_writechar(uint8_t data); + +uint16_t serial_recvblock(uint8_t *block, int blocksize); +void serial_writeblock(uint8_t *data, int datalen); + +#endif /* _SERIAL_H */ diff --git a/stepper/stepper.c b/stepper/stepper.c new file mode 100644 index 0000000..8c4d257 --- /dev/null +++ b/stepper/stepper.c @@ -0,0 +1,396 @@ +#include +#include +#include + +#include +#include + +#include "serial.h" +#include "lcd.h" + +#include "arduino.h" + +// *** pin assignments *** + +// step input +#define PIN_STEP PIN_AIO2 +#define PORT_STEP WPORT_AIO2 +#define READ_STEP RPORT_AIO2 +#define DDR_STEP DDR_AIO2 + +// direction input +#define PIN_DIR PIN_AIO3 +#define PORT_DIR WPORT_AIO3 +#define READ_DIR RPORT_AIO3 +#define DDR_DIR DDR_AIO3 + +// outputs (PWM) - dir lines only below, en lines MUST connect to OCR0A/B (DIO 5/6) +#define PIN_DIR1 PIN_AIO0 +#define PORT_DIR1 WPORT_AIO0 +#define DDR_DIR1 DDR_AIO0 + +#define PIN_DIR2 PIN_AIO1 +#define PORT_DIR2 WPORT_AIO1 +#define DDR_DIR2 DDR_AIO1 + + +// *** machine-specific constants *** + +// 1/2 step, NSTEPPING=2, for 1/4 step, NSTEPPING = 4 etc +#define NSTEPPING 8 +// FULL steps per mm (calculate from 200 steps/rev) +#define FULL_STEPS_PER_MM 5 + +// calculations +#define PRESCALER 256 +#define STEPS_PER_MM (FULL_STEPS_PER_MM * NSTEPPING) + +// units +#define MM * STEPS_PER_MM +#define MM_PER_SEC * STEPS_PER_MM + +#define US * F_CPU / 1000000 / PRESCALER +#define MS * F_CPU / 1000 / PRESCALER +#define S * F_CPU / 1 / PRESCALER + +// *** tunables *** + +#define SPEED (15 MM_PER_SEC) + +// *** step table *** +// sinstepi MUST satisfy 2^n for integer values of n where n = 2 for 1/2 step, 4 for 1/4 step etc +// generate with: +// perl -e 'my $n = 4; my @st; for (0..$n) { push @st, sprintf "%i", sin($_ * 90 * 3.1415926535897932384626433832795029 * 2 / 360 / $n) * 255 }; print "#define sinstepi $n\nstatic uint8_t sintable[sinstepi + 1] = { "; print join ", ", @st; print " };\n";'; + +#if NSTEPPING == 1 +#define sinstepi 1 +static const uint8_t sintable[sinstepi + 1] = { 0, 255 }; + +#elif NSTEPPING == 2 +#define sinstepi 2 +static const uint8_t sintable[sinstepi + 1] = { 0, 180, 255 }; + +#elif NSTEPPING == 4 +#define sinstepi 4 +static uint8_t sintable[sinstepi + 1] = { 0, 97, 180, 235, 255 }; + +#elif NSTEPPING == 8 +#define sinstepi 8 +static uint8_t sintable[sinstepi + 1] = { 0, 49, 97, 141, 180, 212, 235, 250, 255 }; + +#elif NSTEPPING == 16 +#define sinstepi 16 +static uint8_t sintable[sinstepi + 1] = { 0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, 255 }; + +#elif NSTEPPING == 32 +#define sinstepi 32 +static uint8_t sintable[sinstepi + 1] = { 0, 12, 24, 37, 49, 61, 74, 85, 97, 109, 120, 131, 141, 151, 161, 171, 180, 188, 197, 204, 212, 218, 224, 230, 235, 240, 244, 247, 250, 252, 253, 254, 255 }; + +#else +#error Invalid NSTEPPING value + +#endif + +// recalculations - don't touch! +#define STEP_TIME F_CPU / SPEED / PRESCALER +#define MIN_STEP_TIME F_CPU / 1000 / PRESCALER +#define sinstepi2 (sinstepi * 2) +#define sinstepi3 (sinstepi * 3) +#define sinstepi4 (sinstepi * 4) +#define sinsteplast (sinstepi4 - 1) + +// utilities +#define MASK(a) (1 << a) +#define PORT_OUT_MASK (0xF << PIN_LSB_OUT) +#define abs(a) (((a) >= 0)?(a):-(a)) + +// write to lcd function for fdev_setup_stream +static int lcd_putc_fdev(char c, FILE *stream) +{ + lcd_putc(c); + return 0; +} + +int serial_putc_fdev(char c, FILE *stream) +{ + serial_writechar((uint8_t) c); + return 0; +} + +int serial_getc_fdev(FILE *stream) +{ + for (;serial_rxchars() == 0;); + return (int) serial_popchar(); +} + +static FILE lcdo = FDEV_SETUP_STREAM(lcd_putc_fdev, NULL, _FDEV_SETUP_WRITE); +static FILE serio = FDEV_SETUP_STREAM(serial_putc_fdev, serial_getc_fdev, _FDEV_SETUP_RW); + +volatile int32_t pos; +volatile int32_t npos; +volatile uint16_t speed; +volatile uint16_t speed_sync; +volatile uint8_t superstep; // for disabling microstep during high speed runs +volatile uint8_t superstep_sync; +volatile int step1; +volatile int step2; +// uint8_t power0; +// uint8_t power1; + +// integer sine approximation +int sinstep(uint8_t sequence) { + while (sequence >= sinstepi4) + sequence -= sinstepi4; + if (sequence < (sinstepi + 1)) + return sintable[sequence]; + if ((sequence >= (sinstepi + 1)) && (sequence < (sinstepi2 + 1))) + return sintable[sinstepi2 - sequence]; + if ((sequence >= (sinstepi2 + 1)) && (sequence < (sinstepi3 + 1))) + return -sintable[sequence - sinstepi2]; + //if ((sequence >= (sinstepi3 + 1)) && (sequence < (sinstepi4 + 1))) + return -sintable[sinstepi4 - sequence]; +} + +// generate appropriate stepper signals for a sequence number +void stepperseq(uint8_t sequence) { + step1 = sinstep(sequence); + step2 = sinstep(sequence + sinstepi); + + // set directions + if (step1 >= 0) + PORT_DIR1 |= MASK(PIN_DIR1); + else { + PORT_DIR1 &= ~MASK(PIN_DIR1); + } + +// PORT_DIR1 = (PORT_DIR1 & ~MASK(PIN_DIR1)) | ((((step1 >= 0)?255:0) ^ wx) & MASK(PIN_DIR1)); + + if (step2 >= 0) + PORT_DIR2 |= MASK(PIN_DIR2); + else { + PORT_DIR2 &= ~MASK(PIN_DIR2); + } + +// PORT_DIR2 = (PORT_DIR2 & ~MASK(PIN_DIR2)) | ((((step2 >= 0)?255:0) ^ wx) & MASK(PIN_DIR2)); + + // set power + TCNT0 = 0xFD; + OCR0A = ((uint8_t) abs(step1)); + OCR0B = ((uint8_t) abs(step2)); +} + +// // PWM reset interrupt +// ISR(TIMER0_OVF_vect) { +// // now that our counter is at zero, load new power levels +// OCR0A = power0; +// OCR0B = power1; +// } + +// next step interrupt +ISR(TIMER1_COMPA_vect) { + uint8_t i; + + // toggle "L" led + PINB = MASK(PB5); + + // update position + if (npos > pos) + pos += MASK(superstep_sync); + else if (npos < pos) + pos -= MASK(superstep_sync); + + // write new position + i = pos & sinsteplast; + stepperseq(i); + // if we're at a sync point and we're changing microstep rate + if ((i & (sinstepi2 - 1)) == 0) + // do the change now + superstep_sync = superstep; + // update speed + OCR1A = speed << superstep_sync; +} + +void startstep(void) { + if ((TIMSK1 & MASK(OCIE1A)) == 0) + { + OCR1A = speed; +// while ((OCR1A < MIN_STEP_TIME) && (superstep < sinstepi)) { +// OCR1A <<= 1; +// superstep <<= 1; +// } +// while (((OCR1A > (MIN_STEP_TIME * 2)) && (superstep > 1)) || (abs(npos - pos) < superstep)) { +// OCR1A >>= 1; +// superstep >>= 1; +// } + TCNT1 = 0; + } + + // it's possible that the mask is enabled during the check above, but disabled by the time we get here - always set it to avoid a race condition + TIMSK1 |= MASK(OCIE1A); +} + +// main, where it all happens +int main (void) +{ + // set up LCD + lcd_init(LCD_DISP_ON_CURSOR); + + lcd_puts_P("Starting..."); + + // set up STDIN/OUT/ERR + stdin = &serio; + stdout = &lcdo; + stderr = &lcdo; + + // set up serial + serial_init(19200); + + // variables + pos = 0; + uint8_t stepdebounce = 0; + uint16_t spinner = 0; + int r; + int32_t rv; + int rs; + + // setup inputs + DDR_STEP &= ~MASK(PIN_STEP); + DDR_DIR &= ~MASK(PIN_DIR); + + // pull-ups + PORT_STEP |= MASK(PIN_STEP); + PORT_DIR |= MASK(PIN_DIR); + + // direction pins to h-bridge + DDR_DIR1 |= MASK(PIN_DIR1); + DDR_DIR2 |= MASK(PIN_DIR2); + // enable pins to h-bridge - must be DIO5/6 for PWM operation + DDR_DIO5 |= MASK(PIN_DIO5); + DDR_DIO6 |= MASK(PIN_DIO6); + + // setup timer 0 (PWM timer) + TCCR0A = MASK(COM0A1) | MASK(COM0B1) | MASK(WGM01) | MASK(WGM00); // enable PWM output pins (DIO5/6), fast PWM + TCCR0B = MASK(CS00); // prescaler = 1 (max speed) + + // setup timer 1 (step timer) + TCCR1A = 0; + TCCR1B = MASK(WGM12); + #if PRESCALER == 1 + TCCR1B |= MASK(CS10); + #elif PRESCALER == 8 + TCCR1B |= MASK(CS11); + #elif PRESCALER == 64 + TCCR1B |= MASK(CS11) | MASK(CS10); + #elif PRESCALER == 256 + TCCR1B |= MASK(CS12); + #elif PRESCALER == 1024 + TCCR1B |= MASK(CS12) | MASK(CS10); + #else + #error Invalid PRESCALER value: must be one of 1, 8, 64, 256 or 1024 + #endif + + // disable interrupt + TIMSK1 = 0; + // set speed + speed = STEP_TIME; + OCR1A = speed << superstep; + + // initialize stepper drive + //PORT_OUT = (PORT_OUT & ~PORT_OUT_MASK) | ((steps[0] ^ wmod) << PIN_LSB_OUT); + stepperseq(0); + + // enable interrupts + sei(); + + // main loop start + lcd_gotoxy(0, 0); + fprintf(&lcdo, "Stepper OK "); + + // main loop + for (;;) + { + // check logic inputs + if ((READ_STEP & MASK(PIN_STEP)) == 0) { + if (stepdebounce >= 32) { + if (stepdebounce == 32) { + if (READ_DIR & MASK(PIN_DIR)) + npos++; + else + npos--; + stepdebounce++; + } + } + else + stepdebounce++; + } + else + stepdebounce = 0; + + // check serial input + if (serial_rxchars()) { + uint8_t c = getchar(); + switch (c) { + case '>': + npos++; + break; + case '<': + npos--; + break; + case '?': + fprintf(&serio, "pos:%li\n", pos); + break; + case '+': + r = scanf("%li", &rv); + if (r == 0) + npos++; + else + npos += rv; + break; + case '-': + r = scanf("%li", &rv); + if (r == 0) + npos--; + else + npos -= rv; + break; + case 'g': + r = scanf("%li", &rv); + if (r != 0) + npos = rv; + break; + case 's': + r = scanf("%li", &rv); + if (r != 0) + speed = rv; + break; + case 'h': + npos = 0; + break; + case 'x': + r = scanf("%i", &rs); + if (r != 0) + superstep = rs; + break; + case 'R': + npos = pos = 0; + break; + } + } + + if ((npos != pos) && ((TIMSK1 & MASK(OCIE1A)) == 0)) + startstep(); + + if (((spinner++) & 0x0FFF) == 0) { + lcd_clrscr(); + printf("p:%7li", pos); + lcd_gotoxy(8, 0); + printf("s:%i", speed); + lcd_gotoxy(0, 1); + printf("t:%7li", npos); + lcd_gotoxy(8, 1); + // printf("p:%i", PORT_STEP); + printf("%i %i", step1, step2); + // printf("%02X", READ_STEP); + } + } +} diff --git a/stepper/test.c b/stepper/test.c new file mode 100755 index 0000000..cb6d5b4 --- /dev/null +++ b/stepper/test.c @@ -0,0 +1,43 @@ +// + +#include +#include + + +// generate with: +// perl -e 'my $n = 16; my @st; for (0..($n - 1)) { push @st, sprintf "%i", sin($_ * 90 * 3.141592653 * 2 / 360 / ($n - 1)) * 255 }; print "#define sinsteps $n\nstatic uint8_t sintable[sinsteps] = { "; print join ", ", @st; print " };\n";'; +// #define sinsteps 16 +// static uint8_t sintable[sinsteps] = { 0, 26, 53, 78, 103, 127, 149, 170, 189, 206, 220, 232, 242, 249, 253, 255 }; + +#define sinsteps 5 +static uint8_t sintable[sinsteps] = { 0, 97, 180, 235, 255 }; + +#define sinstepi (sinsteps - 1) +#define sinstepi2 (sinstepi * 2) +#define sinstepi3 (sinstepi * 3) +#define sinstepi4 (sinstepi * 4) + +int sinstep(uint8_t sequence) { + while (sequence >= sinstepi4) + sequence -= sinstepi4; + if (sequence < (sinstepi + 1)) + return sintable[sequence]; + if ((sequence >= (sinstepi + 1)) && (sequence < (sinstepi2 + 1))) + return sintable[sinstepi2 - sequence]; + if ((sequence >= (sinstepi2 + 1)) && (sequence < (sinstepi3 + 1))) + return -sintable[sequence - sinstepi2]; + if ((sequence >= (sinstepi3 + 1)) && (sequence < (sinstepi4 + 1))) + return -sintable[sinstepi4 - sequence]; +} + + + +int main(int argc, char **argv) +{ + int i; + for (i = 0; i < ((sinstepi * 4) * 3); i++) + { + printf("%2i: %+4i %+4i\n", i, sinstep(i), sinstep(i + sinstepi)); + } + printf("\n"); +} \ No newline at end of file