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
Hello Teo.
Where can this code be found ?
Thanks
Hi Broderic,
Thanks for the question !
https://en.wikipedia.org/wiki/Differential_Manchester_encoding
Any idea is welcome !
Teo
Hello Teo,
what is the peripheral using the Differential Manchester? Looking for a hardware or software solution?
hi Trastikata ,
Software solution.
Thanks
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?
I'll post how I do the coding.
I use PIC18F46K22.
Thanks,
Teo
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
I'll do tests and tell you what I got.
Thank you very much!
Teo
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
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
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.
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