Convolutional code in FPGA with HLS
Encoding is a necessary operation for FEC (Forward Error Correction) whenever data is to be sent through a noisy medium, where errors can happen and can be corrected (up to a limit) with the corresponding decoding operation.
There are many types of FEC codes and Convolutional codes (plural, it's a family) is just one of them. It is frequently used in space communications, both for LEO and GEO satellites as well as interplanetary missions like Voyager, Mars Pathfinder and Cassini probe.
A convolutional encoder is relatively simple to implement but the decoder is notably more elaborated. That's probably one of the reasons to be used in space where there is a tight budget for electrical and computational power in spacecraft.
Logicore IP vs HLS
AMD Vivado contains a Logicore IP for convolutional encoding. It is handy but I find it a bit clumsy because it has AXI stream ports but only take 1 bit at a time. This means one has to first deserialize data if it comes in bytes or arrange eight encoders in parallel.
I used the IP block as a reference for my HLS design, brought the I/Os to external ports and created a wrapper. Then I wrote a basic testbench that sends a test string of bits. This is the output in behavioural simulation:
Input is 0x123456789abcdef0 and the encoded output is 0x0381404A7C4E8F668CBE7F754371... I will use this result to test my design with HLS.
Coding parameters
The main parameters of a convolutional code are the rate (r), constraint length (K) and generator polynomials (g1, g2, etc). A very popular code used in space communications is C(r = 1/2, K = 7). The rate is the ratio of input to output bits, in this case the bit rate is doubled. The ability of a code to correct errors lie in the redundancy of the extra bits. The constraint length is internal to the encoder and is the length of a shift register.
How encoding works
Below is an example for r = 1/2 (there are two outputs interleaved for one input) and K = 3 (the length of the shift register in blue). The polynomials are the selection of the shift register bits to xor: 111 for the top one and 101 for the bottom.
As simple as that and it has protected data coming from Voyager 1 and 2 that went past Pluto!
领英推荐
The HLS design
I like AXI and AXI stream interfaces, they make moving data within FPGA blocks very easy. Vivado HLS has the library hls_stream supporting these interfaces.
In the design presented here, I take one byte and produce a 16-bit word at the same rate. The code could easily be adapted to other formats like, for example, producing at double rate.
HLS is great for hig level maths but I have to say it's a bit clumsy when it comes to discrete bit manipulation. Here I used the ap_uint library to allow for bit and range extraction.
The whole "project" is... ten code lines long!
Note that the for loop is unrolled to be executed at once and have a one cycle latency. Synthesis confirms that:
Obviously the footprint is tiny, just 158 LUTs. A quick testbench is written to evaluate it:
That when executed produces the same result as the Vivado Logicore IP block:
Conclusion
HLS is really useful and powerful and has a number of advantages over writing HDL. AXI ports are straightforward to implement, something I appreciate as adding them to VHDL or Verilog is a bit more laborious, although it will give you full control.
This is an example of how things can be custom designed, in this case from the original IP taking 1 bit per clock, now it's 8 bits per clock. Obviously the HLS design can be converted into an IP that could be dropped into a block diagram.
Doctoral Candidate in Tiny Systems and Circuits (TSirc) Group at Aalto University | Specializing in Energy-Efficient AI Hardware Accelerator and Mixed-Signal IC Design
1 年Hi do you have Git repository for this?