diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /device/lib/ds390 | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'device/lib/ds390')
| -rw-r--r-- | device/lib/ds390/Makefile | 67 | ||||
| -rw-r--r-- | device/lib/ds390/Makefile.dep | 18 | ||||
| -rw-r--r-- | device/lib/ds390/Makefile.in | 67 | ||||
| -rw-r--r-- | device/lib/ds390/examples/MOVED | 1 | ||||
| -rw-r--r-- | device/lib/ds390/gptr_cmp.c | 98 | ||||
| -rw-r--r-- | device/lib/ds390/i2c390.c | 372 | ||||
| -rw-r--r-- | device/lib/ds390/lcd390.c | 178 | ||||
| -rw-r--r-- | device/lib/ds390/memcpyx.c | 121 | ||||
| -rw-r--r-- | device/lib/ds390/putchar.c | 43 | ||||
| -rw-r--r-- | device/lib/ds390/rtc390.c | 111 | ||||
| -rw-r--r-- | device/lib/ds390/setjmp.c | 72 | ||||
| -rw-r--r-- | device/lib/ds390/tinibios.c | 571 |
12 files changed, 1719 insertions, 0 deletions
diff --git a/device/lib/ds390/Makefile b/device/lib/ds390/Makefile new file mode 100644 index 0000000..b0717d1 --- /dev/null +++ b/device/lib/ds390/Makefile @@ -0,0 +1,67 @@ +# libc/ds390 Makefile + + +srcdir = . +top_builddir = ../../.. + +LIB_TYPE = RANLIB + +CC = $(top_builddir)/bin/sdcc + +# override PORTDIR defined by super (parent) makefile +override PORTDIR = ../build/ds390 + +#VERBOSE = --verbose + +OBJECTS = tinibios.rel memcpyx.rel lcd390.rel i2c390.rel rtc390.rel putchar.rel gptr_cmp.rel + +SOURCES = $(patsubst %.rel,%.c,$(OBJECTS)) + +CPPFLAGS = -I$(srcdir)/../../include +CFLAGS = -mds390 $(CPPFLAGS) $(VERBOSE) --std-c11 + +all: $(OBJECTS) $(PORTDIR)/libds390.lib + +clean: + rm -f *.lst *.rel *.sym *.cdb *.asm \#* *~ *.rst *.hex + rm -f *.ihx temp.lnk *.map *.lib + +distclean: clean + rm -f Makefile Makefile.dep + +$(PORTDIR)/libds390.lib: $(OBJECTS) +ifeq ($(LIB_TYPE), SDCCLIB) + rm -f $@; \ + $(top_builddir)/bin/sdcclib -a $@ $(OBJECTS) +else + ifeq ($(LIB_TYPE), AR) + $(top_builddir)/bin/sdar -rcSD $@ $(OBJECTS) + else + ifeq ($(LIB_TYPE), RANLIB) + $(top_builddir)/bin/sdar -rcD $@ $(OBJECTS) + else + rm -f $@; + for libfile in $(basename $(OBJECTS)); do echo $$libfile >>$@; done + cp $(OBJECTS) $(PORTDIR) + endif + endif +endif + +%.rel: %.c + $(CC) -c $(CFLAGS) $< + +# Creating dependencies +# --------------------- +depend: Makefile.dep + +Makefile.dep: $(SOURCES) + rm -f Makefile.dep + for i in $^; do \ + $(CC) -M $(CPPFLAGS) $$i >$${i}.dep; \ + cat $${i}.dep >>Makefile.dep; \ + rm $${i}.dep; \ + done + +ifeq "$(findstring $(MAKECMDGOALS),clean distclean)" "" + -include Makefile.dep +endif diff --git a/device/lib/ds390/Makefile.dep b/device/lib/ds390/Makefile.dep new file mode 100644 index 0000000..143598d --- /dev/null +++ b/device/lib/ds390/Makefile.dep @@ -0,0 +1,18 @@ +tinibios.rel: tinibios.c ../../include/tinibios.h \ + ../../include/ds80c390.h ../../include/time.h ../../include/stdio.h \ + ../../include/stdarg.h ../../include/sdcc-lib.h \ + ../../include/asm/mcs51/features.h +memcpyx.rel: memcpyx.c ../../include/string.h +lcd390.rel: lcd390.c ../../include/tinibios.h ../../include/ds80c390.h \ + ../../include/time.h ../../include/stdio.h ../../include/stdarg.h \ + ../../include/sdcc-lib.h ../../include/asm/mcs51/features.h +i2c390.rel: i2c390.c ../../include/tinibios.h ../../include/ds80c390.h \ + ../../include/time.h +rtc390.rel: rtc390.c ../../include/tinibios.h ../../include/ds80c390.h \ + ../../include/time.h ../../include/stdio.h ../../include/stdarg.h \ + ../../include/sdcc-lib.h ../../include/asm/mcs51/features.h \ + ../../include/ctype.h +putchar.rel: putchar.c ../../include/tinibios.h ../../include/ds80c390.h \ + ../../include/time.h ../../include/stdio.h ../../include/stdarg.h \ + ../../include/sdcc-lib.h ../../include/asm/mcs51/features.h +gptr_cmp.rel: gptr_cmp.c diff --git a/device/lib/ds390/Makefile.in b/device/lib/ds390/Makefile.in new file mode 100644 index 0000000..e2656e4 --- /dev/null +++ b/device/lib/ds390/Makefile.in @@ -0,0 +1,67 @@ +# libc/ds390 Makefile + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_builddir = @top_builddir@ + +LIB_TYPE = @LIB_TYPE@ + +CC = $(top_builddir)/bin/sdcc + +# override PORTDIR defined by super (parent) makefile +override PORTDIR = ../build/ds390 + +#VERBOSE = --verbose + +OBJECTS = tinibios.rel memcpyx.rel lcd390.rel i2c390.rel rtc390.rel putchar.rel gptr_cmp.rel + +SOURCES = $(patsubst %.rel,%.c,$(OBJECTS)) + +CPPFLAGS = -I$(srcdir)/../../include +CFLAGS = -mds390 $(CPPFLAGS) $(VERBOSE) --std-c11 + +all: $(OBJECTS) $(PORTDIR)/libds390.lib + +clean: + rm -f *.lst *.rel *.sym *.cdb *.asm \#* *~ *.rst *.hex + rm -f *.ihx temp.lnk *.map *.lib + +distclean: clean + rm -f Makefile Makefile.dep + +$(PORTDIR)/libds390.lib: $(OBJECTS) +ifeq ($(LIB_TYPE), SDCCLIB) + rm -f $@; \ + $(top_builddir)/bin/sdcclib -a $@ $(OBJECTS) +else + ifeq ($(LIB_TYPE), AR) + $(top_builddir)/bin/sdar -rcSD $@ $(OBJECTS) + else + ifeq ($(LIB_TYPE), RANLIB) + $(top_builddir)/bin/sdar -rcD $@ $(OBJECTS) + else + rm -f $@; + for libfile in $(basename $(OBJECTS)); do echo $$libfile >>$@; done + cp $(OBJECTS) $(PORTDIR) + endif + endif +endif + +%.rel: %.c + $(CC) -c $(CFLAGS) $< + +# Creating dependencies +# --------------------- +depend: Makefile.dep + +Makefile.dep: $(SOURCES) + rm -f Makefile.dep + for i in $^; do \ + $(CC) -M $(CPPFLAGS) $$i >$${i}.dep; \ + cat $${i}.dep >>Makefile.dep; \ + rm $${i}.dep; \ + done + +ifeq "$(findstring $(MAKECMDGOALS),clean distclean)" "" + -include Makefile.dep +endif diff --git a/device/lib/ds390/examples/MOVED b/device/lib/ds390/examples/MOVED new file mode 100644 index 0000000..a1e8808 --- /dev/null +++ b/device/lib/ds390/examples/MOVED @@ -0,0 +1 @@ +Moved and unpacked to sdcc/device/examples/ds390 diff --git a/device/lib/ds390/gptr_cmp.c b/device/lib/ds390/gptr_cmp.c new file mode 100644 index 0000000..5453a6a --- /dev/null +++ b/device/lib/ds390/gptr_cmp.c @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- +; gptr_cmp.asm - C run-time: compare two generic pointers +; +; Copyright (C) 2011, Maarten Brock +; +; This library is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License as published by the +; Free Software Foundation; either version 2, 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 General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this library; see the file COPYING. If not, write to the +; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, +; MA 02110-1301, USA. +; +; As a special exception, if you link this library with other files, +; some of which are compiled with SDCC, to produce an executable, +; this library does not by itself cause the resulting executable to +; be covered by the GNU General Public License. This exception does +; not however invalidate any other reasons why the executable file +; might be covered by the GNU General Public License. +;------------------------------------------------------------------------*/ + +#ifdef __SDCC_MODEL_FLAT24 + +static void dummy(void) __naked +{ + __asm + .area HOME (CODE) + +; compares two generic pointers. +; if p1 < p2 return NZ and C +; if p1 == p2 return Z and NC +; if p1 > p2 return NZ and NC +; if both are a NULL pointer (yes, we have several) also return Z and NC + +___gptr_cmp:: + mov a,sp + add a,#0xFA + mov dpl1,a + mov a,esp + anl a,#0x03 + addc a,#0xFF + mov dph1,a + mov dpx1,#0x40 + inc dps ;select dptr1 + movx a,@dptr + mov ap,a + inc dptr + movx a,@dptr + orl ap,a + inc dptr + movx a,@dptr + orl a,ap + clr c + jnz 00001$ + mov a,dpl + orl a,dph + orl a,dpx +; if both are NULL, return Z and NC + jz 00002$ +00001$: + orl dps,#0x80 ;decrement dptr1 + inc dptr + inc dptr + anl dps,#0x7F ;increment dptr1 + movx a,@dptr + subb a,dpl + mov ap,a + inc dptr + movx a,@dptr + subb a,dph + orl ap,a + inc dptr + movx a,@dptr + subb a,dpx + orl ap,a + inc dptr + movx a,@dptr + subb a,b + orl a,ap +; p2 < p1, return NZ and C +; p2 = p1, return Z and NC +; p2 > p1, return NZ and NC +00002$: + dec dps ;select dptr0 + ret + + __endasm; +} + +#endif + diff --git a/device/lib/ds390/i2c390.c b/device/lib/ds390/i2c390.c new file mode 100644 index 0000000..e3c115f --- /dev/null +++ b/device/lib/ds390/i2c390.c @@ -0,0 +1,372 @@ +/*------------------------------------------------------------------------- + i2c390.c + + Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl> + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +/* This implemenation is based on an example I once grabbed from + the Philips bbs. + Don't know who wrote it, but is has been hacked so heavily, he/she wouldn't + recogize it anyway */ + +//#define DEBUG_I2C ==> DON'T DO THIS, THIS IS A LIBRARY <== + +#ifdef DEBUG_I2C +#include <stdio.h> +#else +#include <tinibios.h> +#endif + +// we are (ab)using the CAN CTX and CRX for serial data and serial clock +#define SCL_HIGH (P5 |= 1) +#define SCL_LOW (P5 &= ~1) +#define SDA_HIGH (P5 |= 2) +#define SDA_LOW (P5 &= ~2) + +#define SDA_OUT(b) (b ? SDA_HIGH : SDA_LOW) +#define SDA_IN ((P5>>1)&1) +#define SCL_IN (P5&1) + +/* + * I2C error values + */ + +#define I2CERR_OK 0 /* No error */ +#define I2CERR_NAK 1 /* No ACK from slave */ +#define I2CERR_LOST 2 /* Arbitration lost */ +#define I2CERR_BUS 3 /* Bus is stuck (not used yet) */ +#define I2CERR_TIMEOUT 4 /* Timeout on bus */ + +char i2cTransmitBuffer[I2C_BUFSIZE]; /* Global transfer buffers */ +char i2cReceiveBuffer[I2C_BUFSIZE]; + +static char i2cError = 0; /* Last error */ + +#define I2CDELAY 1 + +void I2CDelay(volatile long delay) { + while (delay--) + ; +} + +void I2CDumpError(char error); + +/* + * Makes sure that the bus is in a known condition. Returns 1 on success, + * 0 if some other device is pulling on the bus. + */ + +char I2CReset(void) +{ + SDA_LOW; + SCL_LOW; + SCL_HIGH; + SDA_HIGH; + i2cError = 0; + return (SCL_IN && SDA_IN); +} + + +/* + * Generates a start condition on the bus. Returns 0 on success, 1 if some + * other device is holding the bus. + */ + +char I2CStart(void) +{ + SDA_HIGH; + SCL_HIGH; + I2CDelay(I2CDELAY); + SDA_LOW; /* Pull SDA down... */ + I2CDelay(I2CDELAY); + SCL_LOW; /* ...and then SCL -> start condition. */ + I2CDelay(I2CDELAY); + return 0; +} + + +/* + * Generates a stop condition on the bus. Returns 0 on success, 1 if some + * other device is holding the bus. + */ + +char I2CStop(void) +{ + SDA_LOW; + SCL_HIGH; /* Let SCL go up */ + I2CDelay(I2CDELAY); + SDA_HIGH; /* ...and then SDA up -> stop condition. */ + I2CDelay(I2CDELAY); + + return (SCL_IN && SDA_IN); /* Both will be up, if everything is fine */ +} + + +/* + * Clock out one bit. + * Returns 0 on success, 1 if we lose arbitration. + */ + +char BitOutI2C(unsigned char bout) +{ + SDA_OUT(bout); /* Put data out on SDA */ + I2CDelay(I2CDELAY); + SCL_HIGH; /* Let SCL go up */ + while(!SCL_IN) /* Wait until all other devices are ready */ + { + // should do a timeout here + } + + if (SDA_IN != bout) /* Arbitration lost, release bus and return */ + { + SDA_HIGH; /* Should be up anyway, but make sure */ + i2cError = I2CERR_LOST; + I2CDumpError(i2cError); + return 1; + } + I2CDelay(I2CDELAY); + SCL_LOW; /* Pull SCL back down */ + I2CDelay(I2CDELAY); + return 0; /* OK */ +} + + +/* + * Clock in one bit. + */ + +char BitInI2C(void) +{ + char bin; + + // SDA is opencollector, so: + SDA_HIGH; + + SCL_HIGH; /* Let SCL go up */ + while(!SCL_IN) /* Wait for other devices */ + { + // should do a timeout here + } + bin = SDA_IN; /* Read in data */ + I2CDelay(I2CDELAY); + SCL_LOW; /* Pull SCL back up */ + I2CDelay(I2CDELAY); + return bin; /* Return the sampled bit */ +} + + +/* + * Send one byte on the bus. No start or stop conditions are generated here, + * but i2cError will be set according to the result. + * Returns 0 on success, 1 if we lose arbitration or if the slave doesn't + * acknowledge the byte. Check i2cError for the actual result on error. + */ + +char ByteOutI2C(char dat) +{ + char bit_count; + + bit_count = 8; + while(bit_count) { + if (dat & 0x80) { + if (BitOutI2C(1)) { + I2CDumpError(i2cError); + return 1; + } + } else { + if (BitOutI2C(0)) { + I2CDumpError(i2cError); + return 1; + } + } + dat <<= 1; + bit_count--; + } + + if (BitInI2C()) { + i2cError = I2CERR_NAK; + I2CDumpError(i2cError); + return 1; + } + return 0; +} + + +/* + * Reads one byte in from the slave. Ack must be 1 if this is the last byte + * to be read during this transfer, 0 otherwise (as per I2C bus specification, + * the receiving master must acknowledge all but the last byte during a + * transfer). + */ + +char I2CByteIn(char ack) +{ + char bit_count, byte_in; + + bit_count = 8; + byte_in = 0; + + while(bit_count) + { + byte_in <<= 1; + if (BitInI2C()) byte_in |= 0x01; + bit_count--; + } + + BitOutI2C(ack); + SDA_HIGH; /* Added 18-Jul-95 - thanks to Ray Bellis */ + return byte_in; +} + + +/* + * Send 'count' bytes to slave 'addr'. + * Returns 0 on success. Stop condition is sent only when send_stop is true. + */ + +char I2CSendStop(char addr, char count, char send_stop) +{ + char byteptr, byte_out; + + if (I2CStart()) return 1; + i2cError = 0; + + byte_out = addr & 0xfe; /* Ensure that it's a write address */ + count++; /* Include slave address to byte count */ + byteptr = 0; + while(count) + { + if (ByteOutI2C(byte_out)) + { + if (i2cError == I2CERR_NAK && send_stop) I2CStop(); + return i2cError; + } + byte_out = i2cTransmitBuffer[byteptr]; + byteptr++; + count--; + } + + if (send_stop) I2CStop(); + return 0; +} + + +/* + * Read in 'count' bytes from slave 'addr'. + * Returns 0 on success. + */ + +char i2c_recv(char addr, char count) +{ + char byteptr, byte_in; + + if (I2CStart()) return 1; + i2cError = 0; + byteptr = 0; + + byte_in = addr | 0x01; + + if (ByteOutI2C(byte_in)) + { + if (i2cError == I2CERR_NAK) I2CStop(); + return i2cError; + } + + while(count) + { + count-=1; + if (count) { + byte_in = I2CByteIn(0); + } else { + byte_in = I2CByteIn(1); /* No ACK during last byte */ + } + i2cReceiveBuffer[byteptr] = byte_in; + byteptr++; + } + + I2CStop(); + + return (i2cError ? 1 : 0); +} + + +/* + * Write 'tx_count' bytes to slave 'addr', then use a repeated start condition + * to read 'rx_count' bytes from the same slave during the same transfer. + * Returns 0 on success, 1 otherwise. On error, check i2cError for the actual + * error value. + */ + +char I2CSendReceive(char addr, char tx_count, char rx_count) +{ + if (I2CSendStop(addr, tx_count, 0)) + { + /* If send fails, abort but don't send a stop condition if we lost + arbitration */ + + if (i2cError != I2CERR_LOST) I2CStop(); + return 1; + } + + SDA_HIGH; /* One of these may be low now, in which case the next */ + SCL_HIGH; /* start condition wouldn't be detected so make */ + I2CDelay(I2CDELAY); /* sure that they're up and wait for one delay slot */ + + if (i2c_recv((char)(addr|0x01), rx_count)) return 1; + return (i2cError ? 1 : 0); +} + +/* + * Dump an error message. + */ + +void I2CDumpError(char error) +{ +#ifdef DEBUG_I2C + switch(error) + { + case 0: + puts("I2C: OK."); + break; + case I2CERR_NAK: + puts("I2C: Slave didn't acknowledge"); + break; + case I2CERR_LOST: + puts("I2C: Lost arbitration with another master"); + break; + case I2CERR_TIMEOUT: + puts("I2C: Timeout on bus"); + break; + case I2CERR_BUS: + puts("I2C: The bus is stuck"); + break; + default: + puts("I2C: Unknown error"); + break; + } +#else + error; // hush the compiler +#endif +} diff --git a/device/lib/ds390/lcd390.c b/device/lib/ds390/lcd390.c new file mode 100644 index 0000000..5a70acf --- /dev/null +++ b/device/lib/ds390/lcd390.c @@ -0,0 +1,178 @@ +/*------------------------------------------------------------------------- + lcd.c - lcd routines for the DS80C390 (tested on TINI) + + Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl> + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#include <tinibios.h> +#include <stdio.h> +#include <stdarg.h> + +#define LCD_COLLUMNS 20 +#define LCD_ROWS 4 + +/* set the dd ram addresses for the rows + this one is for a 20x4 LCD +*/ +static unsigned char lcdLinesStart[LCD_ROWS]={0, 0x40, 0x14, 0x54}; + +/* Commercial TINI stick connector boards don't support rw + control for the lcd-display. + My own board does, and it makes it much faster. +*/ + +//#define LCD_RW + +__xdata __at (0x380002) static unsigned char lcdIwr; +__xdata __at (0x38000a) static unsigned char lcdDwr; + +#ifdef LCD_RW + +__xdata __at (0x380003) static unsigned char lcdIrd; +__xdata __at (0x38000b) static unsigned char lcdDrd; + +#define LcdWait { while (lcdIrd&0x80) ; } + +#else // ifdef LCD_RW + +// wait for 100us +#define LcdWait { ClockMicroSecondsDelay(100) ; } + +#endif // ifdef LCD_RW + +void LcdInit() { + + ClockMilliSecondsDelay(16); // >15 ms + + lcdIwr=0x38 ; + ClockMilliSecondsDelay(5); // >4.1 ms + + lcdIwr=0x38; + ClockMicroSecondsDelay(101); // >100 us + + lcdIwr=0x38; + ClockMicroSecondsDelay(101); // >100 us + + lcdIwr=0x38; // interface 8 bit + ClockMicroSecondsDelay(41); // >40 us + + lcdIwr=0x0c; // display on + ClockMicroSecondsDelay(41); // >40 us + + LcdClear(); +} + +void LcdOn() { + lcdIwr=0x0c; // display on + LcdWait; +} + +void LcdOff() { + lcdIwr=0x08; // display off + LcdWait; +} + +void LcdCursorOn() { + // TODO +} + +void LcdCursorOff() { + // TODO +} + +void LcdScrollOn() { + // TODO +} + +void LcdScrollOff() { + // TODO +} + +void LcdCharDefine() { + // TODO +} + +void LcdClear() { + lcdIwr=0x01; // display clear + ClockMilliSecondsDelay(6); // > 5ms +} + +void LcdHome() { + lcdIwr=0x80; // set dd ram address 0 + LcdWait; +} + +void LcdGoto(unsigned int collumnRow) { // msb=collumn, lsb=row + lcdIwr=0x80 + \ + lcdLinesStart[collumnRow&0xff] + (collumnRow>>8); + LcdWait; +} + +void LcdPutChar(char c) { + lcdDwr=c; + LcdWait; +} + +void LcdPutString (char *string) { + char c; + while (c=*string++) { + LcdPutChar (c); + } +} + +void LcdLPutString (unsigned int collumnRow, char *string) { + LcdGoto(collumnRow); + LcdPutString(string); +} + +// let's hope that no one ever printf's more than the display width, +// however they will :), so to be sure +static char lcdPrintfBuffer[LCD_COLLUMNS*4]; + +void LcdPrintf (const char *format, ...) __reentrant { + va_list arg; + + va_start (arg, format); + vsprintf (lcdPrintfBuffer, format, arg); + puts (lcdPrintfBuffer); + LcdPutString(lcdPrintfBuffer); + + va_end (arg); +} + +void LcdLPrintf (unsigned int collumnRow, const char *format, ...) __reentrant { + va_list arg; + + LcdGoto(collumnRow); + + // we can not just call LcdPrintf since we have no idea what is on the stack, + // so we have to do it all over again + va_start (arg, format); + vsprintf (lcdPrintfBuffer, format, arg); + + LcdPutString(lcdPrintfBuffer); + + va_end (arg); +} diff --git a/device/lib/ds390/memcpyx.c b/device/lib/ds390/memcpyx.c new file mode 100644 index 0000000..5ec6eba --- /dev/null +++ b/device/lib/ds390/memcpyx.c @@ -0,0 +1,121 @@ +/*------------------------------------------------------------------------- + memcpyx.c + + Copyright (C) 2000, Kevin Vigor + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#include <string.h> + +void __xdata * memcpyx ( + void __xdata * dst, + void __xdata * src, + int count + ) __naked +{ + /* Shut compiler up about unused parameters. */ + dst; src; count; + +/* AUTO_TOGGLE uses the '390 DPTS toggle bit. */ +#define AUTO_TOGGLE +__asm + ; Destination is in DPTR. Save it on stack so we can return it at end. + + push dpx + push dph + push dpl + + mov dps, #0x1 ; Alternate DPTR. + + ; count is in _memcpyx_PARM_3 + mov dptr, #_memcpyx_PARM_3 + movx a, @dptr + inc dptr + mov r2, a + movx a, @dptr + mov r3, a + + ; src is in _memcpyx_PARM_2 + mov dptr, #_memcpyx_PARM_2 + movx a, @dptr + inc dptr + push acc + movx a, @dptr + inc dptr + push acc + movx a, @dptr + mov dpx1, a + pop dph1 + pop dpl1 + +#ifdef AUTO_TOGGLE + mov dps, #0x21 ; Current DPTR is alt DPTR, toggle after each op. +#else + mov dps, #0x0 ; Current DPTR is normal DPTR, no toggle. +#endif + + ; src is in alt DPTR, dst is in normal DPTR, count is in r2/r3. + + ; If we have zero bytes to copy, quick out. + mov a, r2 + orl a, r3 + jz _memcpy_done + + ; increment r3 if r2 != 0 (makes djnz end-of-loop sequence possible). + inc r3 + cjne r2, #0x0, _memcpyx_loopTop + dec r3 + +_memcpyx_loopTop: + +#ifdef AUTO_TOGGLE + movx a, @dptr + movx @dptr, a + inc dptr + inc dptr +#else + inc dps + movx a, @dptr + inc dptr + dec dps + movx @dptr, a + inc dptr +#endif + + djnz r2, _memcpyx_loopTop + djnz r3, _memcpyx_loopTop + +_memcpy_done: + +#ifdef AUTO_TOGGLE + mov dps, #0x0 +#endif + + pop dpl + pop dph + pop dpx + ret +__endasm; + +} diff --git a/device/lib/ds390/putchar.c b/device/lib/ds390/putchar.c new file mode 100644 index 0000000..51d0fe8 --- /dev/null +++ b/device/lib/ds390/putchar.c @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------- + putchar.c - putchar implementation for DS80C390 + + Copyright (C) 2006, Maarten Brock, sourceforge.brock@dse.nl + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + + +#include <tinibios.h> +#include <stdio.h> + +int putchar (int c) +{ + Serial0PutChar(c); + return(c); +} + +extern int getchar(void) +{ + return Serial0GetChar(); +} + diff --git a/device/lib/ds390/rtc390.c b/device/lib/ds390/rtc390.c new file mode 100644 index 0000000..9910f0d --- /dev/null +++ b/device/lib/ds390/rtc390.c @@ -0,0 +1,111 @@ +/*------------------------------------------------------------------------- + rtc390.c - rtc routines for the DS1315 (tested on TINI) + + Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl> + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#include <tinibios.h> +#include <stdio.h> +#include <time.h> +#include <ctype.h> + +/* this is the address of the ds1315 phantom time chip, although + it doesn't really matter as long as it's in the 300000-3fffff + range since the chip only uses CE3* +*/ + +__xdata __at (0x310000) static volatile unsigned char rtc; + +// this is the 64bit pattern that has to be recognized by the ds1315 +__code unsigned char rtcMagic[8]={0xc5,0x3a,0xa3,0x5c,0xc5,0x3a,0xa3,0x5c}; + +#define BCDtoINT(x) (((x)&0x0f)+((x)>>4)*10) +#define INTtoBCD(x) (((x)%10)+(((x)/10)<<4)) + +static void RtcSync(void) { + unsigned char dummy, byte,bitMask; + + // reset rtc chip + dummy=rtc; + + // say the magic word + for (byte=0; byte<8; byte++) { + for (bitMask=0x01; bitMask; bitMask<<=1) { + rtc = (rtcMagic[byte]&bitMask) ? 0xff : 0x00; + } + } +} + +unsigned char RtcRead(struct tm *rtcDate) { + unsigned char rtcBytes[8]; + unsigned char byte,bitMask; + + RtcSync(); + + for (byte=0; byte<8; byte++) { + rtcBytes[byte]=0; + for (bitMask=0x01; bitMask; bitMask<<=1) { + if (rtc&1) { + rtcBytes[byte]|=bitMask; + } + } + } + rtcDate->tm_year=BCDtoINT(rtcBytes[7])+100; // year since 1900 + rtcDate->tm_mon=BCDtoINT(rtcBytes[6])-1; // jan=0 + rtcDate->tm_mday=BCDtoINT(rtcBytes[5]); + rtcDate->tm_wday=(rtcBytes[4]&0x07)-1; // monday=0? + rtcDate->tm_hour=BCDtoINT(rtcBytes[3]); + rtcDate->tm_min=BCDtoINT(rtcBytes[2]); + rtcDate->tm_sec=BCDtoINT(rtcBytes[1]); + rtcDate->tm_hundredth=BCDtoINT(rtcBytes[0]); + if ((rtcBytes[4]&0x30) || (rtcBytes[3]&0x80)) { + //oscillator not running, reset not active or in 12h mode + return 0; + } + return 1; +} + +void RtcWrite(struct tm *rtcDate) { + unsigned char rtcBytes[8]; + unsigned char byte,bitMask; + + rtcBytes[7]=INTtoBCD(rtcDate->tm_year%100); + rtcBytes[6]=INTtoBCD(rtcDate->tm_mon)+1; + rtcBytes[5]=INTtoBCD(rtcDate->tm_mday); + rtcBytes[4]=(INTtoBCD(rtcDate->tm_wday)+1)&0x07; //set 24h mode + rtcBytes[3]=INTtoBCD(rtcDate->tm_hour)&0x3f; // oscilator on, reset on + rtcBytes[2]=INTtoBCD(rtcDate->tm_min); + rtcBytes[1]=INTtoBCD(rtcDate->tm_sec); + //rtcBytes[0]=INTtoBCD(rtcDate->hundredth); + rtcBytes[0]=0; + + RtcSync(); + + for (byte=0; byte<8; byte++) { + for (bitMask=0x01; bitMask; bitMask<<=1) { + rtc = (rtcBytes[byte]&bitMask) ? 0xff : 0x00; + } + } +} diff --git a/device/lib/ds390/setjmp.c b/device/lib/ds390/setjmp.c new file mode 100644 index 0000000..0bb4ec4 --- /dev/null +++ b/device/lib/ds390/setjmp.c @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + setjmp.c - source file for ANSI routines setjmp & longjmp + + Copyright (C) 1999, Sandeep Dutta . sandeep.dutta@usa.net + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#include <ds80c390.h> +#include <sdcc-lib.h> +#define __SDCC_HIDE_LONGJMP +#include <setjmp.h> + +int __setjmp (jmp_buf buf) +{ + unsigned char sp, esp; + unsigned long lsp; + + /* registers would have been saved on the + stack anyway so we need to save SP + and the return address */ + __critical { + sp = SP; + esp = ESP; + } + lsp = sp; + lsp |= (unsigned int)(esp << 8); + lsp |= 0x400000; + *buf++ = lsp; + *buf++ = lsp >> 8; + *buf++ = *((unsigned char __xdata *) lsp - 0); + *buf++ = *((unsigned char __xdata *) lsp - 1); + *buf++ = *((unsigned char __xdata *) lsp - 2); + return 0; +} + +int longjmp (jmp_buf buf, int rv) +{ + unsigned long lsp; + + lsp = *buf++; + lsp |= (unsigned int)(*buf++ << 8); + lsp |= 0x400000; + *((unsigned char __xdata *) lsp - 0) = *buf++; + *((unsigned char __xdata *) lsp - 1) = *buf++; + *((unsigned char __xdata *) lsp - 2) = *buf++; + __critical { + SP = lsp; + ESP = lsp >> 8; + } + return rv ? rv : 1; +} diff --git a/device/lib/ds390/tinibios.c b/device/lib/ds390/tinibios.c new file mode 100644 index 0000000..8c38d97 --- /dev/null +++ b/device/lib/ds390/tinibios.c @@ -0,0 +1,571 @@ +/*------------------------------------------------------------------------- + tinibios.c - startup and serial routines for the DS80C390 (tested on TINI) + + Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl> + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#include <tinibios.h> +#include <stdio.h> + +#define TIMED_ACCESS(sfr,value) { TA=0xaa; TA=0x55; sfr=value; } + +unsigned char _sdcc_external_startup(void) +{ + IE=0; // disable ALL interrupts + + // use A19..16 and !CE3..0, no CAN + TIMED_ACCESS(P4CNT,0x3f); + + // use !PCE3..0, serial 1 at P5.2/3 + TIMED_ACCESS(P5CNT,0x27); + + // disable watchdog + EWT=0; + + // watchdog set to 9.1 seconds + // CKCON|=0xc0; + + // default stretch cycles for MOVX + //CKCON = (CKCON&0xf8)|(CPU_MOVX_STRETCH&0x07); + CKCON=0xf9; + + // use internal 4k RAM as data(stack) memory at 0x400000 and + // move CANx memory access to 0x401000 and upwards + // use !CE* for program and/or data memory access + TIMED_ACCESS(MCON,0xaf); + + // select default cpu speed + CpuSpeed(CPU_SPEED); + + // Copy the Interrupt Vector Table (128 bytes) from 0x10000 to 0x100000 + // This isn't needed for older bootloaders than the 0515, but it won't harm + __asm + push dpx + push dph + push dpl + push dps + push b + push acc + mov dps,#0x00 ; make sure no autoincrement in progress + mov dptr,#0x10000 ; from + inc dps ; switch to alternate dptr + mov dptr,#0x100000 ; to + mov b,#0x80 ; count + +_Startup390CopyIVT: + inc dps + movx a,@dptr + inc dptr + inc dps + movx @dptr,a + inc dptr + djnz b,_Startup390CopyIVT + + pop acc + pop b + pop dps + pop dpl + pop dph + pop dpx + __endasm; + + // global interrupt enable, all masks cleared + // let the Gods be with us :) + IE = 0x80; + + Serial0Init(SERIAL_0_BAUD,1); + //Serial1Init(SERIAL_1_BAUD,1); + ClockInit(); + //RtcInit(); + //WatchDogInit(); + + // signal _sdcc_gsinit_startup to initialize data (call _sdcc_init_data) + return 0; +} + +/* Set the cpu speed in clocks per machine cycle, valid values are: + 1024: Power management mode + 4: Divide-by-4 mode + 2: Use frequency multiplier (2x) + 1: Use frequency multiplier (4x) (Don't do this on a TINI at 18.432MHz) + + TODO: TINI seems to support only 2 and 4: write only bits in PMR ? +*/ + +unsigned int cpuSpeed; + +void CpuSpeed(unsigned int speed) +{ +#if 0 + while (0 && (EXIF&0x04)) + ; // cpu operates from ring buffer +#endif + PMR = 0x80; // div4, CTM off, multiplier 2x + switch (speed) + { + case 1: + PMR=0x88; // div4, CTM off, multiplier 4x + PMR=0x98; // div4, CTM on, multiplier 4x + while ((EXIF&0x08)==0) { + ; // wait for the multiplier to be ready + } + PMR = 0x18; // use multiplier + cpuSpeed=speed; + break; + case 2: + PMR=0x90; // div4, CTM on, multilier 2x + while ((EXIF&0x08)==0) { + ; // wait for the multiplier to be ready + } + PMR = 0x10; // use multiplier + cpuSpeed=speed; + break; + case 4: + // nothing to do + cpuSpeed=speed; + break; + case 1024: + PMR = 0xc0; // div1024, CTM off + cpuSpeed=speed; + break; + } +} + +// now the serial0 stuff + +// just to make the code more readable +#define S0RBS SERIAL_0_RECEIVE_BUFFER_SIZE + +// this is a ring buffer and can overflow at anytime! +static volatile unsigned char receive0Buffer[S0RBS]; +static volatile int receive0BufferHead=0; +static volatile int receive0BufferTail=0; +// no buffering for transmit +static volatile char transmit0IsBusy=0; + +static __data unsigned char serial0Buffered; + +/* Initialize serial0. + + Available baudrates are from 110 upto 115200 (using 16-bit timer 2) + If baud==0, the port is disabled. + + If buffered!=0, characters received are buffered using an interrupt +*/ + +void Serial0Init (unsigned long baud, unsigned char buffered) +{ + if (baud==0) { + ES0=0; // disable interrupts + SCON0 &= 0xef; // disable receiver + return; + } + + ES0 = 0; // disable serial channel 0 interrupt + TR2 = 0; // stop timer 2 + + // set 8 bit uart with variable baud from timer 1/2 + // enable receiver and clear RI and TI + SCON0 = 0x50; + + PCON |= 0x80; // clock is 16x bitrate + CKCON|=0x20; // timer uses xtal/4 + + T2MOD=0; // no fancy functions + T2CON=0x34; // start timer as a baudrate generator for serial0 + + // set the baud rate + Serial0Baud(baud); + + serial0Buffered=buffered; + + if (buffered) { + RI_0=TI_0=0; // clear "pending" interrupts + ES0 = 1; // enable serial channel 0 interrupt + } else { + RI_0=0; // receive buffer empty + TI_0=1; // transmit buffer empty + } +} + +void Serial0Baud(unsigned long baud) +{ + TR2=0; // stop timer + baud=-((long)OSCILLATOR/(32*baud)); + TL2=RCAP2L= baud; + TH2=RCAP2H= baud>>8; + TF2=0; // clear overflow flag + TR2=1; // start timer +} + +void Serial0IrqHandler (void) __interrupt 4 +{ + if (RI_0) { + receive0Buffer[receive0BufferHead]=SBUF0; + receive0BufferHead=(receive0BufferHead+1)&(S0RBS-1); + if (receive0BufferHead==receive0BufferTail) { + /* buffer overrun, sorry :) */ + receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1); + } + RI_0=0; + } + if (TI_0) { + TI_0=0; + transmit0IsBusy=0; + } +} + +char Serial0CharArrived(void) +{ + if (serial0Buffered) { + if (receive0BufferHead!=receive0BufferTail) + return receive0Buffer[receive0BufferTail]; + } else { + if (RI_0) + return SBUF0; + } + return 0; +} + +void Serial0PutChar (char c) +{ + if (serial0Buffered) { + while (transmit0IsBusy) + ; + transmit0IsBusy=1; + SBUF0=c; + } else { + while (!TI_0) + ; + SBUF0=c; + TI_0=0; + } +} + +char Serial0GetChar (void) +{ + char c; + if (serial0Buffered) { + while (receive0BufferHead==receive0BufferTail) + ; + c=receive0Buffer[receive0BufferTail]; + ES0=0; // disable serial interrupts + receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1); + ES0=1; // enable serial interrupts + } else { + while (!RI_0) + ; + c=SBUF0; + RI_0=0; + } + return c; +} + +void Serial0SendBreak() +{ + P3 &= ~0x02; + ClockMilliSecondsDelay(2); + P3 |= 0x02; +} + +void Serial0Flush() +{ + ES0=0; // disable interrupts + receive0BufferHead=receive0BufferTail=0; + RI_0=0; + if (serial0Buffered) { + TI_0=0; + ES0=1; // enable interrupts + } else { + TI_0=1; + } +} + +/* now let's go for the serial1 stuff, basically it's a replicate of + serial0 except it uses timer 1 +*/ + +// just to make the code more readable +#define S1RBS SERIAL_1_RECEIVE_BUFFER_SIZE + +// this is a ring buffer and can overflow at anytime! +static volatile unsigned char receive1Buffer[S1RBS]; +static volatile int receive1BufferHead=0; +static volatile int receive1BufferTail=0; +// no buffering for transmit +static volatile char transmit1IsBusy=0; + +static __data unsigned char serial1Buffered; + +/* Initialize serial1. + + Available baudrates are from 4800 upto 115200 (using 8-bit timer 1) + If baud==0, the port is disabled. + + If buffered!=0, characters received are buffered using an interrupt +*/ + +void Serial1Init (unsigned long baud, unsigned char buffered) +{ + if (baud==0) { + ES1=0; // disable interrupt + SCON1 &= 0xef; // disable receiver + return; // and don't touch it + } + + ES1 = 0; // disable channel 1 interrupt + TR1 = 0; // stop timer 1 + + // set 8 bit uart with variable baud from timer 1 + // enable receiver and clear RI and TI + SCON1 = 0x50; + + WDCON |= 0x80; // clock is 16x bitrate + CKCON|=0x10; // timer uses xtal/4 + + TMOD = (TMOD&0x0f) | 0x20; // timer 1 is an 8bit auto-reload counter + + // set the baud rate + Serial1Baud(baud); + + serial1Buffered=buffered; + + if (buffered) { + RI_1=TI_1=0; // clear "pending" interrupts + ES1 = 1; // enable serial channel 1 interrupt + } else { + RI_1=0; // receive buffer empty + TI_1=1; // transmit buffer empty + } +} + +void Serial1Baud(unsigned long baud) +{ + TR1=0; // stop timer + baud=-((long)OSCILLATOR/(32*baud)); + TL1=TH1 = baud; + TF1=0; // clear overflow flag + TR1=1; // start timer +} + +void Serial1IrqHandler (void) __interrupt 7 +{ + if (RI_1) { + receive1Buffer[receive1BufferHead]=SBUF1; + receive1BufferHead=(receive1BufferHead+1)&(S1RBS-1); + if (receive1BufferHead==receive1BufferTail) /* buffer overrun, sorry :) */ + receive1BufferTail=(receive1BufferTail+1)&(S1RBS-1); + RI_1=0; + } + if (TI_1) { + TI_1=0; + transmit1IsBusy=0; + } +} + +char Serial1CharArrived(void) +{ + if (serial1Buffered) { + if (receive1BufferHead!=receive1BufferTail) + return receive1Buffer[receive1BufferTail]; + } else { + if (RI_1) + return SBUF1; + } + return 0; +} + +void Serial1PutChar (char c) +{ + if (serial1Buffered) { + while (transmit1IsBusy) + ; + transmit1IsBusy=1; + SBUF1=c; + } else { + while (!TI_1) + ; + SBUF1=c; + TI_1=0; + } +} + +char Serial1GetChar (void) +{ + char c; + if (serial1Buffered) { + while (receive1BufferHead==receive1BufferTail) + ; + c=receive1Buffer[receive1BufferTail]; + ES1=0; // disable serial interrupts + receive1BufferTail=(receive1BufferTail+1)&(S1RBS-1); + ES1=1; // enable serial interrupts + } else { + while (!RI_1) + ; + c=SBUF1; + RI_1=0; + } + return c; +} + +void Serial1SendBreak() +{ + P5 &= ~0x08; + ClockMilliSecondsDelay(2); + P5 |= 0x08; +} + +void Serial1Flush() +{ + ES1=0; // disable interrupts + receive1BufferHead=receive1BufferTail=0; + RI_1=0; + if (serial1Buffered) { + TI_1=0; + ES1=1; // enable interrupts + } else { + TI_1=1; + } +} + +// now let's go for the clock stuff + +// these REALLY need to be in data space for the irq routine! +static __data unsigned long milliSeconds=0; +static __data unsigned int timer0ReloadValue; + +void ClockInit() +{ + unsigned long timerReloadValue=OSCILLATOR/1000; + + switch (cpuSpeed) { + case 4: timerReloadValue/=4; break; + case 1: // not tested yet + case 2: // not tested yet + default: timerReloadValue/=2; break; + } + timer0ReloadValue=~timerReloadValue; + // initialise timer 0 + ET0=0; // disable timer interrupts initially + TCON = (TCON&0xcc)|0x00; // stop timer, clear overflow + TMOD = (TMOD&0xf0)|0x01; // 16 bit counter + CKCON|=0x08; // timer uses xtal/4 + + TL0=timer0ReloadValue&0xff; + TH0=timer0ReloadValue>>8; + + ET0=1; // enable timer interrupts + TR0=1; // start timer +} + +// This needs to be SUPER fast. What we really want is: + +#if 0 +void junk_ClockIrqHandler (void) __interrupt 10 +{ + TL0 = timer0ReloadValue & 0xff; + TH0 = timer0ReloadValue >> 8; + milliSeconds++; +} +#else +// but look at the code, and the pushes and pops, so: +void ClockIrqHandler (void) __interrupt 1 __naked +{ + __asm + push acc + push psw + mov _TL0,_timer0ReloadValue + mov _TH0,_timer0ReloadValue+1 + clr a + inc _milliSeconds+0 + cjne a,_milliSeconds+0,_ClockIrqHandlerDone + inc _milliSeconds+1 + cjne a,_milliSeconds+1,_ClockIrqHandlerDone + inc _milliSeconds+2 + cjne a,_milliSeconds+2,_ClockIrqHandlerDone + inc _milliSeconds+3 + _ClockIrqHandlerDone: + pop psw + pop acc + reti + __endasm; +} +#endif + +// we can't just use milliSeconds +unsigned long ClockTicks(void) +{ + unsigned long ms; + ET0=0; + ms=milliSeconds; + ET0=1; + return ms; +} + +void ClockMilliSecondsDelay(unsigned long delay) +{ + long ms=ClockTicks()+delay; + + while (ms>ClockTicks()) + ; +} + +// stolen from Kevin Vigor, works only for TINI at default speed +void ClockMicroSecondsDelay(unsigned int delay) +{ + delay; /* shut compiler up. */ + + __asm + + ; delay is in dpl/dph + mov r0, dpl + mov r1, dph + + mov a, r0 + orl a, r1 ; quick out for zero case. + jz _usDelayDone + + inc r1 + cjne r0, #0, _usDelayLoop + dec r1 + + _usDelayLoop: + nop + nop + nop + nop + nop + nop + nop ; 7 nops + djnz r0, _usDelayLoop ; 3 cycles x 1 = 3 cycles + ; 10 cycles per iter + ; we want 9.216, but more is better + ; than less. + djnz r1, _usDelayLoop + _usDelayDone: + + __endasm; +} |
