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

0 Members and 1 Guest are viewing this topic.

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • Country: au
Approaches to a Manchester Decoder in Software
« on: July 14, 2019, 03:48:45 am »
I've managed to get a one-way IR link between two chips using the usual Vishay TSOP series receiver and a simple custom Manchester protocol for data transmission.

The routine I've written is basically an interrupt driven state machine. It reads the data & re-clocks on each mid-bit edge, ignoring inter-bit edges and terminating reception if the mid-bit edge does not arrive within a window (currently 1/2 bit time either side of the expected edge).

It works well enough, but should I be:
 a) Re-clocking on the mid-bit edge entirely, instead of performing a smaller adjustment?
 b) Terminating reception entirely if it skips a beat, which would most likely just be a single bit error?
 c) Reading the data directly after the mid-bit edge?
 

Offline mskeete

  • Contributor
  • Posts: 20
  • Country: gb
Re: Approaches to a Manchester Decoder in Software
« Reply #1 on: July 14, 2019, 04:40:51 am »
Is this similar to RC5?
You shouldn't need to reclock so often unless you have inaccurate clocks and or super long messages
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #2 on: July 14, 2019, 04:58:23 am »
Is this similar to RC5?
You shouldn't need to reclock so often unless you have inaccurate clocks and or super long messages

Somewhat similar. 38Khz carrier. 1.9KHz bit period. One start bit, 16 data bits.
As for re-clocking so often, my thinking was mitigating a wonky start bit and ISR latency jitter.
 

Offline mskeete

  • Contributor
  • Posts: 20
  • Country: gb
Re: Approaches to a Manchester Decoder in Software
« Reply #3 on: July 14, 2019, 10:40:31 am »
many moons ago (1996) I wrote some code for a PIC 16C84 to decode RC5
The start bit was detected by polling in the main routine and then the interrupts were synchronised (by reloading the interrupt timer counter) to occur in the middle of the expected data bits.

If the half bits weren't 0,1 or 1,0 (Manchester encoding) then there's an error (dont care which type of error) and you reset and wait again.

That worked very well for me and the PIC was running form a 4Mhz resonator.
You're probably using something a lot faster with smaller latencies so if its working for you then i wouldn't worry too much
 
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #4 on: July 14, 2019, 11:01:26 am »
You're probably using something a lot faster with smaller latencies so if its working for you then i wouldn't worry too much

PIC12F1572 and TMR2 at 8MHz internal RC.

I'll give a slightly different method some thought. It'd be nice to read in each half of the bits into separate registers, then XOR them together for bit error detection.
 

Offline mskeete

  • Contributor
  • Posts: 20
  • Country: gb
Re: Approaches to a Manchester Decoder in Software
« Reply #5 on: July 14, 2019, 11:22:15 am »
Attached is the code I wrote - complete with spelling mistakes.
It's written in assembler.

It was for a remote controlled audio preamplifier so there's a load of code in there for controlling a LMC1983 and storing stuff in EEPROM which you can ignore.

 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #6 on: July 15, 2019, 11:07:22 am »
Nicely done. I rewrote my code to take a similar approach to you, just letting the timer fire in the middle of every half bit.

It works well! Just for fun, I brought it up on the scope. One trace for the IR receiver output, one trace for a micro output that blips when the timer fires. It gets a bit close to the edge of the half bits at the end of the transmission, but not bad.
 

Offline wrynczuk

  • Contributor
  • Posts: 7
  • Country: pl
Re: Approaches to a Manchester Decoder in Software
« Reply #7 on: July 16, 2019, 11:39:47 am »
There is another interesting and neat approach:
https://www.clearwater.com.au/code/rc5

Believe it or not, but I implemented the algorithm successfully (yet few years ago) on an industrial PLC using the ladder language. Definitely, it is a good solution for low-end devices.
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #8 on: July 16, 2019, 01:54:51 pm »
Somewhat similar. 38Khz carrier. 1.9KHz bit period. One start bit, 16 data bits.
As for re-clocking so often, my thinking was mitigating a wonky start bit and ISR latency jitter.

PIC12F1572 and TMR2 at 8MHz internal RC.

I wrote a decoder all in software (polling, no interrupts, no timers), it's for a 6502 @ 1MHz. It self syncs and can decode manchester streams of between 13 and 15 kbits/s in packets of up to 256 bytes maximum.

https://gist.github.com/xk/1f455af5c9017150b8d6234743e9c2a3

The routine I've written is basically an interrupt driven state machine. It reads the data & re-clocks on each mid-bit edge, ignoring inter-bit edges and terminating reception if the mid-bit edge does not arrive within a window (currently 1/2 bit time either side of the expected edge).

It works well enough, but should I be:
 a) Re-clocking on the mid-bit edge entirely, instead of performing a smaller adjustment?
 b) Terminating reception entirely if it skips a beat, which would most likely just be a single bit error?
 c) Reading the data directly after the mid-bit edge?

Mine resyncs at every mid-bit edge, terminates at the first missing mid-bit edge, and it's an err unless the missing mid-bit edge happens just after a complete byte, in which case it means an end of packet which is ok.

What do you mean with "Reading the data directly after the mid-bit edge"? The mid-bit edge (direction) is the data, isn't it?
« Last Edit: July 19, 2019, 08:04:17 pm by GeorgeOfTheJungle »
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #9 on: July 16, 2019, 09:37:54 pm »
What do you mean with "Reading the data directly after the mid-bit edge"? The mid-bit edge (direction) is the data, isn't it?

The interrupt is generated by the edge (interrupt on change), so the ISR reads the value of the pin to determine what the edge was.

Yes, the mid-bit edge is the data. And so is the state of the pin before (inverted) and after said edge within the bit period.
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #10 on: July 17, 2019, 10:57:59 am »
What do you mean with "Reading the data directly after the mid-bit edge"? The mid-bit edge (direction) is the data, isn't it?

The interrupt is generated by the edge (interrupt on change), so the ISR reads the value of the pin to determine what the edge was.

Yes, the mid-bit edge is the data. And so is the state of the pin before (inverted) and after said edge within the bit period.

Oh, ok. Isn't there a race condition?
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • Country: au
Re: Approaches to a Manchester Decoder in Software
« Reply #11 on: July 17, 2019, 11:17:42 am »
What do you mean with "Reading the data directly after the mid-bit edge"? The mid-bit edge (direction) is the data, isn't it?

The interrupt is generated by the edge (interrupt on change), so the ISR reads the value of the pin to determine what the edge was.

Yes, the mid-bit edge is the data. And so is the state of the pin before (inverted) and after said edge within the bit period.

Oh, ok. Isn't there a race condition?

No race condition. The IOC peripheral raises an interrupt when there's a transition on the pin, so the CPU executes the ISR. The ISR checks the source of the interrupt and, if it was from the IOC, reads the value on the pin.
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #12 on: July 17, 2019, 01:54:30 pm »
What do you mean with "Reading the data directly after the mid-bit edge"? The mid-bit edge (direction) is the data, isn't it?

The interrupt is generated by the edge (interrupt on change), so the ISR reads the value of the pin to determine what the edge was.

Yes, the mid-bit edge is the data. And so is the state of the pin before (inverted) and after said edge within the bit period.

Oh, ok. Isn't there a race condition?

No race condition. The IOC peripheral raises an interrupt when there's a transition on the pin, so the CPU executes the ISR. The ISR checks the source of the interrupt and, if it was from the IOC, reads the value on the pin.

And, if the pin has flipped again before the ISR gets to read the value? Say it was a glitch, a 5ns pulse for example?
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline mskeete

  • Contributor
  • Posts: 20
  • Country: gb
Re: Approaches to a Manchester Decoder in Software
« Reply #13 on: July 17, 2019, 02:40:27 pm »
I think you'd have to be very unlucky to get a set of glitches compatible with Manchester encoding.
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 12135
  • Country: gb
    • Mike's Electric Stuff
Re: Approaches to a Manchester Decoder in Software
« Reply #14 on: July 17, 2019, 02:53:55 pm »
Use a capture peripheral to capture and interrupt on every edge, filter noise by rejecting any gap that's too long or short, classify into long or short gaps and decode with a state machine.
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 5834
  • Country: nl
Re: Approaches to a Manchester Decoder in Software
« Reply #15 on: July 17, 2019, 03:09:16 pm »
IIRC on my work we oversampled 16x the signal.
So just sample 16x the bittime and store in a queue and process when you have the time or the queue is getting full.
8x also worked, 4x was not fullproof IIRC (long time ago)
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #16 on: July 17, 2019, 04:08:31 pm »
Ok, that PIC does not tell you if it's been a rising or falling edge. So you can either use two pins tied together, one configured to interrupt on rising edges and the other on falling edges, or do as you're doing with a single pin and look at the pin's value upon entry to the ISR. Hopefully, if it was a glitch and there's been two edges, the ISR will be immediately triggered again upon rti? (If not you've got a problem) And you'll see the timing as not ok on the second invocation of the ISR and abort?
« Last Edit: July 17, 2019, 04:11:40 pm by GeorgeOfTheJungle »
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 5344
  • Country: fr
Re: Approaches to a Manchester Decoder in Software
« Reply #17 on: July 17, 2019, 04:40:51 pm »
Hopefully, if it was a glitch and there's been two edges, the ISR will be immediately triggered again upon rti? (If not you've got a problem) And you'll see the timing as not ok on the second invocation of the ISR and abort?

I would not necessarily count on that, but additionally checking that every edge detected leads to a different state should at least ensure that you won't make a decoding error?
 
The following users thanked this post: GeorgeOfTheJungle

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #18 on: July 17, 2019, 04:48:18 pm »
Yes, that's a good idea. Problem solved!
« Last Edit: July 17, 2019, 05:02:20 pm by GeorgeOfTheJungle »
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 19744
  • Country: nl
    • NCT Developments
Re: Approaches to a Manchester Decoder in Software
« Reply #19 on: July 17, 2019, 07:36:35 pm »
What do you mean with "Reading the data directly after the mid-bit edge"? The mid-bit edge (direction) is the data, isn't it?

The interrupt is generated by the edge (interrupt on change), so the ISR reads the value of the pin to determine what the edge was.

Yes, the mid-bit edge is the data. And so is the state of the pin before (inverted) and after said edge within the bit period.
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.
What I always do to decode manchester like streams is use a timer interrupt at around 6 times the bitrate (in your case it would be 11.4kHz) and sample the input from the timer interrupt. When you detect a change in the signal you can check how many timer interrupts ago the previous edge occured. Between 2 and 3 ticks is a short pulse, between 4 and 7 ticks is a long pulse.
« Last Edit: July 17, 2019, 07:39:36 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 5834
  • Country: nl
Re: Approaches to a Manchester Decoder in Software
« Reply #20 on: July 17, 2019, 08:26:02 pm »
That's how we did it but then with 8x or even 16x oversampling. The int serv routine is only sample the pin and store the boolean or bit in a ringbuffer aka the queue and exit.
When there is time to process or the queue is full you read the queue and write the decoded bits in a different buffer. Then when it is complete you decode the buffer and execute the command or whatever needs to be done.

The only exception is when you're processor has absolutely nothing else to do, if it is a dedicated decoder like the old SAA3049 RC5 decoder back in the day.
In all the other cases first do the RMA analysis.
« Last Edit: July 17, 2019, 08:29:41 pm by Kjelt »
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • Country: tr
Re: Approaches to a Manchester Decoder in Software
« Reply #21 on: July 17, 2019, 08:32:22 pm »
To each his own.
http://brave.com <- BETTER AND FASTER BROWSER. YOUTUBE W/O ADS/INTERRUPTIONS.
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 12135
  • Country: gb
    • Mike's Electric Stuff
Re: Approaches to a Manchester Decoder in Software
« Reply #22 on: July 17, 2019, 10:42:16 pm »
Also bear in mind that Manchester code is polarity-ambivolent so you don't actually need to know the polarity of the edges as long as you detect all of them
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 
The following users thanked this post: Kjelt

Online nctnico

  • Super Contributor
  • ***
  • Posts: 19744
  • Country: nl
    • NCT Developments
Re: Approaches to a Manchester Decoder in Software
« Reply #23 on: July 17, 2019, 11:01:09 pm »
That's how we did it but then with 8x or even 16x oversampling. The int serv routine is only sample the pin and store the boolean or bit in a ringbuffer aka the queue and exit.
When there is time to process or the queue is full you read the queue and write the decoded bits in a different buffer. Then when it is complete you decode the buffer and execute the command or whatever needs to be done.
That is rather cumbersome because of the overhead of buffering and this way also brings non-deterministic code execution. You'll need the processor time anyway and it takes less CPU cycles to do the job when the data enters the system. Life becomes much simpler if you view the interrupt controller as a hardware based time slicing OS.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 5834
  • Country: nl
Re: Approaches to a Manchester Decoder in Software
« Reply #24 on: July 18, 2019, 07:07:22 am »
That is rather cumbersome because of the overhead of buffering and this way also brings non-deterministic code execution. You'll need the processor time anyway and it takes less CPU cycles to do the job when the data enters the system. Life becomes much simpler if you view the interrupt controller as a hardware based time slicing OS.
It all depends on the other processes and priorities that need to be executed. If there are processes running that are time critical you don't want to get stuck too long in your interrupt service routine.
In the end we had multiple signals that needed sampling so we made a RMA to balance the load. We did not have an RTOS back then (8 bitter) and just made our own version handling the tasks according to priorities. IIRC the "jitter" on the rc5 decoding was less than 3ms since it was a human interface well within specifications, I don't know the max response time to human interfaces anymore but believe it was something in the order of 50-100ms or thereabout.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 74
  • 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: 74
  • 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 »
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • 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: 5344
  • 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: 2067
  • 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.
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • 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: 2067
  • 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"
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • 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: 2067
  • 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.
 

Online GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 2483
  • 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: 2067
  • 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: 74
  • 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: 74
  • 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