📄 voip8kisr.asm
字号:
CMP A, [_usbOutIn+LSB]
JNZ .s1 ; USB data available, use it
MOV X, 0x40 ; No USB data yet, just feed
MOV A, 0x00 ; uint15 half-scale values
JMP .goDat
; ^^^^^^^^ No USB data
.s1: AND F, ~FLAG_PGMODE_MASK
OR F, FLAG_PGMODE_2 ; Use IDX_PP here
MOV A, [_usbOutOt+MSB] ; page #
MOV REG[IDX_PP], A
MOV X, [_usbOutOt+LSB] ; page index
TST [X+0], 0x80 ; Test if insert or delete here
JZ .norm ; no
MOV A, [_nulInsDel]
MOV [_nulInsDel], 0 ; Release so main() can adjust again
CMP A, 1
JZ .ins
.del: INC X ; Delete just skips this sample
INC X
JMP .norm
; ^^^^^^^^ Delete/Skip this sample
.ins: AND [X+0], 0x7F ; Erase "special" bit (use next ISR)
MOV X, [_insertVal+MSB] ; and fetch synthesized sample.
MOV A, [_insertVal+LSB] ; LSB
JMP .goDat
; ^^^^^^^^ Insert sample
.norm: MOV A, [X+0] ; MSB
PUSH A
MOV A, [X+1] ; LSB
ADD [_usbOutOt+1], 2 ; ptr += 2
POP X ; MSB
; --------------------------------------------------------------------
; X,A = 15-bit unipolar PCM data to be compressed
; --------------------------------------------------------------------
.goDat: AND F, ~FLAG_PGMODE_MASK ; Restore ISR PageMode_0
CALL adpcmEncode ; X,A = 15-bit unsigned PCM
; A[3:0] = ADPCM
IF LOOPBACK_ADPCM ;#############################################
MOV [timeTmpA], A ; save encoded ADPCM sample for decoding below
ENDIF ; LOOPBACK_ADPCM ;#############################################
MOV X, [bufTxVoipPtr]
TST [_slotCt], 1 ; test for Odd Slot
JNZ .msn ; Odd slots put ADPCM in MSNibble
MOV [X+0], A ; Load LSN, zero MSN
JMP .decode
.msn: ASL A
ASL A
ASL A
ASL A
OR [X+0], A ; Merge MSN with existing LSN
INC [bufTxVoipPtr] ; Next nibble goes in new Byte
; ----------------------------------------------------------------------------
;
; Decode 4-bit ADPCM Radio Sample to 16-bit, 2's complement for USB
;
; ----------------------------------------------------------------------------
.decode:
; Get 4-bit ADPCM sample from Radio Rx buffer
; -------------------------------------------
MOV A, [bufRxVoipPtr] ; Zero if no Rx RF Frame available
JZ .noRxSamples
MOV X, A
MOV A, [X] ; A[7:4],[3:0] = ADPCM samples
TST [_slotCt], 1
JZ .lsn ; Even slots get ADPCM from LSNibble
ASR A ; Odd slots get ADPCM from MSNibble
ASR A ;
ASR A ;
ASR A ;
INC [bufRxVoipPtr] ; Next nibble comes from new Byte
.lsn: AND A, 0x0F
IF LOOPBACK_ADPCM ;#############################################
MOV A, [timeTmpA] ; ;#####
ENDIF ; LOOPBACK_ADPCM ;#############################################
LCALL adpcmDecode ; 4-bit ADPCM -->15-bit unipolar PCM
MOV [timeTmpA], X ; Convert [14: 0] unipolar to
ASL A ; [15: 0] 2's complement for USB
RLC [timeTmpA] ; [timeTmpA],A = 16-bit unipolar
XOR [timeTmpA], 0x80 ; [timeTmpA],A = 2's complement
JMP .save
; --------------------------------------------------------------------
; No RF frame received for this 24-sample set
;
; n = n - (n>>3) low-pass filter
; --------------------------------------------------------------------
.noRxSamples:
IF LOOPBACK_ADPCM ;#############################################
MOV A, [timeTmpA] ; keep feeding data to track
LCALL adpcmDecode ; 4-bit ADPCM -->15-bit unipolar PCM
ENDIF ; LOOPBACK_ADPCM ;#############################################
MOV A, 0 ; No ADPCM samples,
MOV [timeTmpA], 0 ; use 1/2 scale 2's complement PCM
; --------------------------------------------------------------------
.save:
PUSH A ; Park [ 7: 0] of PCM
AND F, ~FLAG_PGMODE_MASK
OR F, FLAG_PGMODE_2 ; Use IDX_PP here
MOV A, [_usbInIn+MSB] ; Page #
MOV REG[IDX_PP], A
MOV X, [_usbInIn+LSB] ; adr within page
MOV A, [timeTmpA]
MOV [X+1], A ; Store MSB (little-endian for USB)
POP A
MOV [X+0], A ; Store LSB (little-endian for USB)
ADD [_usbInIn+LSB], 2 ; buffer wraps mod 256 on single page
AND F, ~FLAG_PGMODE_MASK ; Restore ISR PageMode_0
; ----------------------------------------------------------------------------
; ----------------------------------------------------------------------------
ctrIsrX:
; -----------------------------
POP A ; Restore Direct page pointer
MOV REG[CUR_PP], a
; -----------------------------
POP A ; Restore X page pointer
MOV REG[IDX_PP], a
; -----------------------------
POP A ; Restore MVI Write page pointer
MOV REG[MVW_PP], A
; -----------------------------
POP A ; Restore MVI Read page pointer
MOV REG[MVR_PP], A
; -----------------------------
; ----------------------------------------------------------------------------
; USB OUT WORKAROUND
; Either use non-standard USB workaround: manual increment in USB.ASM
; Or use standard API workaround and possible return to 12 MHz
; ----------------------------------------------------------------------------
IF NOT_NDX_WORKAROUND
M8C_SetBank1 ; START USB OUT ENDPOINT WORKAROUND
POP A ;
MOV reg[OSC_CR0],A ; Restore clock to 12 or 24 MHz clock
M8C_SetBank0 ; STOP USB OUT ENDPOINT WORKAROUND
ENDIF
TEST_LED_LO ; =======================
POP X ; Restore X
POP A ; Restore A
RETI
; ----------------------------------------------------------------------------
;
; startIsr - Do initial synchronization to received VoIP stream
;
; Synchronizes to two consecutive 15-Byte frames with the same content.
; It's imperfect because the frames may have intervening frames of
; non-15 byte lengths
;
; ----------------------------------------------------------------------------
_startIsr:: ; Called by non-ISR to request
MOV [_slotCt], -1 ; synchronization at next ISR
// MOV [isrBufTxCtrlOfsIn], (isrBufTxCtrl + 1)
// MOV [bufTxVoipOfsIn], (bufTxVoip + 1)
; Start loading a NEW Tx frame (basically just initialize vars)
MOV [bufTxVoip+0], [_iEncPredict+0]
MOV [bufTxVoip+1], [_iEncPredict+1]
MOV [bufTxVoip+2], [_bEncStepSizePtr]
MOV [bufTxVoipPtr], bufTxVoip+3 ; Load new frame ADPCM here
MOV [_voiceCh], CH_MIN-1
MOV [rssiCh], CH_MIN-1
MOV [p3RssiFilt], _rssiFiltTbl
MOV [txPktLen], VOIP_PKT_LEN
MOV [bufTxCtlPtr], (bufTxCtl+1)
MOV A, ISR_VAL_NOM_LSB
MOV [isrPeriod], A
MOV X, ISR_VAL_NOM_MSB
LCALL PWM16_1_WritePeriod
LCALL PWM16_1_Start
LCALL PWM16_1_EnableInt
RET
; ----------------------------------------------------------------------------
; doSynchronize - Scan looking for VoIP stream from a Remote.
; Entry and Exit via ISR level.
; ----------------------------------------------------------------------------
doSynchronize:
; LOCAL VARIABLES
rxCnt: equ timeTmpA
dwellTime: equ timeTmpB
ct_277uS: equ timeTmpC
diffVar: equ timeTmpD
bufPtr: equ timeTmpE
parkTime: equ timeTmpF ; sit on initial new chan longer
; General ISR initialization
LCALL PWM16_1_Stop ; No ISRs while synchronizing
MOV [_rxPktAve_Q3], 15<<3 ; Start w/best Rx Packet average
; Clear error statistics
mov [_mibMissRx_1 + 0], 0
mov [_mibMissRx_1 + 1], 0
mov [_mibMissRx_2 + 0], 0
mov [_mibMissRx_2 + 1], 0
mov [_mibMissTx + 0], 0
mov [_mibMissTx + 1], 0
; ---------- goto Rx mode
MOV A, XACT_CFG_ADR + bSPI_WRITE
MOV X, (FRC_END_STATE + END_STATE_RXSYNTH)
CALL isrRadioWrite
.L2: MOV A, XACT_CFG_ADR ; Wait for the FRC_END_STATE
CALL isrRadioRead ; bit in the XACT_CFG register
AND A, FRC_END_STATE ; to clear indicating the force has
JNZ .L2 ; completed.
; --------------------------------------------------------------------
; parkTime - Wait longer on the first new channel because farside
; takes about 50 mS to recognize that we are gone. Farside
; may not recognize a problem until our resynchronization begins.
; --------------------------------------------------------------------
MOV [parkTime], 1
; ---------- RX_GO
.doRxGo:
MOV [dwellTime], 9 ; 9 = 2.5 mS at 24 MHz
.park:
MOV X, [_voiceCh]
MOV A, CHANNEL_ADR + bSPI_WRITE
CALL isrRadioWrite
MOV A, RX_CTRL_ADR + bSPI_WRITE
MOV X, (RX_GO + RXC_IRQ) ; IRQ at RX_COMPLETE (for polling)
CALL isrRadioWrite ;
MOV A, RSSI_ADR ; Clear any pending SOP bit
CALL isrRadioRead
; --------------------------------------------------------------------
; Wait (possibly forever) for RX_COMPLETE IRQ from Radio
; Peiodically change channels.
; Wait for 750uS * 3 for a Rx burst before changing channels
; --------------------------------------------------------------------
MOV [ct_277uS], 0
.Loop3: IS_IRQ_ON
JNZ .rxPkt ; Evaluate Rx packet
DEC [ct_277uS]
JNZ .Loop3
DEC [dwellTime]
JNZ .Loop3
call _nxtVoiceCh ; Next channel
MOV A, [parkTime]
JZ .doRxGo ; Not 1st new ch, short wait
MOV [parkTime], 0 ; 1st new ch has long wait
MOV [dwellTime], 180 ; 180 = 50 mS at 24 MHz
JMP .park
; --------------------------------------------------------------------
; Rx Complete, evaluate frame
; --------------------------------------------------------------------
.rxPkt:
MOV A, RX_IRQ_STATUS_ADR
CALL isrRadioRead
MOV [diffVar], A
TST [diffVar], RXBERR_IRQ + RXE_IRQ
JZ .noErr
; --------------------------------------------------------------------
; Reject: Frame had errors, flush radio buffer if has data
; --------------------------------------------------------------------
TST [diffVar], (RXB16_IRQ + RXB8_IRQ + RXB1_IRQ)
JZ .doRxGo ; Wait for another Rx frame
MOV X, 16 ; X = Length
CALL isrRadioFileReadWipTrash ; Unload data from Radio
JMP .doRxGo ; Wait for another Rx frame
.noErr: MOV A, RX_COUNT_ADR
CALL isrRadioRead
OR A, 0 ; Test flags
JZ .doRxGo ; Ignore frame, No payload data
MOV [rxCnt], A
XOR A, VOIP_PKT_LEN ; Test Rx packet against VoIP length
MOV [diffVar], A ; Z if VoIP length, NZ if wrong len
; --------------------------------------------------------------------
; Copy data from radio buffer to local buffer in Stack Page
; During copy, compare each byte to "matching" byte in opposite buf
; This copy/compare takes about 160uS at 24 MHz CPU, 3 MHz SPI
; --------------------------------------------------------------------
MOV [bufPtr], bufRxVoip0
.Loop4:
MOV A, RX_BUFFER_ADR
CALL isrRadioRead ; Read 1 Byte
PUSH A
MOV X, [bufPtr] ;
XOR A, [X] ; Compare NEW byte with OLD byte
OR [diffVar], A ; NZ if different
POP A
MOV [X], A ; Store NEW byte
INC [bufPtr]
DEC [rxCnt]
JNZ .Loop4 ; Keep loading frame bytes
MOV A, [diffVar]
JNZ .doRxGo ; Wait until get duplicate frames
; ----------------------------------------------------------------------------
;
; Synchronized to Far-End Tx stream: Received duplicate valid VoIP frame.
;
; Now delay to proper phase and begin Rx/Tx cycling
;
; ----------------------------------------------------------------------------
TEST_TIK_HI ; =======================
LOOP_DLY: equ (445 * CPU_MHZ/9) // 1 radio
CTR_INT_DLY: equ 2
MOV X, >LOOP_DLY ;
MOV A, <LOOP_DLY ; Dead delay to sync
.Loop5: DEC A ; 4 (4 + 5) = 9 cycles/iteration
JNZ .Loop5 ; 5
DEC X ;
JNC .Loop5 ;
; --------------------------------------------------------------------
MOV A, ISR_VAL_NOM_LSB
MOV X, ISR_VAL_NOM_MSB
LCALL PWM16_1_WritePeriod ; Resync counter to NOW
LCALL PWM16_1_Start
; --------------------------------------------------------------------
TEST_TIK_LO ; =======================
MOV [_slotCt], 6 ; Next is Rx Slot 0
JMP ctrIsrX
; ----------------------------------------------------------------------------
;
; SHORTER VERSIONS OF RADIO DRIVER FUNCTIONS
;
; This routine is for 24MHz CPU and 3 MHz SPI
;
; isrRadioWrite: A: The register number to write.
; X: The value to write to the selected register.
; isrRadioRead : A: The register number to write.
; X: undefined
; ----------------------------------------------------------------------------
isrRadioWrite:
isrRadioRead:
radioSelect
; Write the address.
MOV REG[SPI_TX_REG], A
.wait1: TST REG[SPI_CTRL_REG], SPI_TX_EMPTY
JZ .wait1
; Write the data (Read just clocks the shift-register)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -