Guzunty / Pi

This repository contains resources to support the Guzunty Pi IO expansion board
110 stars 32 forks source link

[New core request] CPPM (combined PPM) decoder #14

Closed qbit- closed 9 years ago

qbit- commented 11 years ago

Hi everybody here! I'm very new to CPLD programming, but already impressed by the range of things one can do with it. I wonder if it's possible to design a Pulse Position Modulation decoder with Gizunty? This type of signal encoding is increasingly used by modern RC systems. For an example of what it is one can consider this article: http://diydrones.com/profiles/blog/show?id=705844%3ABlogPost%3A984615&commentId=705844%3AComment%3A987491&xg_source=activity or just have a look at the figure: scheme Shortly speaking this signal is a sum of some number of PWM signals. It has a falling edge each time a PWM has a rising edge. By decoding CPPM I mean that CPLD should emit a stream of numbers corresponding to each pulse length through SPI. If such an encoder could be created it will greatly simplify the use of Raspberry Pi and Gizunty by all RC people :)

campbellsan commented 11 years ago

Most interesting. Yes, I think the CPLD could handle that. The limitations on the number and precision of the individual servo control signals as discussed on the servo control waveform pages would unfortunately remain. However, what this would presumably do is to free up lots of PWM outputs that could be used instead to provide digital control or inputs.

So you want to read a CPPM stream and decode the length of a set of pulses for later reading over SPI. What about converting the CPPM signal to conventional PWM outputs? Required or not?

What about the opposite direction? The ability to write servo positions on an SPI stream from the Pi and have those summed onto an outgoing CPPM stream. Not suggesting the XC9572XL CPLD could do all of this at once, it probably can't, but we might make several cores for different purposes. A larger capacity CPLD like the XC95144XL could do more of course, see issue #5.

How many channels would you need? Can you point me at what hardware we would have to buy to test such a core?

qbit- commented 11 years ago

Well, I'm glad you are interested in that. As for the hardware, you could try the mentioned Frsky radio control system, however it's a bit pricy just "for testing". A typical set of transmitter + receiver would cost around 100$. Look at Turnigy 9X + FrSky transmitter module + D8R-II/D4R-II receiver from HobbyKing. May be there are other options I'm not aware of. In my particular project I'm going to use Raspberry Pi as a flight control board, so it has to interface with the receiver (which provides a CPPM signal). I can end up writing a diver to decode CPPM on Pi's GPIOs, but I wonder if it can be done in hardware. Typically, one needs at least 4 channels, but 6-8 is generally preferred. Regarding the last requirement, could you ship a larger CPLD + board with my order :) (and bill me for the price difference)? Converting CPPM to PWM is useful. Although it can require one to write a realtime driver for Raspberry Pi to operate such device, it will save GPIOs as you mentioned. I'm going to get Guzunty particularly to learn how to do that :) Going from another direction can also be interesting. Some people might want to have a PWM/CPPM converter, to interface their old PWM receivers with boards that have few GPIOs available. It will be useful not only in Raspberry Pi domain.

campbellsan commented 11 years ago

So, this: http://www.hobbyking.co.uk/hobbyking/store/__31544__Turnigy_9XR_Transmitter_Mode_2_No_Module_.html?strSearch=turnigy%209x

and this?

http://www.hobbyking.co.uk/hobbyking/store/__14355__FrSky_DF_2_4Ghz_Combo_Pack_for_JR_w_Module_RX.html

campbellsan commented 11 years ago

Regarding the last requirement, could you ship a larger CPLD + board with my order?

Unfortunately not. The larger product exists only in prototype form and is also rather difficult to hand solder. Unless you are a wizard with soldering iron and a rock steady hand, I would not recommend it.

qbit- commented 11 years ago

Yes, the hardware you mentioned is the one I'm going to use (actually this is one of the best and cheapest combinations to my knowledge). For the last, ok, but if you will need someone to test new device I'll be glad to do that (I'm able to use soldering paste and do an "industrial" style assembling).

campbellsan commented 11 years ago

Ok, ideas coming together here. Looking more closely, the signal is quite slow compared to RPi interrupt latency. I think we could do this with a standard Guzunty with no compromises at all. Instead, the Pi would get an interrupt for each channel. The interrupt handler would have to read the value before the data for the next channel was ready, which would be between 1 and 2ms later. What resolution would you need? Would +/- 1024 be enough? i.e. 2048 total range?

campbellsan commented 11 years ago

I found an answer to my own question. 2048 (11 bits) is enough. The Turnigy 9XR produces that level of precision in a slower Oversampling mode only. Normally, it samples sticks etc. at 1024 range or 10 bits.

So, you will get a hardware interrupt for each channel. The interrupt handler will initiate a read of 16 bits from the Pi SPI0.0 device. The top 3 bits will identify the channel (0-7 maps to channels 1-8). The remaining 13 bits will provide 2048 values of positional resolution for that channel.

I believe I can deliver a core that will do the above. In addition, I believe I can make it robust for the 18ms FRSky lock up case discussed in your original link, with one caveat. The core will need at least one recognisable inter frame rest gap in order to sync up. I can provide an IO pin that goes high when sync is achieved if you think that is useful. Prior to sync, the core will return full scale deflection on all channels. Since this is what the transmitter has to be sending for the sync to be ambiguous, I think this is correct expected behaviour. The sync signal (if you want it) will not go high until at least one stick is centred.

Qbit, nice though that radio system is, I can't justify purchasing one unless there are a lot of users. This is a not for profit site, but it is also a 'not for loss' site. :-) So, let's do this here...

I'll make a core that does what you need, and I'll also build a simulation that fully tests the core. Since you have the radio gear, you can wire it up and test that it does what you need. Beyond that, it's up to you to spread the word. Get Pi R/Cer's to add a bump to this issue or buy a Guzunty and mark their Paypal order with a message saying this is what they want it for. Either way, I'd need them to say what make and model of RC equipment they intended to use it with. If there is enough response (a few 10's of users or potential users would do it), I'll buy a radio to provide support. Can't say fairer'n that.

Please let me know if you want me to proceed and build a core and testbench.

qbit- commented 11 years ago

Ok, sounds reasonable. I still don't have a radio gear by myself (it should come the same time as Guzunty :). My original idea was to use an interrupt-driven input with this receiver directly on Xenomai real-time kernel. However, the receiver works at 5V and hardware pulse length calculation will be more precise. So for the device. I think it should have one line to trigger an interrupt at the end of the CPPM packet. As for each of the channels ends, is it possible to generate an interrupt through the SPI bus? Sorry, but I've never dealt with SPI before. Please proceed with the core, and I will try write some simple driver for the Pi.

campbellsan commented 11 years ago

Qbit,

Enjoy your new gear! :-)

Hmm, Xenomai, I think that is a good choice. You should have fewer concerns about interrupt latency or timer accuracy with that. Check that it offers an SPI driver though.

However, the receiver works at 5V and hardware pulse length calculation will be more precise.

Yes, Guzunty should certainly be able to help with both of these.

I think it should have one line to trigger an interrupt at the end of the CPPM packet.

Not sure what you're asking for here. By encoding the channel number in the upper bits of the SPI stream, you always know which channel you're handling. There would be no need for this interrupt. If you're asking for a single interrupt at the end of each CPPM burst, then reading all 8 channels, I am 99.9% sure that it will be beyond the resources of the XC9572XL. The problem is the number of bits that would have to be cached for the channel data. The CPLD has 72 macrocells, each of which has a single flip-flop suitable for cacheing a single bit of data. Eight channels of 13 bits of data blows that out of the water I'm afraid. With my proposal, we'll need just two 16 bit registers; one for the pulse width counter, and one for the output register.

As for each of the channels ends, is it possible to generate an interrupt through the SPI bus?

No. With SPI, the Pi is the master. The CPLD cannot initiate anything via SPI. The proposed core will provide a separate IO line to provide the per channel interrupt, this should work just fine.

Ok, I'll start work on this core with the design I proposed. That is: PPM stream input, minimum 2.1ms inter-frame gap (required to achieve initial sync, but afterwards not required for FrSky 18ms frame size case). Interrupt asserted after each channel pulse width is acquired. 16 bits to be read from the SPI bus within 1ms of the interrupt assertion. SPI data will always provide the last channel acquired with the channel number encoded in the upper 3 bits. The other 13 bits encode the pulse width. Finally, one SYNC signal that goes high when sync is achieved after power up. This may be used to drive an LED or could be sensed on a Pi GPIO line.

One of the nice things about core development is that nothing gets set in concrete, even after delivery. So if clarification of your requirement causes a change to the design, nothing is lost, not even turnaround time. I can email you a new core at any time, or you can get yourself set up with the free Xilinx tools to tweak your own cores if you like. :-)

Watch this space.

qbit- commented 11 years ago

Campbellsan,

Now I understand what you propose, and I think that's a good design. The SYNC signal should, of course, go to some PI's GPIO. From a brief look at the schematic it seems that there is enough GPIOs connected to Gizunty. Thank you for your effort! :)

campbellsan commented 11 years ago

Good news, I have a core that I think will do the trick ...

... and it fits in the CPLD :-)

Now for the test bench. Since I don't have hardware, I'll be extra thorough with the test bench. If I get a good run at it, the core could be available by the weekend.

qbit- commented 11 years ago

Wow! I did not expect you to make it so fast! Well done. I still waiting for hardware to arrive, so can't help with testing either.

campbellsan commented 11 years ago

I still waiting for hardware to arrive, so can't help with testing either.

Did you get your Guzunty ok? I would have thought you would have had that by now.

Actually, testing is almost complete. The simulation shows stable behaviour, even with the Fr Sky 18ms frame rate. I have not yet tested the Fr Sky scenario of full scale all channels from start up. However, I expect it will behave as I specified, i.e. no output until at least one channel is centred.

I have been able to squeeze in some bonus features:

Don't think there is room for much more, but if you can think of anything else, please let me know.

I'd obviously like to see this core get used, not least because I'd love an excuse to buy one of those radios. It might even get me back into R/C after 20 years!

So, with that in mind, what blogs do you read and/or contribute to?

If, when your gear shows up, you should have any trouble getting this to work, I may be able to help. I could make a little test circuit using an Arduino to create a test PPM signal. However, I don't think it will come to that. In my experience, if its working in the simulator, it'll almost always work in the real hardware.

Looking forward to hearing of your experience with it. :-)

I'll try to get the core up on GitHub this weekend. I'll also try to include some example code at the same time.

campbellsan commented 11 years ago

Here is part of the waveform from the simulation:

gz_ppm_wave

See the tiny dotted lines shortly after each ppm_int_req on the sel and miso signals? (You will have to use your browser to expand the image to 100% in oder to see them). This is where the response from the Raspberry Pi is simulated. That blip on miso is where the channel pulse width data is transferred to the Pi. If we zoomed in on that blip, we'd see the 16 bit SPI frame being transferred in the space of 1 us. For the simulation, I have used an interrupt latency of 50 us which is what is specified for Raspbian, though it can be as much as 500 us. Xenomai is much better at 15 - 30 us. This illustrates nicely that the channel data is collected long, long before it would be overwritten by the data for the following channel, which happens at the next falling edge of ppm_in.

You can find the core (gz_ppm.xsvf) here:

https://github.com/Guzunty/Pi/tree/master/src/gz_ppm

I have not yet had a chance to create any example code. So the core is of course untested in hardware at this time.

qbit- commented 11 years ago

Once again, I'm impressed! My Guzunty is still on it's way as well as the radio, but I was able to play with GPIO interrupts on Pi running Xenomai. Under heavy load, i.e. 99% CPU + some IO it's capable to react in ~50 us (got 42 max for a simple interrupt function), so the core should be fine. It's pretty cool that it's also able to emit PWM, so Guzunty already can serve as a converter. If you want ideas what else could be added, one may be interested to read simple PWM in the same way. Most of the controllers emit PWM phase-locked, so it shouldn't be much different from PPM except of the number of pins used :-).
As for the project, I'm mostly following this one: http://veterobot.com/ , but trying to adapt it for something capable to fly. I think this core deserves some promotion :-) I will post on the main RPi forum once I will get it working.

campbellsan commented 11 years ago

So did you get a chance to try this yet? Just curious. :-)

qbit- commented 11 years ago

Sorry for quite a long delay, was out of civilization for a while. Last time i played with that I find myself unable to write an RTDM driver for Xenomai, I need to study this topic more. The core itself seems to work, at least I can read some numbers it produces. Thank you for your work!

campbellsan commented 11 years ago

Absolutely no problem on the delay, no deadlines here! Delighted to hear the core appears to be working.

I have a background in software engineering, so please do let me know if there is anything I can do to help get Xenomai working with the design.

burlutskiy commented 10 years ago

hi there! I'm building autopilot based on RPi and looking for the way to read the PPM signals from receiver. I have FrSky TX+ X8R RX, if you need any help with testing please let me know, I will glad to participate. If it has finished already, I would appreciate if you advise on how to read PPM signal.

campbellsan commented 10 years ago

Hey there and welcome!

There is indeed a finished core for this that needs to be tested.

The source and built core is here: https://github.com/Guzunty/Pi/tree/master/src/gz_ppm

I did not wish to list it in the main gallery of cores without having verified that it works.

Looking at the X8R manual I don't see that it outputs Combined PPM. Since you own one, you may know differently. The FrSky D4R-II definitely does. The current state of the core is described in the preceding comments.

The core works in two ways:

1) It decodes the PPM signal and emits standard PWM on 8 of the pins. This is useful if you just wish to pass the servo signal directly to the actuator. It also means you can test that the core is decoding the incoming PPM signal correctly.

2) As each channel frame is received, the core raises a hardware interrupt, which can be detected and serviced on the Raspberry Pi. The received frame value is then read from the Pi SPI device (/dev/spidev0.0).

Do you have a Guzunty to try this with? Let me know if you need help interpreting the documentation or with Pi software to interface to it.

campbellsan commented 9 years ago

I'm pleased to say that I have finally been able to justify purchase of hardware to enable this core to be tested. Just as well too, the CPPM signal coming out of the receiver was not clean and had to be debounced.

Since the core is now working and meets all of the design goals I'm closing this issue. Oh, and as for other cores, there is a sample demo program that reads the channel data from Guzunty. The minimum value is around 1490 and the maximum around 4075, giving a range of roughly 2585, well in excess of the target precision of 2048.