11
$\begingroup$

[EDIT:July 1st 2016]. I finally did the job by myself and built a (JLink based and limited) redpitaya package that is enough to play with the examples showed on the redpitaya site. I presented it at: 31 March 2016 Marseille seminar with an application to the frequency response measurement of an electric guitar microphone. If someone is interested and can reopen the question, I can put the stuff in the answer.[\EDIT]

I just discovered the Red Pitaya board and borrowed a unit to play during this weekend. Surprisingly I did not find any reference to Mathematica on the Red Pitaya forum, nor did I find any reference to Red Pitaya on Mathematica Stack Exchange.

Can someone give me some leads to a tutorial that shows how to start with the board? In the beginning I just want to store and process a digitized waveform with Mathematica and/or generate an arbitrary waveform, built with Mathematica.

$\endgroup$
  • $\begingroup$ Related devices.wolfram.com (but it's not listed there) $\endgroup$ – Dr. belisarius Sep 11 '15 at 22:10
  • $\begingroup$ Thanks belisarius, I posted a note there. Just in case...:) $\endgroup$ – Christian Néel Sep 11 '15 at 22:35
  • $\begingroup$ Could you also post HERE with more details such as why you think it is important. Let me know if you do post, I could try getting it into developers focus. $\endgroup$ – Vitaliy Kaurov Sep 11 '15 at 23:17
  • 1
    $\begingroup$ As far as I can tell from the documentation, they have both a C API and command line tools. To integrate it will with Mathematica, you can access the C API through MathLink or LibraryLink. This is going to be some work, but it allows you to build well-integrated, convenient tools for Mathematica. The other option is to call the command line tool with StartProcess and related functions. This will be much less work but also less robust. $\endgroup$ – Szabolcs Sep 13 '15 at 11:29
  • 2
    $\begingroup$ I've reopened; go answer your own question! $\endgroup$ – J. M. will be back soon Jul 2 '16 at 8:39
2
$\begingroup$

redpitaya.m package

BeginPackage["redpitaya`"]
Needs["JLink`"];
InstallJava[];
(******************)
(* Initializations*)
(******************)
rpSCPIinit::usage="This function rpSCPIinit[tcpadress_String,tcpport_] initiates a TCP/IP connection to the IP adress \"tcpaddress\" and port number \"tcpport\"
Default IP = \"192.168.1.100\" (string value) .
Default Port = 5000";

rpSCPIclose::usage="This function rpSCPIclose[] has no arguments and closes the TCP port to the SCPI server";

(******************)
(* DIO management *)
(******************)
rpDpinSetLedState::usage ="This function rpDpinSetLedState[LED_Integer,value_Integer] is a function for driving LED's easily.
Parameters are LED number and value (1 for light or 0 for off).
Note : the SCPI allows only controls of LEDs 1 to 7.
LED0 is always blinking due to default FPGA firmware.
LED8 is present on the board and slightly lit but does not react and seems to be affected to a another FPGA function.";

rpDpinSetDioDirection::usage="This function rpDpinSetDioDirection[DIO_Integer,DIR_String,PN_String] defines the direction of a Digital Input\\Output pin.
Parameter pin # DIO (DIO=1..7).
DIR string is \"OUT\" for output, \"INP\" for input.
PN is the type of DIO (see connector pinout location)";

rpDpinGetDioState::usage="This function rpDpinGetDioState[DIO_Integer,PN_String] is a status query of DIO pin
Parameter pin # DIO (DIO=1..7).
PN is the type of DIO (see connector pinout location).
The function returns an Integer (0 or 1)";

rpDpinSetDioState::usage="This function rpDpinSetDioState[DIO_Integer,value_Integer,PN_String] is a staus writing function of DIO pin.
Parameter pin # DIO (DIO=1..7).
Parameter value to write (1 or 0 ).
Parameter PN is the type of DIO (see connector pinout location).";

(******************)
(* slow DAC/ADC   *)
(******************)
rpApinGetAinValue::usage="This function rpApinGetAinValue[CHA_Integer] reads the slow ADC analog Input pin
Parameter CHA is the Analog Input chanel number (CHA=0..3).
The function returns a Real value in volts (0 to 3.3)";

rpApinGetAoutValue::usage="This function rpApinGetAoutValue[CHA_Integer] reads the ADC on the slow DAC analog Output pin.
It can be used a check of the value written on analog Output pin DAC.
Parameter CHA is the Analog Output chanel number (CHA=0..3).
The function returns a Real value in volts (0 to 1.8) because Output chanels are limited ";

rpApinSetAoutValue::usage="This function rpApinSetAoutValue[CHA_Integer,value_] writes the ADC value on the slow DAC output pin.
Parameter CHA is the Analog Output chanel number (CHA=0..3).
The Real \"value\" is in volts (0 to 1.8) and clipped to 1.8 because Output chanels are limited to 1.8V.
Note that the DAC conversion is made by a filtered PWM, so the speed is *really* slow.";

(********************)
(* signal generator *)
(********************)
rpGenReset::usage="This function rpGenReset[] rests the 2 channels of the signal generator.
Note: difficult to see what is the real effect...:-)";

rpGenOutEnable::usage="This function rpGenOutEnable[CH_Integer] enables the signal generator channel \"CH\".
Parameter CH = 1 or 2.
This function normally terminates the setup of each channel.
For example it starts generation or an arbitrary signal that has been preliminaryly defined by a set of data points.";

rpGenOutDisable::usage="This function rpGenOutDisable[CH_Integer] disables the signal generator channel \"CH\".
Parameter CH = 1 or 2.
This function normally terminates the signal generation of the channel.";

rpGenFreq::usage="This function rpGenFreq[CH_Integer,freq_,phase_:0] sets frequence AND phase of the signal generator channel \"CH\".
Parameter CH = 1 or 2.
Parameter freq = 0 to 62.5 x 10^6.
Parametre phase in Degree = -360 to 360 is an option (may be omitted: 0 by default).";

rpGenWaveform::usge="This function rpGenWaveform[CH_Integer,type_String] sets the waveform of the signal generator channel \"CH\".
Parameter CH = 1 or 2.
Parameter type = {\"SINE\",\"SQUARE\",\"TRIANGLE\",\"SAWU\",\"SAWD\"}";

rpGenPWM::usage="This function rpGenPWM[CH_Integer,pwm_:50] sets the specific waveform PWM of the signal generator channel \"CH\".
Parameter CH = 1 or 2.
Parameter pwm = 0..100 is the duty-cycle (may be omitted: 50% by default)";

rpGenArbitrary::usage="This function rpGenArbitrary[CH_Integer,array_List] sets the ARBITRARY waveform of the signal generator channel \"CH\".
Parameter CH = 1 or 2.
Parameter array = a real-valued list of numbers, of maximum length 16384.
Each value of array shoild be in the range -1...+1 volt.";

rpGenAmp::usage="This function rpGenAmp[CH_Integer,amp_:1,offset_:0] sets amplitude AND offset of the signal generator channel \"CH\".
Parameter CH = 1 or 2.
Parameter amp = 0 to 1 (may be omitted: 1 by default).
Parametre offset = -1..+1 is an option (may be omitted: 0 by default).
Note: [amp + offset] value should be less than the maximum output range +1/-1V";

(***************************************************)
(* signal generator: the complicated BURST mode... *)
(***************************************************)
rpGenBurstEnable::usage="This function rpGenBurstEnable[CH_Integer] enables the BURST mode of signal generator channel \"CH\".
Parameter CH = 1 or 2.
This function normally terminates the setup of each channel.
For example it starts generation or an arbitrary signal that has been preliminaryly defined by a set of data points.";

rpGenBurstDisable::usage="This function rpGenBurstDisable[CH_Integer] disables the BURST mode of signal generator channel \"CH\".
Parameter CH = 1 or 2.
This function normally terminates the use of BURST mode of each channel.";

rpGenBurstConfig::usage="This function rpGenBurstConfig[CH_Integer,ncyc_:1,nor_:\"INF\",period_] defines the parameters of the BURST mode of signal generator channel \"CH\".
The signal may be any wawe defined in the wave definition functions such as rpGenWaveform, rpGenPWM, rpGenArbitrary.
Parameter CH = 1 or 2.
Parameter ncyc: Set N number of generated signal periods in one burst. N= {1..50000, \"INF\"}. Default = 1.
Parameter nor: Set R number of repeated bursts. R= {1..50000, \"INF\"}. Default = \"INF\".
Parameter period (not clear in the SCPI documentation) either:
    - the time P between bursts (in that case: burst signal period = N x rpGenFreq +P )
    - or most likely the total period of the burst signal (in that case: burst signal period = P )
Here in Mathematica P is expressed in seconds: P = 10^-6..500";

rpGenBurstTrigSource::usage="This function rpGenBurstTrigSource[CH_Integer,source_String] defines the trigger parameters of the BURST mode of signal generator channel \"CH\".
Parameter CH = 1 or 2.
Parameter source = {\"INT\",\"EXT_PE\",\"EXT_NE\",\"GATED\"}
\"INT\"=Internal.
\"EXT_PE\"=External Positive Edge.
\"EXT_NE\"=External Negative Edge.
\"GATED\ = not sure... maybe burst are generated when and only when the EXT pin is held High. Not Tested";

rpGenBurstTrigger::usage="This function rpGenBurstTrigger[CH_Integer] triggers IMMEDIATELY the burst mode of signal generator channel \"CH\".
Parameter CH = 1 or 2.";

(**********************)
(* signal acquisition *)
(**********************)
rpAcqReset::usage="This function rpAcqReset[] resets the 2 channels of the signal acquisition.
Note: difficult to see what is the real effect...:-)";

rpAcqStart::usage="This function rpAcqStart[] enables the signal acquistion  on bothe channels.
This function normally allows the acquisition on both channels.";

rpAcqStop::usage="This function rpAcqStop[] enables the signal acquistion  on bothe channels.
This function normally terminates the signal generation of both channels.";

rpAcqSetDecimation::usage="This function rpAcqSetDecimation[par_Integer:1] sets the Sampling Rate for BOTH channels
Parameter \"par\" is an integer par== {1,8,64,1024,8192,65536}. Default = 1
par = 1     => Sampling Rate= 125 MHz
par = 8     => Sampling Rate= 15.6 MHz
par = 64    => Sampling Rate= 1.9 MHz
par = 1024  => Sampling Rate= 122 kHz
par = 8192  => Sampling Rate= 15.2 kHz
par = 65536 => Sampling Rate= 1.9 kHz";

rpAcqGetDecimation::usage="This function rpAcqGetDecimation[] reads the sampling rate of BOTH channels
returns an integer in the range:  {1,8,64,1024,8192,65536}. 
par = 1     => Sampling Rate= 125 MHz
par = 8     => Sampling Rate= 15.6 MHz
par = 64    => Sampling Rate= 1.9 MHz
par = 1024  => Sampling Rate= 122 kHz
par = 8192  => Sampling Rate= 15.2 kHz
par = 65536 => Sampling Rate= 1.9 kHz";

rpAcqSetSamplingRate::usage="This function rpAcqSetSamplingRate[par_String:\"125MHz\"]for BOTH channels.
Same as the function rpAcqSetDecimation but with a String parameter and sampling rate expressed directly in (approximative) frequency units
String parameter \"par\" possible values par= {\"125MHz\",\"15_6MHz\",\"1_9MHz\",\"103_8kHz\",\"15_2kHz\",\"1_9kHz\"}.
Default value is \"125MHz\"";

rpAcqGetSamplingRate::usage="This function rpAcqGetSamplingRate[] for BOTH channels returns the samplig Frequency.
Same as the function rpAcqGetDecimation but with a String parameter and sampling rate expressed directly in (approximative) frequency units
returned values of String parameter \"par\" are in the list: {\"125MHz\",\"15_6MHz\",\"1_9MHz\",\"103_8kHz\",\"15_2kHz\",\"1_9kHz\"}";

rpAcqGetSamplingRateHz::usage="This function rpAcqGetSamplingRateHz[] for BOTH channels returns the samplig Frequency in Hz (Number).
Same as the function rpAcqGetSamplingRate but with a sampling rate expressed directly in hertz.
returned values of sampling rate is an Integer or a Real";

rpAcqSetAveraging::usage="This function rpAcqSetAveraging[par_String:\"ON\"] sets filtering ON or OFF for BOTH channels
Parameter \"par\" = {\"ON\",\"OFF\"}
When filtering is \"ON\" the 8, 64, 1024, 8192 or 65536 decimated values are apparently averaged (or filtered with a FIR kernel) to get a smoother signal.
Has probably no impact at 125MHz.
Filtering is \"ON\" by default.";

rpAcqGetAveraging::usage="This function rpAcqGetAveraging[] returns the status of filtering (ON or OFF) for BOTH channels
Returns string in list: {\"ON\",\"OFF\"}";
rpAcqSetTriggerSource::usage="This function rpAcqSetTriggerSource[par_String:\"DISABLED\"] defines the trigger Source for BOTH channels.
par = \"DISABLED\"     => No Triggering (by default)
par = \"NOW\"          => Immediate Trigger.
par = \"CH1_PE\"       => Source = CH1, Trigger on rising edge.
par = \"CH2_PE\"       => Source = CH2, Trigger on rising edge.
par = \"CH1_NE\"       => Source = CH1, Trigger on falling edge.
par = \"CH2_NE\"       => Source = CH2, Trigger on falling edge.
par = \"EXT_PE\"       => Source = EXT, Trigger on rising edge.
par = \"EXT_NE\"       => Source = EXT, Trigger on falling edge.
par = \"AWG_PE\"       => Source = AWG, Trigger on rising edge.
par = \"AWG_NE\"       => Source = AWG, Trigger on falling edge.
Notes: AWG = Arbitrary Waveform Generator.
       EXT= EXT DIO pin (DIO0_P).
       Triggering value is given by the function rpAcqSetTriggerThreshold.";

rpAcqGetTriggerState::usage="This function rpAcqGetTriggerState[] returns a string giving the trigger status.
Possibles values are: 
\"WAIT\" (not triggered yet).
\"TD\" (triggered).
Usefull for polling the status of acquisition.";

rpAcqSetTriggerDelay::usage="This function rpAcqSetTriggerDelay[par_Integer:0] defines the trigger delay for BOTH channels.
Prameter \"par\" = -8192..8192 value of trigger delay in Acquisition sample (real delay in ns depends on Samplig rate).
Default value is 0 => trigger is in the middle of acquired signal.
Min value is -8192 => trigger is in the rigth of acquired signal.
Max value is +8192 => trigger is in the left of acquired signal.";

rpAcqGetTriggerDelay::usage="This function rpAcqGetTriggerDelay[] return a Number value (in samples) of the trigger delay";

rpAcqSetTriggerDelayNS::usage="This function rpAcqSetTriggerDelayNS[par_Integer:0] defines the trigger delay in nanoseconds for BOTH channels.
Prameter \"par\" =  value of trigger delay in nS 
Since real delay in ns depends on Samplig rate a given value may be not realistic (example 10^6 ns with a 125MHz sampling rate would necessitate 125000 samples dalay and the limit of delay is +/-8192 samples).
Default value is 0 => trigger is in the middle of acquired signal.
This function is not very usefull.";

rpAcqGetTriggerDelayNS::usage="This function rpAcqGetTriggerDelayNS[] return a Number value (in nanoseconds) of the trigger delay.
Note that the returned value may be different from the set value, because it is rounded according to the sample rate.";

rpAcqSetTriggerThreshold::usage="This function rpAcqSetTriggerThreshold[par_Integer:0] defines the trigger threshold LEVEL for BOTH channels.
Prameter \"par\" = -20000..20000 value of trigger delay in MILLIVOLTS (max voltage is +/-20V for CH1 & CH2 in HV configuration).
Default value is 0.";

rpAcqGetTriggerThreshold::usage="This function rpAcqGetTriggerThreshold[] return a Number value (in mV) of the trigger Threshold LEVEL.";

rpAcqSetGain::usage="This function rpAcqSetGain[CH_Integer,gain_String:\"LV\"] defines the gain settings (High or Low voltage) of signal generator channel \"CH\"s
Parameter CH = 1 or 2.
Parameter\"gain\" = {\"HV\",\"LV\"}. Default Value is  \"LV\".
Note: HV = +/-20V.
      LV = =/-1V.
This has an impact on the voltage gains conversion for threholds and other displays , in no way it switches automatically the gain setting on the hardware. Gains settings on hardwarware should be set MANUALLY and the HV/LV software value set accordingly.";

rpAcqGetGain::usage="This function rpAcqGetGain[CH_Integer] returns the gain setting(High or Low voltage) of signal generator channel \"CH\"s
Parameter CH = 1 or 2.";

rpAcqGetWritePointer::usage="This function rpAcqGetWritePointer[] returns current position of the write pointer in the buffer";

rpAcqGetWritePointerAtTrig::usage="This function rpAcqGetWritePointerAtTrig[] returns position where trigger event appeared in the buffer";

rpAcqGetBufferSize::usage="This function rpAcqGetBufferSize[] returns the buffer size";

rpAcqSetDataUnit::usage="This function rpAcqSetDataUnit[par_String:\"VOLTS\" defines the data units in the data transfert when reading buffer.
Parameter\"par\" = {\"VOLTS\",\"RAW\"}. Default Value is  \"VOLTS\".";

rpAcqSetDataFormat::usage="This function rpAcqSetDataFormat[par_String:\"FLOAT\"] defines the data format in the data transfert when reading buffer.
Parameter\"par\" = {\"FLOAT\",\"ASCII\"}. Default Value is  \"FLOAT\".";

rpAcqGetFullData::usage="This function rpAcqGetFullData[CH_Integer] returns the full buffer content of signal generator channel \"CH\"s
Parameter CH = 1 or 2.
Data are in string format and should be processed further.";

rpAcqGetFullDataNum::usage="This function rpAcqGetFullDataNum[CH_Integer] returns the full buffer content of signal generator channel \"CH\"s in a Number form.
Parameter CH = 1 or 2.
Data are returned in a List of Nmbers.";

Begin["`private`"];

Clear[rpSCPIinit,rpSCPIclose]
rpSCPIinit[tcpaddress_:"192.168.1.100",tcpport_:5000]:=Module[{},
(*create a Socket object*)
socket=JavaNew["java.net.Socket",tcpaddress,tcpport];
out=JavaNew["java.io.PrintWriter",socket@getOutputStream[],True];
in=JavaNew["java.io.BufferedReader",JavaNew["java.io.InputStreamReader",socket@getInputStream[]]];]
rpSCPIclose[]:=socket@close[];

Clear[rpDpinSetLedState]
rpDpinSetLedState[LED_Integer,value_Integer]:=out@println["DIG:PIN LED"<>ToString[LED]<>","<>ToString[value]]/;LED<9 && LED>=0&&(value==0||value==1)

Clear[rpDpinSetDioDirection];
rpDpinSetDioDirection[DIO_Integer,DIR_String,PN_String]:=out@println["DIG:PIN:DIR "<>DIR<>", DIO"<>ToString[DIO]<>"_"<>PN]/;DIO<8 && DIO>=0 && (PN=="P"||PN=="N")&&(DIR=="OUTP"||DIR=="INP")

Clear[rpDpinGetDioState]
rpDpinGetDioState[DIO_Integer,PN_String]:=Module[{},out@println["DIG:PIN? DIO"<>ToString[DIO]<>"_"<>PN];ToExpression[in@readLine[]]]/;DIO<8 && DIO>0 && (PN=="P"||PN=="N")

Clear[rpDpinSetDioState];
rpDpinSetDioState[DIO_Integer,value_Integer,PN_String]:=out@println["DIG:PIN DIO"<>ToString[DIO]<>"_"<>PN<>","<>ToString[value]]/;DIO<8 && DIO>=0 && (PN=="P"||PN=="N")&&(value==0||value==1)

Clear[rpApinGetAinValue,rpApinGetAoutValue];
rpApinGetAinValue[CHA_Integer]:=Module[{},out@println["ANALOG:PIN? AIN"<>ToString[CHA]];ToExpression[in@readLine[]]]/;CHA<4 && CHA>=0 
rpApinGetAoutValue[CHA_Integer]:=Module[{},out@println["ANALOG:PIN? AOUT"<>ToString[CHA]];ToExpression[in@readLine[]]]/;CHA<4 && CHA>=0 

Clear[rpApinSetAoutValue];
rpApinSetAoutValue[CHA_Integer,value_]:=out@println["ANALOG:PIN AOUT"<>ToString[CHA]<>","<>ToString[Clip[value,{0,1.8}]]]/;CHA<4 && CHA>=0 

Clear[rpGenReset]
rpGenReset[]:=out@println["GEN:RST"]

Clear[rpGenOutEnable,rpGenOutDisable]
rpGenOutEnable[CH_Integer]:=out@println["OUTPUT"<>ToString[CH]<>":STATE ON"]/;CH==1 || CH==2
rpGenOutDisable[CH_Integer]:=out@println["OUTPUT"<>ToString[CH]<>":STATE OFF"]/;CH==1 || CH==2

Clear[rpGenFreq]
rpGenFreq[CH_Integer,freq_,phase_:0]:=Module[{},
out@println["SOUR"<>ToString[CH]<>":FREQ:FIX "<>ToString[freq]];
out@println["SOUR"<>ToString[CH]<>":PHAS "<>ToString[phase]]]/;(CH==1 || CH==2)&& freq>0 &&freq<=62.5 10^6&&Abs[phase]<=360

Clear[rpGenWaveform]
rpGenWaveform[CH_Integer,type_String]:=out@println["SOUR"<>ToString[CH]<>":FUNC "<>type]/;(CH==1 || CH==2)&& (type=="SINE"||type=="SQUARE"||type=="TRIANGLE"||type=="SAWU"||type=="SAWD")

Clear[rpGenPWM]
rpGenPWM[CH_Integer,pwm_:50]:=Module[{},
out@println["SOUR"<>ToString[CH]<>":FUNC PWM"];
out@println["SOUR"<>ToString[CH]<>":DCYC "<>ToString[pwm]]]/;(CH==1 || CH==2)&& pwm>=0&& pwm<=100

Clear[rpGenArbitrary]
rpGenArbitrary[CH_Integer,array_List]:=Module[{},
out@println["SOUR"<>ToString[CH]<>":FUNC ARBITRARY"];
out@println["SOUR"<>ToString[CH]<>":TRAC:DATA:DATA "<>StringRiffle[ToString[#,FormatType->CForm]&/@N[Round[array,10^-3]],","]]]/;(CH==1 || CH==2)&& Length[array]<=16384

Clear[rpGenAmp]
rpGenAmp[CH_Integer,amp_:1,offset_:0]:=Module[{},
out@println["SOUR"<>ToString[CH]<>":VOLT "<>ToString[amp]];
out@println["SOUR"<>ToString[CH]<>":VOLT:OFFS "<>ToString[offset]];]/;(CH==1 || CH==2)&& (Abs[amp+offset]<=1&&Abs[amp]<=1&& Abs[offset]<=1)

Clear[rpGenBurstEnable,rpGenBurstDisable]
rpGenBurstEnable[CH_Integer]:=out@println["BURS"<>ToString[CH]<>":STAT ON"]/;CH==1 || CH==2
rpGenBurstDisable[CH_Integer]:=out@println["BURS"<>ToString[CH]<>":STAT OFF"]/;CH==1 || CH==2

Clear[rpGenBurstConfig]
rpGenBurstConfig[CH_Integer,ncyc_:1,nor_:"INF",period_]:=Module[{},
out@println["SOUR"<>ToString[CH]<>":BURS:NCYC "<>ToString[ncyc]];
out@println["SOUR"<>ToString[CH]<>":BURS:NOR "<>ToString[nor]];
out@println["SOUR"<>ToString[CH]<>":BURS:INT:PER "<>ToString[Floor[10^6 period]]];]/;(CH==1 || CH==2)&& ((ncyc>=1&&ncyc<=50000)||ncyc=="INF")&& ((nor>=1&&nor<=50000)||nor=="INF")&&((period>=10^-6&&period<=500))

Clear[rpGenBurstTrigSource];
rpGenBurstTrigSource[CH_Integer,source_String]:=out@println["SOUR"<>ToString[CH]<>":TRIG:SOUR "<>source]/;(CH==1 || CH==2)&& (source=="INT"||source=="EXT_PE"||source=="EXT_NE"||source=="GATED")

Clear[rpGenBurstTrigger];
rpGenBurstTrigger[CH_Integer]:=out@println["SOUR"<>ToString[CH]<>":TRIG:IMM "]/;(CH==1 || CH==2)
rpGenBurstTrigger[]:=out@println[":TRIG:IMM"]

Clear[rpAcqStart,rpAcqStop,rpAcqReset];
rpAcqStart[]:=out@println["ACQ:START"]
rpAcqStop[]:=out@println["ACQ:STOP"]
rpAcqReset[]:=out@println["ACQ:RST"]

Clear[rpAcqSetDecimation,rpAcqGetDecimation,rpAcqSetSamplingRate,rpAcqGetSamplingRate,rpAcqGetSamplingRateHz,rpAcqSetAveraging,rpAcqGetAveraging]
rpAcqSetDecimation[par_Integer:1]:=out@println["ACQ:DEC "<>ToString[par]]/;(par==1||par==8||par==64||par==1024||par==8192||par==65536)
rpAcqGetDecimation[]:=Module[{},out@println["ACQ:DEC?"];ToExpression[in@readLine[]]]
rpAcqSetSamplingRate[par_String:"125MHz"]:=out@println["ACQ:SRAT "<>ToString[par]]/;(par=="125MHz"||par=="15_6MHz"||par=="1_9MHz"||par=="103_8kHz"||par=="15_2kHz"||par=="1_9kHz")
rpAcqGetSamplingRate[]:=Module[{},out@println["ACQ:SRAT?"];in@readLine[]]
rpAcqGetSamplingRateHz[]:=Module[{},out@println["ACQ:SRA:HZ?"];ToExpression[in@readLine[]]]
rpAcqSetAveraging[par_String:"ON"]:=out@println["ACQ:AVG "<>ToString[par]]/;(par=="ON"||par=="OFF")
rpAcqGetAveraging[]:=Module[{},out@println["ACQ:AVG?"];in@readLine[]]

Clear[rpAcqSetTriggerSource,rpAcqGetTriggerState,rpAcqSetTriggerDelay,rpAcqGetTriggerDelay,rpAcqSetTriggerDelayNS,rpAcqGetTriggerDelayNS,rpAcqSetTriggerThreshold,rpAcqGetTriggerThreshold]
rpAcqSetTriggerSource[par_String:"DISABLED"]:=out@println["ACQ:TRIG "<>ToString[par]]/;(par=="DISABLED"||par=="NOW"||par=="CH1_PE"||par=="CH1_NE"||par=="CH2_PE"||par=="CH2_NE"||par=="EXT_PE"||par=="EXT_NE"||par=="AWG_PE"||par=="AWG_NE")
rpAcqGetTriggerState[]:=Module[{},out@println["ACQ:TRIG:STAT?"];in@readLine[]]
rpAcqSetTriggerDelay[par_Integer:0]:=out@println["ACQ:TRIG:DLY "<>ToString[par]]/;(par>=-8192&&par<=16384)
rpAcqGetTriggerDelay[]:=Module[{},out@println["ACQ:TRIG:DLY?"];ToExpression[in@readLine[]]]
rpAcqSetTriggerDelayNS[par_Integer:0]:=out@println["ACQ:TRIG:DLY:NS "<>ToString[par]]/;(Abs[par]<=16384)
rpAcqGetTriggerDelayNS[]:=Module[{},out@println["ACQ:TRIG:DLY:NS?"];ToExpression[in@readLine[]]]
rpAcqSetTriggerThreshold[par_Integer:0]:=out@println["ACQ:TRIG:LEV "<>ToString[par]]/;(Abs[par]<=20000)
rpAcqGetTriggerThreshold[]:=Module[{},out@println["ACQ:TRIG:LEV?"];ToExpression[in@readLine[]]]

Clear[rpAcqSetGain,rpAcqGetGain]
rpAcqSetGain[CH_Integer,gain_String:"LV"]:=out@println["ACQ:SOUR"<>ToString[CH]<>":GAIN "<> gain]/;(CH==1||CH==2)&&(gain=="HV"||gain=="LV")
rpAcqGetGain[CH_Integer]:=Module[{},out@println["ACQ:SOUR"<>ToString[CH]<>":GAIN?"];in@readLine[]]

Clear[rpAcqGetWritePointer,rpAcqGetWritePointerAtTrig,rpAcqGetBufferSize]
rpAcqGetWritePointer[]:=Module[{},out@println["ACQ:WPOS?"];ToExpression[in@readLine[]]](*inutile?*)
rpAcqGetWritePointerAtTrig[]:=Module[{},out@println["ACQ:TPOS?"];ToExpression[in@readLine[]]]
rpAcqGetBufferSize[]:=Module[{},out@println["ACQ:BUF:SIZE?"];ToExpression[in@readLine[]]]

Clear[rpAcqSetDataUnit,rpAcqSetDataFormat]
rpAcqSetDataUnit[par_String:"VOLTS"]:=out@println["ACQ:DATA:UNITS "<>ToString[par]]/;(par=="VOLTS"||par=="RAW")
rpAcqSetDataFormat[par_String:"FLOAT"]:=out@println["ACQ:DATA:FORMAT "<>ToString[par]]/;(par=="FLOAT"||par=="ASCII")

Clear[rpAcqGetFullData,rpAcqGetFullDataNum]
rpAcqGetFullData[CH_Integer]:=Module[{data},out@println["ACQ:SOUR"<>ToString[CH]<>":DATA?"];in@readLine[]
]/;(CH==1||CH==2)
rpAcqGetFullDataNum[CH_Integer]:=Module[{data},
data=StringSplit[rpAcqGetFullData[CH],","];
data[[1]]=StringDelete[data[[1]],"{"];
data[[-1]]=StringDelete[data[[-1]],"}"];
data=ToExpression[data]]/;(CH==1||CH==2) (*same function that returns extracted numbers*)
End[];
EndPackage[];
$\endgroup$
1
$\begingroup$

I finally got something with this RedPitaya board using the redPitaya SCPI server and string commands through TCP/IP connection. It works ways faster than the serial port access. Below is a tutorial I built while experimenting with the board and SCPI commands and existing examples. I hope it could be useful for others. For me it answers my original question. :) PS : Thanks also to Pavel on the Redpitaya Forum who helped a lot.

Christian Néel


Communication via TCP/IP device

Launch the SCPI interface from Serial console :

Here we start communication with the board using a simple Serial console on USB COM port and PuTTY. (PuTTY utility allow simple serial communication as well as Raw TCP/IP or SSH within the same utility)

Console from COM port

Note: this could be done by editing the initialisation on Red Pitaya SD Card,or communicating with Serial link by Mathematica ...

After launching SCPI server:

initialization of TCP/IP with JLink

I got the source from from this link: "Mathematica TCP socket client toward Trading Platform" on Mathematica StackExchange

Needs["JLink`"];
InstallJava[];
(*ip addess and port where SCPI server is running*)
tcpaddress = "192.168.1.100";
tcpport = 5000;
(*create a Socket object*)
socket = JavaNew["java.net.Socket", tcpaddress, tcpport];
out = JavaNew["java.io.PrintWriter", socket@getOutputStream[], True];
in = JavaNew["java.io.BufferedReader", 
   JavaNew["java.io.InputStreamReader", socket@getInputStream[]]];

Using SCPI / API functions

example of simplest SCPI command communication. Everything is a string...

(*send the request*)
out@println["ACQ:DEC?"];
(*read the response*)in@readLine[]

After use, the socket is closed

socket@close[];

Note: this was done using MMA10.1, after 10.1 the TCPsocket funtion are native function in MMA.

Using package redpitaya.m

For convenience I wrote a package that contents a set of function that matches (approximately) the API name in the SCPI definition document. The function list includes as well the TCP initialisations For reference, see the SCPI command release link at :http:// http://redpitaya.com/examples-new//. Since I found that the above link may evolve the reference of SCPI function on: https://github.com/RedPitaya/RedPitaya// and more precisely on: https://github.com/RedPitaya/RedPitaya/blob/master/scpi-server/doc/SCPIAPI_commands.odt?raw=true

Now we load the specific package that wraps the SCPI functions with Mathematica (in this example it is located in this notebook directory)

SetDirectory[NotebookDirectory[]];
 <<redpitaya.m

Then, test package has been loaded by typing a command help (type ?rp*)

?rp*

and get a list of all available functions of the package). Clicking a fonction name displays the help at the bottom of the list

enter image description here

Or type directly the requested function help:

enter image description here

Initialize communication

rpSCPIinit[]

Test communication

rpAcqGetGain[1]

LV


Builds from Matlab examples on site

This set of examples follows (roughly) the specifications of Matlab example that are provided on the Red Pitaya Site Reference examples here : http://redpitaya.com/examples-new/

Digital

Blink

Test function which lights LED1 for 5 seconds then turn it off.

rpDpinSetLedState[1, 1];
Pause[5];
rpDpinSetLedState[1, 0];

The function is just a text wrapper for calling SCPI server as shown in the package help:

enter image description here

Bar graph with LEDs

Matlab example here : http://redpitaya.com/examples-new/bar-graph-with-leds/

Test function which displays the LED based on a discretized value p from 0 to 7:

Clear[barLED];
barLED[p_] := (rpDpinSetLedState @@ #) & /@Table[{i, Boole[Floor[Clip[p, {0, 7}]] == i]}, {i, 0, 7}];

Tests

barLED[5];
Pause[1];
barLED[-33];
Pause[1];
barLED[22];
Pause[1];
barLED[0];

Push button and turn on LED diode

Matlab example here : http://redpitaya.com/examples-new/push-button-and-turn-on-led-diode/

Code below is for test purpose only, a better implementation could be done using Mathematica scheduling capabilities;

rpDpinSetDioDirection[5, "INP", "N"]
s = 0; While[ s == 0,
 s = 1 - rpDpinGetDioState[5, "N"];
 rpDpinSetLedState[7, s]]

Test button

Interactive LED bar graph

Matlab example here : http://redpitaya.com/examples-new/interactive-led-bar-graph/

Bar graph with Slider control

Slider[Dynamic[LED], {0, 7, 1}]
Dynamic[(rpDpinSetLedState @@ #) & /@Transpose[{Range[0, 7],Boole[# <= LED] & /@ Range[0, 7]}];]
(* using (#\[GreaterEqual]LED)& or(#<=LED)functions gives a thermometer or ribbon display*)

enter image description here

Sorry no video here but the first tests of moving slider on the screen and seing the LED position moving on the board is quite rewarding :)

Analog

Read analog voltage on slow analog input

Matlab example here http://redpitaya.com/examples-new/read-analog-voltage-on-slow-analog-input/

Read 10 turns Potentiometer and put it on the LED bar display...for a while. Test with potard

Again this code is just for checking, a better implementation still to be done with Mathematica scheduling capabilities.

Do[barLED[7/3.3*rpApinGetAinValue[3]], {100}]

Set analog voltage on slow analog output

Matlab example here: http://redpitaya.com/examples-new/set-analog-voltage-on-slow-analog-output-4/

here we apply a variable voltage setpoint to AOUT2 and we measure the voltage with the corresponding ADC. Some additionnal info about the functions:

enter image description here

enter image description here

data = {};
Do[rpApinSetAoutValue[2, voltage];
 AppendTo[data, {voltage, rpApinGetAoutValue[2]}], {voltage, 0, 3.3, 
  0.01}]
ListPlot[data]

enter image description here

Then draw the transfert function error for evaluation of the DAC/ADC chain:

ListPlot[Transpose[{data[[;; , 1]], 
   data[[;; , 2]] - Clip[data[[;; , 1]], {0, 1.8}]}], Joined -> True]

Residual between DAC an ADC

Interactive voltage setting on slow analog output

Matlab example here : http://redpitaya.com/examples-new/interactive-voltage-setting-on-slow-analog-output-2/

Get slider input and put it on the slow DAC output and read it back with ADC on demand.

    data = {}; Manipulate[rpApinSetAoutValue[2, value]; 
 Grid[{{Button["Read & display", data = rpApinGetAoutValue[2]], 
    data}}, Frame -> All], {value, 0, 1.8, .01}]

Slider for writing DAC and display ADC

Generating signals at RF outputs (125 MS/s)

Generate continuous signal

Matlab example here : http://redpitaya.com/examples-new/generate-continuous-signal-on-fast-analog-outputs/

Use API-Like basic functions for driving generator (see definition in the redpitaya.m package).

rpGenWaveform[1, "SINE"]
rpGenFreq[1, 20000]
rpGenAmp[1, 0.9]
rpGenOutEnable[1]

enter image description here

Using the redpitaya WebScope application for visualizing the signals in the same time is also Ok. Image below show the result after the waveform has been changed with the following instructions:

rpGenOutDisable[1]
rpGenWaveform[1, "SQUARE"]
rpGenOutEnable[1]

enter image description here

Beware! when you close the Web browser windows, the communication with the Red Pitaya is closed and you need to restart the SCPI server (well...at least it worked for me).

Simultaneous generation on both channels:

rpGenOutDisable[#] & /@ {1, 2};
rpGenWaveform[#, "SINE"] & /@ {1, 2};
rpGenFreq[1, 20000, 0]
rpGenFreq[2, 40000, 75]
rpGenAmp[#, 0.5, 0.5] & /@ {1, 2};
rpGenOutEnable[#] & /@ {1, 2};

2 channels

Using PWM output

rpGenPWM[1, 10];
rpGenPWM[2, 10];
rpGenFreq[1, 20000, 0]
rpGenFreq[2, 20000, 180]

enter image description here

Generate signal pulses

Matlab example here : http://redpitaya.com/examples-new/generate-signal-pulses/

Configure using API-Like basic functions for driving generator (see definition in the redpitaya.m package).

rpGenReset[];
rpGenOutDisable[1];
rpGenWaveform[1, "SINE"];
rpGenFreq[1, 5000];
rpGenBurstConfig[1, 5, 3, 
  0.002];(*note that the period is expressed in seconds, it is \
expressed in \[Micro]s in the SCPI*)
rpGenBurstEnable[];
rpGenBurstTrigSource[1, "INT"];
rpGenBurstTrigger[1];(*prepare trigger but wait for outpt enable*)

Launch burst in a controlled manner

rpGenOutEnable[1];

enter image description here

Clean-up for return to normal operation

rpGenBurstConfig[1, "INF", "INF", 1]
rpGenBurstDisable[1];

Test for return to normal operation

rpGenWaveform[1, "TRIANGLE"]
rpGenFreq[1, 2000]
rpGenAmp[1, 0.9]
rpGenOutEnable[1]

Note: It is a bit awkward to organize the sequencing of all functions to get a good control of the burst, The matlab example shows a good sequencing of calls but some subtilities are hidden in the Red Pitaya SCPI. Probably need to build a more sophisticated function for easier use.

EDIT The most recent update of the redpitaya SCPI server (march 2016 in my understanding) seems to show a more straightforward burst mode (but I had no time to play with).

Generate signal on external trigger

Matlab example here :http://redpitaya.com/examples-new/generate-signal-on-fast-analog-outputs-with-external-triggering/

Configure using API-Like basic functions for driving generator (see definition in the redpitaya.m package).

rpGenReset[];
rpGenWaveform[1, "SINE"]
rpGenFreq[1, 20000]
rpGenAmp[1, 1]
rpGenBurstConfig[1, 4, 1, 
  0.001];(*note that the period is expressed in seconds, it is \
expressed in \[Micro]s in the SCPI*)
rpGenBurstEnable[];
rpGenBurstTrigSource[1, "GATED"]
rpGenOutEnable[1]
(*prepare trigger and wait for external input *)

enter image description here

Clean-up for return to normal operation

rpGenBurstConfig[1, "INF", "INF", 1]
rpGenBurstDisable[1];

Custom waveform signal generation

Matlab example here :http://redpitaya.com/examples-new/custom-signal-generating/

Generate two arbitrary waveforms:

{x, y} = Transpose[Table[{Sin[t] + Sin[3 t]/3, 1/2 Sin[t] + Sin[4 t]/4}, {t, 0, 2 Pi,2 Pi/16383}]] // N;
ListPlot[Transpose[{x, y}], PlotLabel -> "XY graph"]
ListPlot[{x, y}, PlotLabel -> "Waveforms"]

enter image description here enter image description here

Configure using API-Like basic functions for driving generator (see definition in the redpitaya.m package).

rpGenReset[];
rpGenArbitrary[1, x]
rpGenArbitrary[2, y]
rpGenFreq[#, 10000] & /@ Range[2];
rpGenAmp[#, 1] & /@ Range[2];
rpGenOutEnable /@ Range[2];

enter image description here

Acquiring signals at RF inputs (125 MS/s)

On trigger signal acquisition

Matlab example here :http://redpitaya.com/examples-new/single-buffer-acquire/ Configure using API-Like basic functions for driving generator (see definition in the redpitaya.m package).

setup Generators CH1 & CH2 (CH2 connected to Acq CH1 on my RP configuration and vice versa)

rpGenReset[]
rpGenWaveform[1, "TRIANGLE"]
rpGenWaveform[2, "SINE"]
rpGenFreq[1, 10000, 90]
rpGenFreq[2, 10000]
rpGenAmp[#, 1, 0] & /@ Range[2];
rpGenOutEnable[#] & /@ Range[2];

setup Acquisition CH1 & CH2

rpAcqReset[]
n = 64;(*decimation factor see RP documentation  here we sample at \
about 103kHz*)
rpAcqSetDecimation[64](*125/n MS/s and n=1,8,64,1024,8192,65535*)
timebase = Table[N[i n/((125 10^6))], {i, 0, 16383}];
(*timebase ticks for display later*)
rpAcqSetAveraging["OFF"]
rpAcqSetTriggerThreshold[500](*trigger level 500mV*)
rpAcqSetTriggerDelay[8192];(*triggers at the beginning of the buffer*)
rpAcqSetGain[1, "HV"];
rpAcqSetGain[2, "HV"];
rpAcqSetDataUnit["VOLTS"];
rpAcqSetDataFormat["FLOAT"];

enter image description here

Run Acquisition CH1 & CH2

rpAcqStart[]
rpAcqSetTriggerSource["CH1_PE"]
(*Trigger source setting must be after ACQ:START*)
While[rpAcqGetTriggerState[] != "TD"](*wait for trigger*)
rpAcqGetWritePointerAtTrig[](*print current trigger pointer*)
data1 = Transpose@{timebase,rpAcqGetFullDataNum[1]};(*get full buffer CH1*)
data2 = Transpose@{timebase,rpAcqGetFullDataNum[2]};(*get full buffer CH2*)
ListPlot[{data1, data2}, Joined -> True, PlotRange -> {{0, 500 10^-6}, All},ImageSize -> "Large", PlotTheme -> "Detailed"]
rpAcqStop[]

enter image description here Oops! seems that picture was taken when the CH1 was disconnected (Hardware issue..).Anyway, it is possible to play with the data:

ListPlot[{Log@Abs@Fourier[(Transpose@data1)[[2]]], Log@Abs@Fourier[(Transpose@data2)[[2]]]}, PlotRange -> {{0, All}, All}, Joined -> True, ImageSize -> "Large", PlotTheme -> "Detailed"]

enter image description here

Signal acquisition on external trigger

Matlab example here :http://redpitaya.com/examples-new/on-given-external-trigger-acquire-signal-on-fast-analog-input/

Configure using API-Like basic functions for driving generator (see definition in the redpitaya.m package).

setup Generators CH1 & CH2 (CH2 connected to Acq CH1 on my RP configuration and vice versa)

rpGenReset[]
rpGenWaveform[1, "TRIANGLE"]
rpGenWaveform[2, "SINE"]
rpGenFreq[1, 10000, 90]
rpGenFreq[2, 10000]
rpGenAmp[#, 1, 0] & /@ Range[2];
rpGenOutEnable[#] & /@ Range[2];

setup Acquisition CH1 & CH2

rpAcqReset[]
n = 64;(*decimation factor see RP documentation  here we sample at about 103kHz*)
rpAcqSetDecimation[64](* x 125/n MS/s and n=1,8,64,1024,8192,65535*)
timebase = Table[N[i n/((125 10^6))], {i, 0, 16383}];
(*timebase ticks for display later*)
rpAcqSetAveraging["OFF"]
rpAcqSetTriggerThreshold[500](*trigger level 500mV*)
rpAcqSetTriggerDelay[8192];(*triggers at the beginning of the buffer*)
rpAcqSetGain[1, "HV"];
rpAcqSetGain[2, "HV"];
rpAcqSetDataUnit["VOLTS"];
rpAcqSetDataFormat["FLOAT"];

Run Acquisition CH1 & CH2

rpAcqStart[]
rpAcqSetTriggerSource["EXT_PE"](*Trigger source setting must be after \
ACQ:START*)
While[rpAcqGetTriggerState[] != "TD"](*wait for trigger*)
rpAcqGetWritePointerAtTrig[](*print current trigger pointer*)
data1 = Transpose@{timebase, rpAcqGetFullDataNum[1]};(*get full buffer CH1*)
data2 = Transpose@{timebase, rpAcqGetFullDataNum[2]};(*get full buffer CH2*)
ListPlot[{data1, data2}, Joined -> True, PlotRange -> {{0, 500 10^-6}, All},ImageSize -> "Large", PlotTheme -> "Detailed"]
rpAcqStop[]

enter image description here

Synchronised one pulse signal generation and acquisition

Matlab example here :http://redpitaya.com/examples-new/synchronized-one-pulse-generating-and-acquiring/

Configure using API-Like basic functions for driving generator (see definition in the redpitaya.m package).

rpGenReset[]
rpAcqReset[]
(*waveform settings*)
rpGenWaveform[1, "SINE"];
rpGenFreq[1, 10000]
rpGenAmp[1, 0.5];
(* burst generation settings*)
rpGenBurstEnable[];
rpGenBurstConfig[1, 5, 2, 0.004]
rpGenOutEnable[1];
(*acuqisition settings*)
rpAcqSetDecimation[64];
rpAcqGetSamplingRateHz[]
rpAcqSetGain[1, "HV"];
rpAcqSetTriggerThreshold[0.25];
rpAcqSetTriggerDelay[8192];
rpAcqSetTriggerSource["AWG_PE"];
(*acquisition phase*)
rpAcqStart[];(*acquisition launch*)
rpGenBurstTrigger[]
(*wait for trigger & display*)
While[rpAcqGetTriggerState[] != "TD"];
data1 = rpAcqGetFullDataNum[1];
ListPlot[data1, Joined -> True, ImageSize -> "Large", PlotRange -> All, PlotTheme -> "Detailed"]
rpAcqReset[]

enter image description here

End

rpSCPIclose[]

The full package:

I have no room left (limited number of characters) to put the package code here. I'll try to put it in a second answer.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.