News:

Let's find out together what makes a PIC Tick!

Main Menu

Manchester Differential Code

Started by Teo, Jun 17, 2023, 07:03 PM

Previous topic - Next topic

Teo

Hi ,
Has anyone had the opportunity to "Play with Manchester Differential Code".
The coding part I fixed but the decoding part fails.
Any idea will be appreciated,
Teo

broderic

Hello Teo.
Where can this code be found ?
Thanks

Teo


trastikata

Hello Teo,

what is the peripheral using the Differential Manchester? Looking for a hardware or software solution?

Teo

hi Trastikata ,
Software solution.
Thanks

trastikata

Quote from: Teo on Jun 18, 2023, 03:53 PMSoftware solution.

Can you give more information about the peripheral using it? Is it to understand that you are receiving the (double sized) bit-stream successfully and need to recover the original message from the already received bit-stream?

Teo

I'll post how I do the coding.
I use PIC18F46K22.
Thanks,
Teo

trastikata

Quote from: Teo on Jun 18, 2023, 05:14 PMI'll post how I do the coding.

This is a variation of the normal Manchester decoding I did long time ago. Basically looping through the received bit stream and comparing every pair of two bits in the incoming message. Differential Manchester is not much different, so if two bits are equal then it's 0 (or 1 depending on the selected coding scheme) and if not then it's 1 (or 0 depending on the selected coding scheme). Load the corresponding bit in the result output.

This is very crude and basic code based on my old code, can be optimized and made much better - not sure if it will help but possibly will give you an idea.

Dim waInMessage[4] As Word      'Message to decode
Dim baOutMessage[4] As Byte     'Decoded message
Dim bCounter1 As Byte           'Loop counter 1
Dim bCounter2 As Byte           'Loop counter 2
Dim bCounter3 As Byte           'Loop counter 3
Dim pBit0 As Bit                'Temporary Bit Variable
Dim pBit1 As Bit                'Temporary Bit Variable
Dim wTemp1 As Byte              'Temporary Word Variable
Dim bTemp2 As Byte              'Temporary Byte Variable

'Loop through incoming word message word by word
For bCounter1 = 0 To 3     
    'Set initial bit position for result variable to 7
    bCounter3 = 7
    'Loop through all bits in InMessage word in steps of 2 bits
    For bCounter2 = 15 To 1 Step -2
        'Temporary variable holds the value from the array
        wTemp1 = waInMessage[bCounter1]
        'Get two adjoining bits
        pBit0 = GetBit wTemp1, bCounter2
        pBit1 = GetBit wTemp1, bCounter2 - 1
        'Compare bits
        If pBit0 <> pBit1 Then   
            'If bits are different, then no change in phase - then load 0 in the decoded Byte
            LoadBit bTemp2, bCounter3, 0 
        Else
            'If bits are not different, then change in phase - then load 1 in the decoded Byte
            LoadBit bTemp2, bCounter3, 1
        EndIf 
        'Decrement bit position in the temporary reult variable
        Dec bCounter3   
    Next
    'Copy the temporary result variable in the decoded message array
    baOutMessage[bCounter1] = bTemp2
Next

Teo

I'll do tests and tell you what I got.
Thank you very much!
Teo

trastikata

#9
Quote from: trastikata on Jun 18, 2023, 05:28 PMThis is a variation of the normal Manchester decoding I did long time ago. Basically looping through the received bit stream and comparing every pair of two bits in the incoming message. Differential Manchester is not much different, so if two bits are equal then it's 0 (or 1 depending on the selected coding scheme) and if not then it's 1 (or 0 depending on the selected coding scheme). Load the corresponding bit in the result output.

With Teo's permission I am posting an explanation how to decode Differential Manchester encoding aka Biphase mark code.

First some simplified clarification premises:

1. Manchester encoding effectively doubles the bit-rate 
- for each bit in the original message you will need one extra bit in the encoded message
2. The purpose of Manchester encoding is to avoid long periods of 0's or 1's during transmission
- you can't have more than two consecutive 0's or 1's
3. Differential Manchester encoding is a variation of Manchester encoding
- encoding and decoding are using similar methods
4. There are different variants how to represent 1's and 0's from the original message
- you need to know in advance the coding scheme

Teo sent me the following screenshot with an encoded and decoded message using a logical analyzer, once I explain the decoding logic, it would be easy to create your own program decoding the Differential Manchester.

The incoming bit-stream in Teo's example is:

11001010101101001101010100101100101101001100

"Basically looping through the received bit stream and comparing every pair of two bits in the incoming message"
will produce the following pairs of 0's and 1's:

11 00 10 10 10 11 01 00 11 01 01 01 00 10 11 00 10 11 01 00 11 00

so if two bits are equal then it's 0 (or 1 depending on the selected coding scheme) and if not then it's 1 (or 0 depending on the selected coding scheme).
In our case if we have a pair of the same bits 00 or 11 this will mean No Transition which equals to 0 according to our coding scheme and if we have a pair of different bits 01 or 10 this would mean a Transition which equals to 1 according to our coding scheme, so:

pair 11 which is No Transition or we write decoded 0
pair 00 which is No Transition or we write decoded 0
pair 10 which is Transition or we write decoded 1
...
pair 01 which is Transition or we write decoded 1
...

Thus decoded message becomes:

0011101001110100101000

We know that our first 8 bits are the preamble:

00111010

and then we have 14 bits of message:

01110100101000

But we have indicated that the LSB is first, thus reverse the bit order:

Preamble: 01011100 = 92
Message: 00010100101110 = 1326

As you can see there are several combination and variations of coding schemes and countless possibilities for preamble and message lengths and order, therefore it is important to understand the underlying encoding/decoding principle and then it would be a matter of code writing to implement the encoding/decoding schemes.


Differential Manchester.jpg

trastikata

#10
Teo asked if I could help with some code for reception and decoding of the Differential Manchester Code. The payload message consists of one 8-bit byte and one 14-bit word.

The problem with the Differential Manchester Code is that it can't be read through the USART port, because it doesn't follow the standard UART protocol. But since the message in his case is very short and the the speed is quite low, one can use the IOC (interrupt on change) pin and measure with the TMR0 timer the length between interrupts to determine the length of the symbol (input change):
- invalid symbol length
- one bit symbol length
- two bit symbol length 

This is an entirely software solution for low bit rates and short messages. The code has not been tested and I can't guarantee it will work (probably won't from the first try  ;D) without debugging. It is a crude code and not optimized - the byte arrays to record incoming bits and to buffer them is very inefficient way to do it and it can be optimized to bit level but will complicate the code. Anyway the purpose is to give an idea as a start solution.

P.s. I had some thoughts as a vague idea to decode Differential Manchester Code using PWM, Timers and Comparators and and hardware triggers routed to different pins to free some of the software overhead but I don't have time to read datasheets and it still not clear in my mind if it is feasible that way. 

Device = 18F46K22
Declare Xtal 64

Symbol RxPin = PORTB.4
Input RxPin

Symbol MaxValid1BitLength = 270 'Maximum length for 1 valid bit
Symbol MaxValid2BitLength = 520 'Maximum length for 2 valid bits     

Dim wTimer0 As TMR0L.Word       '16-bit Word from registers TMR0
Dim wTimer0Counter As Word      'Overflow counter for TMR0
Dim bBuffer[44] As Byte         'Byte array to hold the bit values
Dim bArray[44] As Byte          'Byte array to hold the bit values
Dim bCounter As Byte            'Counter for the Byte Array
Dim bTemp As Byte               'Temp variable
Dim wTemp As Word               'Temp variable
Dim pDiscardIOC As Bit          'Flag preamble Or Break
Dim pStartEndOfMessage As Bit   'Flag current message status - start, end
Dim pMessageReceived As Bit     'Flag whether or not the message has been completely received
Dim bMessage As Byte            'First byte of the message
Dim wMessage As Word            'Second part of the message
Dim i As Byte                   'Loop counter
Dim j As Byte                   'Loop counter

On_Hardware_Interrupt GoTo ISR_HANDLER
GoTo MAIN_PROGRAM_LOOP

ISR_HANDLER:
    Context Save
        If INTCONbits_RBIF = 1 Then                                     'Check for IOC flag                                 
            wTemp =  wTimer0                                            'Copy TMR0 value
            wTimer0 = 0                                                 'Reset TMR0
            bTemp = RxPin                                               'Read the PORTB.4 state
           
            If wTimer0Counter > 0 Or wTemp >= MaxValid2BitLength Then   'Check for preamble or break
                pDiscardIOC = 1                                         'Dicard IOC
                If pStartEndOfMessage = 1 Then pStartEndOfMessage = 0   'Message has finished                           
            EndIf
           
            If pDiscardIOC = 0 Then                                     'Valid bit length detected                                 
                If pStartEndOfMessage = 0 Then                         
                    pStartEndOfMessage = 1                              'Start of message detected
                    bCounter = 0                                        'Reset Byte array counter
                EndIf
               
                If wTemp < MaxValid1BitLength Then                      'One bit length IOC detected
                    bArray[bCounter] = bTemp                            'Copy RxPin state to the byte array
                    Inc bCounter                                        'One increment of array counter
                Else                                                    'Two bit length IOC detected
                    bArray[bCounter] = bTemp                            'Copy RxPin state to the byte array
                    Inc bCounter                                        'One increment of array counter
                    bArray[bCounter] = bTemp                            'Copy RxPin state to the byte array
                    Inc bCounter                                        'One increment of array counter
                EndIf                                   
            EndIf
           
            If bCounter >= 44 Then                                      'All 44 bits received     
                For bTemp = 0 To 43                                     'Copy bArray to the bBuffer array
                    bBuffer[bTemp] = bArray[bTemp] 
                Next           
                pMessageReceived = 1                                    'Flag Message completerly received
                bCounter = 0                                            'Reset array counter
            EndIf
           
            wTimer0Counter = 0                                          'Reset TMR0 overflow counter
            pDiscardIOC = 0                                             'Reset Dicard IOC
            INTCONbits_RBIF = 0                                         'Clear IOC flag
        EndIf 
       
        If INTCONbits_TMR0IF = 1 Then                                   'Check for TMR0 overflow
            INTCONbits_TMR0IF = 0                                       'Clear TMR0IF
            Inc wTimer0Counter                                          'Increment TMR0 overflow counter
        EndIf 
    Context Restore

MAIN_PROGRAM_LOOP:
    Clear : wTimer0 = 0
    'Set TMR0 to 16bit with PS 256
    T0CON = %00000111
    INTCONbits_TMR0IF = 0
    'Set Interrupts - IOC and TMR0
    INTCONbits_PEIE = 1
    INTCONbits_TMR0IE = 1
    INTCONbits_RBIE = 1
    'Set IOC for PORTB.4
    IOCBbits_IOCB4 = 1
    INTCONbits_RBIF = 0
    'Enable interrupts
    T0CONbits_TMR0ON = 1
    INTCONbits_GIE = 1
   
    While 1 = 1
        If pMessageReceived = 1 Then                                    'Message completerly received
            GoSub DECODE_MESSAGE                                        'Decode message
            pMessageReceived = 0                                        'Reset flag for Message completerly received
        EndIf
        'Do something else
    Wend
   
DECODE_MESSAGE:
    bMessage = 0 : wMessage = 0                                         'Clear payload variables
    j = 0                                                               'Clear bit index counter
    For i = 0 To 14 Step 2                                              'Decode the fisrt byte of the payload
        If bBuffer[i] = bBuffer[i + 1] Then                             'No bit transition detected
            ClearBit bMessage, j                                        'Set the corresponding bit in the payload variable 
            Inc j     
        Else                                                            'Bit transition detected
            SetBit bMessage, j                                          'Set the corresponding bit in the payload variable   
            Inc j
        EndIf   
    Next
   
    j = 0                                                               'Clear bit index counter
    For i = 16 To 42 Step 2                                             'Decode the second part of the payload
        If bBuffer[i] = bBuffer[i + 1] Then                             'No bit transition detected
            ClearBit wMessage, j                                        'Set the corresponding bit in the payload variable 
            Inc j     
        Else                                                            'Bit transition detected
            SetBit wMessage, j                                          'Set the corresponding bit in the payload variable   
            Inc j
        EndIf   
    Next
Return   

'250 Bits/s --> 4mS / Bit --> 1 Bit = 250 TMR0 clocks at 64MHz Fosc




 

top204

#11
An excellent piece of coding trastikata, and I truly mean that. It is always such a pleasure to see the compiler used so creatively and so precisely. :-) It gives my heart an uplift and my life a purpose. :-)

A tip....

Move the interrupt handler code to the end of the program listing, then there is no need for a jump over it and the main program loop is the first to be viewed in the listing and the interrupt handler routine is out of site from the other procedures. It makes no difference if the interrupt handler is at the end of code, because the compiler makes a jump to it anyway from the device's interrupt vector address.

keytapper

Quote from: top204 on Nov 07, 2023, 12:26 PMMove the interrupt handler code to the end of the program listing
It's what a commonly do  ;D
Ignorance comes with a cost