Platform independent CPU/FPGA co-design: the OscImp-Digital framework
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Goavec-Merou, G.
Bourgeois, P.-Y.
Friedt, J.-M.
Combining the flexibility of FPGA hardware configuration with the high abstraction level of an operating system running on a general purpose central processing unit (CPU) requires mastering a broad range of knowledge, from low level hardware configuration to kernel drivers to libraries and userspace application. While some vendor specific frameworks tackle the challenge, we focus on a vendor independent solution applicable to current FPGA Systen on Chip providers: the OscImp Digital framework provides a comprehensive set of FPGA IP, associated Linux driver, library and userspace examples based on GNU Radio running on the embedded CPU. We demonstrate its use on the Redpitaya platform processing baseband signals as well as the Zynq, most significantly associated with the AD9363 radiofrequency frontend on the PlutoSDR board. In both cases, the FPGA is not only used to stream I/Q coefficients but pre-process the datastream in order to reduce bandwidth and efficiently feed the CPU: we demonstrate embedded FM broadcast radio reception as well as GPS decoding on the PlutoSDR custom bitstream.
 Okay, our next talk will be by Gornel Goevec and he's talking to us about platform independent CPU FPGA code design. Thank you. This talk is about this work, this ecosystem. We have developed an ecosystem to be able to assemble and generate design in FPGA and using the CPU for example on the Zinc board, the CPU to configure the design and to configure each block at the run time. It's possible to modify some parameters in live. It's fully pipelined. It's not no 5.4, nothing. It's just a sample arrive is used. So we try at possible to avoid using RAM to simplify design. Since we use a CPU with Linux, this ecosystem comply with the structure of an architecture of operating system. We have drive IP, IP are connected to the CPU to communicate with respect of system and in the better way we provide driver for this IP. And finally some IPs are some complex configurations. So we provide again library to avoid to duplicate piece of code. It's more the user has to focus on the design, on the application and nothing else. The last wish about this framework is to be as possible independent of the hardware. The same design must be generate for Zinc platform for Cyclone 5 platform and maybe other new one existing. We are validated. It's not exhaustive on Zinc, on Cyclone 5 with some different board, other board with other hardware, but it's some ID. It's not alone. Other ecosystem, the first one of course is a A2S RF knock use in the USRP. It's a great thing because your USRP as a firmware like a toolbox with some IPs available to be used. It's possible to configure which processing is done in the FPGA, which processing is done in the CPU by you just adding refnug block or new radio block. But if your design has no an IP you need for your specific application, you need to generate a new firmware with this IP. And the refnug structure has a limited slot available to add your IPs, five or seven. I don't remember exactly. I have tried to use a refnug on a Z board with an A2D converter. Finally the FPGA part, it's okay. It's not really hard, but UHD, I never, it's a fail. UHD do some assumption about the hardware. You have an EUDEPROM to detect the motherboard, the daughter board. You need to have a TXN, a RACCN. And finally it's just too complex for some small design. So it's really good, but with USRP. Another ecosystem from work is Pavel Domain, Red Pitaya note. It's this ecosystem has been present here. The good thing about this ecosystem is the repository provides some already available design, you have just to do some make and you have SD card ready to be used. Each project has a documentation with everything and it's directly compatible with the new radio. Finally, Osmo is there as a client for Red Pitaya CPU server part and you have a Red Pitaya exactly as the DVB Tiki USRP or another. But it's dedicated to the Red Pitaya platform and it's more or less limited to the already available project. To move from another board or to create your self project, it's less documented. Okay. Now the ecosystem look like this. We have the IPs. The IPs has a specific repository. The IPs is connected to the CPU using driver to communicate library or not and device tree because with the SOC system, the way to describe a platform is a device tree and this overlay is used to open the default runtime device tree. And finally, you provide some tools to build the application, to provide some wrapper to generate some part of design. First thing, maybe the most important part is the FPGA and the IP. It's for simplified simulation where split between the implementation part, the algorithm implementation and the communication for the configuration of the design. Exactly as new radio, we use a custom interface. This allows the user to plug one block to connect one block to one other and thanks to this interface, it's okay. It's the current data stream. For the user, it's just a wire like this one, but to provide more information, we have in this interface, this series of signal data control and clock and reset to be sure to have a correct coherence with the cross clock domain. More precisely about content, you have on the complex, you have i and q data bus on real just one data, unable to specify when a new data is available to be processed and you have some control signal, start of frame, stop of frame. Finally, an A2D converter or D2A converter has just an infinite data stream. No start, no stop, nothing. But when you have some design with when we want to propagate data only on the event, it's mandatory to know the start sample and sample of the data set. It's exactly the same for, for example, the FFT. The FFT has the start frequency, stop frequency. And this two signal allows to simplify the logic per IP to handle this data set. Okay, we have IP. Now we must connect IP, generate the design. It's possible, of course, to use the graphical approach with VivaDo or with Quartus and QCIS, but all vendor tools provide some procedure to build a design using TCL. The interest of this is small, able to version, and it's great thing. But VivaDo provides some function, create DB, create BD cell, etc. It's a specific procedure for VivaDo. It's the same thing for Quartus. And finally, VivaDo provides, need one TCL file to generate everything. Quartus need two files to generate everything. So we have added our procedure and some make file to generate. This, for example, this procedure is implemented in the VivaDo context, in the Quartus context. If you want to add a new vendor tool, you need just to fill this procedure to be able to build the design for a new platform with a new tool. I've do some tests with two different FPGA and two different vendor tools. The same design, the same application is able to work in all cases. Some stuff are just regenerate for each platform, but it's not a problem. It's just generate. The rest is perfectly compatible. This design is just a support for project. A project looks like this. You have the project directory, subdirectory, where we store everything about the design. On the design bit, it's possible to use TCL script to analyze Xperia or Quartus equivalent to extract which IPs are connected to the CPU, the base address for each of them to generate an XML file. This XML file is used by a tool to generate a template of application. The last thing for the user is just to create a C++ or Python file to configure everything in the FPGA. This set is generated by Modulator. You have an XML file. You have a project name. You have an IP, a second IP. IP is the name of the IP in the repository. For each of them, you have instance IP with a specific name, with a specific address. Based on this, it's possible to generate the script. Script is to simplify the run of the application. You copy the bit stream. You flash the FPGA. You update the device tree. You update the device tree with your specific case and load the driver for this specific project. First one. Second device tree. You need to open and you find exactly you opened the FPGA. It's a node dedicated to the FPGA. You have the firmware name. You have one driver with this same base address. It's exactly the same. And finally, a make file. Make file is just used to cross compile the application, to compile everything, and to install in the board everything. It's finally all about the ecosystem. Just we provide this block. It's not all block available, but it's subset. You have a local oscillator frequency transposition. You have an IP used to handle A2D converter, D2A converter for the red pitaya. You have a sound card. You have some block used to start the propagation when a specific event upper on the block on the pin of the FPGA for a trigger event. You have a radio frequency signal, CA code used for GNSS GPS, FIIR filter. You have FIIR filter rule for interface rule complex for interface complex. Some peer generator, a cross curator, again used to, for example, with the GPS. And some utilities to add a specific constant to all sample resaves. It's exactly an offset. You have other subsector. You add one input to the other input, mean on a simple accumulator. And some utilities convert from one interface to another interface, in custom interface, dupe because interface as is one to one. And sometimes we want to have one to many. So we have this to allow these possibilities. Expander shifter is for bit manipulating for bit shifting or expanding. Switch is just a select. You have two inputs. You have a mix, finally. And some interface between our custom interface and ACSI interface used, for example, when you need to use a FIIR filter provided by Xilinx to do a cross-clock domain. Now we have seen the ecosystem. But why doing this? First one is the GPS decoding. The idea is we have a Plutor SDR. The Plutor SDR is able to directly sample the signal. We have a satellite constellation with the same carrier frequency, but with a Doppler shift and with each satellite as a unique parent code. But when you use the Plutor SDR like this one with the stock firmware, finally the Plutor SDR do quite nothing. You have to have data to transmit data and it's all to detect which satellite light as present. You need to loop on the frequency. You need to loop on the PRN. So you need to cross-correlate the signal with all possible PRN code with a new radio on CPU at stake, one or two seconds per satellite. The idea is to update the firmware by adding our specific IP to do exactly the same thing, but in processing. This look like this. You have your RF front end. The local oscillator of the RF front end take some time to be reconfigured. So we have added NCO, a local oscillator mixer to do a second step frequency transposition. You have our CA code generator. This block provides all possible CA code in parallel. So we use the user space to configure our CA code to move from to loop frequency and to select which PRN we want to use. And you have the cross-correlator and the result is just send to the RAM and received from the CPU. Thanks to finally the most important thing we have added this part, but we don't break anything. The Pluto work exactly like with a default firmware, but we are with a bonus block. Thanks to this modification, it's possible to divide by five the time to process all satellite for all frequency. But now, but we are just limited by the zinc. The FPGA part is a bit small, so it's not possible to add more than one cross-correlator in the FPGA. So we have moved on the analog device board with the biggest FPGA to be able to cross-correlate all satellite at the same time. It's a work in progress. Currently, the design fits in the FPGA in parallel on the official data stream, but we need just to verify it's working. Next demonstration is more funny demonstration. Again, the Pluto S0 do quite nothing, but this board uses built-root to generate the firmware, the root file system, the Linux system, etc. Built-root supports new radio, so it's possible to add new radio in the firmware on the board. We have dosage, and the second idea is to have really totally embedded. So we have added a sound card in parallel in the FPGA. And finally, we have an application C++, Python, what you want, just to do this, low-pass filter, WBFM receiver, and output on the sound card. Just look like this. You have the default, Eric's chain, the IIO used as a source by a new radio. The process is done by a new radio, and an audio sync is used connected to the ALZA framework. We provide a driver-compatible ALZA to communicate with the Sigma Delta IP in the FPGA and the RC filter. This is using this approach, it's just due to the small amount of available pins for FPGA. So and for the fun, sorry, I just have just launched a specific application by providing a frequency, and it's all the PC do nothing. Just connect with SSH and it's all. Everything is done in the Plutor SDR board. The reception, the processing, and the output on the audio sync. Now to conclude, this is a flexible framework. In addition, we have demonstrated with some specific design and to end, but we have to use our approach with the analog device environment to merge, to mix our approach and analog device approach. And it's definitely working. It's a platform-independent. It's possible to use with Altera, Xilinx, maybe other. It's a respect, the structure of a Linux system with where the IP is exactly as all controllers around the core in the SOC component. Perspective, the first one is to finalize the GNSS parallel goal code. Verify and push on the GitHub for everyone to improve the documentation. Some part has quite, I suppose, well documented. There are some tutorials for HEPITIA, for Plutor SDR, but there are some missing parts around many TCL approach, and it's a work in progress. And the final thing, currently for RISC-5 seems to be an important concurrent to ARM processor, so it may be interesting to try to demonstrate with the SOFCORE RISC-5 instead of an ARTCORE ARM. Of course, we have the built-root extension for the RedPittaya. Again, same thing for the Plutor SDR with configuration, default configuration and configuration with new radio already enabled. And of course, the GitHub, the Oskim Digital GitHub, where everything is available, just mandatory to get cloned on the registry and to read doc tutorials to see how to start with this ecosystem. Thank you very much. Questions? No, I use actually for some block, I use a specific dev car device, but it's true. I need to use IIO, UIO, or some specific structure of the kernel. The configuration is done by the user space? The repetition between, for configuration between user and kernel to configure the IP, definitely the driver is know how to communicate with the IP, but for depending on the IP, part is done by the user space. For example, the NCO, you have an input frequency, you have an output frequency, you have the phase accumulator, and this is done in the user space through LibLibrary. For the filter, you have just a set of data, you write, you use the write on the file descriptor and the kernel do everything about that. It's a problem. You compare, you compare the speed of native nativery with the GPU, you compare, with you have a new tape to receive GPS and you compared your FPGA implementation to it, but did you also have a, for example, a new radio photograph to compare this decoder speed? The speed comparison between the hardware implementation and the software implementation? Yeah. Finally, in the FPGA, we are just limited by the input, the sample rate. If you, if the sample rate is 1 mega-sample, we have 1 microsecond between 2 new samples. If you need to cross-correct about 1 kilopoint, you have just 1 millisecond. It's not possible to reduce this because this is the FF front end, the limitation. And finally, it's just not mandatory to, to quick, to speed up this because it's the fastest way, the fastest due to the input frequency. And the real gain is after that, you have results in the CPU, not you have sample to compute. It's just a latency in between the error front end and the CPU. With a classic, classical approach with Octave or you need to store a big data set. You process this. It's just the big difference. It's okay after you, it's possible to use a GPU to improve this, but you have always the acquisition time before able to be, to process data.
 Okay, our next talk will be by Gornel Goevec and he's talking to us about platform independent  CPU FPGA code design.  Thank you.  This talk is about this work, this ecosystem.  We have developed an ecosystem to be able to assemble and generate design in FPGA and  using the CPU for example on the Zinc board, the CPU to configure the design and to configure  each block at the run time.  It's possible to modify some parameters in live.  It's fully pipelined.  It's not no 5.4, nothing.  It's just a sample arrive is used.  So we try at possible to avoid using RAM to simplify design.  Since we use a CPU with Linux, this ecosystem comply with the structure of an architecture  of operating system.  We have drive IP, IP are connected to the CPU to communicate with respect of system  and in the better way we provide driver for this IP.  And finally some IPs are some complex configurations.  So we provide again library to avoid to duplicate piece of code.  It's more the user has to focus on the design, on the application and nothing else.  The last wish about this framework is to be as possible independent of the hardware.  The same design must be generate for Zinc platform for Cyclone 5 platform and maybe other new  one existing.  We are validated.  It's not exhaustive on Zinc, on Cyclone 5 with some different board, other board with  other hardware, but it's some ID.  It's not alone.  Other ecosystem, the first one of course is a A2S RF knock use in the USRP.  It's a great thing because your USRP as a firmware like a toolbox with some IPs available  to be used.  It's possible to configure which processing is done in the FPGA, which processing is done  in the CPU by you just adding refnug block or new radio block.  But if your design has no an IP you need for your specific application, you need to generate  a new firmware with this IP.  And the refnug structure has a limited slot available to add your IPs, five or seven.  I don't remember exactly.  I have tried to use a refnug on a Z board with an A2D converter.  Finally the FPGA part, it's okay.  It's not really hard, but UHD, I never, it's a fail.  UHD do some assumption about the hardware.  You have an EUDEPROM to detect the motherboard, the daughter board.  You need to have a TXN, a RACCN.  And finally it's just too complex for some small design.  So it's really good, but with USRP.  Another ecosystem from work is Pavel Domain, Red Pitaya note.  It's this ecosystem has been present here.  The good thing about this ecosystem is the repository provides some already available  design, you have just to do some make and you have SD card ready to be used.  Each project has a documentation with everything and it's directly compatible with the new  radio.  Finally, Osmo is there as a client for Red Pitaya CPU server part and you have a Red  Pitaya exactly as the DVB Tiki USRP or another.  But it's dedicated to the Red Pitaya platform and it's more or less limited to the already  available project.  To move from another board or to create your self project, it's less documented.  Okay.  Now the ecosystem look like this.  We have the IPs.  The IPs has a specific repository.  The IPs is connected to the CPU using driver to communicate library or not and device tree  because with the SOC system, the way to describe a platform is a device tree and this overlay  is used to open the default runtime device tree.  And finally, you provide some tools to build the application, to provide some wrapper to  generate some part of design.  First thing, maybe the most important part is the FPGA and the IP.  It's for simplified simulation where split between the implementation part, the algorithm  implementation and the communication for the configuration of the design.  Exactly as new radio, we use a custom interface.  This allows the user to plug one block to connect one block to one other and thanks to  this interface, it's okay.  It's the current data stream.  For the user, it's just a wire like this one, but to provide more information, we have in  this interface, this series of signal data control and clock and reset to be sure to  have a correct coherence with the cross clock domain.  More precisely about content, you have on the complex, you have i and q data bus on real  just one data, unable to specify when a new data is available to be processed and you  have some control signal, start of frame, stop of frame.  Finally, an A2D converter or D2A converter has just an infinite data stream.  No start, no stop, nothing.  But when you have some design with when we want to propagate data only on the event,  it's mandatory to know the start sample and sample of the data set.  It's exactly the same for, for example, the FFT.  The FFT has the start frequency, stop frequency.  And this two signal allows to simplify the logic per IP to handle this data set.  Okay, we have IP.  Now we must connect IP, generate the design.  It's possible, of course, to use the graphical approach with VivaDo or with Quartus and QCIS,  but all vendor tools provide some procedure to build a design using TCL.  The interest of this is small, able to version, and it's great thing.  But VivaDo provides some function, create DB, create BD cell, etc.  It's a specific procedure for VivaDo.  It's the same thing for Quartus.  And finally, VivaDo provides, need one TCL file to generate everything.  Quartus need two files to generate everything.  So we have added our procedure and some make file to generate.  This, for example, this procedure is implemented in the VivaDo context, in the Quartus context.  If you want to add a new vendor tool, you need just to fill this procedure to be able  to build the design for a new platform with a new tool.  I've do some tests with two different FPGA and two different vendor tools.  The same design, the same application is able to work in all cases.  Some stuff are just regenerate for each platform, but it's not a problem.  It's just generate.  The rest is perfectly compatible.  This design is just a support for project.  A project looks like this.  You have the project directory, subdirectory, where we store everything about the design.  On the design bit, it's possible to use TCL script to analyze Xperia or Quartus equivalent  to extract which IPs are connected to the CPU, the base address for each of them to  generate an XML file.  This XML file is used by a tool to generate a template of application.  The last thing for the user is just to create a C++ or Python file to configure everything  in the FPGA.  This set is generated by Modulator.  You have an XML file.  You have a project name.  You have an IP, a second IP.  IP is the name of the IP in the repository.  For each of them, you have instance IP with a specific name, with a specific address.  Based on this, it's possible to generate the script.  Script is to simplify the run of the application.  You copy the bit stream.  You flash the FPGA.  You update the device tree.  You update the device tree with your specific case and load the driver for this specific  project.  First one.  Second device tree.  You need to open and you find exactly you opened the FPGA.  It's a node dedicated to the FPGA.  You have the firmware name.  You have one driver with this same base address.  It's exactly the same.  And finally, a make file.  Make file is just used to cross compile the application, to compile everything, and to  install in the board everything.  It's finally all about the ecosystem.  Just we provide this block.  It's not all block available, but it's subset.  You have a local oscillator frequency transposition.  You have an IP used to handle A2D converter, D2A converter for the red pitaya.  You have a sound card.  You have some block used to start the propagation when a specific event upper on the block on  the pin of the FPGA for a trigger event.  You have a radio frequency signal, CA code used for GNSS GPS, FIIR filter.  You have FIIR filter rule for interface rule complex for interface complex.  Some peer generator, a cross curator, again used to, for example, with the GPS.  And some utilities to add a specific constant to all sample resaves.  It's exactly an offset.  You have other subsector.  You add one input to the other input, mean on a simple accumulator.  And some utilities convert from one interface to another interface, in custom interface,  dupe because interface as is one to one.  And sometimes we want to have one to many.  So we have this to allow these possibilities.  Expander shifter is for bit manipulating for bit shifting or expanding.  Switch is just a select.  You have two inputs.  You have a mix, finally.  And some interface between our custom interface and ACSI interface used, for example, when  you need to use a FIIR filter provided by Xilinx to do a cross-clock domain.  Now we have seen the ecosystem.  But why doing this?  First one is the GPS decoding.  The idea is we have a Plutor SDR.  The Plutor SDR is able to directly sample the signal.  We have a satellite constellation with the same carrier frequency, but with a Doppler  shift and with each satellite as a unique parent code.  But when you use the Plutor SDR like this one with the stock firmware, finally the Plutor  SDR do quite nothing.  You have to have data to transmit data and it's all to detect which satellite light as  present.  You need to loop on the frequency.  You need to loop on the PRN.  So you need to cross-correlate the signal with all possible PRN code with a new radio  on CPU at stake, one or two seconds per satellite.  The idea is to update the firmware by adding our specific IP to do exactly the same thing,  but in processing.  This look like this.  You have your RF front end.  The local oscillator of the RF front end take some time to be reconfigured.  So we have added NCO, a local oscillator mixer to do a second step frequency transposition.  You have our CA code generator.  This block provides all possible CA code in parallel.  So we use the user space to configure our CA code to move from to loop frequency and  to select which PRN we want to use.  And you have the cross-correlator and the result is just send to the RAM and received  from the CPU.  Thanks to finally the most important thing we have added this part, but we don't break  anything.  The Pluto work exactly like with a default firmware, but we are with a bonus block.  Thanks to this modification, it's possible to divide by five the time to process all  satellite for all frequency.  But now, but we are just limited by the zinc.  The FPGA part is a bit small, so it's not possible to add more than one cross-correlator  in the FPGA.  So we have moved on the analog device board with the biggest FPGA to be able to cross-correlate  all satellite at the same time.  It's a work in progress.  Currently, the design fits in the FPGA in parallel on the official data stream, but  we need just to verify it's working.  Next demonstration is more funny demonstration.  Again, the Pluto S0 do quite nothing, but this board uses built-root to generate the  firmware, the root file system, the Linux system, etc.  Built-root supports new radio, so it's possible to add new radio in the firmware on the board.  We have dosage, and the second idea is to have really totally embedded.  So we have added a sound card in parallel in the FPGA.  And finally, we have an application C++, Python, what you want, just to do this, low-pass  filter, WBFM receiver, and output on the sound card.  Just look like this.  You have the default, Eric's chain, the IIO used as a source by a new radio.  The process is done by a new radio, and an audio sync is used connected to the ALZA  framework.  We provide a driver-compatible ALZA to communicate with the Sigma Delta IP in the FPGA and the  RC filter.  This is using this approach, it's just due to the small amount of available pins for  FPGA.  So and for the fun, sorry, I just have just launched a specific application by providing  a frequency, and it's all the PC do nothing.  Just connect with SSH and it's all.  Everything is done in the Plutor SDR board.  The reception, the processing, and the output on the audio sync.  Now to conclude, this is a flexible framework.  In addition, we have demonstrated with some specific design and to end, but we have to  use our approach with the analog device environment to merge, to mix our approach and analog device  approach.  And it's definitely working.  It's a platform-independent.  It's possible to use with Altera, Xilinx, maybe other.  It's a respect, the structure of a Linux system with where the IP is exactly as all  controllers around the core in the SOC component.  Perspective, the first one is to finalize the GNSS parallel goal code.  Verify and push on the GitHub for everyone to improve the documentation.  Some part has quite, I suppose, well documented.  There are some tutorials for HEPITIA, for Plutor SDR, but there are some missing parts  around many TCL approach, and it's a work in progress.  And the final thing, currently for RISC-5 seems to be an important concurrent to ARM  processor, so it may be interesting to try to demonstrate with the SOFCORE RISC-5 instead  of an ARTCORE ARM.  Of course, we have the built-root extension for the RedPittaya.  Again, same thing for the Plutor SDR with configuration, default configuration and configuration  with new radio already enabled.  And of course, the GitHub, the Oskim Digital GitHub, where everything is available, just  mandatory to get cloned on the registry and to read doc tutorials to see how to start with  this ecosystem.  Thank you very much.  Questions?  No, I use actually for some block, I use a specific dev car device, but it's true.  I need to use IIO, UIO, or some specific structure of the kernel.  The configuration is done by the user space?  The repetition between, for configuration between user and kernel to configure the IP,  definitely the driver is know how to communicate with the IP, but for depending on the IP,  part is done by the user space.  For example, the NCO, you have an input frequency, you have an output frequency, you have the  phase accumulator, and this is done in the user space through LibLibrary.  For the filter, you have just a set of data, you write, you use the write on the file descriptor  and the kernel do everything about that.  It's a problem.  You compare, you compare the speed of native nativery with the GPU, you compare, with  you have a new tape to receive GPS and you compared your FPGA implementation to it,  but did you also have a, for example, a new radio photograph to compare this decoder speed?  The speed comparison between the hardware implementation and the software implementation?  Yeah.  Finally, in the FPGA, we are just limited by the input, the sample rate.  If you, if the sample rate is 1 mega-sample, we have 1 microsecond between 2 new samples.  If you need to cross-correct about 1 kilopoint, you have just 1 millisecond.  It's not possible to reduce this because this is the FF front end, the limitation.  And finally, it's just not mandatory to, to quick, to speed up this because it's the fastest way,  the fastest due to the input frequency.  And the real gain is after that, you have results in the CPU, not you have sample to compute.  It's just a latency in between the error front end and the CPU.  With a classic, classical approach with Octave or you need to store a big data set.  You process this.  It's just the big difference.  It's okay after you, it's possible to use a GPU to improve this,  but you have always the acquisition time before able to be, to process data.
fsr_platform_independent_cpu_fpga_co_design_0_167.png fsr_platform_independent_cpu_fpga_co_design_168_767.png fsr_platform_independent_cpu_fpga_co_design_768_3575.png fsr_platform_independent_cpu_fpga_co_design_3576_7835.png fsr_platform_independent_cpu_fpga_co_design_7836_8927.png fsr_platform_independent_cpu_fpga_co_design_8928_10031.png fsr_platform_independent_cpu_fpga_co_design_10032_12143.png fsr_platform_independent_cpu_fpga_co_design_12144_14843.png fsr_platform_independent_cpu_fpga_co_design_14844_16103.png fsr_platform_independent_cpu_fpga_co_design_16104_18143.png fsr_platform_independent_cpu_fpga_co_design_18144_21287.png fsr_platform_independent_cpu_fpga_co_design_21288_21947.png fsr_platform_independent_cpu_fpga_co_design_21948_23075.png fsr_platform_independent_cpu_fpga_co_design_23076_24611.png fsr_platform_independent_cpu_fpga_co_design_24612_26195.png fsr_platform_independent_cpu_fpga_co_design_26196_27659.png fsr_platform_independent_cpu_fpga_co_design_27660_28847.png fsr_platform_independent_cpu_fpga_co_design_28848_29423.png fsr_platform_independent_cpu_fpga_co_design_29424_29555.png fsr_platform_independent_cpu_fpga_co_design_29556_35807.png fsr_platform_independent_cpu_fpga_co_design_35808_35855.png fsr_platform_independent_cpu_fpga_co_design_35856_35951.png fsr_platform_independent_cpu_fpga_co_design_35952_35999.png fsr_platform_independent_cpu_fpga_co_design_36000_36059.png fsr_platform_independent_cpu_fpga_co_design_36060_36107.png fsr_platform_independent_cpu_fpga_co_design_36108_37067.png fsr_platform_independent_cpu_fpga_co_design_37068_37115.png fsr_platform_independent_cpu_fpga_co_design_37116_37163.png fsr_platform_independent_cpu_fpga_co_design_37164_37211.png fsr_platform_independent_cpu_fpga_co_design_37212_37295.png fsr_platform_independent_cpu_fpga_co_design_37296_37379.png fsr_platform_independent_cpu_fpga_co_design_37380_37499.png fsr_platform_independent_cpu_fpga_co_design_37500_37571.png fsr_platform_independent_cpu_fpga_co_design_37572_37619.png fsr_platform_independent_cpu_fpga_co_design_37620_37667.png fsr_platform_independent_cpu_fpga_co_design_37668_37799.png fsr_platform_independent_cpu_fpga_co_design_37800_39671.png fsr_platform_independent_cpu_fpga_co_design_39672_39795.png