Abstract
In a processor-controlled system, power consumption is directly proportional to the clock speed of the processor. If the computational load on the processor is small, most of this power is wasted. Modulating the processor speed to the slowest possible frequency while maintaining the minimum computational power to perform the task at hand can reduce this waste. This application note describes using the DS1077, controlled via a PC master, to control the clock speed of an 8051-type microprocessor.
Introduction
The DS1077 is a solid-state, CMOS, oscillator capable of generating frequencies from 8kHz up to 133.33MHz. It can be used as a fixed frequency stand-alone oscillator, or as a processor-controlled frequency generator. The frequency of the two, synchronous, oscillator outputs are user adjustable in sub-multiples of the master frequency through the use of two on-chip programmable prescalers and divider. The frequency and mode settings are configurable "on-the-fly" and stored in EEPROM using a 2-wire serial interface which can address up to eight DS1077s on a single 2-wire bus. Two digital control inputs, CTRL0 and CTRL1 are also capable of controlling the frequency or mode. Also available is the DS1077L, which is a 3V version of the DS1077 and is capable of generating frequencies from 4.87kHz up to 66.66MHz. Throughout the remainder of this document, unless otherwise specified, both the 3V and 5V versions of the DS1077 will be referred to as the DS1077.
This application note will show several examples of using a DS1077. It will show how a DS1077 can be used in place of a crystal to clock an 8051 microcontroller and a Microchip PIC™ microcontroller. This application note will also show how to use multiple DS1077s on a single 2-wire bus. Finally, example 8051 firmware is included to show how to implement a 2-wire master, along with the lower layer communication routines to communicate with each DS1077 on the bus.
System Overview
The reference schematic in Figure 1 shows two systems that are independent of each other. Both systems operate at a frequency generated by the DS1077. In this example, although each system is independent of each other, they are both controlled by a common 2-wire master. This 2-wire master can be part of a larger system that needs control of its subsystems. The master can decide to reduce the operating frequencies of the subsystems that are not currently needed in order to conserve power, reduce heat in some cases, or maybe even reduce EMI radiation. It is sometimes advantageous to use a DS1077 to avoid running high frequency clocks throughout a large system, like over a backplane. It is much easier and safer to distribute a relatively low frequency 2-wire bus. Likewise, one could also conceive of using the DS1077 to reduce the system operating frequency instead of the microcontroller (many micros can reduce its speed or even go into a low current sleep mode), since the DS1077 can reduce the frequency of the entire system, and not just the micro alone. All this stated, applications using the DS1077 can be large and complex, but for the purpose of this application note, the example schematic has been greatly simplified and is intended to make several points. It shows multiple DS1077s on a common bus, and it also shows that the DS1077 can directly drive some popular microcontrollers.
Using the DS1077 as a System Clock
In the reference schematic, U1, the DS1077Z-125, is used to generate the clock for U3, an 8051 microcontroller. The particular 8051 that was used to develop the firmware found in Appendix A was the DS87C520. The DS87C520 is able to operate up to a frequency of 33MHz. Since U1 is the 125MHz version of the DS1077, OUT0 can only generate 125MHz, 62.5MHz, 31.025MHz, and 15.625MHz. While this would be fine if our application only needed full-speed and half-speed (using the 66MHz version of the DS1077), but again for the development of the firmware it was desirable to run the microcontroller all the way down to the kHz range. OUT0 does not have a divider, only a prescaler which divides by 1, 2, 4, or 8. OUT1 on the other hand, has in addition to the prescaler, a divider that can further divide the frequency by 2 through 1025. Therefore, OUT1 was chosen to clock the 8051. OUT0 can then still be used to clock other components of the system. For the purpose of simplicity, CTRL0 and CTRL1 were not used and were tied to GND. However, note that caution must be taken if CTRL0 and CTRL1 inputs are used to either disable the output or enter power-down mode because floating the microcontrollers' crystal input can cause unwanted oscillations or false clocking.
The second system shown in the reference schematic shows U2, a DS1077 clocking the OSC1 pin of U4, a PIC microcontroller. Again, the DS1077 is used in place of a fixed-frequency crystal. The PIC used in this example can operate up to 20MHz, so like with the 8051 example, OUT1 is used in order to take advantage of the 2-1025 divider, which is only provided by OUT1. OUT0 can be used by other components of the system. However, if either output is not used, and therefore not connected, it would be wise to disable the unused output by using the corresponding CTRL pin. This will cause a noticeable reduction in the supply current, as well as reduce the probability of unwanted EMI radiation. Although, as with the 8051 system, for simplicity CTRL0 and CTRL1 were not used and tied to ground.
Like always, it is important that sufficient decoupling be provided. Likewise, it is important that the decoupling capacitors C1 and C2 have good high-frequency performance and are physically located as close as possible to each DS1077 using short PCB traces.
Advantages of Using a Ds1077 Over a Crystal
There are several important reasons why a DS1077 might be preferred over a crystal. First, the DS1077 frequency can be changed. In fact, it can be changed on-the-fly, or even disabled. Second, the DS1077 offers dual, synchronous, individually controllable outputs. Also, the DS1077 eliminates the need for messy tank circuits when operating a crystal at one of its harmonic frequencies (for crystals above 30MHz). Finally, the DS1077 is much less susceptible to vibration than crystals.
Controlling the DS1077
The DS1077 can be used in fixed-frequency applications as well as variable-frequency applications. In fixedfrequency applications, the 2-wire master is not needed and the CTRL inputs are optional. But for applications that require control of the frequency or mode, the CTRL inputs and/or the 2-wire master must be used depending on the amount of flexibility required.
CTRL0 and CTRL1 Inputs
If an application needs the ability to instruct the DS1077 to enter power-down mode to conserve energy, or if the application would like to turn off (tri-state) the oscillator outputs, then CTRL0 and CTRL1 must be used. While there are no specific 2-wire commands to enter power-down mode or to disable the outputs, there are some tricks that can be done in firmware to achieve the same results. For example, while the CTRL inputs are at a known state, the corresponding bit in the MUX register can be set or cleared to turn on and off the desired function.
2-Wire Interface
When an application needs to generate frequencies other than divide by 1, 2, 4, or 8, then the 2-wire interface is required. Interfacing to an existing 2-wire bus is simple. Just connect SDA and SCL (and GND). Be sure that somewhere the bus contains the bus pull-up resistors. These are R1 and R2 in the reference schematic. Although 4.7kΩ resistors were used in the example, these may need to be tweaked depending on the bus capacitance, the number of devices on the bus, and the desired communication speed. However, 4.7kΩ will work for the majority of applications. If there is not an existing bus, then one can be created with a micro. Example firmware for an 8051 microcontroller is given in Appendix A. Also, if the 2-wire interface will not be used at all in an application, be sure that SDA and SCL are tied to well-defined logic levels and not left floating.
Notice that in the example there are more than one DS1077s on the same bus. In order for the 2-wire master to communicate with each DS1077 individually, each needs to have a unique address. Three bits in the BUS register allow up to 8 DS1077s on the bus at once. U1 was programmed to have an address of '000', while U2 was programmed to have an address of '001'. For examples of 2-wire communication, refer to the DS1077 or DS1077L data sheet as well as the firmware listed in Appendix A.
DS1077 Controlling the 2-WIRE Master
Having read this far, one may wonder why an additional 2-wire master was used in the example application when there were two fine microcontrollers quite capable of generating the 2-wire protocol needed to communicate with the DS1077. While it can be done, it is dangerous and extra caution must be taken. First of all, when the frequency of the microcontroller is changed, so will the timing of 2-wire routines. Also, just as with the 8051 example and PIC examples, some micros may have a minimum operating frequency spec in addition to a maximum frequency. Finally, disabling the outputs are out of the question since the micro would no longer be clocking, and therefore, no longer be able to issue a command to re-enable the oscillator. But if it must be done, it is very important to check the data sheet of the microcontroller being used.
Firmware
Firmware for an 8051-based system is included in Appendix A. It is intended to show an example of the lower layer routines needed to talk to the DS1077s. However, note that the firmware implements an open-loop system. Closing the loop is very application-specific. But for the purpose of illustrating examples of communicating with the DS1077, a menu-based, open-loop example is beneficial. A PC terminal program is used to give the DS1077s commands. The commands can then be looked up in the firmware to see exactly what is being performed. The basic menu commands are as follows:
- Read the selected DS1077 and display the registers
- Edit the MUX word
- Edit the DIV word
- Edit the BUS word
- Write to the DS1077 at address '000'
- Write to the DS1077 at address '000'
- Write to the DS1077 at address '001'
- Write to the DS1077 at address '001'
- Change firmware 2-wire communication address
Since the DS1077 settings are stored in EEPROM, the DS1077 powers up to the values stored in EEPROM. The values of the MUX, DIV, and BUS registers can be written to using the corresponding menu commands. The firmware for menu commands 2 to 8 show examples how to perform 2-wire writes, while menu command 1 shows a 2-wire read. Finally, menu command 9 shows how to change the 2-wire address that will be addressed.
Here is an example of writing 1234h to the DIV register of DS1077 at address '000':
LCALL START2WIRE ; 2-WIRE START MOV A,#0B0H ; DEVICE IDENTIFIER, SLAVE ADDRESS, WRITE LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#01H ; ACCESS DIV COMMAND LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#12H LCALL WRITEBITS ; SEND MSB LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#34H LCALL WRITEBITS ; SEND LSB LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL STOP2WIRE ; 2-WIRE STOP To write the same to the DS1077 at address '001', simply replace: MOV A,#0B0H ; DEVICE IDENTIFIER, SLAVE ADDRESS, WRITE with the following: MOV A,#0B2H ; DEVICE IDENTIFIER, SLAVE ADDRESS, WRITE
And here is an example of reading the DS1077 at address '000' DIV register.
LCALL START2WIRE ; 2-WIRE START MOV A,#0B0H ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#01H ; READ DIVREG COMMAND LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL START2WIRE ; REPEATED 2-WIRE START MOV A,#0B1H ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL READBITS ; READ DATA FROM DS1077 A MOV DIVDATAMSB,A ; SAVE MUX MSB TO A VARIABLE LCALL ACKSLAVEREAD ; ACK SLAVE SO WE CAN READ NEXT BYTE LCALL READBITS ; READ DATA FROM DS1077 A MOV DIVDATALSB,A ; SAVE MUX LSB TO A VARIABLE ;LCALL ACKSLAVEREAD; NO ACK - NO MORE TO READ LCALL STOP2WIRE ; 2-WIRE STOP
The firmware found in Appendix A, as well as additional information can be found on our ftp site listed at the end of this application note under Contact Information.
Conclusion
The DS1077 can often be used as a replacement for a crystal when more flexibility and control are required. Furthermore, the DS1077 can be used to generate a wide range frequencies from the kHz range up to 133MHz. Depending on the amount of control needed, it can operate stand-alone, or processor-controlled using the 2-wire interface. While the example circuit was simple, it demonstrated several key features of the DS1077. Consider using a DS1077 in your next application.
APPENDIX A
;****************************************************************************** ;* DS1077/1077L APPNOTE FIRMWARE * ;* Copyright (c) 1999,2000,2001 Dallas Semiconductor/MAXIM * ;****************************************************************************** ;* * ;* This program is used to show an example of how to use the DS1077 in a * ;* real application. * ;* * ;* Revision History * ;* 1.0 12/16/01 BJV Initial Release * ;* * ;****************************************************************************** ;* * ;* DS87C520 Reference: * ;* * ;* P0.0 - 74ACQ573 P2.0 - A8 * ;* P0.1 - " P2.1 - A9 * ;* P0.2 - " P2.2 - A10 * ;* P0.3 - " P2.3 - A11 * ;* P0.4 - " P2.4 - A12 * ;* P0.5 - " P2.5 - A13 * ;* P0.6 - " P2.6 - A14 * ;* P0.7 - " P2.7 - A15 * ;* * ;* P3.0 - P1.0 - SCL * ;* P3.1 - P1.1 - SDA * ;* P3.2 - P1.2 - RXD1 - TO PC SERIAL PORT * ;* P3.3 - P1.3 - TXD1 - TO PC SERIAL PORT * ;* P3.4 - P1.4 - ACK FAIL LED * ;* P3.5 - P1.5 - LED * ;* P3.6 - *WR P1.6 - LED * ;* P3.7 - *RD P1.7 - HEARTBEAT LED * ;* * ;* BANK 0 R0 - Used for 2-wire read and write, Do not destroy! * ;* BANK 0 R3 - Used for binasc routine, Do not destroy! * ;* BANK X R7 - Temp variable * ;* * ;****************************************************************************** ;* Notes: * ;* 1. DS87C520 is running at 22.1184MHz * ;* 2. Connect serial port 1 (P1.2 and P1.3) to PC * ;* * ;****************************************************************************** ;****************************************************************************** $NOMOD51 ;disable predefined 8051 registers $INCLUDE (REG520.INC) ;DS87C520 definition file ;------------------------------------------------------------------ ; SOFTWARE VERSION ;------------------------------------------------------------------ MAJOR_VERSION EQU 1 ;major version number MINOR_VERSION EQU 0 ;minor version number ;------------------------------------------------------------------ ; CONSTANTS ;------------------------------------------------------------------ CR EQU 0DH ;ASCII CARRIAGE RETURN LF EQU 0AH ;ASCII LINE FEED BS EQU 08H ;ASCII BACK SPACE ETX EQU 03H ;ASCII END OF TEXT BEL EQU 07H ;ASCII BELL NAK EQU 15H ;ASCII NEGATIVE ACKNOWLEDGE ;------------------------------------------------------------------ ; SERIAL PORT CONFIGURATION ;------------------------------------------------------------------ SBUFIN EQU SBUF1 ;USE SERIAL PORT 1 SBUFON EQU SBUF1 RIN BIT SCON1.0 TIN BIT SCON1.1 ;------------------------------------------------------------------ ; DS1077 SPECIFIC ;------------------------------------------------------------------ ACCESSDIV EQU 01H ;Access DIV register DS1077 command ACCESSMUX EQU 02H ;Access MUX register DS1077 command ACCESSBUS EQU 0DH ;Access BUS register DS1077 command WRITEE2 EQU 3FH ;Write E2 DS1077 command DSEG AT 30H DS1077READ: DS 1 ;control byte, A0=A1=A2=X, read DS1077WRITE:DS 1 ;control byte, A0=A1=A2=X, write MUXDATAMSB: DS 1 ;DS1077 DATA MUXDATALSB: DS 1 ;DS1077 DATA DIVDATAMSB: DS 1 ;DS1077 DATA DIVDATALSB: DS 1 ;DS1077 DATA BUSDATA: DS 1 ;DS1077 DATA ;------------------------------------------------------------------ ; 2-WIRE SPECIFIC ;------------------------------------------------------------------ SDA BIT P1.1 SCL BIT P1.0 ADDRESS: DS 1 ;2-WIRE ADDRESS TO COMMUNICATE WITH STACK EQU $ ;STACK IS ABOVE DATA ;********************************************************************* ;* Hardware Interrupt Vectors (Table on page 95 of DS databook) * ;********************************************************************* CSEG AT 0 ;Power up and Reset LJMP MAIN ; CSEG AT 002Bh ;Timer 2 Interrupt LJMP TMR2_INT ;Service Heartbeat LED ;********************************************************************* ;* Main Program * ;********************************************************************* CSEG AT 0080h MAIN: CLR EA ;DISABLE INTERRUPTS MOV ADDRESS,0 ;SET TO ADDRESS A0=A1=A2=0 MOV DS1077READ,#0B1H ;SET TO ADDRESS A0=A1=A2=0 MOV DS1077WRITE,#0B0H ;SET TO ADDRESS A0=A1=A2=0 MOV SP,#STACK ;INITIALIZE STACK LCALL INIT_520 ;INITIALIZE DS87C520 LCALL INIT_LCD ;INITIALIZE LCD LCALL PTBANNER ;PRINT BANNER TO SCREEN LCALL INIT2WIRE ;INITIALIZE 2-WIRE PORT LCALL READ1077 ;INITIALIZE DS1077'S LCALL LCDSHOWSTAT ;DISPLAY DS1077 DATA TO LCD SETB EA ;ENABLE INTERRUPTS ;********************************************************************* MAINLOOP: LCALL CRLF ;NEWLINE MOV DPTR, #MENU ;POINT TO MENU STRING LCALL PTXT ;DISPLAY MENU MAINLOOP2: JNB RIN,NOCHAR ;CHECK FOR USER INPUT FROM UART LCALL ECHO ;ECHO CHAR TO SCREEN LCALL CRLF ;NEWLINE CLR RIN ;CLEAR RECEIVE FLAG CJNE A,#ETX,PRECHAR1 ;JUMP IF NOT ETX (CTRL-C) CALL PTBANNER ;REPRINT THE BANNER TO THE SCREEN LJMP MAINLOOP2 ;LOOP FOREVER NOCHAR:CPL P1.6 ;TOGGLE LED - FOR DEBUG ONLY LJMP MAINLOOP2 ;LOOP FOREVER PRECHAR1: ;****************************************************** ;*** MENU COMMANDS *** ;****************************************************** CHAR1:CJNE A,#'1',CHAR2 ;<1> READ DS1077 AND DISPLAY REGISTERS LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 DATA TO LCD LJMP MAINLOOP ;****************************************************** CHAR2:CJNE A,#'2',CHAR3 ;<2> EDIT MUX WORD MOV DPTR, #MUXPROMPT ;POINT TO MESSAGE TO BE DISPLAYED LCALL PTXT ;DISPLAY MESSAGE LCALL INHEXD ;GET FIRST INPUT CHAR FROM KEYBOARD SWAP A ;SWAP INPUT TO UPPER NIBBLE ANL A,#0F0H ;CLEAR LOWER NIBBLE MOV MUXDATAMSB,A ;STORE WHILE GETTING SECOND CHAR LCALL INHEXD ;GET SECOND INPUT CHAR FROM KEYBOARD ANL A,#00Fh ;CLEAR UPPER NIBBLE ORL A,MUXDATAMSB ;OR FIRST AND SECOND CHARS TOGETHER MOV MUXDATAMSB,A ;STORE MSB - FIRST TWO DIGITS LCALL INHEXD ;GET THIRD INPUT CHAR FROM KEYBOARD SWAP A ;SWAP INPUT TO UPPER NIBBLE ANL A,#0F0H ;CLEAR LOWER NIBBLE MOV MUXDATALSB,A ;STORE WHILE GETTING FOURTH CHAR LCALL INHEXD ;GET FOURTH INPUT CHAR FROM KEYBOARD ANL A,#00Fh ;CLEAR UPPER NIBBLE ORL A,MUXDATALSB ;OR THIRD AND FOURTH CHARS TOGETHER MOV MUXDATALSB,A ;STORE LSB - THIRD AND FOURTH DIGITS LCALL CRLF ;NEWLINE LCALL WRITE1077MUX ;WRITE MUX REGISTER TO DS1077 (2 BYTES) LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR3:CJNE A,#'3',CHAR4 ;<3> EDIT DIV WORD MOV DPTR, #DIVPROMPT ;POINT TO MESSAGE TO BE DISPLAYED LCALL PTXT ;DISPLAY MESSAGE LCALL INHEXD ;GET FIRST INPUT CHAR FROM KEYBOARD SWAP A ;SWAP INPUT TO UPPER NIBBLE ANL A,#0F0H ;CLEAR LOWER NIBBLE MOV DIVDATAMSB,A ;STORE WHILE GETTING SECOND CHAR LCALL INHEXD ;GET SECOND INPUT CHAR FROM KEYBOARD ANL A,#00Fh ;CLEAR UPPER NIBBLE ORL A,DIVDATAMSB ;OR FIRST AND SECOND CHARS TOGETHER MOV DIVDATAMSB,A ;STORE MSB - FIRST TWO DIGITS LCALL INHEXD ;GET THIRD INPUT CHAR FROM KEYBOARD SWAP A ;SWAP INPUT TO UPPER NIBBLE ANL A,#0F0H ;CLEAR LOWER NIBBLE MOV DIVDATALSB,A ;STORE WHILE GETTING FOURTH CHAR LCALL INHEXD ;GET FOURTH INPUT CHAR FROM KEYBOARD ANL A,#00Fh ;CLEAR UPPER NIBBLE ORL A,DIVDATALSB ;OR THIRD AND FOURTH CHARS TOGETHER MOV DIVDATALSB,A ;STORE LSB - THIRD AND FOURTH DIGITS LCALL CRLF ;NEWLINE LCALL WRITE1077DIV ;WRITE DIV REGISTER TO DS1077 (2 BYTES) LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR4:CJNE A,#'4',CHAR5 ;<4> EDIT BUS WORD MOV DPTR, #BUSPROMPT ;POINT TO MESSAGE TO BE DISPLAYED LCALL PTXT ;DISPLAY MESSAGE LCALL INHEXD ;GET FIRST INPUT CHAR FROM KEYBOARD SWAP A ;SWAP INPUT TO UPPER NIBBLE ANL A,#0F0H ;CLEAR LOWER NIBBLE MOV BUSDATA,A ;STORE WHILE GETTING SECOND CHAR LCALL INHEXD ;GET SECOND INPUT CHAR FROM KEYBOARD ANL A,#00Fh ;CLEAR UPPER NIBBLE ORL A,BUSDATA ;OR FIRST AND SECOND CHARS TOGETHER MOV BUSDATA,A ;STORE - ONE BYTE REGISTER LCALL CRLF ;NEWLINE LCALL WRITE1077BUS ;WRITE BUS REGISTER TO DS1077 (1 BYTE) LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR5:CJNE A,#'5',CHAR6 ;<5> FIRST DS1077 FAST MOV ADDRESS,#00H ;ADDRESS OF FIRST DS1077 MOV DS1077WRITE,#0B0H ;SET WHICH DS1077 ON BUS TO WRITE MOV DS1077READ,#0B1H ;SET WHICH DS1077 ON BUS TO READ MOV DIVDATAMSB,#00H ;SET DIV REGISTER (2 BYTES) MOV DIVDATALSB,#40H ;SET DIV REGISTER (2 BYTES) LCALL WRITE1077DIV ;WRITE TO DIV REGISTER LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR6:CJNE A,#'6',CHAR7 ;<6> FIRST DS1077 SLOW MOV ADDRESS,#00H ;ADDRESS OF FIRST DS1077 MOV DS1077WRITE,#0B0H ;SET WHICH DS1077 ON BUS TO WRITE MOV DS1077READ,#0B1H ;SET WHICH DS1077 ON BUS TO READ MOV DIVDATAMSB,#10H ;SET DIV REGISTER (2 BYTES) MOV DIVDATALSB,#00H ;SET DIV REGISTER (2 BYTES) LCALL WRITE1077DIV ;WRITE TO DIV REGISTER LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR7:CJNE A,#'7',CHAR8 ;<7> SECOND DS1077 FAST MOV ADDRESS,#01H ;ADDRESS OF SECOND DS1077 MOV DS1077WRITE,#0B2H ;SET WHICH DS1077 ON BUS TO WRITE MOV DS1077READ,#0B3H ;SET WHICH DS1077 ON BUS TO READ MOV DIVDATAMSB,#01H ;SET DIV REGISTER (2 BYTES) MOV DIVDATALSB,#00H ;SET DIV REGISTER (2 BYTES) LCALL WRITE1077DIV ;WRITE TO DIV REGISTER LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR8:CJNE A,#'8',CHAR9 ;<8> SECOND DS1077 SLOW MOV ADDRESS,#01H ;ADDRESS OF SECOND DS1077 MOV DS1077WRITE,#0B2H ;SET WHICH DS1077 ON BUS TO WRITE MOV DS1077READ,#0B3H ;SET WHICH DS1077 ON BUS TO READ MOV DIVDATAMSB,#20H ;SET DIV REGISTER (2 BYTES) MOV DIVDATALSB,#00H ;SET DIV REGISTER (2 BYTES) LCALL WRITE1077DIV ;WRITE TO DIV REGISTER LCALL READ1077 ;READ DS1077 LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS TO LCD LJMP MAINLOOP ;****************************************************** CHAR9:CJNE A,#'9',CHAR0 ;<9> CHANGE 2-WIRE COMMUNICATION ADDRESS MOV DPTR, #ADDRESSPROMPT; POINT TO MESSAGE TO BE DISPLAYED LCALL PTXT ;DISPLAY MESSAGE LCALL INHEXD ;GET INPUT CHAR FROM KEYBOARD (0-7) ANL A,#07H ;ONLY XXXXX210 MOV ADDRESS,A ;SAVE UNFORMATTED ADDRESS RL A ;CONVERT TO BITS 3-1 ANL A,#0EH ;STRIP OTHER BITS ORL A,#0B0H ;OR IN DEVICE IDENTIFIER MOV DS1077WRITE,A ;SAVE FOR WRITE COMMANDS R/W=0 ORL A,#01H ;SET R/W BIT MOV DS1077READ,A ;SAVE FOR READ COMMAND R/W=1 LCALL CRLF ;NEWLINE LCALL READ1077 ;READ DS1077 REGISTERS LCALL LCDSHOWSTAT ;DISPLAY DS1077 REGISTERS LJMP MAINLOOP ;****************************************************** CHAR0:CJNE A,#'0',LAST ;<0> DO NOTHING LJMP MAINLOOP ;****************************************************** LAST: LJMP MAINLOOP ; ;*************************************************************************** ;**** TIMER 2 ISR - LED Heartbeat **** ;**** **** ;*************************************************************************** TMR2_INT: CLR EA ; DISABLE INTERRUPTS PUSH ACC ; SAVE ACC ANL T2CON,#07FH ; ACKNOWLEDGE INTERRUPT CPL P1.7 ; TOGGLE LED NOHEART:POP ACC ; RESTORE ACC SETB EA ; ENABLE INTERRUPTS RETI ;*************************************************************************** ;**** Spurious Interrupt - Used as a trap for unknown/unwanted ints. **** ;**** **** ;*************************************************************************** NOISR:MOV DPTR, #DB_NOISR ; POINT TO MESSAGE TO BE DISPLAYED LCALL PTXT ; DISPLAY MESSAGE RETI ;*************************************************************************** ;**** Initialize DS87C520 - **** ;**** INITIALIZE SERIAL PORT 1 FOR 19200 BAUD (22.1184MHZ) **** ;*************************************************************************** INIT_520: MOV WDCON,#0A0H ; SMOD=1(UP TO 115200 BPS) AND TURN ON PFI MOV SCON1,#50H ; MODE1, ASYNC, 10BITS, TIMER1 MOV TMOD,#21H ; TIMER1-8BIT AUTO RELOAD,TIMER0-16BIT MOV TCON,#50H ; TIMER0 AND 1 ENABLED,/INT0 AND 1 NOT USED MOV TH1,#0FAH ; TIMER1 RESET VALUE FOR 19200 BAUD MOV P1,#0FFH ; TURN OFF PORT1 LEDS MOV T2CON,#04H ; TURN ON TIMER2 MOV IE,#020H ; ENABLE TIMER2 INTERRUPT CLR RS0 ; SELECT REGISTER BANK 0 CLR RS1 RET ;*************************************************************************** ;**** Read the DS1077 registers **** ;**** **** ;*************************************************************************** READ1077: ; READ MUX LCALL START2WIRE ; 2-WIRE START MOV A,DS1077WRITE ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#ACCESSMUX ; READ MUXREG COMMAND LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL START2WIRE ; REPEATED 2-WIRE START MOV A,DS1077READ ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL READBITS ; READ DATA FROM DS1077 A MOV MUXDATAMSB,A ; SAVE MUX MSB LCALL ACKSLAVEREAD ; ACK SLAVE SO WE CAN READ NEXT BYTE LCALL READBITS ; READ DATA FROM DS1077 A MOV MUXDATALSB,A ; SAVE MUX LSB ;LCALL ACKSLAVEREAD; NO ACK - NO MORE TO READ LCALL STOP2WIRE ; 2-WIRE STOP ; READ DIV LCALL START2WIRE ; 2-WIRE START MOV A,DS1077WRITE ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#ACCESSDIV ; READ DIVREG COMMAND LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL START2WIRE ; REPEATED 2-WIRE START MOV A,DS1077READ ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL READBITS ; READ DATA FROM DS1077 A MOV DIVDATAMSB,A ; SAVE MUX MSB LCALL ACKSLAVEREAD ; ACK SLAVE SO WE CAN READ NEXT BYTE LCALL READBITS ; READ DATA FROM DS1077 A MOV DIVDATALSB,A ; SAVE MUX LSB ;LCALL ACKSLAVEREAD; NO ACK - NO MORE TO READ LCALL STOP2WIRE ; 2-WIRE STOP ; READ BUS BYTE LCALL START2WIRE ; 2-WIRE START MOV A,DS1077WRITE ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#ACCESSBUS ; READ BUSREG COMMAND LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL START2WIRE ; REPEATED 2-WIRE START MOV A,DS1077READ ; DEVICE IDENTIFIER, SLAVE ADDRESS, READ LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL READBITS ; READ DATA FROM DS1077 A MOV BUSDATA,A ; SAVE MUX MSB ;LCALL ACKSLAVEREAD; NO ACK - NO MORE TO READ LCALL STOP2WIRE ; 2-WIRE STOP RET ;*************************************************************************** ;**** Write the DS1077 MUX register **** ;**** **** ;*************************************************************************** WRITE1077MUX: ; WRITE MUX LCALL START2WIRE ; 2-WIRE START MOV A,DS1077WRITE ; DEVICE IDENTIFIER, SLAVE ADDRESS, WRITE LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,#ACCESSMUX ; MUXREG COMMAND LCALL WRITEBITS ; SEND COMMAND BYTE LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,MUXDATAMSB LCALL WRITEBITS ; SEND MSB LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE MOV A,MUXDATALSB LCALL WRITEBITS ; SEND LSB LCALL ACKSLAVEWRITE ; CHECK FOR SLAVE ACKNOWLEDGE LCALL STOP2WIRE ; 2-WIRE STOP RET ;********************************************************************* ;**** 2-Wire Start Condition Generator Routine **** ;********************************************************************* ;* requires wait2us routine * ;* uses no registers * ;********************************************************************* START2WIRE: SETB SDA NOP NOP NOP NOP SETB SCL NOP NOP NOP NOP CLR SDA ; PULL SDA LOW LCALL WAIT2US ; WAIT 2US CLR SCL ; PULL SCL LOW LCALL WAIT2US ; WAIT 2US RET ;********************************************************************* ;**** 2-Wire Stop Condition **** ;**** Used to send a stop condition **** ;********************************************************************* ;* requires wait2us routine * ;* uses no registers * ;********************************************************************* STOP2WIRE: CLR SDA ; PULL SDA LOW ; SDA MUST BE LOW SO IT CAN GO HIGH ; WHILE THE CLOCK IS HIGH TO GENERATE ; THE STOP CONDITION NOP ; WASTE 180NS/NOP, STOP SETUP TIME NOP NOP NOP SETB SCL ; PULL SCL HIGH NOP NOP NOP NOP SETB SDA ; PULL SDA HIGH LCALL WAIT2US ; WAIT 2US RET ;********************************************************************* ;**** 2-Wire Initialization Routine **** ;**** Inits SCL and SDA to Set Condition **** ;********************************************************************* ;* requires no routines * ;* Uses no Registers * ;********************************************************************* INIT2WIRE: SETB SCL ; START PROGRAM WITH SCL HIGH SETB SDA ; START PROGRAM WITH SDA HIGH RET ;********************************************************************* ;**** Write Bits Routine **** ;**** Serializes and Transmits the data in the Accumulator at **** ;**** the time the routine is called **** ;********************************************************************* ;* requires no other routines * ;* Destroys Window 0 R0 register and ACC * ;********************************************************************* WRITEBITS: MOV R0, #8 ; sets up for transfer of 8 bits NEXTWRITEBIT: RLC A ; move the MSB of the ACC into C MOV SDA, C ; write C onto SDA line SETB SCL ; set SCL NOP NOP ; clock high time, 180ns/nop NOP NOP CLR SCL ; clear SCL NOP NOP ; clock low time, 180ns/nop + other NOP ; instructions between last nop and NOP ; next setb SCL DJNZ R0, NEXTWRITEBIT ; if the 8th data bit not sent yet ; then keep sending data RET ;********************************************************************* ;**** 2-Wire Readbits Routine **** ;**** Reads 8-bits of data from the slave device, and stores **** ;**** the received data in the Accumulator **** ;********************************************************************* ;* requires no other routines * ;* Destroys Window0 R0 register and ACC * ;********************************************************************* READBITS: SETB SDA ; SDA must be set for an open ; collector read MOV R0, #8 ; sets up for transfer of 8 bits NEXTREADBIT: SETB SCL ; set SCL NOP ; clock high time, 180ns/nop + other NOP ; instructions before clr SCL MOV C, SDA ; Place Data on SDA into C RLC A ; move the C into LSB of A CLR SCL ; clear SCL NOP NOP ; clock low time, 180ns/nop + other NOP ; instructions before next setb SCL NOP NOP DJNZ R0, NEXTREADBIT ; if the 8th data bit not sent yet ; keep sending data RET ;********************************************************************* ;**** 2-Wire Acknowledge Slave Routine for WRITES **** ;**** Used to acknowledge slave devices DURING WRITES **** ;********************************************************************* ;* requires outstr routines * ;* uses DPTR register * ;********************************************************************* ACKSLAVEWRITE: SETB SDA ; set SDA NOP ; wait 180ns/nop NOP SETB SCL ; set SCL NOP NOP ; wait 180ns/nop + other instructions NOP ; with clock high JB SDA, ACK_FAIL ; if SDA high (acknowledge fails), ; then jump to error routine CLR SCL ; else ack passes, set SCL and NOP ; wait 180ns/nop + other instructions NOP ; for clock to go high SETB P1.4 ; turn off LED RET ; return ACK_FAIL: CLR P1.4 ; turn on LED CLR SCL ; clr SCL CLR SDA ; clr SDA NOP NOP ; clock time low, 180ns/nop + clr NOP ; SDA instruction NOP NOP NOP SETB SCL ; set SCL NOP NOP ; clock time high, 180ns/nop NOP NOP NOP NOP NOP SETB SDA ; create stop condition RET ;********************************************************************* ;**** 2-Wire Acknowledge Slave Routine for READS **** ;**** Used to acknowledge slave devices DURING READS **** ;********************************************************************* ;* requires no other routines * ;* uses no registers * ;********************************************************************* ACKSLAVEREAD: CLR SDA ; clear SDA NOP ; wait 180ns/nop NOP SETB SCL ; set SCL NOP NOP ; wait 180ns/nop NOP NOP CLR SCL ; clear SCL RET ;*************************************************************************** ;**** DISPLAY DS1050 DATA TO LCD **** ;*************************************************************************** LCDSHOWSTAT: MOV A,#0C0h ; SET TO SECOND LINE OF LCD DISPLAY MOV DPTR,#8000h ; ADDRESS OF LCD MOVX @DPTR,A ; WRITE ADDRESS TO LCD LCALL DELAY40U ; WAIT FOR LCD LCALL DELAY40U ; WAIT FOR LCD MOV DPTR,#MUXREG ; TEXT MESSAGE TO DISPLAY LCALL LCDSTR ; PRINT TEXT TO LCD MOV A,MUXDATAMSB ; RECALL DATA LCALL BINTOASCII ; ACC=FIRST DIGIT,B=SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (FIRST DIGIT) MOV A,B ; GET SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (SECOND DIGIT) MOV A,MUXDATALSB ; RECALL DATA LCALL BINTOASCII ; ACC=FIRST DIGIT,B=SECOND DIGIT LCALL LCDCHAR ; DISPLAY PWM1 DATA ON LCD (FIRST DIGIT) MOV A,B ; GET SECOND DIGIT LCALL LCDCHAR ; DISPLAY PWM1 DATA ON LCD (SECOND DIGIT) MOV A,#094h ; SET TO THIRD LINE OF LCD DISPLAY MOV DPTR,#8000h ; ADDRESS OF LCD MOVX @DPTR,A ; WRITE ADDRESS TO LCD LCALL DELAY40U ; WAIT FOR LCD LCALL DELAY40U ; WAIT FOR LCD MOV DPTR,#DIVREG ; TEXT MESSAGE TO DISPLAY LCALL LCDSTR ; PRINT STRING TO LCD MOV A,DIVDATAMSB ; RECALL DATA LCALL BINTOASCII ; ACC=FIRST DIGIT,B=SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (FIRST DIGIT) MOV A,B ; GET SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (SECOND DIGIT) MOV A,DIVDATALSB ; RECALL DATA LCALL BINTOASCII ; ACC=FIRST DIGIT,B=SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (FIRST DIGIT) MOV A,B ; GET SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (SECOND DIGIT) MOV A,#0D4h ; SET TO THIRD LINE OF LCD DISPLAY MOV DPTR,#8000h ; ADDRESS OF LCD MOVX @DPTR,A ; WRITE ADDRESS TO LCD LCALL DELAY40U ; WAIT FOR LCD LCALL DELAY40U ; WAIT FOR LCD MOV DPTR,#BUSREG ; TEXT MESSAGE TO DISPLAY LCALL LCDSTR ; PRINT STRING TO LCD MOV A,BUSDATA ; RECALL DATA LCALL BINTOASCII ; ACC=FIRST DIGIT,B=SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (FIRST DIGIT) MOV A,B ; GET SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (SECOND DIGIT) MOV DPTR,#ADDRESSREG ; TEXT MESSAGE TO DISPLAY LCALL LCDSTR ; PRINT STRING TO LCD MOV A,ADDRESS ; RECALL 2-WIRE COMMUNICATION ADDRESS LCALL BINTOASCII ; ACC=FIRST DIGIT,B=SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (FIRST DIGIT) MOV A,B ; GET SECOND DIGIT LCALL LCDCHAR ; DISPLAY DATA ON LCD (SECOND DIGIT) RET ;********************************************************************* ;**** Wait 2us Function **** ;**** Wastes 1.6us of processor time with call, nop and return **** ;********************************************************************* ;* Requires no other routines or registers * ;********************************************************************* WAIT2US: NOP ; 1 nops @4cc each + lcall @16cc + ret @16cc ; produces approximately 1.6us of delay with a ; 22.22MHz clock RET ;*************************************************************************** ;**** 40us Delay **** ;*************************************************************************** DELAY40U:MOV A,#000Fh ;180ns*2cycles LOOP40U: NOP ;180ns NOP NOP NOP NOP NOP NOP NOP NOP NOP ; DEC A ; JNZ LOOP40U ;14 cycles in loop RET ;4 cycles ;*************************************************************************** ;**** Delay 5ms **** ;*************************************************************************** DELAY5MS:MOV A,#079h LOOP5MS: PUSH ACC ; WASTE TIME LCALL DELAY40U ; WASTE TIME POP ACC ; WASTE TIME DEC A ; LOOP COUNTER JNZ LOOP5MS ; CONTINUE WASTING TIME RET ;*************************************************************************** ;**** STRINGS AND ERROR MESSAGES **** ;*************************************************************************** BANNER: DB CR,LF DB 'DS1077(L) APPNOTE FIRMWARE REV ', ETX BANNER2: DB CR,LF DB 'DS1077(L) ', CR, LF, ETX PERIOD: DB '.', ETX PROMPT: DB CR, '> ', ETX MENU: DB 'MENU COMMANDS', CR,LF DB '1 -READ DS1077 AND DISPLAY TO LCD',CR,LF DB '2 -EDIT MUX REGISTER OF DS1077', CR, LF DB '3 -EDIT DIV REGISTER OF DS1077', CR, LF DB '4 -EDIT BUS REGISTER OF DS1077', CR, LF DB '5 -FIRST DS1077 FAST', CR, LF DB '6 -FIRST DS1077 SLOW', CR, LF DB '7 -SECOND DS1077 FAST', CR, LF DB '8 -SECOND DS1077 SLOW', CR, LF DB '9 -CHANGE COMMUNICATION ADDRESS', CR, LF DB 'ENTER YOUR SELECTION: ',ETX LCDBANNER: DB 'DS1077(L) APPNOTE',00h MUXPROMPT: DB 'Enter 4 hex digits for MUX register: ', ETX DIVPROMPT: DB 'Enter 4 hex digits for DIV register: ', ETX BUSPROMPT: DB 'Enter 2 hex digits for BUS register: ', ETX ADDRESSPROMPT:DB 'Enter 1 hex digit for 2-wire address: ', ETX MUXREG: DB 'MUX = ',00h DIVREG: DB 'DIV = ',00h BUSREG: DB 'BUS = ',00h ADDRESSREG: DB ' ADDRESS=',00h ACKF: DB 'ACK FAILED', CR, LF, ETX DB_POWER: DB 'LOW POWER INT', CR, LF, ETX DB_NOISR: DB 'NOISR INT', CR, LF, ETX BUETX: DB ETX ;Just in case ;*************************************************************************** $INCLUDE (DSLIB.A51) ;SERIAL PORT DEBUG ROUTINES END ;******************************************************************************