📄 psocradio.asm
字号:
.Done: MOV A, [RadioSpiTemp]
; Get the return value.
radioDeselect
; Deassert the Slave Select
RET_RESTORE_IE_THROUGH_X
.endsection
.section
;--------------------------------------------------------------------------------
;
; RadioSetPtr: Set the buffer pointer address for RadioBurstRead,
; RadioFileRead, RadioBurstWrite and RadioFileWrite functions.
;
; 'C' Call: void RadioSetPtr(unsigned char ramPtr);
;
_RadioSetPtr:: MOV [RadioPtr], X
RET
.endsection
.section
;--------------------------------------------------------------------------------
;
; RadioSetLength: Set the buffer length for RadioBurstRead & RadioFileRead.
;
; 'C' Call: void RadioSetLength(unsigned char length);
;
_RadioSetLength:: MOV [RadioLen], A
RET
.endsection
.section
;--------------------------------------------------------------------------------
;
; RadioBurstWriteWip:
; Write a sequence of bytes to a sequence of Radio registers.
; This, like all the WIP versions of the file read and write
; functions uses RadioWipPtr instead of RadioPtr as the data pointer.
;
; Assembly Call: RadioWipPtr: Address of buffer to write.
; A: The register number to write.
; (Top two bits MUST be clear.)
; X: Length of the buffer.
;
; Assembly Return: A: Undefined
; X: Undefined
;
RadioBurstWriteWip::
OR A, bSPI_AUTO_INC ; Set the increment flag.
JMP RadioFileWriteWip
;--------------------------------------------------------------------------------
;
; RadioBurstWrite: Write a sequence of bytes to a sequence of Radio registers.
;
; 'C' Call: void RadioBurstWrite(unsigned char regAddr, unsigned char cnt);
; (Must set RadioPtr by calling RadioSetPtr prior to RadioBurstWrite.)
;
; Assembly Call: RadioPtr: Address of buffer to write.
; A: The register number to write.
; (Top two bits MUST be clear.)
; X: Length of the buffer.
;
; Assembly Return: A: Undefined
; X: Undefined
;
RadioBurstWrite::
_RadioBurstWrite:: OR A, bSPI_AUTO_INC ; Set the increment flag.
;--------------------------------------------------------------------------------
;
; RadioFileWrite: Write a sequence of bytes to a single Radio register.
;
; 'C' Call: void RadioFileWrite(LS_REG_ADDR regAddr, BYTE cnt);
; (Must set RadioPtr by calling RadioSetPtr prior to RadioFileWrite.)
;
; Assembly Call: RadioPtr: Address of buffer to write.
; A: The register number to write.
; (Top two bits MUST be clear.)
; X: Length of the buffer.
;
; Assembly Return: A: Undefined
; X: Undefined
;
; TODO: Remove Empty/Complete race and IRQ disable.
;
RadioFileWrite::
_RadioFileWrite:: MOV [RadioWipPtr], [RadioPtr] ; Copy the buffer pointer.
RadioFileWriteWip::
DEC X ; If the length is zero
JC .Done ; do nothing at all.
CLEAR_TEMP_IE ; Disable global IRQ for this function.
OR A, bSPI_WRITE ; Set the write flag.
radioSelect
; Assert Radio Select.
MOV REG[SPIM_Radio_TX_BUFFER_REG],A
.Burst: MVI A,[RadioWipPtr] ; Get the data.
.WaitLoop8: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_TX_BUFFER_EMPTY
JZ .WaitLoop8
MOV REG[SPIM_Radio_TX_BUFFER_REG],A
DEC X
JNC .Burst
;
; All done bursting, wait for the last byte to leave the holding register.
;
.Burst0: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_TX_BUFFER_EMPTY
JZ .Burst0
;
; Wait for the shifting to complete and the SPI transaction to finish.
;
.WaitComp: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_SPI_COMPLETE
JZ .WaitComp
radioDeselect
; Deassert the Slave Select
.Done: RET_RESTORE_IE_THROUGH_X
.endsection
.section
;--------------------------------------------------------------------------------
;
; RadioBurstReadWip:
; Read a sequence of bytes from a sequence of Radio registers
; using RadioWipPtr as the buffer pointer.
;
; Assembly Call: RadioWipPtr: Address of buffer to read.
; A: The register number to write.
; (Top two bits MUST be clear.)
; X: Length of the buffer.
;
; Assembly Return: A: Undefined
; X: Undefined
;
RadioBurstReadWip::
OR A,bSPI_AUTO_INC ; Set the increment flag.
JMP RadioFileReadWip
.endsection
.section
;--------------------------------------------------------------------------------
;
; RadioBurstRead: Read a sequence of bytes from a sequence of Radio registers.
;
; 'C' Call: void RadioBurstRead(unsigned char cnt);
; (Must set RadioPtr by calling RadioSetPtr prior to RadioBurstRead.)
;
; Assembly Call: RadioPtr: Address of buffer to read.
; A: The register number to write.
; (Top two bits MUST be clear.)
; X: Length of the buffer.
;
; Assembly Return: A: Undefined
; X: Undefined
;
RadioBurstRead::
_RadioBurstRead:: OR A,bSPI_AUTO_INC ; Set the increment flag.
;--------------------------------------------------------------------------------
;
; RadioFileRead: Read a sequence of bytes from a single Radio registers.
;
; time-> |8spiclk|8spiclk|8spiclk|
; Assert Slave Select | | | |
; Write Address | | | |
; Wait for Empty(1)----+ | | |
; Write Nul Data | | |
; Wait for Empty(2)------------+ | |
; Write Nul Data | |
; Read Nul Data | |
; Wait for Empty(3)--------------------+ |
; Write Nul Data |
; Read Data |
; Wait for Empty and complete------------------+
; Read Data
; De-assert Slave Select
;
; As it stands the main loop of this routine is a littler
; slower than it should be. With a 12MHz CPU the burst is not
; always continuous. There are occasionally gaps between bytes
; in the burst. It should be possible to correct this, but it
; is a minor problem and this is already pretty convoluted
; to deal with the latency caused by the TX and RX holding
; buffers.
;
; This routine properly handles all cases of length including
; zero and one.
;
; 'C' Call: (Must set RadioPtr and RadioLen by calling RadioSetPtr prior
; to RadioFileRead.)
; void RadioFileRead(unsigned char regAddr, unsigned char cnt);
;
; Assembly Call: RadioPtr: Address of buffer to read.
; RadioLen: Size of buffer
; A: The register number to write.
; (Top two bits MUST be clear.)
; X: Length of the buffer.
;
; Assembly Return: A: Undefined
; X: Undefined
;
RadioFileRead::
_RadioFileRead:: MOV [RadioWipPtr], [RadioPtr] ; Initialize working pointer
MOV [RadioWipLen], [RadioLen] ; and length.
RadioFileReadWip::DEC X ; Check for zero length case.
JC .Done ; If zero, nothing to do.
CLEAR_TEMP_IE ; Disable global IRQ for this function.
;
; At this point X is the number of bytes in the file read -1. This last one needs
; to be handled specially by waiting for COMPLETE instead of EMPTY - that is done
; below at .LastByte.
;
radioSelect
MOV REG[SPIM_Radio_TX_BUFFER_REG],A ; Write the SPI address.
;
; For speed we are going to use the SP as our data point to write data into the buffer.
; This would not be possible if interrupts were not disabled. Swap SP<->RadioWipPtr.
; (PUSH A is 6 cycles faster than MVI).
;
SWAP A, SP
SWAP [RadioWipPtr], A
SWAP A, SP
.WaitLoop1: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_TX_BUFFER_EMPTY
JZ .WaitLoop1
MOV REG[SPIM_Radio_TX_BUFFER_REG],A ; Write null data.
;
; We need to get three items set up for this execution of the routine and the next as
; well based on whether there is room in the buffer.
; bytes to read(X) - space in buffer(RadioWipLen)
; C (RadioWipLen>X) NC (RadioWipLen<=X)
;------------------------------------------------------------------------------------
; Reads that fit in buffer : X = X = RadioWipLen
; Reads thrown away : RadioSpiTemp = 0 = X-RadioWipLen
; Bytes left in buffer : RadioWipLen = RadioWipLen-X = 0
;
MOV A, X
SUB A, [RadioWipLen]
;
; This test does not affect C.
;
.WaitLoop2: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_TX_BUFFER_EMPTY
JZ .WaitLoop2
; Throw (address phase) data away .
JNC .1
MOV [RadioSpiTemp], 0
MOV A, X
SUB [RadioWipLen], A
JMP .BurstBottom
;
; A contains the number of bytes we are going to move -1. We need to subtract the total
; number of bytes which is A+1.
;
.1: MOV [RadioSpiTemp], A
MOV X, [RadioWipLen]
MOV [RadioWipLen], 0
JMP .BurstBottom
.BurstLoop1: MOV REG[SPIM_Radio_TX_BUFFER_REG],A
; Write null data.
.WaitLoop3: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_TX_BUFFER_EMPTY
JZ .WaitLoop3
MOV A,REG[SPIM_Radio_RX_BUFFER_REG]
; Get data.
PUSH A ; write the data.
.BurstBottom: DEC X ; Count
JNC .BurstLoop1 ; Repeat
;
; We've moved all the data we have room for in the buffer. Do we need to pull any
; extra data from the register that we are not going to store? If so, the count
; is in RadioSpiTemp
;
MOV X, [RadioSpiTemp]
JMP .BurstBottom2
.BurstLoop2: MOV REG[SPIM_Radio_TX_BUFFER_REG],A
.WaitLoop4: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_TX_BUFFER_EMPTY
JZ .WaitLoop4
.BurstBottom2: DEC X
JNC .BurstLoop2
;
; Moved moved all the data except for one last byte. Wait for it and if we have room
; in the buffer, go get it and store it.
;
.LastByte: TST REG[SPIM_Radio_CONTROL_REG],SPIM_Radio_SPIM_SPI_COMPLETE
JZ .LastByte
CMP [RadioWipLen], 0
JZ .Done2
MOV A,REG[SPIM_Radio_RX_BUFFER_REG] ; Get the data
PUSH A ; and save it.
DEC [RadioWipLen]
.Done2: radioDeselect
;
; Swap back SP<->RadioWipPtr.
;
SWAP A, SP
SWAP [RadioWipPtr], A
SWAP A, SP
.Done: RET_RESTORE_IE_THROUGH_X ; Restore IRQ state.
.endsection
;
; Re-enable code compression.
;
ENABLE_CODE_COMPRESSION
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -