Author Topic: Approaches to a Manchester Decoder in Software  (Read 2216 times)

0 Members and 1 Guest are viewing this topic.

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #25 on: July 18, 2019, 07:48:01 am »
Don't implement it like that. Having interrupts fire on GPIOs is asking for trouble. If something goes wrong in the hardware a GPIO interrupt can easely swamp your processor and at least cause an uneven / fluctuating / erratic processing load causing hard to reproduce problems and worst case crash the whole thing.

Good point. But short of discarding IOC events altogether, I think it would be better to simply enable them when expected. Sample as you need but take advantage of IOC to realign to the signal.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #26 on: July 18, 2019, 07:57:50 am »
Ok, that PIC does not tell you if it's been a rising or falling edge.

It can, but it takes a bit more work. The IOC peripheral has two separate circuits for rising and falling edges, but they both flip the same interrupt flag. These two parts can be enabled separately, meaning you get only one type or the other, but this of course requires a bit more work in software.

I was just taking the lazy approach of enabling both and checking the pin value immediately following. And there's nothing wrong with that approach, given the speed the ISR is coming through at compared to the signal.
« Last Edit: July 18, 2019, 08:00:08 am by Dabbot »
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2482
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #27 on: July 18, 2019, 10:19:50 am »
Also bear in mind that Manchester code is polarity-ambivalent so you don't actually need to know the polarity of the edges as long as you detect all of them

What you say only applies to differential Manchester encoding I think. In a single ended stream the direction is the value, thus you need to know it.
« Last Edit: July 18, 2019, 11:09:41 am by GeorgeOfTheJungle »
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 5330
  • Country: fr
Re: Approaches to a Manchester Decoder in Software
« Reply #28 on: July 18, 2019, 01:33:19 pm »
Also bear in mind that Manchester code is polarity-ambivalent so you don't actually need to know the polarity of the edges as long as you detect all of them

What you say only applies to differential Manchester encoding I think. In a single ended stream the direction is the value, thus you need to know it.

Yep. Original Manchester relies on fixed transitions to code 1's and 0's (there are two opposing conventions though). So it's definitely not polarity-agnostic.
Differential Manchester is.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2055
  • Country: ca
Re: Approaches to a Manchester Decoder in Software
« Reply #29 on: July 18, 2019, 02:46:48 pm »
It is not necessary to capture both edges. If you only measure times between consecutive rising edges (or consecutive falling edges), this is enough to re-construct the data.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2482
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #30 on: July 19, 2019, 12:52:01 pm »
It is not necessary to capture both edges. If you only measure times between consecutive rising edges (or consecutive falling edges), this is enough to re-construct the data.

Sorry but I don't get it, please explain, if S is short and L is long, what byte is this?

if rising edge= 1
⎺\___/‾‾‾\___/‾\_/‾‾‾\_/‾\_/‾\_ => 01011000
S  L   L   L  S S  L  S S S S
_/‾‾‾\___/‾‾‾\_/‾\___/‾\_/‾\_/‾ => 10100111

if rising edge= 0
⎺\___/‾‾‾\___/‾\_/‾‾‾\_/‾\_/‾\_ => 10100111
S  L   L   L  S S  L  S S S S
_/‾‾‾\___/‾‾‾\_/‾\___/‾\_/‾\_/‾ => 01011000
« Last Edit: July 19, 2019, 01:06:34 pm by GeorgeOfTheJungle »
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2055
  • Country: ca
Re: Approaches to a Manchester Decoder in Software
« Reply #31 on: July 19, 2019, 02:19:31 pm »
It is not necessary to capture both edges. If you only measure times between consecutive rising edges (or consecutive falling edges), this is enough to re-construct the data.

Sorry but I don't get it, please explain, if S is short and L is long, what byte is this?

Your shorts and longs are between edges of different polarity. What I said is that you only need to detect edges of one polarity - either you detect only rising edges, or only falling edges. And then you measure the distance between consecutive edges of the same polarity. Of course, you know whether you capture rising or falling edges. You also know whether your Manchester represnts '1' with riding edges or with falling edges.

You need to synchronize it first so that you know where the edge is as you normally do at the beginning - a string of '1', or a string of '0' - which looks the same, but you know how the transmission begins. Then you start decoding. Assuming rising edge is '1' and falling edge is '0':

If the last decoded bit was '1' and the distance between consecutive rising edges is:

- 1 bit - you received "1"
- 1 1/2 bits - you received "00"
- 2 bits - you received "01"

If the last decoded bit was '0' and the distance between consecutive rising edges is:

- 1 bit - you received "0"
- 1 1/2 bits - you received "1"
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2482
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #32 on: July 19, 2019, 07:58:19 pm »
Of course, you know whether you capture rising or falling edges. You also know whether your Manchester represents '1' with riding edges or with falling edges.

Ok, we're on the same page then. With the durations S L L L S S L S S S S alone it isn't enough to decode the data, AFAIK. Thanks!
« Last Edit: July 19, 2019, 08:01:38 pm by GeorgeOfTheJungle »
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2055
  • Country: ca
Re: Approaches to a Manchester Decoder in Software
« Reply #33 on: July 19, 2019, 08:32:39 pm »
Ok, we're on the same page then. With the durations S L L L S S L S S S S alone it isn't enough to decode the data, AFAIK. Thanks!

Don't know what do you mean by the "same page". We're talking about totally different things. I'm saying that you can decode by capturing only one kind of edges (either rising or falling) as opposed to capturing both rising and falling edges. You're saying something about pulse duration which you classified as S and L, but I don't really get what you're saying and how it is related to my considerations.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2482
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #34 on: July 19, 2019, 10:51:22 pm »
Ok, we're on the same page then. With the durations S L L L S S L S S S S alone it isn't enough to decode the data, AFAIK. Thanks!

Don't know what do you mean by the "same page". We're talking about totally different things. I'm saying that you can decode by capturing only one kind of edges (either rising or falling) as opposed to capturing both rising and falling edges. You're saying something about pulse duration which you classified as S and L, but I don't really get what you're saying and how it is related to my considerations.

You said:

Quote
If you only measure times between consecutive rising edges (or consecutive falling edges), this is enough to re-construct the data

http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2055
  • Country: ca
Re: Approaches to a Manchester Decoder in Software
« Reply #35 on: July 20, 2019, 05:01:35 am »
You said:

Quote
If you only measure times between consecutive rising edges (or consecutive falling edges), this is enough to re-construct the data

Yep. I don't know how to explain this better. I'll try graphics. Here's the signal (from your previous post):

Code: [Select]
⎺\___/‾‾‾\___/‾\_/‾‾‾\_/‾\_/‾\_
Here's all the edges (rising and falling):

Code: [Select]
\   /   \   / \ /   \ / \ / \
Here's rising edges only:

Code: [Select]
     /       /   /     /   /   
Here's the distances between them:

Code: [Select]
2, 1, 1 1/2, 1
This is enough to reconstruct data.

Here's the method in case you're interested (from my previous post):

Assuming rising edge is '1' and falling edge is '0':

If the last decoded bit was '1' and the distance between consecutive rising edges is:

- 1 bit - you received "1"
- 1 1/2 bits - you received "00"
- 2 bits - you received "01"

If the last decoded bit was '0' and the distance between consecutive rising edges is:

- 1 bit - you received "0"
- 1 1/2 bits - you received "1"

Makes sense?
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #36 on: July 20, 2019, 07:21:10 am »
You need to synchronize it first so that you know where the edge is as you normally do at the beginning - a string of '1', or a string of '0' - which looks the same, but you know how the transmission begins. Then you start decoding. Assuming rising edge is '1' and falling edge is '0':

If the last decoded bit was '1' and the distance between consecutive rising edges is:

- 1 bit - you received "1"
- 1 1/2 bits - you received "00"
- 2 bits - you received "01"

If the last decoded bit was '0' and the distance between consecutive rising edges is:

- 1 bit - you received "0"
- 1 1/2 bits - you received "1"

That would be an interesting method to try. I might give that a go once I'm done experimenting with the current code.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #37 on: July 21, 2019, 05:27:28 am »
Here's what I've come up with. Code below.

When the signal begins, TMR2 is loaded with the period and offset to interrupt in the middle of each half bit. The value on the pin is sampled each time TMR2 fires, with the left-hand and right-hand bits stored in respective registers. However, the receiver will not check the vaildity of received bits, leaving that for main code.

It will reclock on mid-bit edges, but only within a window, ignoring anything too whacky.

I've also taken nctnico's advice on potential IOC spam trapping the microcontroller in its ISR, so IOC is only enabled when expecting an edge and disabled once it is received / missed.

The receiver indicates completion via its state register. It's enabled again in main code by clearing the state register and enabling IOC on the pin.

The main code just transforms and spits the data out to the EUSART.

Code: [Select]

#include "p12f1572.inc"

; CONFIG1
; __config 0xFFAC
 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_SWDTEN & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF
; CONFIG2
; __config 0xFEFC
 __CONFIG _CONFIG2, _WRT_ALL & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LPBOREN_OFF & _LVP_ON



; ********** Common RAM working registers **********

; Main
 cblock 0x70
    AREG, BREG, CREG, DREG
    LREG, HREG, TEMP0, TEMP1
 endc

TEMP = 0x76

; ISR
 cblock 0x78
    ISR_AREG, ISR_BREG, ISR_CREG, ISR_DREG
    ISR_LREG, ISR_HREG, ISR_TEMP0, ISR_TEMP1
 endc

ISR_TEMP = 0x7E



; ********** General registers **********

; IR receiver registers on bank 0
ISR_IRRX_STATE = 0x0060 ; Receiver state
ISR_IRRX_DATL0 = 0x0061 ; First byte of left hand bits
ISR_IRRX_DATL1 = 0x0062 ; Second byte of left hand bits
ISR_IRRX_DATR0 = 0x0063 ; First byte of right hand bits
ISR_IRRX_DATR1 = 0x0064 ; Second byte of right hand bits



; ********** FIFO locations **********

RX_FIFO = 0x0140 ; Start of receiver FIFO data structure. Occupies 10 bytes.
TX_FIFO = 0x0150 ; Start of transmitter FIFO data structure. Occupies 10 bytes.


 
; ********** Constants **********
; PR2 values for 3.8KBd manchester
; Assume Fosc/4 = 2MHz, TMR2 prescaler = 1:4
IRRX_14BIT = d'65' ; PR2 value for 1/4 bit period
IRRX_12BIT = d'131' ; PR2 value for 1/2 bit period

IRRX_RCLK_L = d'45' ; Reclocking window lower limit
IRRX_RCLK_H = d'85' ; Reclocking window upper limit



; ********** Reset vector **********

RES_VECT CODE 0x0000
GOTO INIT



; ********** Interrupt vector **********

ISR CODE 0x0004
BANKSEL PIR1

BTFSC PIR1, TMR2IF ; Infrared receiver. TMR2 handler.
GOTO ISR_IRRX_T

BTFSC INTCON, IOCIF ; Infrared receiver. IOC handler.
GOTO ISR_IRRX_P

BTFSC PIR1, RCIF ; EUSART receiver
GOTO ISR_EURX

BTFSC PIR1, TXIF ; EUSART transmitter
GOTO ISR_EUTX

RESET ; Oops!


ISR_IRRX_T BCF PIR1, TMR2IF

BANKSEL LATA ; Pulse debugging pin
BSF LATA, LATA0
BCF LATA, LATA0

BANKSEL 0 ; Read branching state
MOVLW b'00000011'
ANDWF ISR_IRRX_STATE, W

BRW ; Branch to handler
GOTO IRRX_T_START
GOTO IRRX_T_BITL
GOTO IRRX_T_BITR
GOTO IRRX_T_FINISH


IRRX_T_START ; We shouldn't get a timeout in this state
BANKSEL T2CON
BCF T2CON, TMR2ON ; Turn TMR2 off

BANKSEL 0
BSF ISR_IRRX_STATE, 0 ; Set branching state to finish
BSF ISR_IRRX_STATE, 1

RETFIE ; Done


IRRX_T_BITL ; Receive left-hand bit
BANKSEL 0

BCF STATUS, C ; Read inverted data
BTFSS PORTA, RA2 ; PORTA is on bank 0
BSF STATUS, C

MOVF ISR_IRRX_STATE, W ; Have we received all data?
XORLW b'01000101' ; 16 bits + start bit + current branching state
BTFSC STATUS, Z ; If not, continue
GOTO IRRX_T_LAST ; If so, finish up

RLF ISR_IRRX_DATL1, F ; Rotate left bit onto registers
RLF ISR_IRRX_DATL0, F

BCF ISR_IRRX_STATE, 0 ; Set branching state to BITR
BSF ISR_IRRX_STATE, 1

BANKSEL IOCAF ; Enable IOC for RA2
BSF IOCAP, IOCAP2
BSF IOCAN, IOCAN2

RETFIE ; Done


IRRX_T_BITR ; Receive right-hand bit
BANKSEL 0

BCF STATUS, C ; Read inverted data
BTFSS PORTA, RA2 ; PORTA is on bank 0
BSF STATUS, C

RLF ISR_IRRX_DATR1, F ; Rotate right bit onto registers
RLF ISR_IRRX_DATR0, F

MOVLW b'00000100' ; Increment bit count
ADDWF ISR_IRRX_STATE, F

BSF ISR_IRRX_STATE, 0 ; Set branching state to BITL
BCF ISR_IRRX_STATE, 1

BANKSEL IOCAF
BCF IOCAP, IOCAP2 ; Disable IOC for RA2
BCF IOCAN, IOCAN2
BCF IOCAF, IOCAF2 ; Clear IOC flag for RA2

RETFIE ; Done


IRRX_T_LAST ; All bits received and last edge has passed
BSF ISR_IRRX_STATE, 0 ; Set state to FINISH
BSF ISR_IRRX_STATE, 1

BANKSEL T2CON ; Turn TMR2 off
BCF T2CON, TMR2ON

RETFIE ; Done


IRRX_T_FINISH ; We shouldn't get a timeout in this state
BANKSEL T2CON ; Turn TMR2 off
BCF T2CON, TMR2ON

RETFIE ; Done


ISR_IRRX_P
BANKSEL IOCAF
BCF IOCAP, IOCAP2 ; Disable IOC for RA2
BCF IOCAN, IOCAN2
BCF IOCAF, IOCAF2 ; Clear IOC flag for RA2

BANKSEL 0 ; Read branching state
MOVLW b'00000011'
ANDWF ISR_IRRX_STATE, W

BRW ; Branch to handler
GOTO IRRX_P_START
RETFIE
GOTO IRRX_P_RCLK
RETFIE


IRRX_P_START ; Start edge received. ISR latency (instruction cycles): 17
; When accounting for ISR latency, use:
; ( instruction cycles + 4 ) / TMR2 prescaler (4)
BANKSEL T2CON ; Configure and start TMR2

MOVLW IRRX_14BIT + 7 ; Offset TMR2 to middle of 1/2 bit, accounting for ISR latency
MOVWF TMR2

MOVLW IRRX_12BIT ; TMR2 will fire in the middle of every 1/2 bit
MOVWF PR2

BSF T2CON, TMR2ON ; ISR latency (instruction cycles): 23

BANKSEL 0
BSF ISR_IRRX_STATE, 0 ; Set branching state to BITL
BCF ISR_IRRX_STATE, 1

RETFIE ; Done


IRRX_P_RCLK ; Reclock TMR2. ISR latency (instruction cycles): 17
; When accounting for ISR latency, use:
; ( instruction cycles + 4 ) / TMR2 prescaler (4)
BANKSEL T2CON

MOVF TMR2, W ; Capture TMR2 value. ISR latency (instruction cycles): 19
ADDLW -6 ; Account for ISR latency
MOVWF ISR_TEMP

;MOVF ISR_TEMP, W
SUBLW IRRX_RCLK_H ; Determine if the edge arrived within the reclock window
MOVLW IRRX_RCLK_L ; STATUS, C will be set if within the reclock window
BTFSC STATUS, C
SUBWF ISR_TEMP, W

MOVLW IRRX_14BIT + 8 ; Offset TMR2 to middle of 1/2 bit, accounting for ISR latency
BTFSC STATUS, C ; Skip the adjustment if not within reclock window
MOVWF TMR2 ; ISR latency (instruction cycles): 28

BANKSEL LATA
BTFSC STATUS, C ; Pulse debugging pin if reclocked
BSF LATA, LATA0
BCF LATA, LATA0

RETFIE ; Done


ISR_EURX
BANKSEL RCSTA

BTFSC RCSTA, FERR ; Discard if framing error
GOTO EURX_DISCARD

MOVLW high RX_FIFO ; Select RX FIFO
MOVWF FSR0H
MOVLW low RX_FIFO
MOVWF FSR0

MOVIW 1 [FSR0] ; Check if RX FIFO is full
SUBWF INDF0, W
XORLW d'8'

BTFSC STATUS, Z ; Discard if RX FIFO is full
GOTO EURX_DISCARD

MOVF INDF0, W ; Enqueue data into RX FIFO
ANDLW d'7'
MOVWF ISR_TEMP
ADDWF FSR0L, F
MOVF RCREG, W
MOVWI 2 [FSR0]
MOVF ISR_TEMP, W
SUBWF FSR0L, F
INCF INDF0, F

RETFIE ; Done


EURX_DISCARD MOVF RCREG, W ; Discard received character
RETFIE ; Done


ISR_EUTX
BANKSEL TXREG

MOVLW high TX_FIFO ; Select TX FIFO
MOVWF FSR0H
MOVLW low TX_FIFO
MOVWF FSR0

MOVIW 1 [FSR0] ; Check if TX FIFO is empty
XORWF INDF0, W

BTFSC STATUS, Z ; If TX FIFO is empty, disable interrupts and return
GOTO EUTX_OFF

MOVIW ++ FSR0 ; Dequeue data from TX FIFO and transmit
ANDLW d'7'
MOVWF ISR_TEMP
ADDWF FSR0L, F
MOVIW 1 [FSR0]
MOVWF TXREG
MOVF ISR_TEMP, W
SUBWF FSR0L, F
INCF INDF0, F

RETFIE ; Done


EUTX_OFF ; Switch transmitter interrupts off
BANKSEL PIE1
BCF PIE1, TXIE
RETFIE ; Done



; ********** Main loop **********

MAIN_PROG CODE

INIT
BANKSEL OSCCON
MOVLW b'01110000' ; Software PLL disabled, 8MHz IRCF, clock as per FOSC<1:0> in config words
MOVWF OSCCON


BANKSEL LATA ; Pin config
CLRF LATA

BANKSEL ANSELA
BCF ANSELA, ANSA2 ; Switch off analog for RA2 (IR RX)
BCF ANSELA, ANSA4 ; Switch off analog for RA4 (UART TX)

BANKSEL TRISA
BCF TRISA, TRISA0 ; RA0 as output for LED / debug

;BANKSEL IOCAP
;BSF IOCAP, IOCAP2 ; Enable positive edge interrupts for RA2
;BSF IOCAN, IOCAN2 ; Enable negative edge interrupts for RA2

BANKSEL T2CON
MOVLW b'00000001' ; Configure TMR2. No postscaler, off, 1:4 prescaler
MOVWF T2CON

BANKSEL APFCON ; Place the EUSART on alternate pins
BSF APFCON, RXDTSEL ; RX on RA5
BSF APFCON, TXCKSEL ; TX on RA4


BANKSEL BAUDCON ; EUSART
;MOVLW b'01000000' ; Default POR value
;MOVWF BAUDCON

BCF TXSTA, SYNC ; 9600 baud rate async for 8MHz Fosc
BCF TXSTA, BRGH
BCF BAUDCON, BRG16
MOVLW d'12'
MOVWF SPBRG
CLRF SPBRGH

BSF TXSTA, TXEN ; Enable transmitter
BSF RCSTA, CREN ; Enable receiver
BSF RCSTA, SPEN ; Enable the serial port


BANKSEL PIE1 ; Interrupts
BSF PIE1, RCIE ; Enable receiver interrupt
BSF PIE1, TMR2IE ; TMR2 interrupt
BSF INTCON, PEIE ; Enable peripheral interrupts
BSF INTCON, IOCIE ; Enable interrupt on change
BSF INTCON, GIE ; Enable global interrupts


BANKSEL RX_FIFO ; Initialise the FIFOs
CLRF RX_FIFO
CLRF RX_FIFO + 1
CLRF TX_FIFO
CLRF TX_FIFO + 1

BANKSEL 0

MAIN_LOOP
CLRF ISR_IRRX_STATE ; Reset IR receiver state

BANKSEL IOCAP ; Enable IR receiver
BSF IOCAN, IOCAN2

BANKSEL 0 ; Wait until we have data from IR receiver
WAIT_IR_DATA MOVLW b'00000011'
ANDWF ISR_IRRX_STATE, W
XORLW b'00000011'
BTFSS STATUS, Z
GOTO WAIT_IR_DATA

SWAPF ISR_IRRX_STATE, W ; Convert data to hexadecimal chars and send via UART
CALL BIN2HEX
CALL SEND_CHAR

MOVF ISR_IRRX_STATE, W
CALL BIN2HEX
CALL SEND_CHAR

MOVLW a' '
CALL SEND_CHAR

SWAPF ISR_IRRX_DATL0, W
CALL BIN2HEX
CALL SEND_CHAR

MOVF ISR_IRRX_DATL0, W
CALL BIN2HEX
CALL SEND_CHAR

MOVLW a' '
CALL SEND_CHAR

SWAPF ISR_IRRX_DATL1, W
CALL BIN2HEX
CALL SEND_CHAR

MOVF ISR_IRRX_DATL1, W
CALL BIN2HEX
CALL SEND_CHAR

MOVLW a' '
CALL SEND_CHAR

SWAPF ISR_IRRX_DATR0, W
CALL BIN2HEX
CALL SEND_CHAR

MOVF ISR_IRRX_DATR0, W
CALL BIN2HEX
CALL SEND_CHAR

MOVLW a' '
CALL SEND_CHAR

SWAPF ISR_IRRX_DATR1, W
CALL BIN2HEX
CALL SEND_CHAR

MOVF ISR_IRRX_DATR1, W
CALL BIN2HEX
CALL SEND_CHAR

MOVLW d'13'
CALL SEND_CHAR
MOVLW d'10'
CALL SEND_CHAR


GOTO MAIN_LOOP



; ********** Subroutines **********


; Enqueue data in WREG for transmission via EUSART.
; If the FIFO is full, wait for room.

SEND_CHAR MOVWF TEMP0 ; Store data to send

MOVLW high TX_FIFO ; Select TX FIFO data structure
MOVWF FSR0H
MOVLW low TX_FIFO
MOVWF FSR0

SEND_CHAR_W MOVIW 1 [FSR0] ; Wait for room
SUBWF INDF0, W
XORLW d'8'
BTFSC STATUS, Z
GOTO SEND_CHAR_W

MOVF INDF0, W ; Enqueue data onto FIFO
ANDLW d'7'
MOVWF TEMP1
ADDWF FSR0L, F
MOVF TEMP0, W
MOVWI 2 [FSR0]
MOVF TEMP1, W
SUBWF FSR0L, F
INCF INDF0, F

MOVF BSR, W ; Back up BSR
BANKSEL PIE1 ; Enable the transmitter
BSF PIE1, TXIE
MOVWF BSR ; Restore BSR

RETLW d'0' ; Done


; Return the ASCII hexadecimal character
;  for the least significant nibble in WREG.
BIN2HEX ANDLW b'00001111'
BRW
RETLW a'0'
RETLW a'1'
RETLW a'2'
RETLW a'3'
RETLW a'4'
RETLW a'5'
RETLW a'6'
RETLW a'7'
RETLW a'8'
RETLW a'9'
RETLW a'A'
RETLW a'B'
RETLW a'C'
RETLW a'D'
RETLW a'E'
RETLW a'F'
    END

« Last Edit: July 21, 2019, 08:49:44 am by Dabbot »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf