#BAUD = 115200
DRAM_8BIT = 1
+#I2C = 1
TARGET = avrcpm
ASRC0 = avrcpm.asm
ASRC0 += 8080int-orig.asm 8080int.asm 8080int-jmp.asm 8080int-t3.asm 8080int-t3-jmp.asm Z80int-jmp.asm
ifneq ($(DRAM_8BIT),0)
- ASRC0 += dram-8bit.inc dram-8bit.asm sw-uart.asm
+ ASRC0 += dram-8bit.inc dram-8bit.asm sw-uart.asm i2c.asm
else
ASRC0 += dram-4bit.inc dram-4bit.asm hw-uart.asm
endif
ASRC := $(ASRC0) svnrev.inc
# Place -D or -U options here
-CDEFS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(MCU) -DDRAM_8BIT=$(DRAM_8BIT)
+CDEFS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(MCU) -DDRAM_8BIT=$(DRAM_8BIT)
+ifdef I2C
+ CDEFS += -DI2C=$(I2C)
+endif
ASPATH = C:/Programme/Atmel/AVR\ Tools/AvrAssembler2
DEFS = $(ASPATH)/Appnotes
.org INT_VECTORS_SIZE
.include "init.asm"
-#if DRAM_8BIT /* Implies software uart */
+#if DRAM_8BIT /* Implies software uart */
.include "sw-uart.asm"
.include "dram-8bit.asm"
-#else /* 4 bit RAM, hardware uart */
+ .include "i2c.asm"
+#else /* 4 bit RAM, hardware uart */
.include "hw-uart.asm"
.include "dram-4bit.asm"
#endif
#ifndef BAUD
#define BAUD 38400 /* console baud rate */
#endif
-
-#define K 1024
-#define M 1024*K
-
-;#define RAMSIZE 256*K*4 /* 1 chip 256Kx4 */
-#define RAMSIZE 4*M*4 * 2 /* 2 chips 4Mx4 */
+#ifndef I2C
+ #define I2C DRAM_8BIT /* I2C requires 8 bit DRAM */
+#endif
+#if I2C && !DRAM_8BIT
+ #error "I2C requires 8 bit DRAM (DRAM_8BIT=1)!"
+#endif
-#define EM_Z80 1 /* Emulate Z80 if true */
+#define EM_Z80 1 /* Emulate Z80 if true, else 8080 */
#ifndef FAT16_SUPPORT
#define FAT16_SUPPORT 1 /* Include Support for FAT16 Partitions */
#define RXBUFSIZE 128 /* USART recieve buffer size. Must be power of 2 */
#define TXBUFSIZE 128 /* USART transmit buffer size. Must be power of 2 */
+#define I2C_CLOCK 100000 /* 100kHz */
+#define I2C_BUFSIZE 17 /* largest message size including address byte (SLA) */
-#if EM_Z80
- #define CPUSTR "Z80"
-#else
- #define CPUSTR "8080"
-#endif
.equ BOOTWAIT = 1
.equ MEMTEST = 1
#define DBG_TRACE_BOTTOM 0x01 /* Page boundaries for INS_DEBUG and PRINT_PC */
#define DBG_TRACE_TOP 0xdc /* Trace is off, below bottom page and above top page. */
+#if EM_Z80
+ #define CPUSTR "Z80"
+#else
+ #define CPUSTR "8080"
+#endif
+
;-----------------------------------------------------------------------
; Port declarations
#define startTraceCmd 1
#define stopTraceCmd 0
+; Virtual I2C Interface
+#define I2CSTAT 0x05
+#define I2CCTRL 0x05
+#define I2CBLEN 0x06
+#define I2CADR 0x07
+#define I2CADRL 0x07
+#define I2CADRH 0x08
+
+; Port-Expander PCF8574
+#define PORT 0x80
+#define PORT0 0x80
+#define PORT1 0x81
+#define PORT2 0x82
+#define PORT3 0x83
+#define PORT4 0x84
+#define PORT5 0x85
+#define PORT6 0x86
+#define PORT7 0x87
+
#if defined __ATmega8__
.equ RXTXDR0 = UDR
; vim:set ts=8 noet nowrap
-
--- /dev/null
+; I2C (TWI) master interface.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+;
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm 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 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm 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 avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+#if I2C
+
+/* General TWI Master status codes */
+#define TWI_START 0x08 /* START has been transmitted */
+#define TWI_REP_START 0x10 /* Repeated START has been transmitted */
+#define TWI_ARB_LOST 0x38 /* Arbitration lost */
+
+/* TWI Master Transmitter status codes */
+#define TWI_MTX_ADR_ACK 0x18 /* SLA+W has been transmitted and ACK received */
+#define TWI_MTX_ADR_NACK 0x20 /* SLA+W has been transmitted and NACK received */
+#define TWI_MTX_DATA_ACK 0x28 /* Data byte has been transmitted and ACK received */
+#define TWI_MTX_DATA_NACK 0x30 /* Data byte has been transmitted and NACK received */
+
+/* TWI Master Receiver status codes */
+#define TWI_MRX_ADR_ACK 0x40 /* SLA+R has been transmitted and ACK received */
+#define TWI_MRX_ADR_NACK 0x48 /* SLA+R has been transmitted and NACK received */
+#define TWI_MRX_DATA_ACK 0x50 /* Data byte has been received and ACK transmitted */
+#define TWI_MRX_DATA_NACK 0x58 /* Data byte has been received and NACK transmitted */
+
+/* TWI Miscellaneous status codes */
+#define TWI_NO_STATE 0xF8 /* No relevant state information available */
+#define TWI_BUS_ERROR 0x00 /* Bus error due to an illegal START or STOP condition */
+
+
+#define I2C_BR ((F_CPU / (2 * I2C_CLOCK)) - 8) /* I2C Bit Rate */
+
+;----------------------------------------------------------------------
+;
+; TWINT: TWI Interrupt Flag
+; TWEA: TWI Enable Acknowledge Bit
+; TWSTA: TWI START Condition Bit
+; TWSTO: TWI STOP Condition Bit
+; TWEN: TWI Enable Bit
+; TWIE: TWI Interrupt Enable
+;
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)| (1<<TWEA)
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+;
+; default:
+; (1<<TWEN)| (1<<TWINT)| (1<<TWSTO)
+;
+; Init:
+; (1<<TWEN)
+;
+; start read/write:
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+;
+; wait ready:
+; (1<<TWIE)|(1<<TWSTO)
+;
+;----------------------------------------------------------------------
+
+ .dseg
+
+i2c_var:
+i2ci_idx:
+ .byte 1
+i2c_result:
+ .byte 1
+i2c_bufcnt:
+ .byte 1
+i2c_buf:
+ .byte I2C_BUFSIZE
+
+ .equ oi2ci_idx = 0
+ .equ oi2c_result = 1
+ .equ oi2c_bufcnt = 2
+ .equ oi2c_buf = 3
+
+;------------------------------------------------------------------
+
+ .cseg
+
+
+ INTERRUPT TWIaddr
+
+ push temp
+ in temp,sreg
+ push temp
+ push temp2
+ push zh
+ push zl
+
+ ldiw z,i2c_var
+ ldd temp2,z+oi2ci_idx
+
+ inm8 temp,TWSR
+
+ cpi temp,TWI_START
+ breq i2ci_START
+ cpi temp,TWI_REP_START
+ breq i2ci_REP_START
+ cpi temp,TWI_MTX_ADR_ACK
+ breq i2ci_MTX_ADR_ACK
+ cpi temp,TWI_MTX_DATA_ACK
+ breq i2ci_MTX_DATA_ACK
+ cpi temp,TWI_MRX_ADR_ACK
+ breq i2ci_MRX_ADR_ACK
+ cpi temp,TWI_MRX_DATA_ACK
+ breq i2ci_MRX_DATA_ACK
+ cpi temp,TWI_MRX_DATA_NACK
+ breq i2ci_MRX_DATA_NACK
+ rjmp i2ci_default
+
+i2ci_START:
+i2ci_REP_START:
+ clr temp2 ;reset buffer pointer
+i2ci_MTX_ADR_ACK:
+i2ci_MTX_DATA_ACK:
+ ldd temp,z+oi2c_bufcnt
+ cp temp2,temp
+ brsh i2ci_12
+ add zl,temp2
+ adc zh,_0
+ inc temp2
+ ldd temp,z+oi2c_buf
+ outm8 TWDR,temp
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ rjmp i2ci_end
+
+i2ci_12:
+ std z+oi2c_result,_255
+ rjmp i2ci_default
+
+i2ci_MRX_DATA_ACK:
+ add zl,temp2
+ adc zh,_0
+ inc temp2
+ inm8 temp,TWDR
+ std z+oi2c_buf,temp
+i2ci_MRX_ADR_ACK:
+ lds temp,i2c_bufcnt
+ dec temp
+ cp temp2,temp
+ brsh i2ci_32
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)
+ rjmp i2ci_end
+i2ci_32:
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ rjmp i2ci_end
+
+i2ci_MRX_DATA_NACK:
+ std z+oi2c_result,_255 ;result = 1
+ add zl,temp2
+ adc zh,_0
+ inm8 temp,TWDR
+ std z+oi2c_buf,temp
+; fall thru
+
+i2ci_default:
+ ldi temp,(1<<TWEN)|(1<<TWINT)|(1<<TWSTO)
+
+i2ci_end:
+ outm8 TWCR,temp
+ sts i2ci_idx,temp2
+ pop zl
+ pop zh
+ pop temp2
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+
+;------------------------------------------------------------------
+
+i2c_init:
+ ldi temp,I2C_BR
+ outm8 TWBR,temp
+ outm8 TWDR,_255 ;
+ ldi temp,(1<<TWEN) ;Enable TWI, disable Interupts.
+ outm8 TWCR,temp
+
+ ldi temp,1
+ sts i2c_result,temp
+ ret
+
+;------------------------------------------------------------------
+
+i2c_waitready:
+ push temp
+i2c_b:
+ inm8 temp,TWCR
+ andi temp,(1<<TWIE)|(1<<TWSTO)
+ brne i2c_b
+ pop temp
+ ret
+
+;------------------------------------------------------------------
+;
+; z: Pointer to the data to write.
+; First byte is slave address
+; temp2: Number of bytes to write including address byte.
+;
+
+i2c_write:
+ rcall i2c_waitready
+
+ push zh
+ push zl
+ push xh
+ push xl
+
+#if 0
+ rcall printstr
+ .db '\r', 'W', 0,0
+ mov temp,temp2
+ rcall printhex
+ rcall printstr
+ .db ": ", 0,0
+ rcall dbg_hexdump_line
+#endif
+
+ ldiw x,i2c_result
+ st x+,_0 ;result = 0
+ st x+,temp2 ;store size
+ ld temp,z+
+ cbr temp,0x01
+i2c_wl:
+ st x+,temp
+ dec temp2
+ breq i2c_wle
+ ld temp,z+
+ rjmp i2c_wl
+i2c_wle:
+ ; Enable TWI, TWI int and initiate start condition
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ outm8 TWCR,temp
+
+ pop xl
+ pop xh
+ pop zl
+ pop zh
+ ret
+
+
+;------------------------------------------------------------------
+;
+; z: Pointer to data buffer.
+; First byte of buffer is slave address
+; temp2: Number of bytes to write including address byte.
+;
+; temp: return (fail = 0, else succsess)
+
+i2c_read:
+ rcall i2c_waitready
+
+ push zh
+ push zl
+ push xh
+ push xl
+ ldiw x,i2c_result
+ st x+,_0 ;result = 0
+ st x+,temp2 ;store size
+ ld temp,z
+ sbr temp,0x01
+ st x,temp
+
+ ; Enable TWI, TWI int and initiate start condition
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ outm8 TWCR,temp
+
+ rcall i2c_waitready
+
+#if 0
+ rcall printstr
+ .db '\r', 'R', 0,0
+ mov temp,temp2
+ rcall printhex
+ rcall printstr
+ .db ": ", 0,0
+#endif
+
+ lds temp,i2c_result
+ tst temp
+ breq i2c_ex ;
+i2c_rl:
+ ld temp,x+
+ st z+,temp
+ dec temp2
+ brne i2c_rl
+
+i2c_ex:
+ lds temp,i2c_result
+ pop xl
+ pop xh
+ pop zl
+ pop zh
+#if 0
+ rcall dbg_hexdump_line
+#endif
+ ret
+
+;------------------------------------------------------------------
+
+ .dseg
+
+vi2c_stat:
+ .byte 1
+vi2c_blen:
+ .byte 1
+vi2c_addr:
+ .byte 2
+
+ .cseg
+
+vi2c_stat_get:
+ lds temp,vi2c_stat
+ ret
+
+vi2c_param_get:
+ ldiw z,vi2c_blen
+ add zl,temp3
+ adc zh,_0
+ ld temp,z
+ ret
+
+vi2c_param_set:
+ ldiw z,vi2c_blen
+ add zl,temp3
+ adc zh,_0
+ st z,temp
+ ret
+
+;------------------------------------------------------------------
+;
+; x: Pointer to the data buffer.
+; First byte is slave address
+; temp3: Number of bytes to write including address byte.
+;
+
+vi2c_read:
+ rcall i2c_waitready
+
+ ldiw z,i2c_var
+ std z+oi2c_result,_0 ;result = 0
+ lds temp3,vi2c_blen
+ std z+oi2c_bufcnt,temp3 ;store size
+ adiw z,oi2c_buf
+ ldsw x,vi2c_addr
+ lcall dram_read_pp
+ sbr temp,0x01
+ st z+,temp
+ dec temp3
+
+ ; Enable TWI, TWI int and initiate start condition
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ outm8 TWCR,temp
+
+ rcall i2c_waitready
+
+ lds temp,i2c_result
+ tst temp
+ breq vi2c_ex ;
+vi2c_rl:
+ ld temp,z+
+ lcall dram_write_pp
+ dec temp3
+ brne vi2c_rl
+
+vi2c_ex:
+ ret
+
+;------------------------------------------------------------------
+;
+; x: Pointer to the data to write.
+; First byte is slave address
+; temp2: Number of bytes to write including address byte.
+;
+
+vi2c_write:
+ rcall i2c_waitready
+ ldiw z,i2c_var
+ std z+oi2c_result,_0 ;result = 0
+ lds temp3,vi2c_blen
+ std z+oi2c_bufcnt,temp3 ;store size
+ adiw z,oi2c_buf
+ ldsw x,vi2c_addr
+ lcall dram_read_pp
+ cbr temp,0x01
+vi2c_wl:
+ st z+,temp
+ dec temp3
+ breq vi2c_wle
+ lcall dram_read_pp
+ rjmp vi2c_wl
+vi2c_wle:
+ ; Enable TWI, TWI int and initiate start condition
+ ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ outm8 TWCR,temp
+
+ ret
+
+
+vi2c_ctrl:
+ cpi temp,1
+ brne vi2c_c1
+ rcall vi2c_read
+ rjmp vi2c_ce0
+vi2c_c1:
+ cpi temp,2
+ breq vi2c_c2
+ ldi temp,0xff
+ rjmp vi2c_ce
+vi2c_c2:
+ rcall vi2c_write
+vi2c_ce0:
+ lds temp,i2c_result
+ com temp
+vi2c_ce:
+ sts vi2c_stat,temp
+ ret
+
+;------------------------------------------------------------------
+
+
+pcf8574_in:
+ ; make a buffer on stack
+ push _255 ;place holder for input value
+ in zh,sph
+ in zl,spl
+ ldi temp,0x20 ;pcf8574 address (7 bit)
+ add temp,temp3
+ lsl temp
+ push temp ;slave address
+ ldi temp2,2
+ rcall i2c_read
+ pop temp ;remove slave address from stack
+ pop temp ;return input value
+ ret
+
+pcf8574_out:
+ ; make a buffer on stack
+ push temp ;output value
+ in zh,sph
+ in zl,spl
+ ldi temp,0x20 ;pcf8574 address (7 bit)
+ add temp,temp3
+ lsl temp
+ push temp ;slave address
+ ldi temp2,2
+ rcall i2c_write
+ pop temp ;remove buffer from stack
+ pop temp ;
+ ret
+
+
+#endif /* I2C */
+;------------------------------------------------------------------
+; vim:set ts=8 noet nowrap
+
cpc zh,temp2
brne clr_l
-
; Init clock/timer system
; Init timer 1 as 1 ms system clock tick.
sei
+#if I2C
+ rcall i2c_init ; Init I2C master
+ rcall rtc_get
+#endif
+
.if BOOTWAIT
ldi temp,10
.equ timerofs = cnt_1ms-timer_ms
clk_out:
- .byte 6 ;
+ .byte 7 ;
clock:
- .byte 6 ;Format (bin): Y M D H M S
+ .byte 7 ;Format (bin): s m h D M YY
.equ clkofs = clock-clk_out
.cseg
outm8 OCR1BL,zl
#if DRAM_8BIT /* Implies software uart */
- lds zl,srx_char_to
+ lds zl,srx_char_to ;try to decrement character timout
subi zl,1
- brcs syscl0
- sts srx_char_to,zl
- brne syscl0
+ brcs syscl0 ;timer was 0 before (not running)
+ sts srx_char_to,zl ;timer is running, store new value
+ brne syscl0
rcall srx_to
syscl0:
#endif
subi zl,1
brcs syscl_t2n
sts delay_timer2,zl
-syscl_t2n:
- lds zl,cnt_1ms
+syscl_t2n:
+
+ lds zl,cnt_1ms ;count milli seconds
lds zh,cnt_1ms+1
adiw z,1
-
sts cnt_1ms,zl
sts cnt_1ms+1,zh
- cpi zl,low(1000)
- ldi zl,high(1000) ;doesn't change flags
+ cpi zl,low(1000) ;one second ?
+ ldi zl,high(1000) ;doesn't change flags
cpc zh,zl
brge syscl_utime
rjmp syscl_end
sts uptime+3,zl
syscl_clk:
- lds zl,clock+5 ;sec
+ lds zl,clock+0 ;sec
inc zl
- sts clock+5,zl
+ sts clock+0,zl
cpi zl,60
brlo syscl_end
- sts clock+5,_0
- lds zl,clock+4 ;min
+ sts clock+0,_0
+ lds zl,clock+1 ;min
inc zl
- sts clock+4,zl
+ sts clock+1,zl
cpi zl,60
brlo syscl_end
- sts clock+4,_0
- lds zl,clock+3 ;hour
+ sts clock+1,_0
+ lds zl,clock+2 ;hour
inc zl
- sts clock+3,zl
+ sts clock+2,zl
cpi zl,24
- brlo syscl_end
- sts clock+3,_0
+ brsh syscl_clk_date
+ rjmp syscl_end
+
+syscl_clk_date:
+ sts clock+2,_0
push temp
ldiw z,dayspm_tab*2 - 1
- lds temp,clock+1 ;month
+ lds temp,clock+4 ;month
add zl,temp
adc zh,_0
lpm zh,z ;days this month
cpi temp,2
- brne syscl_clknf ;february, may be leap year
- lds zl,(clock+0) ;year
- andi zl,0xfc
+ brne syscl_clknl ;february, may be leap year
+ lds zl,(clock+5) ;year
+ andi zl,0x03
brne syscl_clknl
inc zh ;leap year
syscl_clknl:
-syscl_clknf:
- lds zl,clock+2 ;day
+ lds zl,clock+3 ;day
inc zl
- sts clock+2,zl
+ sts clock+3,zl
cp zh,zl
brsh syscl_clke
ldi zl,1
- sts clock+2,zl
+ sts clock+3,zl
inc temp ;month
- sts clock+1,temp
+ sts clock+4,temp
cpi temp,13
brlo syscl_clke
- sts clock+1,zl
- lds zl,clock+0 ;year
+ sts clock+4,zl
+ lds zl,clock+5 ;low year
inc zl
- sts clock+0,zl
+ sts clock+5,zl
+ brne syscl_clke
+ lds zl,clock+6 ;high year
+ inc zl
+ sts clock+6,zl
syscl_clke:
pop temp
; ----------------------------------------------
;
-
clockget:
- ldi temp,0xFF
- subi temp2,CLOCKPORT
- brcs clkget_end ;Port number in range?
ldiw z,clk_out
+ tst temp3
breq clkget_copy ;lowest byte requestet, latch clock
- cpi temp2,6
- brsh clkget_end ;Port number to high?
- add zl,temp2
+ add zl,temp3
adc zh,_0
ld temp,z
clkget_end:
ret
-
+
clkget_copy:
- ldi temp2,6
+ ldi temp3,7
cli
clkget_l:
ldd temp,z+clkofs
st z+,temp
- dec temp2
+ dec temp3
brne clkget_l
sei
+
+ ld temp2,-z
+ ld temp, -z
+ rcall binbcd4
+ std z+0,temp
+ std z+1,temp2
+ ldi temp3,5
+clkget_l2:
+ ld temp,-z
+ rcall binbcd2
+ st z,temp
+ dec temp3
+ brne clkget_l2
+
lds temp,clk_out
- ;req. byte in temp
- ret
+ ret ;req. byte in temp
+; ----------------------------------------------
+;
clockput:
- subi temp2,CLOCKPORT
- brcs clkput_end ;Port number in range?
-
ldiw z,clk_out
- breq clkput_copy ;lowest byte requestet, latch clock
- cpi temp2,6
- brsh clkput_end ;Port number to high?
-
- add zl,temp2
+ add zl,temp3
adc zh,_0
st z,temp
+ tst temp3
+ breq clkput_copy ;lowest byte stored, latch clock
clkput_end:
- ldiw z,clk_out
ret
+
clkput_copy:
- st z,temp
- ldi temp2,6
+ ldi temp3,5
+clkput_l2:
+ ld temp,z
+ rcall bcdbin2
+ st z+,temp
+ dec temp3
+ brne clkput_l2
+
+ ldd temp,z+0
+ ldd temp2,z+1
+ rcall bcdbin4
+ st z+,temp
+ st z+,temp2
+
+ ldi temp3,7
cli
clkput_l:
- ld temp,z+
- std z+clkofs-1,temp
- dec temp2
+ ld temp,-z
+ std z+clkofs,temp
+ dec temp3
brne clkput_l
sei
- ldiw z,clk_out
+#if I2C
+ rcall rtc_set ; set hardware clock
+#endif
+ ret
+
+
+; ----------------------------------------------
+
+; convert binary to bcd
+; (only range 0 - 99)
+
+binbcd2:
+ push temp2
+ ldi temp2,10
+ mov _tmp0,_255
+tobcd_l:
+ inc _tmp0
+ sub temp,temp2
+ brcc tobcd_l
+ add temp,temp2
+ swap _tmp0
+ add temp,_tmp0
+ pop temp2
+ ret
+
+
+binbcd4:
+ ldi temp3,16
+ mov _tmp0,temp
+ mov _tmp1,temp2
+ clr temp
+ clr temp2
+binbcd4l:
+ lsl _tmp0
+ rol _tmp1
+ rol temp
+ rol temp2
+ dec temp3
+ breq binbcd4e
+
+ subi temp2,-0x03
+ sbrs temp2,3
+ subi temp2,0x03
+ subi temp2,-0x30
+ sbrs temp2,7
+ subi temp2,0x30
+ subi temp,-0x03
+ sbrs temp,3
+ subi temp,0x03
+ subi temp,-0x30
+ sbrs temp,7
+ subi temp,0x30
+ rjmp binbcd4l
+
+binbcd4e:
+ ret
+
+; convert bcd to binary
+
+bcdbin2:
+ push temp2
+ mov temp2,temp ;temp2 = high digit
+ swap temp2
+ andi temp2,0x0f
+ andi temp,0x0f ;temp = low digit
+ mov _tmp0,temp2
+ ldi temp2,10
+ mul temp2,_tmp0 ;high digit * 10
+ add temp,_tmp0 ;high digit * 10 + low digit
+ pop temp2
+ ret
+
+bcdbin4:
+ rcall bcdbin2
+ push temp
+ mov temp,temp2
+ rcall bcdbin2
+ ldi temp2,100
+ mul temp,temp2
+ pop temp
+ mov temp2,_tmp1
+ add temp,_tmp0
+ adc temp2,_0
ret
+
+#if I2C
+
+; ----------------------------------------------
+; Set software clock from hardware clock
+
+rtc_get:
+ push _0 ;Placeholder for month/weekday
+ push _0 ;day/year
+ push _0 ;hours
+ push _0 ;minutes
+ ldi temp,0x10 ;register address
+ push temp ;save reg adr/placeholder for sec
+ in zh,sph
+ in zl,spl
+ ldi temp,0xA0 ;PCF8583 slave address
+ push temp
+
+ ldi temp2,2
+ rcall i2c_write
+ ldi temp2,3
+ rcall i2c_read ;get year (stored in RTC-RAM addr. 10h)
+ tst temp
+ breq rtc_get_e
+
+ ldd temp3,z+1 ;save year
+ ldd temp4,z+2
+
+ ldi temp2,2 ;register pointer. 2 = secs
+ std z+1,temp2
+ rcall i2c_write
+ ldi temp2,6
+ rcall i2c_read
+ tst temp
+ breq rtc_get_e
+
+ ldd temp,z+4 ;get year
+ rol temp
+ rol temp
+ rol temp
+ eor temp,temp3
+ andi temp,0x03
+ breq rtc_get_1
+ inc temp3
+ adc temp4,_0
+rtc_get_1:
+ ldiw x,clock
+ cli
+
+ ldd temp,z+1 ;get seconds
+ rcall bcdbin2
+ st x+,temp
+ ldd temp,z+2 ;get minutes
+ rcall bcdbin2
+ st x+,temp
+ ldd temp,z+3 ;get hours
+ rcall bcdbin2
+ st x+,temp
+ ldd temp,z+4 ;get day
+ andi temp,0x3f
+ rcall bcdbin2
+ st x+,temp
+ ldd temp,z+5 ;get months
+ andi temp,0x1f
+ rcall bcdbin2
+ st x+,temp ;store month
+ st x+,temp3 ;store year
+ st x+,temp4 ;store year century
+ sei
+
+rtc_get_e:
+ pop temp
+ pop temp
+ pop temp
+ pop temp
+ pop temp
+ pop temp
+ ret
+
+;----------------------------------------------
+; Set hardware clock from software clock
+;
+; Register: temp2: s
+; temp3: m
+; temp4: h
+; xl: D
+; temp: M
+; yl: Yl
+; yh: Yh
+
+rtc_set:
+ ldiw z,clock
+ cli
+ ldd temp2,z+0 ;sec
+ ldd temp3,z+1 ;min
+ ldd temp4,z+2 ;hours
+ ldd xl,z+3 ;day
+ ldd temp,z+4 ;month
+ ldd yl,z+5 ;yearl
+ ldd yh,z+6 ;yearh
+ sei
+ rcall binbcd2
+ push temp ;-1 save month
+ mov temp,xl
+ rcall binbcd2
+ mov xl,yl ; least significant 2 bits of year
+ swap xl
+ lsl xl
+ lsl xl
+ andi xl,0xc0
+ or temp,xl ; combine with day
+ push temp ;-2 save year/day
+ mov temp,temp4
+ rcall binbcd2
+ push temp ;-3 save hours
+ mov temp,temp3
+ rcall binbcd2
+ push temp ;-4 save min
+ mov temp,temp2
+ rcall binbcd2
+ push temp ;-5 save sec
+
+ push _0 ;-6 1/10s, 1/100s
+ ldi temp,0x84 ; stop count, alarm enable
+ push temp ;-7
+ push _0 ;-8 register address
+ in zh,sph
+ in zl,spl
+ ldi temp,0xA0 ; PCF8583 slave address
+ push temp ;(-9)
+
+ ldi temp2,9
+ rcall i2c_write
+ ldi temp,0x04 ;enable counting
+ std z+2,temp
+ ldi temp2,3
+ rcall i2c_write
+ std z+3,yh ;store year in RTC RAM
+ std z+2,yl
+ ldi temp,0x10
+ std z+1,temp
+ ldi temp2,4
+ rcall i2c_write
+
+ addiw z,8 ;remove buffer from stack
+ cli
+ out spl,zl
+ sei
+ out sph,zh
+
+ ret
+#endif
+
; ----------------------------------------------
;
;03 3 in - "UART" status: bit 0 = rx, bit 1 = tx
;04 4 in - "UART" data register, no wait
;
+;------------------------ Virtual I2C interface --------------------------
+;05 5 out - Control Port: 1 = Start read operation
+; 2 = Start write operation
+;05 5 in - Status of last Transfer: 0 = ok, else fail
+;06 6 in/out - Number of bytes to transfer, including Slave address
+;07,08 7,8 in/out - Read/Write address low/high
+;
+;------------------------ Disk I/O ---------------------------------------
;0D,0E 13,14 in/out - Set address of Bios Controll Block
;0F 15 in/out - Disk select
;10,11 16,17 in/out - Track select
;16 22 in - Result of last read/write operation.
; 0x00 = ok, 0xff = error (--> Bad Sector)
;
+;
+;
+;------------------------ Wall Clock and Timers --------------------------
;40 64-71 in/out - Timer/Clock control.
;41-46
;
-;47-4C clock - Binary format: y, m, d, h, m, s
+;47-4D clock - BCD format: ss, mm, hh, DD, MM, YYl, YYh
+;
+;------------------------ Ports ------------------------------------------
+;80-87 in/out - Port-Expander PCF8574 (max. 8 Chips)
+;88-8F in/out - Port-Expander PCF8574A (not implemented yet!)
; ---------------------------------------------- Start of Code Segment
.dw utimeget
.dw utimeput
- .db CLOCKPORT,6 ;Clock format (bin): y, m, d, h, m, s
+ .db CLOCKPORT,7 ;Clock format (bcd): ss, mm, hh, DD, MM, YYl, YYh
.dw clockget
.dw clockput
.db DEBUGPORT,1
.dw dbg_stat
.dw dbg_ctrl
+
+#if I2C
+ .db I2CCTRL,1
+ .dw vi2c_stat_get
+ .dw vi2c_ctrl
+
+ .db I2CBLEN,3 ;
+ .dw vi2c_param_get
+ .dw vi2c_param_set
+
+ .db PORT,8
+ .dw pcf8574_in
+ .dw pcf8574_out
+#endif
+
.db 0,0 ; Stop mark
;---------------------------------------------------------------------
adiw z,4
rjmp vprw_loop
vprw_found:
- brtc PC+2
- adiw z,2
+ brtc PC+2 ;read or write?
+ adiw z,2 ;skip read function pointer
lpm _tmp0,z+
lpm _tmp1,z+
movw z,_tmp0
\r
maclib CFGACPM.LIB\r
\r
+cr equ 0dh\r
+lf equ 0ah\r
+\r
aseg\r
org 100h\r
.phase bios\r
.z80\r
\r
-nsects equ ($-ccp)/128 ;warm start sector count\r
+nsects equ ($-ccp)/128 ;warm start sector count\r
\r
- jp boot\r
+ jp boot\r
wboote: \r
- jp wboot\r
- jp const\r
- jp conin\r
- jp conout\r
- jp list\r
- jp punch\r
- jp reader\r
- jp home\r
- jp seldsk\r
- jp settrk\r
- jp setsec\r
- jp setdma\r
- jp read\r
- jp write\r
- jp listst\r
- jp sectran\r
+ jp wboot\r
+ jp const\r
+ jp conin\r
+ jp conout\r
+ jp list\r
+ jp punch\r
+ jp reader\r
+ jp home\r
+ jp seldsk\r
+ jp settrk\r
+ jp setsec\r
+ jp setdma\r
+ jp read\r
+ jp write\r
+ jp listst\r
+ jp sectran\r
+ jp 0 ;zsdos (?)\r
+ jp 0 ;zsdos (?)\r
+ jp 0 ;zsdos (?)\r
+ jp clock ;zsdos compatible clock set/get\r
+\r
\r
.8080\r
maclib AVRCPM.LIB\r
db cr,lf,0\r
\r
const:\r
- in a,(0)\r
+ in a,(0)\r
ret\r
\r
conin:\r
- in a,(0)\r
- cp 0ffh\r
- jp nz,conin\r
+ in a,(0)\r
+ cp 0ffh\r
+ jp nz,conin\r
\r
- in a,(1)\r
+ in a,(1)\r
ret\r
\r
conout:\r
- ld a,c\r
- out (1),a\r
+ ld a,c\r
+ out (1),a\r
ret\r
\r
list:\r
ret\r
\r
listst:\r
- ld a,0\r
+ ld a,0\r
ret\r
\r
punch:\r
ret\r
\r
reader:\r
- ld a,01Fh\r
+ ld a,01Fh\r
ret\r
\r
prmsg:\r
ld h,0\r
ret\r
\r
+;------------------------------------------------------------------------\r
+; ZSDOS clock drivers may use registers BC and D without restoring them, \r
+; but must preserve the Z80's alternate and index registers. \r
+; Other registers must be used exactly as follows:\r
+;\r
+; Enter: C = 00H to Read the Clock, 01H to Set the Clock\r
+; DE = Address of a 6-byte field to Receive or from which \r
+; to Set time in DateStamper format (BCD digits as: \r
+; YY MM DD HH MM SS). 24-hour operation is assumed.\r
+;\r
+; Exit : A = 01H for a successful operation,\r
+; 0FFH for a failure of any sort (Can't set, etc.)\r
+;\r
+; When Reading the Clock:\r
+; E = Original contents of Entry value of DE plus 5\r
+; HL = Entry value of DE plus 5 (Seconds field)\r
+\r
+clock:\r
+ dec c\r
+ jr z,clk_set\r
+ inc c\r
+ ret nz\r
+\r
+clk_read:\r
+ ex de,hl\r
+ ld bc,5*256 + CLOCKPORT-1\r
+clkg_l:\r
+ inc c\r
+ ini\r
+ jr nz,clkg_l\r
+ ld e,(hl)\r
+ in a,(CLOCKPORT+5)\r
+ ld (hl),a\r
+ jr clk_e\r
+\r
+clk_set:\r
+ ld hl,5\r
+ add hl,de\r
+ ld bc,6*256 + CLOCKPORT+6\r
+clks_l:\r
+ dec c\r
+ outd\r
+ jr nz,clks_l\r
+clk_e:\r
+ ld a,1\r
+ ret\r
+\r
+;------------------------------------------------------------------------\r
+\r
bcb: dw drvtbl\r
dw dirbuf\r
dw enddat\r
buff equ 0080h ;default buffer address\r
retry equ 3 ;max retries on disk i/o before error\r
\r
+\r
+;copy from avr/virt_ports.asm:\r
+; Port Direction Function\r
+;hex dez\r
+;-------------------------------------------------------------------------\r
+;00 0 in - Con status. \r
+; Returns 0xFF if the UART has a byte, 0 otherwise.\r
+;01 1 in/out - Console input, aka UDR. / Console Output\r
+;02 2 out - Console Output (deprecated)\r
+;03 3 in - "UART" status: bit 0 = rx, bit 1 = tx\r
+;04 4 in - "UART" data register, no wait\r
+;\r
+;------------------------ Virtual I2C interface --------------------------\r
+;05 5 out - Control Port: 1 = Start read operation\r
+; 2 = Start write operation \r
+;05 5 in - Status of last Transfer: 0 = ok, else fail\r
+;06 6 in/out - Number of bytes to transfer, including Slave address\r
+;07,08 7,8 in/out - Read/Write address low/high\r
+;\r
+;------------------------ Disk I/O ---------------------------------------\r
+;0D,0E 13,14 in/out - Set address of Bios Controll Block\r
+;0F 15 in/out - Disk select\r
+;10,11 16,17 in/out - Track select\r
+;12,13 18,19 in/out - Sector select\r
+;14,15 20,21 in/out - Write addr\r
+; \r
+;16 22 out - Trigger disk i/o operations\r
+; Bit 7 = 1: Read sector\r
+; Bit 6 = 1: Write sector\r
+; Bit 5 = 1: BIOS WBOOT\r
+; Bit 4 = 1: BIOS Home\r
+; Only one of bits 4..7 may be set.\r
+; If Write function (bit 6=1):\r
+; Bits 0..2: 0 - write to allocated\r
+; 1 - write to directory\r
+; 2 - write unallocated\r
+; 3 - write to directory \r
+;\r
+;16 22 in - Result of last read/write operation.\r
+; 0x00 = ok, 0xff = error (--> Bad Sector)\r
+;\r
+;\r
+;\r
+;------------------------ Wall Clock and Timers --------------------------\r
+;40 64-71 in/out - Timer/Clock control. \r
+;41-46\r
+;\r
+;47-4D clock - BCD format: ss, mm, hh, DD, MM, YYl, YYh\r
+;\r
+;------------------------ Ports ------------------------------------------\r
+;80-87 in/out - Port-Expander PCF8574 (max. 8 Chips)\r
+;88-8F in/out - Port-Expander PCF8574A (not implemented yet!)\r
+\r
+\r
READ_FUNC equ 7\r
WRITE_FUNC equ 6\r
BOOT_FUNC equ 5\r
HOME_FUNC equ 4\r
\r
-cr equ 13\r
-lf equ 10\r
+TIMERCTL equ 040h\r
+TIMER_MSECS equ TIMERCTL+1\r
+TIMER_SECS equ TIMER_MSECS+2\r
+starttimercmd equ 1\r
+quitTimerCmd equ 2\r
+printTimerCmd equ 15\r
+uptimeCmd equ 16\r
+\r
+CLOCKPORT equ TIMERCTL+7\r
+\r
+DEBUGPORT equ 04FH\r
+StartTraceCmd equ 1\r
+StopTraceCmd equ 0\r
+\r
+\r
+\r
+\r
\r
dd conv=sync bs=128 count=7 if=BIOS.BIN >> tmpCPM.BIN &&\
mv tmpCPM.BIN CPM.BIN
+zsdossys: IPL.BIN CCP.BIN ZSDOS.BIN BIOS.BIN
+ dd conv=sync bs=118 count=1 if=IPL.BIN > tmpCPM.BIN &&\
+ echo -n "<CPM_Disk>" >> tmpCPM.BIN &&\
+ dd conv=sync bs=128 count=16 if=CCP.BIN >> tmpCPM.BIN &&\
+ dd conv=sync bs=128 count=28 if=ZSDOS.BIN >> tmpCPM.BIN &&\
+ dd conv=sync bs=128 count=7 if=BIOS.BIN >> tmpCPM.BIN &&\
+ mv tmpCPM.BIN zsdossys
+
BIOS.PRN BIOS.REL : AVRCPM.LIB CFGACPM.LIB
IPL.PRN IPL.REL : CFGACPM.LIB
@echo -e "The following make targets are supported:\n"\
" diskimage - Build a complete CP/M image. (default)\n"\
" CPM.BIN - Build CP/M system (IPL+CCP+BDOS+BIOS).\n"\
+ " zsdossys - Build ZSDOS system (IPL+CCP+ZSDOS+BIOS).\n"\
"\n"\
" BIOS.PRN - Make a listing file from bios.asm\n"\
" IPL.PRN - Dito for ipl\n"\
"\n"\
" clean - Remove intermediate and output files.\n"\
" help - Print this message and exit.\n"
+
--- /dev/null
+VERS EQU 02\r
+ .Z80\r
+; NAME AVRCLK ; Change this to no more than 6-char\r
+ ; name for the REL driver module\r
+\r
+;---------------------------------------------------------------------\r
+; Time format (6 bytes packed BCD)\r
+; \r
+; TIME+0 last 2 digits of year (prefix 19 assumed for 78 to 99, else 20 assumed)\r
+; TIME+1 month [1..12]\r
+; TIME+2 day [1..31]\r
+; TIME+3 hour [0..23]\r
+; TIME+4 minute [0..59]\r
+; TIME+5 second [0..59]\r
+; \r
+\r
+; This first section contains identification information for the driver\r
+; The information is not placed in the clock driver code section, but are\r
+; located in a different area located by the _CLKID Named Common directive.\r
+\r
+ COMMON /_CLKID/\r
+\r
+DESCST: DEFW 0000 ; Add label here if a static year byte\r
+ ; is used by your clock driver. The\r
+ ; label should point to the year byte\r
+\r
+ ;123456789012345678901234\r
+CLKNAM: DEFB 'AVRCPM Clock ' ; Exactly 24 chars in name\r
+ DEFB VERS/10+'0','.',VERS MOD 10 +'0',0\r
+\r
+DESCR: DEFB 'This is the AVRCPM clock',0\r
+\r
+\r
+;---------------------------------------------------------------------\r
+; This section contains any configurable parameters needed for the\r
+; clock driver. They must be structured in the manner shown in order\r
+; for the loader to properly match and set the values.\r
+; The values in this section are not loaded in the same code section\r
+; as the actual driver code, but are located in another base referenced\r
+; by the _PARM_ Named Common directive.\r
+\r
+ COMMON /_PARM_/\r
+\r
+PARBAS: DEFW 0 ; # of parameters (Set to 00 if none)\r
+ DEFW 0 ; Pointer to STRS (Set to 00 if none)\r
+\r
+;------------------------------------------------------------------\r
+; This section should contain the actual Clock Driver code, and all\r
+; entries here are located in the CSEG, or Code Segment.\r
+\r
+ CSEG\r
+\r
+MHZ equ 2 ; Base Processor speed\r
+CLOCKPORT equ 47h\r
+\r
+;-----------------------------------------------------------\r
+; Z S D O S C L O C K H E A D E R\r
+;-----------------------------------------------------------\r
+; Enter: HL points to a 6-byte buffer to Get/Set time\r
+; Exit : A=1 on Success, A=FFH if error\r
+; HL points to last char in buffer\r
+; E contains original seconds (HL+5)\r
+; NOTE: If clock Set is not included, comment these two jumps\r
+; out to save a few bytes. The loader, SETUPZST, uses\r
+; these two jumps to recognize a full ZSDOS clock and\r
+; modify the interface code.\r
+\r
+PRGBAS: JP GETTIM ; Jump to Read Clock\r
+ JP WRCLK ; Jump to Set Clock\r
+\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+; R e a d T h e C l o c k\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+GETTIM: ; The work of reading the clock\r
+ ; goes here. Values needing to be set\r
+ ; during installation are referenced as:\r
+ ld bc,5\r
+ add hl,bc\r
+ push hl\r
+ ld b,6\r
+ ld c,CLOCKPORT\r
+ ld e,(hl)\r
+GETT_l:\r
+ in a,(c)\r
+ ld (hl),a\r
+ inc c\r
+ dec hl\r
+ djnz GETT_l\r
+ pop hl\r
+ ld a,1\r
+ ret\r
+ \r
+\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+; S e t T h e C l o c k\r
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+WRCLK:\r
+ ld a,(hl)\r
+ cp 78h\r
+ ld a,19h\r
+ jr nc,WRC_1\r
+ ld a,20h\r
+WRC_1:\r
+ out (CLOCKPORT+6),a\r
+ ld b,6\r
+ ld c,CLOCKPORT+5\r
+WRC_l:\r
+ ld a,(hl)\r
+ out (c),a \r
+ dec c\r
+ inc hl\r
+ djnz WRC_l\r
+ dec hl\r
+ ld a,1\r
+ ret\r
+\r
+\r
+;-------------------------------------------------------------\r
+; This code installs configurable items into the clock module\r
+; Enter with DE pointing to the physical base address of the\r
+; relocatable module. DE MUST BE USED TO SET VALUES IN\r
+; THE CSEG PORTION OF CODE!\r
+; NOTE: Code in this section is not added to the actual clock\r
+; driver, but placed in a different area referenced to\r
+; the common base _POST_.\r
+\r
+ COMMON /_POST_/\r
+\r
+; Values in the _PARM_, _POST_ and _PRE_ sections may be loaded\r
+; and saved directly, since their addresses are constant from\r
+; linkage through execution. Setting or reading values in the\r
+; CSEG must be indirect based on the value in the DE register\r
+; pair. The following examples show how to access the various\r
+; sections.\r
+;\r
+; LD A,(XYR) ; EXAMPLE - Get byte from _PARM_ directly\r
+; LD HL,YYR ; " - Begin offset into CSEG indirectly\r
+; ADD HL,DE ; " - HL now addresses relocated loc'n\r
+; LD (HL),A ; " - ..so value can be stored\r
+;\r
+; Likewise, 16-bit values must be accessed indirectly, and may use\r
+; the BC register pair as transfer storage.\r
+;\r
+; LD BC,(XPORT) ; EXAMPLE - Get word from _PARM_ directly\r
+; LD HL,YPORT1 ; " - Begin offset into CSEG indirectly\r
+; ADD HL,DE ; " - HL now addresses relocated loc'n\r
+; LD (HL),C ; " - ..so value can be saved..\r
+; INC HL ; " - ...a byte..\r
+; LD (HL),B ; " - ....at a time..\r
+;\r
+; LD (YPORT2),BC ; EXAMPLE - Values can be stored directly into\r
+; " - other sections such as _PRE_\r
+\r
+ RET ; This RETURN MUST be present even if no other\r
+ ; code is included in this section\r
+\r
+\r
+;----------------------------------------------------------------\r
+; This module is executed just prior to installing the module to\r
+; insure that a valid clock is present\r
+; Enter with DE pointing to base of relocated clock code segment\r
+;---------------------------------------------------------------\r
+; Read clock and wait for seconds to roll - watchdog protected\r
+; Enter with: DE pointing to relocated clock read routine\r
+; HL pointing to base of high module\r
+\r
+ COMMON /_PRE_/\r
+\r
+; Optional final setup of the clock module may go here. Examples of such\r
+; code would be installation-dependant items such as physical RAM location\r
+; for the driver module. If any code is added here, the DE register pair\r
+; MUST be preserved to properly inter PRECLOCK code (If included).\r
+\r
+;YPORT2 EQU $+1 ; EXAMPLE - just to show accessing method\r
+; LD BC,0000 ; " - ..from _POST_ code.\r
+\r
+ INCLUDE PRECLOCK.LIB ; This section of code merely calls the\r
+ ; clock and waits an arbitrary period of\r
+ ; time (>> 1 second) to see if the time\r
+ ; changes. It returns an error if not.\r
+ if 0\r
+TSTRD: JR TSTRD0 ; Jump around address store\r
+\r
+ DEFW TSTRD ; Org location of the code\r
+TSTRD0: SCF\r
+ LD A,1\r
+ RET\r
+ endif\r
+\r
+\r
+\r
+ END\r
+\1a\r
--- /dev/null
+program RTCDemo;\r
+{$C- } {Sonst funktioniert 'keypressed' nicht}\r
+\r
+{---------------------------------------------------------------------\r
+ AVRCPM \r
+ Test und Demonstration des I2C-Interface\r
+ I2C Uhrenchip PCF8583 \r
+ Zeit und Datum lesen und schreiben\r
+\r
+ Moegliche Erweiterung (TODO:):\r
+ - Control/Status-Register und Alarmregister lesen/schreiben\r
+ - RAM lesen/schreiben\r
+\r
+ $Id$\r
+----------------------------------------------------------------------}\r
+ \r
+const\r
+ I2CCMD = 5; {adr of I2C Command Port (1=read, 2=write)}\r
+ I2CMSGLEN = 6; {Transferpuffergroesse}\r
+ I2CADRL = 7; {Transferpufferadresse low/high}\r
+ I2CADRH = 8;\r
+\r
+ I2C_CMD_Read = 1; {I2C Read Command}\r
+ I2C_CMD_Write = 2; {I2C Write Command}\r
+\r
+ { TP Delay Loop }\r
+ T100ms = 100; {20MHz AVR + Config fuer 3 MHz Z80 (TINST)}\r
+ {T100ms = 75;} {20MHz AVR + Config fuer 4 MHz Z80 (TINST default)}\r
+\r
+type\r
+ I2CBufLen = 0..16;\r
+\r
+ CalTime = record\r
+ sec: 0..59;\r
+ min: 0..59;\r
+ hrs: 0..23;\r
+ day: 1..31;\r
+ month: 1..12;\r
+ year: integer;\r
+ end;\r
+\r
+ DTinput = array [1..3] of integer;\r
+\r
+var\r
+ msgbuf : array[0..16] of Byte; {TODO: Transferbuffer nicht global}\r
+\r
+ Time : CalTime;\r
+ Done: boolean;\r
+\r
+{---------------------------------------------------------------------\r
+ Debugging: Print 16 byte RAM ab adr \r
+----------------------------------------------------------------------}\r
+procedure hexdump(adr: integer);\r
+var\r
+ i: integer;\r
+ c: byte;\r
+\r
+ function hexdigit(c: byte): char;\r
+ begin\r
+ if c < 10 then\r
+ hexdigit := char(c + $30)\r
+ else\r
+ hexdigit := char(c - 10 + $41);\r
+ end;\r
+\r
+{TODO: print adr }\r
+begin\r
+ for i := 0 to 15 do\r
+ begin\r
+ c := Mem[adr+i];\r
+ write(hexdigit(c shr 4), hexdigit(c and $f), ' ');\r
+ end;\r
+ writeln;\r
+end;\r
+\r
+{---------------------------------------------------------------------\r
+ I2C - Routinen\r
+----------------------------------------------------------------------}\r
+procedure i2c_init;\r
+var\r
+ i: integer;\r
+begin\r
+ msgbuf[0] := $A0; {I2C-Adresse des RTC-Chips}\r
+\r
+ Port[I2CADRH] := Hi(Addr(msgbuf));\r
+ Port[I2CADRL] := Lo(Addr(msgbuf));\r
+end;\r
+\r
+procedure i2c_write(len:Byte);\r
+begin\r
+ Port[I2CMSGLEN] := len;\r
+ Port[I2CCMD] := I2C_CMD_Write;\r
+end;\r
+\r
+procedure i2c_read(len:Byte);\r
+begin\r
+ Port[I2CMSGLEN] := len;\r
+ Port[I2CCMD] := I2C_CMD_Read;\r
+end;\r
+\r
+\r
+function BCDtoBINbyte(i: byte): byte;\r
+begin\r
+ BCDtoBINbyte := (i div 16) * 10 + (i and $F);\r
+end;\r
+\r
+function BINtoBCDbyte(i: byte): byte;\r
+begin\r
+ BINtoBCDbyte := (i div 10) * 16 + (i mod 10);\r
+end;\r
+\r
+procedure ReadRTC(var t: CalTime);\r
+begin\r
+ msgbuf[1] := 2;\r
+ i2c_write(2);\r
+ i2c_read(6);\r
+ with t do\r
+ begin\r
+ sec := BCDtoBINbyte(msgbuf[1]);\r
+ min := BCDtoBINbyte(msgbuf[2]);\r
+ hrs := BCDtoBINbyte(msgbuf[3] and $3F);\r
+ end;\r
+ msgbuf[1] := $10;\r
+ i2c_write(2);\r
+ i2c_read(3);\r
+ with t do\r
+ begin\r
+ day := BCDtoBINbyte(msgbuf[4] and $3F);\r
+ month:= BCDtoBINbyte(msgbuf[5] and $1F);\r
+ year := msgbuf[1] + 256*msgbuf[2];\r
+ while Lo(year) and $3 <> (msgbuf[4] shr 6) do\r
+ year := year + 1;\r
+ end;\r
+end;\r
+\r
+\r
+procedure WriteRTC(t: CalTime);\r
+begin\r
+ with t do begin\r
+ msgbuf[1] := 1; {register address}\r
+ msgbuf[2] := 0; {hundredth of sec}\r
+ msgbuf[3] := BINtoBCDbyte(sec);\r
+ msgbuf[4] := BINtoBCDbyte(min);\r
+ msgbuf[5] := BINtoBCDbyte(hrs);\r
+ msgbuf[6] := BINtoBCDbyte(day) + (Lo(year) shl 6);\r
+ msgbuf[7] := BINtoBCDbyte(month); {TODO: weekdays}\r
+ end;\r
+ i2c_write(8);\r
+\r
+ msgbuf[1] := $10; {register address}\r
+ with t do begin\r
+ msgbuf[2] := Lo(year);\r
+ msgbuf[3] := Hi(year);\r
+ end;\r
+ i2c_write(4);\r
+end;\r
+\r
+{---------------------------------------------------------------------\r
+ Dialog Routinen\r
+----------------------------------------------------------------------}\r
+\r
+procedure PrintTime(t: CalTime);\r
+begin\r
+ with t do {TODO: Fuehrende '0' statt ' '}\r
+ begin\r
+ write('Zeit: ', hrs:2, ':',min:2, ':',sec:2, ' ',\r
+ 'Datum: ', day, '.', month, '.', year);\r
+ end;\r
+end;\r
+\r
+procedure PrintMenu;\r
+begin\r
+ ClrScr;\r
+ writeln('Menu:');\r
+ writeln(' T) Zeit setzen');\r
+ writeln(' D) Datum setzen');\r
+ writeln(' Q) Quit');\r
+ writeln('> ');\r
+end;\r
+\r
+function GetKey: char;\r
+var\r
+ c: char;\r
+begin\r
+ Read(Kbd, c);\r
+ GetKey := c;\r
+end;\r
+\r
+{Daemliche input routine ohne Fehlerpruefung (TODO:)}\r
+procedure GetDateTime(var a: DTinput; sep: char);\r
+var\r
+ line: String[80];\r
+ s: String[4];\r
+ i,j,k: integer;\r
+ rc: integer;\r
+\r
+begin\r
+ readln(line);\r
+ line := line + sep;\r
+ j := 1;\r
+ for i := 1 to 3 do\r
+ begin\r
+ k := 1;\r
+ while line[k+j] in ['0'..'9'] do\r
+ k := k + 1;\r
+ s := Copy(line, j, k);\r
+ val(s, a[i], rc);\r
+ j := j + k + 1;\r
+ end;\r
+end;\r
+\r
+procedure SetTime;\r
+var\r
+ a: DTinput;\r
+\r
+begin\r
+ write('Zeit (hh:mm:ss): ');\r
+ a[1] := -1;\r
+ GetDateTime(a, ':');\r
+{ writeln('intime:', a[1], ':', a[2], ':', a[3]);\r
+}\r
+ if (a[1] in [0..24]) and (a[2] in [0..59]) and (a[3] in [0..59]) then\r
+ begin\r
+ ReadRTC(Time);\r
+ Time.hrs := a[1];\r
+ Time.min := a[2];\r
+ Time.sec := a[3];\r
+ WriteRTC(Time);\r
+ end else\r
+ begin\r
+ writeln('Fehler in Eingabe.');\r
+ end;\r
+end;\r
+\r
+procedure SetDate;\r
+var\r
+ a: DTinput;\r
+\r
+begin\r
+ write('Datum (TT.MM.JJJJ): ');\r
+ a[1] := -1;\r
+ GetDateTime(a, '.');\r
+{ writeln('indate:', a[1], '.', a[2], '.', a[3]);\r
+}\r
+ if (a[1] in [1..31]) and (a[2] in [1..12]) and (a[3] > 0) and (a[3] <= 2076) then\r
+ begin\r
+ ReadRTC(Time);\r
+ Time.day := a[1];\r
+ Time.month:= a[2];\r
+ Time.year := a[3];\r
+ WriteRTC(Time);\r
+ end else\r
+ begin\r
+ writeln('Fehler in Eingabe.');\r
+ end;\r
+end;\r
+\r
+procedure CleanConsolebuffer;\r
+var\r
+ c: char;\r
+begin\r
+ while keypressed do c := GetKey;\r
+end;\r
+\r
+{---------------------------------------------------------------------\r
+ main\r
+----------------------------------------------------------------------}\r
+\r
+begin\r
+ PrintMenu;\r
+ i2c_init;\r
+\r
+ writeln;\r
+ Done := False;\r
+ repeat\r
+ Delay(T100ms);\r
+ ReadRTC(Time);\r
+ GotoXY(35,1); PrintTime(Time); ClrEol;\r
+ gotoXY(2,5); ClrEol;\r
+\r
+ if keypressed then\r
+ begin\r
+ gotoXY(1,7); ClrEol;\r
+ gotoXY(1,6); ClrEol;\r
+ case UpCase(GetKey) of\r
+ 'T': SetTime;\r
+ 'D': SetDate;\r
+ 'Q': Done := True;\r
+ end;\r
+ end;\r
+ until Done;\r
+ CleanConsolebuffer;\r
+end.\r
+\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a\1a
\ No newline at end of file