diff --git a/recipes-app/fofb-pscgen/files/pscgen b/recipes-app/fofb-pscgen/files/pscgen
new file mode 100644
index 0000000000000000000000000000000000000000..25e620b54eeadc9dd45af6d99dffb16fb9e847d9
--- /dev/null
+++ b/recipes-app/fofb-pscgen/files/pscgen
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+import deviceaccess
+import logging
+import argparse
+import numpy as np
+
+
+# Prepare logger
+logger = logging.getLogger("pscgen")
+
+
+# DAQ device
+deviceaccess.setDMapFilePath("/opt/fofb/map/devices.dmap")
+appdev = deviceaccess.Device("APPUIO")
+appdev.open()
+
+def configure_raw(idx, rst=None, phincr=None, phoffs=None, scale=None, offset=None):
+    """
+    Configure PSC sinewave generator for a PSCID.
+    If a parameter is set on 'None', the value is kept unchanged.
+
+    PARAMETERS:
+    -----------
+    idx: int
+        PSCID of the line to configure
+    rst: bool
+        Set the reset bit
+    phincr: int
+        Phase increment value. NCO is on 16 bits.
+    phoffs: int
+        Phase offset value. NCO is on 16 bits.
+    scale: int
+        Amplitude scaler. Unsigned on 16 bits.
+    offset: int
+        Amplitude offset. Signed on 16 bits.
+    """
+    _phincr = appdev.getOneDRegisterAccessor(np.uintc, "APP.pscgen_0.TABLE_PHASE_INCR")
+    _phoffs = appdev.getOneDRegisterAccessor(np.uintc, "APP.pscgen_0.TABLE_PHASE_OFFS")
+    _scale = appdev.getOneDRegisterAccessor(np.uintc, "APP.pscgen_0.TABLE_SCALE")
+    _phincr.read()
+    _phoffs.read()
+    _scale.read()
+
+    if not rst is None:
+        if rst==1:
+            _phoffs[idx] = _phoffs[idx] | 0x10000
+        else:
+            _phoffs[idx] = _phoffs[idx] & 0xFFFF
+
+    if not phincr is None:
+        _phincr[idx] = phincr
+
+    if not phoffs is None:
+        _phoffs[idx] = phoffs + (_phoffs[idx] & 0x10000)
+
+    if not scale is None:
+        _scale[idx] = (_scale[idx] & 0xFFFF0000) + scale
+
+    if not offset is None:
+        _scale[idx] = (_scale[idx] & 0xFFFF) + (offset<<16)
+
+    _scale.write()
+    _phincr.write()
+    _phoffs.write()
+
+def configure(idx, freq=None, phase=None, amp=None, offset=None):
+    """
+    Convenient method to set PSC sinewave generator with physical inputs (Hz, A, degree)
+    It calls psc_configure() and return the exact values.
+
+    PARAMETERS:
+    -----------
+    idx: int
+        PSCID of the line to configure
+    freq: float
+        Set the sine wave frequency (Hz, <5000)
+        A negative value reset the generator.
+    phase: float
+        Set the sine wave phase (deg, 0<=phase<360)
+    amp: float
+        Peak to peak amplitude of the sine wave (A, <20))
+    offset: float
+        Offset of the sine wave (A, -10<=offset<=10))
+
+    RETURNS
+    -------
+    idx, rst, phincr, phoffs, scale, offset:
+        Parameters used to call psc_configure()
+    """
+
+    if not freq is None:
+        if freq > 5000:
+            raise ValueError("Frequency shall be < 5000")
+        phincr = int(np.round(freq/10079*2**16))
+        rst = 0
+        if freq <= 0:
+            rst = 1
+            phincr=None
+    else:
+        phincr = None
+        rst= None
+
+    if not phase is None:
+        if phase >= 360 or phase < 0:
+            raise ValueError("Phase shall be 0 <= phase < 360")
+        phoffs = int(np.round(phase/360*2**16))
+    else:
+        phoffs = None
+
+    if not amp is None:
+        if amp > 20 or amp < 0:
+            raise ValueError("Amp shall be in [ 0 ; 20 ] A")
+        scale = int(0xFFFF * amp/20)
+    else:
+        scale=None
+
+    if not offset is None:
+        if offset > 10 or offset < -10:
+            raise ValueError("Amp shall be in [ -10 ; 10 ] A")
+        if offset >= 0:
+            offset = int(0x7FFF * offset/10)
+        else:
+            offset = int(0xFFFF+0x7FFF*offset/10)
+    else:
+        offset=None
+
+    logger.debug("rst={} phincr={} phoffs={} scale={} offset={}".format(rst, phincr, phoffs, scale, offset))
+    configure_raw(idx, rst, phincr, phoffs, scale, offset)
+
+    return idx, rst, phincr, phoffs, scale, offset
+
+def reset():
+    # Table depth to 100 entries
+    appdev.write("APP.pscgen_0.TABLE_DEPTH", np.uintc(100))
+
+    # Ticker rate to 10075 Hz
+    appdev.write("APP.pscgen_0.TICKER_RATE", np.uintc(100e6//10074))
+
+    # All line to reset, scale 0, offset 0
+    for i in range(100):
+        configure_raw(i, rst=1, scale=0, offset=0)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description="PSC sine wave generator")
+
+    parser.add_argument("--reset", action="store_true", help="Reset configuration. First action performed if selected.")
+    parser.add_argument("--raw", action="store_true", help="Switch to raw inputs: phase increment, DAC units. All inputs must be given")
+
+    parser.add_argument("pscid", type=int, help="ID of the PSC to configure")
+    parser.add_argument("-f", type=float, default=None, help="Set frequency in Hz. Use a negative frequency to reset NCO")
+    parser.add_argument("-p", type=float, default=None, help="Set phase in degree")
+    parser.add_argument("-a", type=float, default=None, help="Set pk-pk amplitude in A")
+    parser.add_argument("-o", type=float, default=None, help="Set DC offset in A")
+
+    args = parser.parse_args()
+
+    if args.reset:
+        reset()
+
+    if args.raw:
+        configure_raw(args.pscid, 0, int(args.f), int(args.p), int(args.a), int(args.o))
+    else:
+        configure(args.pscid, args.f, args.p, args.a, args.o)
diff --git a/recipes-app/fofb-pscgen/fofb-pscgen_1.0.bb b/recipes-app/fofb-pscgen/fofb-pscgen_1.0.bb
new file mode 100644
index 0000000000000000000000000000000000000000..e1e48cfcebecaf3f655aacdecd11c9acfc849427
--- /dev/null
+++ b/recipes-app/fofb-pscgen/fofb-pscgen_1.0.bb
@@ -0,0 +1,16 @@
+SUMMARY = "Simple python tool to use the PSC sinus generator"
+SECTION = "opt"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+SRC_URI = " file://pscgen"
+
+RDEPENDS_${PN}=" deviceaccess-mapfiles deviceaccess-python-bindings"
+
+FILES_${PN}+="/usr/bin/pscgen"
+
+do_install() {
+    # Add FPGA version reader and FoFb Configurator
+    install -d ${D}/usr/bin/
+    install -m 0755 ${WORKDIR}/pscgen ${D}/usr/bin/pscgen
+}
diff --git a/recipes-core/images/zup-image-soleil-fofb.bb b/recipes-core/images/zup-image-soleil-fofb.bb
index c69ef873190a671cc7cddc3ead6916470bf18134..d1c879d9e0c6633b9472a7d27157d5c02c0fde4e 100644
--- a/recipes-core/images/zup-image-soleil-fofb.bb
+++ b/recipes-core/images/zup-image-soleil-fofb.bb
@@ -28,7 +28,7 @@ IMAGE_INSTALL_append = " deviceaccess"
 IMAGE_INSTALL_append = " deviceaccess-python-bindings"
 IMAGE_INSTALL_append = " fofb-opcua-server"
 IMAGE_INSTALL_append = " fofb-init"
-IMAGE_INSTALL_append = " fofb-daqcapt"
+IMAGE_INSTALL_append = " fofb-daqcapt fofb-pscgen"
 IMAGE_INSTALL_append = " nfs-utils"
 
 # We do not need that