; ******************************************************************************
; Copyright © [05/15/1999] Scenix Semiconductor, Inc. All rights reserved.
;
; Scenix Semiconductor, Inc. assumes no responsibility or liability for
; the use of this [product, application, software, any of these products].
; Scenix Semiconductor conveys no license, implicitly or otherwise, under
; any intellectual property rights.
; Information contained in this publication regarding (e.g.: application,
; implementation) and the like is intended through suggestion only and may
; be superseded by updates. Scenix Semiconductor makes no representation
; or warranties with respect to the accuracy or use of these information,
; or infringement of patents arising from such use or otherwise.
;******************************************************************************
;
; Filename: v_23_originate_1_37.src
;
; Author: Chris Fogelklou
; Applications Engineer
; Scenix Semiconductor Inc.
;
; Revision: 1.37
;
; Part: SX28AC datecode 9929AA/ SX52BD datecode AB9919AA
; Freq: 50Mhz
;
; Compiled Using: SX-Key v.1.07 and SASM V. 1.43
;
; Date: May 23, 1999.
;
; Revised November 30, 1999
;
; Program Description:
; This program performs V.23 origination on the Scenix/IDC
; modem boards V.1.2. These specifications are followed:
;
; User Interface
; - Software UART will provide the modem’s interface.
; - 1200 baud
; - No Parity
; - 8 Data Bits
; - 1 Stop Bit
; - Hardware Flow Control (CTS, RTS)
; - Compact AT command set
; - 64-byte command buffer
; - Dial: “ATDTxxxxxxxxx…”
; - Switch from data mode to command mode: “+++”
; To escape, wait at least 3 seconds from the last transmitted
; character, and type +++ with less than 1 second between each
; character. The modem will return to command mode if another
; character is not received in 3 seconds.
; - Switch from command mode to data mode: “ATO”
; - Hang up: “ATH”
; - Initialize: “ATZ”
; - Automatic Hybrid Adjustment: “ATY”
;
; Signal Generation/Detection Software
; - DTMF Generation for Dialing
; - Tones generated: 697Hz, 770Hz, 852Hz, 941Hz, 1209Hz, 1336Hz, 1477Hz,1633Hz
; - On time = 100ms
; - Off time = 100ms
; - Off-hook delay time before dialing = 4 s
; - D/A conversion provided by filtered PDM output
; - Data transmission and modulation
; - FSK transmission data rate at 75bps
; - Hardware flow control, 16-byte buffer, and 75bps asynchronous transmitter for
; data rate conversion from 1200bps to 75bps
; - Logic ‘1’ (mark) modulated by 390 Hz
; - Logic ‘0’ (space) modulated by 450 Hz
; - Transmission power = -15dB
; - D/A conversion provided by filtered PDM output
; - Data reception and demodulation
; - FSK reception data rate at 1200bps
; - Logic ‘1’ (mark) demodulated from 1300Hz carrier
; - Logic ‘0’ (space) demodulated from 2100Hz carrier
; - Carrier detection
; - Timed-Zero-Cross algorithm
; - D/A conversion
; - Pulse Position Modulation with maximum output frequency of 307kHz
;
; Hardware Specifications
; - Filtering
; - Low pass filter on PDM output (fc = 1633Hz)
; - High pass filter on FSK input (fc = 1300Hz)
; - Hybrid (removes tx signal from rx signal)
; - Four settings provided for automatic hybrid adjustment for various line
; impedance’s
; - Hybrid adjusted by outputting signal onto line and measuring fed-back signal
; with a low-resolution sigma-delta A/D converter
; - FSK input sensitivity = -30dB
; - Auto-Hybrid removed in V.1.37
; - UART
; - RS-232 interface provided through MAX232 or similar IC
; - Interface provided through RXD, TXD, RTS, and CTS lines
;
; Testing Specifications
; - Initial tests using function generator and off-the-shelf V.23 modems
; - Second round of testing performed with IDC’s modem test equipment
; - Tests performed:
; - Input Sensitivity
; - DTMF output level
; - FSK output level
; - Error rate
; - FCC part 68 and FCC part 15 qualified
; - CTR-21 ready
; - All test results will be documented
;
; Program Instructions;
; To use this program, the modem board must be connected to a serial port at
; these settings:
; 1200 bps
; No parity
; 8 Data Bits
; 1 stop bit
; Hardware flow control ON!!! (CTS/RTS)
;
; These AT commands can be used:
;
; ATDT - Used to dial into a remote modem
; ATH - Used to hang up a call
; ATZ - Used to initialize the modem settings
; ATO - Switches back to data mode from command mode
; +++ - Switches from data mode to command mode.
; ? - Re-prints the help screen to the terminal.
;
; Revision History:
; 1.10 Took semi-working V.23 code and cleaned it up. Kept it working, but made
; few improvements to the operation.
; 1.15 Finally got FSK receive to work error free!!! Whooopeee!!!
; 1.17 Added documentation.
; 1.20 Added carrier detection to the software
; 1.30 Added automatic hybrid adjustment to the software.
; 1.32 Automatic hybrid adjustment tweaked until working. Component values for A/D:
; C = 470pF, R1 = 22k, R2 = 10k
; 1.35 Added guard times around the “+++” coming in.
; 1.37 Removed Auto-Hybrid Adjust. Made sure assembly worked in SASM.
; Removed CARRYX directive and modified source code accordingly.
;
;
; RESOURCES:
; Program memory: TBD
; Data memory: TBD
; I/O Count: TBD
;
;*****************************************************************************************
; Target SX
; Uncomment one of the following lines to choose the SX18AC, SX20AC, SX28AC, SX48BD/ES,
; SX48BD, SX52BD/ES or SX52BD. For SX48BD/ES and SX52BD/ES, uncomment both defines,
; SX48_52 and SX48_52_ES.
;*****************************************************************************************
;SX18_20
SX28
;*****************************************************************************************
; Assembler Used
; Uncomment the following line if using the Parallax SX-Key assembler. SASM assembler
; enabled by default.
;*****************************************************************************************
SX_Key
;*********************************************************************************
; Assembler directives:
; high speed external osc, turbo mode, 8-level stack, and extended option reg.
;
; SX18/20/28 - 4 pages of program memory and 8 banks of RAM enabled by default.
; SX48/52 - 8 pages of program memory and 16 banks of RAM enabled by default.
;
;*********************************************************************************
IFDEF SX_Key ;SX-Key Directives
IFDEF SX18_20 ;SX18AC or SX20AC device directives for SX-Key
device SX18L,oscxt4,turbo,stackx_optionx
ENDIF
IFDEF SX28 ;SX28AC device directives for SX-Key
device SX28L,oscxt4,turbo,stackx_optionx
ENDIF
freq 50_000_000
ELSE ;SASM Directives
IFDEF SX18_20 ;SX18AC or SX20AC device directives for SASM
device SX18,oschs1,turbo,stackx,optionx
ENDIF
IFDEF SX28 ;SX28AC device directives for SASM
device SX28,oschs1,turbo,stackx,optionx
ENDIF
ENDIF
ID 'v23org13' ; Version = 1.1
reset reset_entry ; JUMP to reset_entry label on reset
;*****************************************************************************************
; Macros
;*****************************************************************************************
;*********************************************************************************
; Macro: _bank
; Sets the bank appropriately for all revisions of SX.
;
; This is required since the bank instruction has only a 3-bit operand, it cannot
; be used to access all 16 banks of the SX48/52. For this reason FSR.4 (for SX48/52BD/ES)
; or FSR.7 (SX48/52bd production release) needs to be set appropriately, depending
; on the bank address being accessed. This macro fixes this.
;
; So, instead of using the bank instruction to switch between banks, use _bank instead.
;
;*********************************************************************************
_bank macro 1
bank \1
IFDEF SX48_52
IFDEF SX48_52_ES
IF \1 & %00010000 ;SX48BD/ES and SX52BD/ES (engineering sample) bank instruction
setb fsr.4 ;modifies FSR bits 5,6 and 7. FSR.4 needs to be set by software.
ENDIF
ELSE
IF \1 & %10000000 ;SX48BD and SX52BD (production release) bank instruction
setb fsr.7 ;modifies FSR bits 4,5 and 6. FSR.7 needs to be set by software.
ELSE
clrb fsr.7
ENDIF
ENDIF
ENDIF
endm
;*********************************************************************************
; Macro: _mode
; Sets the MODE register appropriately for all revisions of SX.
;
; This is required since the MODE (or MOV M,#) instruction has only a 4-bit operand.
; The SX18/20/28AC use only 4 bits of the MODE register, however the SX48/52BD have
; the added ability of reading or writing some of the MODE registers, and therefore use
; 5-bits of the MODE register. The MOV M,W instruction modifies all 8-bits of the
; MODE register, so this instruction must be used on the SX48/52BD to make sure the MODE
; register is written with the correct value. This macro fixes this.
;
; So, instead of using the MODE or MOV M,# instructions to load the M register, use
; _mode instead.
;
;*********************************************************************************
_mode macro 1
IFDEF SX48_52
mov w,#\1 ;loads the M register correctly for the SX48BD and SX52BD
mov m,w
ELSE
mov m,#\1 ;loads the M register correctly for the SX18AC, SX20AC
;and SX28AC
ENDIF
endm
;*****************************************************************************************
; Error generating macros
;*****************************************************************************************
tableStart macro 0 ; Generates an error message if code that MUST be in
; the first half of a page is moved into the second half.
if $ & $100
ERROR 'Must be located in the first half of a page.'
endif
endm
tableEnd macro 0 ; Generates an error message if code that MUST be in
; the first half of a page is moved into the second half.
if $ & $100
ERROR 'Must be located in the first half of a page.'
endif
endm
;*****************************************************************************************
; Data Memory address definitions
; These definitions ensure the proper address is used for banks 0 - 7 for 2K SX devices
; (SX18/20/28) and 4K SX devices (SX48/52).
;*****************************************************************************************
IFDEF SX48_52
ERROR ' This program has not been ported to SX48/52'
; Let the programmer know that this program
; will only work on the SX28.
ELSE
global_org = $08
bank0_org = $10
bank1_org = $30
bank2_org = $50
bank3_org = $70
bank4_org = $90
bank5_org = $B0
bank6_org = $D0
bank7_org = $F0
ENDIF
;*****************************************************************************************
; Global Register definitions
; NOTE: Global data memory starts at $0A on SX48/52 and $08 on SX18/20/28.
;*****************************************************************************************
org global_org
flags ds 1
dtmf_gen_en equ flags.0 ; Signifies whether or not DTMF output is enabled
sine_gen_en equ flags.1 ; Enables the sine generator(s) for DTMF generation and
; FSK generation
timer_flag equ flags.2 ; Set every time the timers roll over.
fsk_tx_en equ flags.3 ; enables the fsk transmission portion of the ISR
fsk_rx_en equ flags.4 ; enables the fsk reception portion of the ISR
rx_flag equ flags.5 ; this flag is set when a byte is received via the UART
fsk_rx_bit equ flags.6 ; this bit indicates the current state of the FSK being
carrier_detected equ flags.7 ; indicates the presence of a carrier
; received.
flags2 ds 1
swCarryFlag equ flags2.0
temp ds 1 ; Temporary register
temp2 ds 1 ; Temporary register
task_switcher ds 1 ; Used in the ISR to switch between tasks.
push_index ds 1 ; Used by the 64-byte buffer to store bytes.
pop_index ds 1 ; Used by the 64-byte buffer to retrieve bytes.
command_index ds 1 ; Used by the string parser to remember the current
; command being checked.
;******************************************************************************
; Bank 0 Variables
;******************************************************************************
org bank0_org
sine_gen_bank = $
freq_acc_low ds 1 ; 16-bit accumulator which decides when to increment the sine wave
freq_acc_high ds 1 ;
freq_count_low ds 1 ; 16-bit counter which decides which frequency for the sine wave
freq_count_high ds 1 ; freq_count = Frequency * 6.83671552
sine_index ds 1 ; Index into the sine table for sine wave 1
sine_index2 ds 1 ; Index into the sine table for sine wave 2
freq_count_low2 ds 1 ; 16-bit counter which sets the sine wave frequency
freq_count_high2 ds 1 ; freq_count = Frequency * 6.83671552
freq_acc_high2 ds 1 ;
freq_acc_low2 ds 1 ; 16-bit accumulator which decides when to increment the sine wave
curr_sine ds 1 ; The current value of the sine wave
curr_sine2 ds 1 ; The current value of sine wave 2
sine2_temp ds 1 ; This register is used to do a temporary shift/add register
PDM_bank = $
PDM0_acc ds 1 ; PDM accumulator
PDM0_out ds 1 ; current PDM output (D/A)
;******************************************************************************
; Bank 1 Variables
;******************************************************************************
org bank1_org
timers = $
timer_l ds 1 ; The low byte of the 24-bit timer
timer_h ds 1 ; the middle byte of the 24-bit timer
timer_hh ds 1 ; the high byte of the 24-bit timer
serial = $ ;UART bank
tx_high ds 1 ;hi byte to transmit
tx_low ds 1 ;low byte to transmit
tx_count ds 1 ;number of bits sent
tx_divide ds 1 ;xmit timing (/16) counter
rx_count ds 1 ;number of bits received
rx_divide ds 1 ;receive timing counter
rx_byte ds 1 ;buffer for incoming byte
rx_count2 ds 1 ;number of bits received
rx_divide2 ds 1 ;receive timing counter
rx_byte2 ds 1 ;buffer for incoming byte
string ds 1 ;the address of the string to be sent
byte ds 1 ;semi-temporary serial register
plus_count ds 1 ;stores the number of consecutive '+''s received during
; FSK i/o mode.
;******************************************************************************
; Bank 2 Variables
;******************************************************************************
org bank2_org
fsk_transmit_bank = $
fsk_receive_bank = $
fsk_serial_bank = $
fsk_tx_high ds 1 ;hi byte to transmit
fsk_tx_low ds 1 ;low byte to transmit
fsk_tx_count ds 1 ;number of bits sent
fsk_tx_divide ds 1 ;xmit timing (/16) counter
fsk_tx_divide_2 ds 1
fsk_trans_count ds 1 ; This register counts the number of counts
; between transitions at the pin
fsk_last_trans ds 1
fsk_rb_past_state ds 1 ; This register keeps track of the previous
; state of port RB, to watch for transitions
fsk_temp_trans ds 1 ; Temporarily stores the transition count after
; a transition has occurred, until it can be processed.
fsk_flags ds 1
fsk_answering equ fsk_flags.0
fsk_tx_bit equ fsk_flags.1
fsk_processing_required_1 equ fsk_flags.2
;******************************************************************************
; Bank 3 Variables
;******************************************************************************
org bank3_org
carrier_detect_bank = $
cd_trans_count ds 1
cd_trans_avg_l ds 1
cd_trans_avg_h ds 1
cd_avg_count ds 1
cd_rb_past_state ds 1
;*************************************************************
; Bank 4, 5, 6, 7 (for 64-byte buffer, but can be reused.)
;*************************************************************
org bank4_org
buffer = $
org bank5_org
buffer2 = $
org bank6_org
buffer3 = $
org bank7_org
buffer4 = $
;*************************************************************
; Equates for the FSK receive part of the modem
;*************************************************************
threshold = 180 ; How many counts to look for for a transition from high frequency to low frequency
fsk_hysterises = 6 ; The number of counts over/under the threshold to allow an actual transition
; from high to low on RX-bit
;*************************************************************
;**************************************************************************
; Baud rate defines
;**************************************************************************
; *** 150 baud
; baud_bit = 7 ;for 2400 baud
; start_delay = 128+64+1 ; " " "
; int_period = 163 ; " " "
; *** 600 baud
; baud_bit = 5
; start_delay = 32+16+1
; int_period = 163
; *** 1200 baud
baud_bit = 4
start_delay = 16+8+1
int_period = 163
;**************************************************************************
; Equates for common data comm frequencies
;**************************************************************************
f697_h equ $012 ; DTMF Frequency
f697_l equ $09d
f770_h equ $014 ; DTMF Frequency
f770_l equ $090
f852_h equ $016 ; DTMF Frequency
f852_l equ $0c0
f941_h equ $019 ; DTMF Frequency
f941_l equ $021
f1209_h equ $020 ; DTMF Frequency
f1209_l equ $049
f1336_h equ $023 ; DTMF Frequency
f1336_l equ $0ad
f1477_h equ $027 ; DTMF Frequency
f1477_l equ $071
f1633_h equ $02b ; DTMF Frequency
f1633_l equ $09c
;******************************************************************************
; Equates for FSK generation
;******************************************************************************
f390_h equ $00a ; V.23 backchannel logic '1' (mark)
f390_l equ $06a
f450_h equ $00c ; V.23 backchannel logic '0' (space)
f450_l equ $004
f1300_h equ $022 ; V.23 forward channel logic '1' (mark)
f1300_l equ $0b7
f2100_h equ $038 ; V.23 forward channel logic '0' (space)
f2100_l equ $015
f2225_h equ $03b ; Bell 103 forward channel logic '1' (mark)
f2225_l equ $06b
f2025_h equ $036 ; Bell 103 forward channel logic '0' (space)
f2025_l equ $014
f1070_h equ $01c ; Bell 103 backward channel logic '1' (mark)
f1070_l equ $093
f1270_h equ $021 ; Bell 103 backward channel logic '0' (space)
f1270_l equ $0ea
;*********************************************************************************
; Pin Definitions: These are the pins on the Scenix Modem board. Not all are
; necessary. Check the documentation at the top of this
; program.
;*********************************************************************************
PDM_pin equ ra.0 ; D/A output pin
rx_pin equ ra.1 ; RS-232 reception pin
tx_pin equ ra.2 ; RS-232 transmission pin
nothing equ ra.3 ; N/C
RA_latch equ %11111111 ;SX18/20/28/48/52 port A latch init
RA_DDIR equ %11111010 ;SX18/20/28/48/52 port A DDIR value
RA_LVL equ %00000000 ;SX18/20/28/48/52 port A LVL value
RA_PLP equ %11111111 ;SX18/20/28/48/52 port A PLP value
led_pin equ rb.0 ; LED pin
rxa_pin equ rb.1 ; FSK receive pin
cntrl_1 equ rb.2 ; drive cntrl_1 low to disable the output of the LPF
ring equ rb.3 ; ring detection pin
hook equ rb.4 ; drive hook low to go off-hook
cntrl_3 equ rb.5 ; drive cntrl_3 low to disable the output of the HPF
rts equ rb.6 ; indicates to the SX that the PC wants to transmit data
cts equ rb.7 ; indicates to the PC that the SX is ready to receive data
RB_latch equ %11011011 ;SX18/20/28/48/52 port B latch init
RB_DDIR equ %01101010 ;SX18/20/28/48/52 port B DDIR value: HPF
RB_ST equ %11111111 ;SX18/20/28/48/52 port B ST value
RB_LVL equ %00000000 ;SX18/20/28/48/52 port B LVL value
RB_PLP equ %11111111 ;SX18/20/28/48/52 port B PLP value
fskRxPort equ rb
fskRxMask equ %00000010
rc_450_mask equ %11100101 ; Hybrid set-up for 450 ohms
rc_600_mask equ %11010101 ; Hybrid set-up for 600 ohms
rc_750_mask equ %10110101 ; Hybrid set-up for 750 ohms
rc_900_mask equ %01110101 ; Hybrid set-up for 900 ohms
dtmf_in_pin equ rc.0 ; DTMF input pin
dtmf_fdbk_pin equ rc.1 ; Negative feedback output for DTMF input
AtoD_in_pin equ rc.2 ; A/D input pin
AtoD_fdbk_pin equ rc.3 ; Negative feedback for A/D input
imp_450_pin equ rc.4 ; Set to an output to set hybrid for 450ohm line impedance. Tristate otherwise.
imp_600_pin equ rc.5 ; Set to an output to set hybrid for 600ohm line impedance. Tristate otherwise.
imp_750_pin equ rc.6 ; Set to an output to set hybrid for 750ohm line impedance. Tristate otherwise.
imp_900_pin equ rc.7 ; Set to an output to set hybrid for 900ohm line impedance. Tristate otherwise.
RC_latch equ %00001111 ;SX18/20/28/48/52 port C latch init
RC_DDIR equ rc_600_mask ;SX18/20/28/48/52 port C DDIR value
RC_ST equ %11111111 ;SX18/20/28/48/52 port C ST value
RC_LVL equ %00000000 ;SX18/20/28/48/52 port C LVL value
RC_PLP equ %11111111 ;SX18/20/28/48/52 port C PLP value
;*********************************************************************************
; SX18AC/20AC/28AC Mode addresses
; *On SX18/20/28, all registers addressed via mode are write only, with the exception of
; CMP and WKPND which do an exchange with W.
;*********************************************************************************
; Exchange addresses
CMP equ $08 ;Exchange Comparator enable/status register with W
WKPND equ $09 ;Exchange MIWU/RB Interrupts pending with W
; Port setup (read) addresses
WKED_W equ $0A ;Write MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_W equ $0B ;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_W equ $0C ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_W equ $0D ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
PLP_W equ $0E ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
DDIR_W equ $0F ;Write Port Direction
;************************ Beginning of program space ***************************
org $0
;******************************************************************************
; Interrupt
;
; With a retiw value of -163 and an oscillator frequency of 50MHz, this
; code runs every 3.26us.
;******************************************************************************
PDM_output
bank PDM_bank ; Update the PDM pin
add PDM0_acc,PDM0_out
snc
setb PDM_pin
sc
clrb PDM_pin
;**************************************************************************
jmp @ISR ; The ISR is in the second page, so go there.
;******************************************************************************
reset_entry
; Program Starts Here on Power Up
;******************************************************************************
;**********************************************************************
; First, call init to initialize the program
;**********************************************************************
call @init
mov !option,#%00011111 ; enable wreg and rtcc interrupt
setb tx_pin ; set the RS-232 tx_pin
setb CTS ; Don't allow PC to transmit
mov w,#25 ; delay 250 milliseconds
call @delay_10n_ms
;**********************************************************************
; Send "hello" string
;**********************************************************************
mov w,#_hello ; say 'hello'
call @send_string
mov w,#_help
call @send_string
;**********************************************************************
; Send prompt
;**********************************************************************
main_2
_send_prompt mov w,#_prompt ; send prompt
call @send_string
clrb CTS ; Allow PC to transmit
clr push_index ; Clear the buffer_push pointer
clr pop_index ; Clear the buffer_pop pointer
;**********************************************************************
; Fill the command buffer with input characters. Backspace will delete
; the last value entered.
;**********************************************************************
_cmd_loop
jnb rx_flag,$ ; Wait until we receive a byte via. RS-232
clrb rx_flag ; clear the flag
bank serial
mov byte,rx_byte ; Move the received byte to 'byte' and
call @uppercase ; convert it to uppercase
mov w,#$20 ; compare the byte to ' '
xor w,byte
jz _cmd_loop ; If byte == space, ignore it.
mov w,#$0a ; compare the byte to LF
xor w,byte
jz _cmd_loop ; If byte == line feed, ignore it.
mov w,#$0d ; compare the byte to CR
xor w,byte
jz :enter ; if byte == CR, parse the string.
mov w,byte ; if it does not resemble the above characters, echo it.
call @send_byte ; send via. RS-232
mov w,#$08 ; compare the byte to a backspace.
xor w,byte
jz :backspace ; if it equals a backspace, delete one character in the buffer.
call @buffer_push ; otherwise, store it
jmp _cmd_loop ; and come back for more.
:backspace
call @buffer_backspace
jmp _cmd_loop
:enter ; If the user presses enter, then parse the string.
;**************************************************************************
; String parser (Checks to see if buffer = any commands)
; -Checks contents of ascii buffer against any commands stored in ROM
; -If a command = the contents of the ascii buffer, a routine will be called
; -Each routine MUST perform a retw 0 on exit, or parse_string will not
; know that a routine has run and it should exit back to command mode.
; -Exits back to command mode when it detects a zero after the table look-up.
; -Outputs 'OK' if no commands are matched.
;**************************************************************************
parse_string
clr pop_index ; Clear the index into the ascii buffer
clr command_index ; And the index into the commands
:loop call @buffer_get ; Get a vale from the buffer at ascii_index
call command_table ; Get a character from one of the commands
test wreg ; If the return value is 0, then this matched
jz :nothing ; the command and ran a routine. Exit.
bank serial
xor w,byte ; compare the command's character with the
jnz :not_equal ; buffer's character.
call @inc_pop_index ; Increment the index into the buffer.
jmp :loop
:not_equal
inc command_index ; If the buffer did not equal the command,
clr pop_index ; start from the beginning of a new command
cjne command_index,#5,:loop ; compare command_index with 5 (This number = # of commands)
:nothing clrb fsk_rx_en
setb tx_pin
mov w,#20
call @delay_10n_ms
mov w,#_CR
call @send_string
mov w,#_OK ; If we have checked all 5 commands, then this
call @send_string ; did not equal any so send an 'OK' message.
:done
bank buffer
clr pop_index
clr push_index
clr buffer
jmp _send_prompt
;**************************************************************************
command_table
mov w,command_index
add pc,w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
jmp command_1
jmp command_2
jmp command_3
jmp command_4
jmp command_5
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
command_1 ; Dial command
mov w,pop_index
add PC,w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw 'A'
retw 'T'
retw 'D'
retw 'T'
jmp DIAL_MODE
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
command_2 ; Hang up command
mov w,pop_index
add PC,w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw 'A'
retw 'T'
retw 'H'
jmp HANG_UP
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
command_3 ; Initialize
mov w,pop_index
add PC,w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw 'A'
retw 'T'
retw 'Z'
jmp INITIALIZE
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
command_4 ; Data mode
mov w,pop_index
add PC,w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw 'A'
retw 'T'
retw 'O'
jmp FSK_IO
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
command_5 ; Hybrid Set-up
mov w,pop_index
add PC,w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw '?'
jmp HELP
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
; END of String parser (Checks to see if buffer = any commands)
;**************************************************************************
;**********************************************************************
; Hang Up
;**********************************************************************
HANG_UP
call @disable_o
clrb fsk_rx_en ; Disable fsk detection
mov w,#50
call @delay_100n_ms ; Pause for 5 seconds.
setb hook ; hang-up
retw 0
;**********************************************************************
; Initialize
;**********************************************************************
INITIALIZE
mov w,#10
call @delay_100n_ms ; Pause for 1 second
call @init
clr flags
retw 0
;**********************************************************************
; Send Help string
;**********************************************************************
HELP mov w,#_HELP
call @send_string
retw 0
;**************************************************************************
; Dial Mode:
; -Dials contents of ascii buffer, starting from location pointed
; to by ascii_index.
; -Responds to these commands:
; 0-9, *, # - Dials the specified number
; , - Pause for 2 seconds
; -Jumps to data mode after dialing.
;**************************************************************************
DIAL_MODE
clrb sine_gen_en ; Disable sine generation
clrb fsk_tx_en ; Disable fsk generation
clrb dtmf_gen_en ; Disable dtmf generation
clrb hook ; go off-hook
mov m,#$0f
mov w,#%01101010 ; rb.5 (cntrl_3) is tristate, rb.2 (cntrl_1) is low
mov !rb,w
clrb cntrl_1 ; Enable lowest low-pass filter on output
mov w,#40 ; delay 4 seconds before dialing
call @delay_100n_ms
mov w,#_CR ; Send a carriage return
call @send_string
mov w,#_DIALING ; send "Dialing" to screen
call @send_string
bank serial
:dial_loop call @buffer_get ; Get a character from the buffer
call @uppercase ; convert it to uppercase
mov w,byte ; test byte for zero
snz
jmp :originate_mode ; If byte is zero, dialing is done.
call @send_byte
cje byte,#',',:pause ; if the character = ',', pause for 2s
call @digit_2_index ; convert the ascii digit to an
; index value
call @load_frequencies ; load the frequency registers
call @dial_it ; dial the number for 60ms and return.
:inc call @inc_pop_index ; increment the index into the table
jmp :dial_loop
:pause
mov w,#20 ; delay 2s
call @delay_100n_ms
jmp :inc
:originate_mode
;******************************************************************
; Set/clear proper flags for origination
;******************************************************************
bank fsk_transmit_bank
clr fsk_tx_divide_2 ; clear the transmit-divider
clr flags ; clear all flags.
clrb fsk_answering ; we are not answering.
setb fsk_tx_bit ; set the transmit bit to logic '1'
setb sine_gen_en ; enable the sine generators
setb fsk_tx_en ; enable the fsk transmitter
mov w,#50 ; delay 5 seconds after dialing to wait for carrier
call @delay_100n_ms
jb carrier_detected,FSK_IO ; if there still is no carrier, exit
mov w,#50 ; delay 5 seconds after dialing to wait for carrier
call @delay_100n_ms
jb carrier_detected,FSK_IO ; if there still is no carrier, exit
mov w,#100 ; delay 10 seconds after dialing to wait for carrier
call @delay_100n_ms
jb carrier_detected,FSK_IO
mov w,#150 ; delay 15 seconds after dialing to wait for carrier
call @delay_100n_ms
jb carrier_detected,FSK_IO
no_carrier
clrb fsk_rx_en
setb tx_pin
mov w,#80 ; give carrier 8 more seconds to re-appear
call @delay_100n_ms
jb carrier_detected,FSK_IO_AGAIN
mov w,#_no_carrier
call @send_string
jmp INITIALIZE
;******************************************************************
; Once at FSK I/O mode, the program sends/receives data. In
; originate mode, the send is at 75bps and the receive is at 1200bps.
; Because of the difference in baud rates, hardware flow control
; is used. CTS is disabled when the buffer is close to capacity,
; and re-enabled when the buffer is completely empty.
;******************************************************************
FSK_IO
mov w,#_DATA_MODE ; Send "connect" message
call @send_string
FSK_IO_AGAIN clr plus_count ; clear the plus count
clr push_index ; clear the push pointer to buffer
clr pop_index ; clear the pop pointer to buffer
setb fsk_rx_en ; enable the FSK reception part of ISR
mov m,#$0f
mov w,#%01101010 ; rb.5 (cntrl_3) is tristate, rb.2 (cntrl_1) is low
mov !rb,w
clrb cntrl_1 ; Enable lowest low-pass filter on output
clrb cts ; clear CTS to tell PC "ready for data"
;******************************************************************
; This is the main loop for FSK I/O. Sends FSK bytes, and receives
; bytes from the UART. The FSK receive portion of FSK I/O is completely
; handled by the ISR
;******************************************************************
:loop2
jnb timer_flag,:no_timeout ; if (timer_flag)
bank serial
test plus_count ; if (plus_count)
jz :no_timeout
mov w,plus_count ; if (plus_count==3)
xor w,#3 ; return;
snz
retw 0
jmp :clr_plus_count ; else clr_plus_count();
; else no_timout();
; else no_timeout();
:no_timeout jnb carrier_detected,no_carrier
jb rx_flag,:got_byte ; Received a byte of data. Handle it.
bank fsk_transmit_bank ; If no byte, check to see if we need to transmit
test fsk_tx_count ; Are we transmitting anything?
sz ; if no, then send next byte.
jmp :loop2 ; else jump here forever (ISR does all the work)
mov w,pop_index ; If pop_index == push_index, everything in the buffer has been sent.
xor w,push_index
sz
jmp :not_empty_yet
;******************************************************************
; The buffer is empty: initialize the buffer and enable CTS.
;******************************************************************
:empty
clr push_index ; so clear the buffer indexes
clr pop_index
clrb cts ; and clear cts to allow more data from DCE
jmp :loop2
;******************************************************************
; The buffer is not empty, keep sending stuff..
;******************************************************************
:not_empty_yet
call @buffer_get ; if the buffer is not empty, get the next byte
call @fsk_send_byte ; from the buffer and send it via. FSK
call @inc_pop_index ; and increment the pop index
and pop_index,#$0f
jmp :loop2
;******************************************************************
; The we just received a byte, so put it on the buffer.
;******************************************************************
:got_byte
bank serial
clrb rx_flag
mov byte,rx_byte
call @buffer_push
;******************************************************************
; Check to see if the pop index is at (push index + 5)
;******************************************************************
and push_index,#$0f
mov w,#5
add w,push_index
and w,#$0f ; keep push index < 16
xor w,pop_index ; if (push_index + 5 == pop_index, the buffer is almost full so indicate this)
snz
setb cts ; If push index == pop index, disable CTS
bank serial
mov w,#'+' ; If the byte = '+', increment plus_count, otherwise, plus_count == 0
xor w,rx_byte ; If byte = '+'
jz :plus_received ; plus_received();
:clr_plus_count ; Else
clr plus_count ; clr_plus_count();
mov w,#255 ;
call @reset_timers ;
jmp :loop2 ;
:plus_received ; plus_received();
test plus_count ; If !(plus_count)
jz :zero_plus_count ; zero_plus_count();
:some_pluses jb timer_flag,:clr_plus_count; else if (timer_flag)
:inc_plus_count inc plus_count ; clr_plus_count();
mov w,#200 ; else
call @reset_timers ; inc_plus_count();
jmp :loop2
:zero_plus_count
sb timer_flag ; If (timer_flag)
jmp :clr_plus_count ; clr_plus_count();
jmp :inc_plus_count ; else inc_plus_count
;**************************************************************************
; Miscellaneous subroutines....
;**************************************************************************
org $200
;**************************************************************************
reset_timers
; This subroutine times 'w' ticks, and returns with a '1' in w when
; the specified time has timed out. Each tick is 13.35296 ms.
; This subroutine uses the TEMP2 register. Call this routine with w = 0
; to poll for a time_out.
;**************************************************************************
bank timers
not w
inc wreg
mov timer_h,w
clr timer_l
clrb timer_flag
retp
;**************************************************************************
buffer_push
; This subroutine pushes the contents of byte onto the 64-byte ascii buffer.
;**************************************************************************
bank serial ; Move the byte into the buffer
mov temp,byte
mov fsr,#buffer
add fsr,push_index
mov indf,temp
; Increment index and keep it in range
call @inc_push_index
mov fsr,#buffer ; Null terminate the buffer.
add fsr,push_index
clr indf
bank serial
retp
;**************************************************************************
;**************************************************************************
buffer_backspace
; This subroutine deletes one value of the buffer and decrements the index
;**************************************************************************
dec push_index
and push_index,#%01101111
mov fsr,#buffer
add fsr,push_index
clr indf
bank serial
retp
;**************************************************************************
inc_pop_index
;**************************************************************************
mov fsr,#pop_index
jmp inc_index
;**************************************************************************
inc_push_index
;**************************************************************************
mov fsr,#push_index
;**************************************************************************
inc_index
; This subroutine increments the index into the buffer
;**************************************************************************
mov w,indf
and w,#%00001111
xor w,#%00001111
jnz :not_on_verge
inc indf
mov w,#16
add w,indf
and w,#$7f
mov indf,w
retp
:not_on_verge
inc indf
retp
;**************************************************************************
buffer_get
; This subroutine retrieves the buffered value at index
;**************************************************************************
mov fsr,#buffer
add fsr,pop_index
mov w,indf
bank serial
mov byte,w
retp
;**************************************************************************
delay_10n_ms
; This subroutine delays 'w'*10 milliseconds. (not exactly, but pretty close)
; This subroutine uses the TEMP register
; INPUT w - w/10 milliseconds to delay for.
; OUTPUT Returns after 10 * n milliseconds.
;**************************************************************************
mov temp,w
bank timers
:loop clrb timer_flag ; This loop delays for 10ms
mov timer_h,#$0ff
mov timer_l,#$041
jnb timer_flag,$
dec temp ; do it w-1 times.
jnz :loop
clrb timer_flag
retp
;**************************************************************************
delay_100n_ms
; This subroutine delays 'w'*100 milliseconds. (not exactly, but pretty close)
; This subroutine uses the TEMP register
; INPUT w - w/100 milliseconds to delay for.
; OUTPUT Returns after 100 * n milliseconds.
;**************************************************************************
mov temp,w
bank timers
:loop clrb timer_flag ; This loop delays for 10ms
mov timer_h,#$0f8
mov timer_l,#$083
jnb timer_flag,$
dec temp ; do it w-1 times.
jnz :loop
clrb timer_flag
retp
;**************************************************************************
zero_ram
; Subroutine - Zero all ram.
; INPUTS: None
; OUTPUTS: All ram locations (except special function registers) are = 0
;**************************************************************************
CLR FSR
:loop SB FSR.4 ;are we on low half of bank?
SETB FSR.3 ;If so, don't touch regs 0-7
CLR IND ;clear using indirect addressing
IJNZ FSR,:loop ;repeat until done
retp
;**************************************************************************
; Subroutine - Disable the outputs
; Load DC value into PDM and disable the output switch.
;**************************************************************************
disable_o
bank PDM_bank ; input mode.
mov PDM0_out,#128 ; put 2.5V DC on PDM output pin
clrb sine_gen_en
clrb dtmf_gen_en
clrb fsk_tx_en
retp
;**************************************************************************
init
; Initializes the program.
;**************************************************************************
_mode ST_W ;point MODE to write ST register
mov w,#RB_ST ;Setup RB Schmitt Trigger, 0 = enabled, 1 = disabled
mov !rb,w
mov w,#RC_ST ;Setup RC Schmitt Trigger, 0 = enabled, 1 = disabled
mov !rc,w
_mode LVL_W ;point MODE to write LVL register
mov w,#RA_LVL ;Setup RA CMOS or TTL levels, 0 = TTL, 1 = CMOS
mov !ra,w
mov w,#RB_LVL ;Setup RB CMOS or TTL levels, 0 = TTL, 1 = CMOS
mov !rb,w
mov w,#RC_LVL ;Setup RC CMOS or TTL levels, 0 = TTL, 1 = CMOS
mov !rc,w
_mode PLP_W ;point MODE to write PLP register
mov w,#RA_PLP ;Setup RA Weak Pull-up, 0 = enabled, 1 = disabled
mov !ra,w
mov w,#RB_PLP ;Setup RB Weak Pull-up, 0 = enabled, 1 = disabled
mov !rb,w
mov w,#RC_PLP ;Setup RC Weak Pull-up, 0 = enabled, 1 = disabled
mov !rc,w
_mode DDIR_W ;point MODE to write DDIR register
mov w,#RA_DDIR ;Setup RA Direction register, 0 = output, 1 = input
mov !ra,w
mov w,#RB_DDIR ;Setup RB Direction register, 0 = output, 1 = input
mov !rb,w
mov w,#RC_DDIR ;Setup RC Direction register, 0 = output, 1 = input
mov !rc,w
mov w,#RA_latch ;Initialize RA data latch
mov ra,w
mov w,#RB_latch ;Initialize RB data latch
mov rb,w
mov w,#RC_latch ;Initialize RC data latch
mov rc,w
setb hook ; go on hook.
clrb cts
setb led_pin ; turn on LED
clr flags ; Clear all flags
call zero_ram
call @disable_o
retp
;**************************************************************************
; Subroutine - Get byte via serial port and echo it back to the serial port
; INPUTS:
; -NONE
; OUTPUTS:
; -received byte in rx_byte
;**************************************************************************
get_byte jnb rx_flag,$ ;wait till byte is received
clrb rx_flag ;reset the receive flag
bank serial ;switch to serial bank
mov byte,rx_byte ;store byte (copy using W)
; & fall through to echo char back
;**************************************************************************
; Subroutine - Send byte via serial port
; INPUTS:
; w - The byte to be sent via RS-232
;**************************************************************************
send_byte bank serial
:wait test tx_count ;wait for not busy
jnz :wait ;
not w ;ready bits (inverse logic)
mov tx_high,w ; store data byte
setb tx_low.7 ; set up start bit
mov tx_count,#10 ;1 start + 8 data + 1 stop bit
RETP ;leave and fix page bits
;**************************************************************************
; Subroutine - Send byte via serial port
; INPUTS:
; w - The byte to be sent via RS-232
;**************************************************************************
fsk_send_byte bank fsk_serial_bank
:wait test fsk_tx_count ;wait for not busy
jnz :wait ;
not w ;ready bits (inverse logic)
mov fsk_tx_high,w ; store data byte
setb fsk_tx_low.7 ; set up start bit
mov fsk_tx_count,#10 ;1 start + 8 data + 1 stop bit
RETP ;leave and fix page bits
;**************************************************************************
; Subroutine - Send string pointed to by address in W register
; INPUTS:
; w - The address of a null-terminated string in program
; memory
; OUTPUTS:
; outputs the string via. RS-232
;**************************************************************************
send_string bank serial
mov string,w ;store string address
:loop mov w,string ;read next string character
mov m,#3 ; with indirect addressing
iread ; using the mode register
mov m,#$F ;reset the mode register
test w ;are we at the last char?
snz ;if not=0, skip ahead
RETP ;yes, leave & fix page bits
call send_byte ;not 0, so send character
inc string ;point to next character
jmp :loop ;loop until done
;**************************************************************************
; Subroutine - Make byte uppercase
; INPUTS:
; byte - The byte to be converted
; OUTPUTS:
; byte - The uppercase byte
;**************************************************************************
uppercase
csae byte,#'a' ;if byte is lowercase, then skip ahead
RETP
sub byte,#'a'-'A' ;change byte to uppercase
RETP ;leave and fix page bits
;**************************************************************************
org $300
;**************************************************************************
; String data (for RS-232 output) and tables
;**************************************************************************
_hello dw 13,10,'V.23 Originate V.1.37',13,10,0
_instructions dw '- ? For Help',0
_DIALING dw 'DIAL ',0
_PROMPT dw 13,10,'>',0
_OK dw 'OK',13,10,0
_CR dw 13,10,0
_DATA_MODE dw 13,10,'CONNECT 1275',13,10,0
_no_carrier dw 13,10,'NO CARRIER',0
_HELP dw 13,10,'ATDT- Dial',13,10,'ATH - Hang Up',13,10,'ATO - Data Mode',13,10,'ATZ - Init',13,10,'+++ - Command Mode',0
;**************************************************************************
org $400 ; FSK subroutines and the Interrupt Service Routine.
;**************************************************************************
answer_tone
; This subroutine sends out an answer tone of 2100Hz for 3 seconds.
;**************************************************************************
bank sine_gen_bank ; send out the answer tone for 3 seconds
clr curr_sine
mov freq_count_high2,#f2100_h
mov freq_count_low2,#f2100_l
setb sine_gen_en ; enable the FSK transmitter
mov w,#30
call @delay_100n_ms
retp
;**************************************************************************
; THESE ROUTINES ARE RUN WITHIN THE ISR... DO NOT CALL THEM FROM THE MAINLINE.
;**************************************************************************
;******************************************************************************
carrier_detect
bank carrier_detect_bank
inc cd_trans_count
jnz :no_rollover
dec cd_trans_count
jmp :sample
:no_rollover
mov w,rb
xor w,cd_rb_past_state
and w,#%00000010
snz
retp
xor cd_rb_past_state,w
sb cd_rb_past_state.1
retp
:sample
mov w,cd_trans_count
add cd_trans_avg_l,w
snc
inc cd_trans_avg_h
clr cd_trans_count
inc cd_avg_count
sz
retp
setb carrier_detected
mov w,#-8
add w,cd_trans_avg_h
sc
clrb carrier_detected
mov w,#-16
add w,cd_trans_avg_h
snc
clrb carrier_detected
clr cd_trans_avg_h
clr cd_trans_avg_l
retp
;**************************************************************************
fsk_receive_main ; This code is speed critical and runs in every
; ISR. It increments the FSK transition couters
; and checks for a transition. If a transition
; has occured, it sets a flag, and saves the
; transition count for later processing by the
; fsk_receive_processing1 subroutine.
;**************************************************************************
bank fsk_receive_bank
sb fsk_rx_en
retp
inc fsk_trans_count
snz
dec fsk_trans_count
mov w,fsk_rb_past_state
xor w,rb
and w,#%00000010
snz
retp
xor fsk_rb_past_state,w
setb fsk_processing_required_1
mov fsk_temp_trans,fsk_trans_count
clr fsk_trans_count
retp
;**************************************************************************
fsk_receive_main_2 ; This code removes some of the jitter away from
; the low frequency detection algorithm by
; continuously checking the transition count
; to see if it has now reached a point where it
; is safe to say that there is no high frequency
; present.
;**************************************************************************
bank fsk_receive_bank
sb fsk_rx_en
retp
mov w,#-(threshold+fsk_hysterises)
add w,fsk_trans_count
snc
; setb fsk_rx_bit
; setb test_pin
setb tx_pin
add w,fsk_last_trans
snc
; setb test_pin
; setb fsk_rx_bit
setb tx_pin
retp
;**************************************************************************
fsk_receive_processing1 ; This subroutine runs only when a transition has
; occurred. It adds the last transition count
; to the current one and checks this against the
; high/low frequency threshold. If the transition
; count is below the threshold, the fsk_rx_bit
; flag is cleared.
;**************************************************************************
bank fsk_receive_bank
sb fsk_processing_required_1
retp ; Exit if disabled
clrb fsk_processing_required_1
mov w,#-25 ; compare the transition count with 5
add w,fsk_temp_trans
jnc :glitch ; If the transition count is less than 5, handle the glitch.
mov w,#-(threshold-fsk_hysterises) ; compare the transition count with
add w,fsk_temp_trans ; the threshold (-hysterises)
snc
mov w,#$ff
add w,fsk_last_trans
sc
; clrb test_pin
; clrb fsk_rx_bit
clrb tx_pin ; Clear the TX_PIN if the transition count is less than the threshold
mov fsk_last_trans,fsk_temp_trans ; save the last transition count.
retp
:glitch
mov w,fsk_last_trans ; of the last transition
add w,fsk_temp_trans
snc
mov w,#$ff
mov fsk_last_trans,w
retp
;**************************************************************************
task_manager
; This portion of the ISR allows 1 of 16 separate tasks to run in each
; interrupt.
;**************************************************************************
inc task_switcher
mov w,task_switcher
and w,#$0f
jmp pc+w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
;*** TASKS ***
jmp fsk_receive_main_2 ;0
jmp transmit ;1
jmp receive ;2
jmp fsk_transmit_uart ;3
jmp fsk_receive_main_2 ;4
jmp transmit_fsk ;5
jmp do_timers ;6
jmp fsk_receive_processing1 ;7
jmp fsk_receive_main_2 ;8
jmp carrier_detect ;9
retp ;10
retp ;11
jmp fsk_receive_main_2 ;12
retp ;13
retp ;14
retp ;15
jmp fsk_receive_main_2 ;16
retp ; (just in case)
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
fsk_transmit_uart
; This is an asynchronous RS-232 transmitter
; INPUTS:
; tx_divide.baud_bit - Transmitter only executes when this bit is = 1
; tx_high - Part of the data to be transmitted
; tx_low - Some more of the data to be transmitted
; tx_count - Counter which counts the number of bits transmitted.
; OUTPUTS:
; tx_pin - Sets/Clears this pin to accomplish the transmission.
;**************************************************************************
bank fsk_serial_bank
sb fsk_answering
inc fsk_tx_divide_2
and fsk_tx_divide_2,#$0f ; Divide the 1200bps UART by 16 to
; achieve 75bps
sz
retp
clrb fsk_tx_divide.baud_bit ;clear xmit timing count flag
inc fsk_tx_divide ;only execute the transmit routine
STZ ;set zero flag for test
SNB fsk_tx_divide.baud_bit ; every 2^baud_bit interrupt
test fsk_tx_count ;are we sending?
snz
retp ;if not, go to :receive
clc ;yes, ready stop bit
rr fsk_tx_high ; and shift to next bit
rr fsk_tx_low ;
dec fsk_tx_count ;decrement bit counter
movb fsk_tx_bit,/fsk_tx_low.6 ;output next bit
retp
;**************************************************************************
transmit
; This is an asynchronous RS-232 transmitter
; INPUTS:
; tx_divide.baud_bit - Transmitter only executes when this bit is = 1
; tx_high - Part of the data to be transmitted
; tx_low - Some more of the data to be transmitted
; tx_count - Counter which counts the number of bits transmitted.
; OUTPUTS:
; tx_pin - Sets/Clears this pin to accomplish the transmission.
;**************************************************************************
bank serial
clrb tx_divide.baud_bit ;clear xmit timing count flag
inc tx_divide ;only execute the transmit routine
STZ ;set zero flag for test
SNB tx_divide.baud_bit ; every 2^baud_bit interrupt
test tx_count ;are we sending?
snz
retp ;if not, go to :receive
clc ;yes, ready stop bit
rr tx_high ; and shift to next bit
rr tx_low ;
dec tx_count ;decrement bit counter
movb tx_pin,/tx_low.6 ;output next bit
retp
;**************************************************************************
receive
; This is an asynchronous receiver for RS-232 reception
; INPUTS:
; rx_pin - Pin which RS-232 is received on.
; OUTPUTS:
; rx_byte - The byte received
; rx_flag - Set when a byte is received.
;**************************************************************************
bank serial
movb c,rx_pin ;get current rx bit
test rx_count ;currently receiving byte?
jnz :rxbit ;if so, jump ahead
mov w,#9 ;in case start, ready 9 bits
sc ;skip ahead if not start bit
mov rx_count,w ;it is, so renew bit count
mov rx_divide,#start_delay ;ready 1.5 bit periods
:rxbit djnz rx_divide,:rxdone ;middle of next bit?
setb rx_divide.baud_bit ;yes, ready 1 bit period
dec rx_count ;last bit?
sz ;if not
rr rx_byte ; then save bit
snz ;if so
setb rx_flag ; then set flag
:rxdone
retp
;**************************************************************************
do_timers
; The 24-bit timer increments every 52.16us when called by task_manager.
;**************************************************************************
bank timers ; Update the timers
inc timer_l
snz
inc timer_h
snz
setb timer_flag
snz
inc timer_hh
snz
dec timer_hh
setb led_pin
sb timer_h.2
clrb led_pin
retp
;**************************************************************************
transmit_fsk
;**************************************************************************
bank fsk_transmit_bank
sb fsk_tx_en
retp
jb fsk_answering,transmit_answer_tones
transmit_originate_tones
jnb fsk_tx_bit,:low_bit
:high_bit
bank sine_gen_bank
mov freq_count_high2,#f390_h
mov freq_count_low2,#f390_l
retp
:low_bit
bank sine_gen_bank
mov freq_count_high2,#f450_h
mov freq_count_low2,#f450_l
retp
transmit_answer_tones
jnb fsk_tx_bit,:low_bit
:high_bit
bank sine_gen_bank
mov freq_count_high2,#f1300_h
mov freq_count_low2,#f1300_l
retp
:low_bit
bank sine_gen_bank
mov freq_count_high2,#f2100_h
mov freq_count_low2,#f2100_l
retp
;******************************************************************************
; Interrupt
;
; With a retiw value of -163 and an oscillator frequency of 50MHz, this
; code runs every 3.26us.
;******************************************************************************
ISR
;******************************************************************************
FSK_output
jnb dtmf_gen_en,:dtmf_disabled
call @sine_generator1
call @DTMF_twist
jmp :task_switcher
:dtmf_disabled
jnb sine_gen_en,:task_switcher ; Output the frequencies set by the freq_count registers
call @sine_generator2
call @SINE_out ; Output each discrete value of the sine table
call fsk_receive_main
:task_switcher
call task_manager
;******************************************************************************
ISR_DONE
; This is the end of the interrupt service routine. Now load -163 into w and
; perform a retiw to interrupt 163 cycles from the start of this one.
; (3.26us@50MHz)
;******************************************************************************
mov w,#-163 ;1 ; interrupt 163 cycles after this interrupt
retiw ;3 ; return from the interrupt
;******************************************************************************
; End of the Interrupt Service Routine
;******************************************************************************
;**************************************************************************
org $600 ; These subroutines are on page 3.
;**************************************************************************
; DTMF transmit functions/subroutines
;**************************************************************************
;**************************************************************************
DTMF_TABLE ; DTMF tone constants
; This routine returns with the constant used for each of the frequency
; detectors.
; INPUT: w - Index into the table (0-15 value)
; OUTPUT: w - Constant at that index
;**************************************************************************
jmp PC+w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw f697_l
retw f697_h
retw f770_l
retw f770_h
retw f852_l
retw f852_h
retw f941_l
retw f941_h
retw f1209_l
retw f1209_h
retw f1336_l
retw f1336_h
retw f1477_l
retw f1477_h
retw f1633_l
retw f1633_h
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
ASCII_TABLE ; Ascii value at index (0-15)
; INPUT: w - Index into the table (0-15 value)
; OUTPUT: w - Constant at that index
;**************************************************************************
jmp PC+w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw '1'
retw '2'
retw '3'
retw 'A'
retw '4'
retw '5'
retw '6'
retw 'B'
retw '7'
retw '8'
retw '9'
retw 'C'
retw '*'
retw '0'
retw '#'
retw 'D'
tableEnd ; Will cause a compiler error if not located in the lower half of a page.
;**************************************************************************
index_2_digit
; This subroutine converts a digit from 0-9 or a '*' or a '#' to a table
; lookup index which can be used by the load_frequencies subroutine. To use
; this routine, pass it a value in the 'byte' register. No invalid digits
; are used. (A, B, C, or D)
;**************************************************************************
call ASCII_TABLE
retp
;**************************************************************************
digit_2_index
; This subroutine converts a digit from 0-9 or a '*' or a '#' to a table
; lookup index which can be used by the load_frequencies subroutine. To use
; this routine, pass it a value in the 'byte' register. No invalid digits
; are used. (A, B, C, or D)
;**************************************************************************
bank serial
clr temp
:loop
mov w,temp
call ASCII_TABLE
xor w,byte
jz :done
inc temp
jb temp.4,:done
jmp :loop
:done mov w,temp
retp
;**************************************************************************
load_frequencies
; This subroutine loads the frequencies using a table lookup approach.
; The index into the table is passed in the byte register. The DTMF table
; must be in the range of $400 to $500.
;**************************************************************************
mov temp,w
bank sine_gen_bank
mov w,>>temp
and w,#%00000110
call DTMF_TABLE
mov freq_count_low,w
mov w,>>temp
and w,#%00000110
inc wreg
call DTMF_TABLE
mov freq_count_high,w
rl temp
setb temp.3
mov w,temp
and w,#%00001110
mov temp,w
call DTMF_TABLE
mov freq_count_low2,w
mov w,temp
inc wreg
call DTMF_TABLE
mov freq_count_high2,w
retp
;**************************************************************************
dial_it ; This subroutine puts out whatever frequencies were loaded
; for 100ms, and then stops outputting the frequencies.
;**************************************************************************
bank sine_gen_bank
clr sine_index
clr sine_index2
mov w,#1
call @delay_100n_ms ; delay 100ms
setb dtmf_gen_en
mov w,#1
call @delay_100n_ms ; delay 100ms
clrb dtmf_gen_en
call @disable_o ; now disable the outputs
:end_dial_it retp
;**************************************************************************
sine_generator1 ;(Part of interrupt service routine)
; This routine generates a sine wave with values from the sine table
; at the end of this program. Frequency is specified by the counter. To set
; the frequency, put this value into the 16-bit freq_count register:
; freq_count = FREQUENCY * 6.83671552 (@50MHz)
;**************************************************************************
bank sine_gen_bank
clrb swCarryFlag
add freq_acc_low,freq_count_low
snc
setb swCarryFlag
add freq_acc_high,freq_count_high
snb swCarryFlag
inc freq_acc_high
snz
jmp :change ; if zero, this definetely caused a rollover.
sc
jmp :no_change
:change inc sine_index
mov w,sine_index
and w,#$1f
call sine_table
mov curr_sine,w ;1
:no_change
;**************************************************************************
sine_generator2 ;(Part of interrupt service routine)
; This routine generates a sine wave with values from the sine table
; at the end of this program. Frequency is specified by the counter. To set
; the frequency, put this value into the 16-bit freq_count register:
; freq_count = FREQUENCY * 6.83671552 (@50MHz)
;**************************************************************************
bank sine_gen_bank
clrb swCarryFlag
add freq_acc_low2,freq_count_low2
snc
setb swCarryFlag
add freq_acc_high2,freq_count_high2
snb swCarryFlag
inc freq_acc_high2
snz
jmp :change ; if zero, this definetely caused a rollover.
sc
jmp :no_change
:change inc sine_index2
mov w,sine_index2
and w,#$1f
call sine_table
mov curr_sine2,w
:no_change
retp
;**************************************************************************
SINE_out
; This subroutine moves the FSK output to the PDM register
;**************************************************************************
bank sine_gen_bank
mov w,#127
add w,curr_sine2
mov PDM0_out,w
retp
;**************************************************************************
DTMF_twist
; This subroutine adds twist to the high frequency of the DTMF output.
;**************************************************************************
bank sine_gen_bank
mov PDM0_out,curr_sine2 ; mov sin2 into PDM0
rr wreg
rr wreg
and w,#$3f
snb wreg.5
or w,#$C0
add PDM0_out,w ; (1.25)(sin2) = sin2 + (0.25)(sin2)
add PDM0_out,curr_sine ; add the value of SIN into the PDM output
add PDM0_out,#128 ; for result = PDM0 = 1.25*sin2 + 1*sin
retp ; return with page bits intact
;******************************************************************************
sine_table
; The values in this table can be changed to increase/decrease the amplitude of
; the output sine wave.
; This sine table gives an output level of approximately -15dB into a 600 ohm
; impedance
;******************************************************************************
jmp pc+w
tableStart ; Will cause a compiler error if not located in the lower half of a page.
retw 0
retw 4
retw 8
retw 11
retw 14
retw 16
retw 18
retw 19
retw 20
retw 19
retw 18
retw 16
retw 14
retw 11
retw 8
retw 4
retw 0
retw -4
retw -8
retw -11
retw -14
retw -16
retw -18
retw -19
retw -20
retw -19
retw -18
retw -16
retw -14
retw -11
retw -8
retw -4
tableEnd ; Will cause a compiler error if not located in the lower half of a page. ; Will cause a compiler error if not locat
;******************************************************************************
; Copyright © 1998 Scenix Semiconductor, Inc. All rights
; reserved.
;
; Scenix Semiconductor, Inc. assumes no responsibility or liability for
; the use of this [product, application, software, any of these products].
;
; Scenix Semiconductor conveys no license, implicitly or otherwise, under
; any intellectual property rights.
; Information contained in this publication regarding (e.g.: application,
; implementation) and the like is intended through suggestion only and may
; be superseded by updates. Scenix Semiconductor makes no representation
; or warranties with respect to the accuracy or use of these information,
; or infringement of patents arising from such use or otherwise.
;
; Scenix Semiconductor products are not authorized for use in life support
; systems or under conditions where failure of the product would endanger
; the life or safety of the user, except when prior written approval is
; obtained from Scenix Semiconductor.
;******************************************************************************
file: /Techref/scenix/lib/io/dev/modem/v_23_originate_1_37.src, 68KB, , updated: 2001/10/27 12:18, local time: 2024/11/14 08:31,
|
| ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/Techref/scenix/lib/io/dev/modem/v_23_originate_1_37.src"> scenix lib io dev modem v_23_originate_1_37</A> |
Did you find what you needed?
|