├── LICENSE ├── README.rst ├── docs ├── conf.py └── requirements.txt ├── examples ├── acquisition │ ├── acq_ext_trig.ipynb │ ├── acq_instant.ipynb │ └── acq_trigger_level.ipynb ├── acquisition_generation │ └── acq_gen_synced_pulse.ipynb ├── analog │ ├── analog_input.ipynb │ ├── analog_output.ipynb │ └── img │ │ └── analogLoopBack.png ├── click_shield_examples │ └── click_board_examples │ │ ├── basic │ │ ├── buttonG.ipynb │ │ ├── cap_touch.ipynb │ │ └── relay.ipynb │ │ ├── click_board_examples.ipynb │ │ ├── motor │ │ ├── dc_motor2.ipynb │ │ └── vibro_motor.ipynb │ │ └── sensor │ │ ├── current.ipynb │ │ ├── light.ipynb │ │ ├── motion.ipynb │ │ └── thermo16.ipynb ├── digital │ ├── gpio.ipynb │ └── led.ipynb ├── dma │ └── dma.ipynb ├── generation │ ├── gen_arbitrary_signal.ipynb │ ├── gen_burst_async_signals.ipynb │ ├── gen_bursts.ipynb │ ├── gen_continuous_signal.ipynb │ ├── gen_ext_trigger.ipynb │ └── gen_sync_two_channel.ipynb ├── hardware │ ├── calibration.ipynb │ └── hwid.ipynb ├── img │ ├── FastIOLoopBack.png │ ├── LED-blink.gif │ ├── RedPitaya_pinout.jpg │ ├── generate_continous_signal_on_fast_analog_output.png │ └── on_given_trigger_acquire_signal_on_fast_analog_input.png ├── multiboard_sync │ ├── click_shield_1.ipynb │ └── daisy_chain_1.ipynb └── outdated │ ├── cable_length.ipynb │ ├── exam_temp.ipynb │ ├── home_automation.ipynb │ ├── img │ ├── cable_length.jpg │ ├── nest.jpeg │ ├── on_off_control.png │ ├── temp_reg_setup.jpg │ ├── temp_sensor.jpg │ └── temp_sensor_sch.png │ ├── la_trigger.ipynb │ └── lg_counter.ipynb ├── experiments ├── axi4lite_gpio.ipynb ├── monitor_classic_fpga.ipynb ├── scope_filter.ipynb └── xadc.ipynb ├── redpitaya ├── __init__.py ├── app │ ├── __init__.py │ ├── generator.py │ └── oscilloscope.py ├── drv │ ├── __init__.py │ ├── acq.py │ ├── asg_bst.py │ ├── asg_per.py │ ├── clb.py │ ├── evn.py │ ├── fixp.py │ ├── gen.py │ ├── gen_out.py │ ├── hwid.py │ ├── la.py │ ├── la_msk.py │ ├── la_rle.py │ ├── la_trg.py │ ├── lg.py │ ├── lg_out.py │ ├── mgmt.py │ ├── osc.py │ ├── osc_fil.py │ ├── osc_trg.py │ ├── overlay.py │ ├── pdm.py │ ├── uio.py │ └── wave.py └── overlay │ ├── __init__.py │ └── mercury.py ├── setup.py └── welcome.ipynb /README.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | Red Pitaya JupyterLab 3 | ============================== 4 | 5 | Here you can find examples on how to control Red Pitaya through the on-board JupyerLab application. 6 | 7 | - OS versions including and up to 2.00-18 use a modified FPGA image reffered to as Mercury. 8 | - OS versions above 2.00-23 use a standard Red Pitaya FPGA image and the JupyterLab commands have been changed, so that they are now the same as C and Python API commands. The new Jupyter commands run corresponding C API functions in the background. 9 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | bokeh 4 | ipywidgets 5 | IPython 6 | pyudev 7 | python-periphery 8 | # support for http://wavedrom.com 9 | sphinxcontrib-wavedrom 10 | -------------------------------------------------------------------------------- /examples/acquisition/acq_ext_trig.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Triggering on external trigger\n", 8 | "In the third example, we will learn how to configure the acquisition to capture data on an external trigger\n", 9 | "\n", 10 | "**Note:** \n", 11 | "The voltage range of fast analog inputs on the Red Pitaya depends on the input jumper position. HV sets the input range to ±20 V, while LV sets the input range to ±1 V. For more information, please read the following [chapter](https://redpitaya.readthedocs.io/en/latest/developerGuide/hardware/125-14/fastIO.html#analog-inputs).\n", 12 | "\n", 13 | "Create a loop-back from fast analog outputs to fast analog inputs, as shown in the picture below. \n", 14 | "Please make sure the jumpers are set to ±1 V (LV).\n", 15 | "\n", 16 | "![Fast loop back](../img/FastIOLoopBack.png \"Example of the fast loop back.\")" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Libraries and FPGA image\n", 24 | "\n", 25 | "We need the additional functionality of *numpy* and *matplotlib* for data plotting and faster array operations." 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "import numpy as np\n", 35 | "from matplotlib import pyplot as plt\n", 36 | "from rp_overlay import overlay\n", 37 | "import rp\n", 38 | "\n", 39 | "fpga = overlay()\n", 40 | "rp.rp_Init()" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "## Macros\n", 48 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 49 | "\n", 50 | "- **Decimation** - RP_DEC_1, RP_DEC_2, RP_DEC_4, RP_DEC_8, RP_DEC_16, RP_DEC_32, RP_DEC_64, RP_DEC_128, RP_DEC_256, RP_DEC_512, RP_DEC_1024, RP_DEC_2048, RP_DEC_4096, RP_DEC_8192, RP_DEC_16384, RP_DEC_32768, RP_DEC_65536 \n", 51 | "- **Acquisition trigger** - RP_TRIG_SRC_DISABLED, RP_TRIG_SRC_NOW, RP_TRIG_SRC_CHA_PE, RP_TRIG_SRC_CHA_NE, RP_TRIG_SRC_CHB_PE, RP_TRIG_SRC_CHB_NE, RP_TRIG_SRC_EXT_PE, RP_TRIG_SRC_EXT_NE, RP_TRIG_SRC_AWG_PE, RP_TRIG_SRC_AWG_NE\n", 52 | "- **Acquisition trigger state** - RP_TRIG_STATE_TRIGGERED, RP_TRIG_STATE_WAITING\n", 53 | "- **Buffer size** - ADC_BUFFER_SIZE, DAC_BUFFER_SIZE\n", 54 | "- **Fast analog channels** - RP_CH_1, RP_CH_2\n", 55 | "\n", 56 | "SIGNALlab 250-12 only:\n", 57 | "- **Input coupling** - RP_DC, RP_AC\n", 58 | "\n", 59 | "STEMlab 125-14 4-Input only:\n", 60 | "- **Fast analog channels** - RP_CH_3, RP_CH_4\n", 61 | "- **Acquisition trigger** - RP_TRIG_SRC_CHC_PE, RP_TRIG_SRC_CHC_NE, RP_TRIG_SRC_CHD_PE, RP_TRIG_SRC_CHD_NE\n" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "## External trigger\n", 69 | "The external trigger is located on the DIO0_P pin on the extension connector E1. It is recommended that the applied source meets the 3V3 CMOS signal conditions. For this simple experiment, we can use a simple jumper wire to touch the pin or connect it to the pin, which acts as an antenna and picks up environmental signals to trigger the acquisition.\n", 70 | "\n", 71 | "Now that we are already familiar with the process, let's jump right in.\n", 72 | "\n", 73 | "Parameters:" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "# Generator parameters\n", 83 | "channel = rp.RP_CH_1\n", 84 | "channel2 = rp.RP_CH_2\n", 85 | "waveform = rp.RP_WAVEFORM_SINE\n", 86 | "freq = 100000\n", 87 | "ampl = 1.0\n", 88 | "\n", 89 | "# Acquisition paramters\n", 90 | "dec = rp.RP_DEC_1\n", 91 | "\n", 92 | "trig_lvl = 0.5\n", 93 | "trig_dly = 0\n", 94 | "\n", 95 | "acq_trig_sour = rp.RP_TRIG_SRC_EXT_PE\n", 96 | "N = 16384\n", 97 | "\n", 98 | "rp.rp_GenReset()\n", 99 | "rp.rp_AcqReset()" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "Generator code (if needed):" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "print(\"Gen_start\")\n", 116 | "rp.rp_GenWaveform(channel, waveform)\n", 117 | "rp.rp_GenFreqDirect(channel, freq)\n", 118 | "rp.rp_GenAmp(channel, ampl)\n", 119 | "\n", 120 | "rp.rp_GenWaveform(channel2, waveform)\n", 121 | "rp.rp_GenFreqDirect(channel2, freq)\n", 122 | "rp.rp_GenAmp(channel2, ampl)\n", 123 | "\n", 124 | "rp.rp_GenTriggerSource(channel, rp.RP_GEN_TRIG_SRC_INTERNAL)\n", 125 | "\n", 126 | "rp.rp_GenOutEnableSync(True)\n", 127 | "rp.rp_GenSynchronise()" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "Acquisition code:" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "# Set Decimation\n", 144 | "rp.rp_AcqSetDecimation(dec)\n", 145 | "\n", 146 | "# Set trigger level and delay\n", 147 | "rp.rp_AcqSetTriggerLevel(rp.RP_T_CH_1, trig_lvl)\n", 148 | "rp.rp_AcqSetTriggerDelay(trig_dly)\n", 149 | "\n", 150 | "# Start Acquisition\n", 151 | "print(\"Acq_start\")\n", 152 | "rp.rp_AcqStart()\n", 153 | "\n", 154 | "# Specify trigger - immediately\n", 155 | "rp.rp_AcqSetTriggerSrc(acq_trig_sour)\n", 156 | "\n", 157 | "# Trigger state\n", 158 | "while 1:\n", 159 | " trig_state = rp.rp_AcqGetTriggerState()[1]\n", 160 | " if trig_state == rp.RP_TRIG_STATE_TRIGGERED:\n", 161 | " break\n", 162 | "\n", 163 | "# Fill state\n", 164 | "while 1:\n", 165 | " if rp.rp_AcqGetBufferFillState()[1]:\n", 166 | " break\n", 167 | "\n", 168 | "\n", 169 | "### Get data ###\n", 170 | "# RAW\n", 171 | "ibuff = rp.i16Buffer(N)\n", 172 | "res = rp.rp_AcqGetOldestDataRaw(rp.RP_CH_1, N, ibuff.cast())[1]\n", 173 | "\n", 174 | "# Volts\n", 175 | "fbuff = rp.fBuffer(N)\n", 176 | "res = rp.rp_AcqGetOldestDataV(rp.RP_CH_1, N, fbuff)[1]\n", 177 | "\n", 178 | "data_V = np.zeros(N, dtype = float)\n", 179 | "data_raw = np.zeros(N, dtype = int)\n", 180 | "X = np.arange(0, N, 1)\n", 181 | "\n", 182 | "for i in range(0, N, 1):\n", 183 | " data_V[i] = fbuff[i]\n", 184 | " data_raw[i] = ibuff[i]\n", 185 | "\n", 186 | "figure, axis = plt.subplots(1, 2) \n", 187 | "\n", 188 | "axis[0].plot(X, data_V) \n", 189 | "axis[0].set_title(\"Volts\")\n", 190 | "\n", 191 | "axis[1].plot(X, data_raw) \n", 192 | "axis[1].set_title(\"RAW\") \n", 193 | "\n", 194 | "plt.show()" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [ 203 | "# Release resources\n", 204 | "rp.rp_Release()" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "### Note\n", 212 | "There are a lot of different commands for the Acquisition. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n" 213 | ] 214 | } 215 | ], 216 | "metadata": { 217 | "language_info": { 218 | "name": "python" 219 | } 220 | }, 221 | "nbformat": 4, 222 | "nbformat_minor": 2 223 | } 224 | -------------------------------------------------------------------------------- /examples/acquisition/acq_instant.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Instant signal acquisition\n", 8 | "\n", 9 | "In the second example, we will learn how to force an acquisition to trigger in the specified moment.\n", 10 | "\n", 11 | "**Note:** \n", 12 | "The voltage range of fast analog inputs on the Red Pitaya depends on the input jumper position. HV sets the input range to ±20 V, while LV sets the input range to ±1 V. For more information, please read the following [chapter](https://redpitaya.readthedocs.io/en/latest/developerGuide/hardware/125-14/fastIO.html#analog-inputs).\n", 13 | "\n", 14 | "Create a loop-back from fast analog outputs to fast analog inputs, as shown in the picture below. \n", 15 | "Please make sure the jumpers are set to ±1 V (LV).\n", 16 | "\n", 17 | "![Fast loop back](../img/FastIOLoopBack.png \"Example of the fast loop back.\")" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## Libraries and FPGA image\n", 25 | "\n", 26 | "We need the additional functionality of *numpy* and *matplotlib* for data plotting and faster array operations." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": { 33 | "scrolled": false 34 | }, 35 | "outputs": [], 36 | "source": [ 37 | "import time\n", 38 | "import numpy as np\n", 39 | "from matplotlib import pyplot as plt\n", 40 | "from rp_overlay import overlay\n", 41 | "import rp\n", 42 | "\n", 43 | "fpga = overlay()\n", 44 | "rp.rp_Init()" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "## Macros\n", 52 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 53 | "\n", 54 | "- **Decimation** - RP_DEC_1, RP_DEC_2, RP_DEC_4, RP_DEC_8, RP_DEC_16, RP_DEC_32, RP_DEC_64, RP_DEC_128, RP_DEC_256, RP_DEC_512, RP_DEC_1024, RP_DEC_2048, RP_DEC_4096, RP_DEC_8192, RP_DEC_16384, RP_DEC_32768, RP_DEC_65536 \n", 55 | "- **Acquisition trigger** - RP_TRIG_SRC_DISABLED, RP_TRIG_SRC_NOW, RP_TRIG_SRC_CHA_PE, RP_TRIG_SRC_CHA_NE, RP_TRIG_SRC_CHB_PE, RP_TRIG_SRC_CHB_NE, RP_TRIG_SRC_EXT_PE, RP_TRIG_SRC_EXT_NE, RP_TRIG_SRC_AWG_PE, RP_TRIG_SRC_AWG_NE\n", 56 | "- **Acquisition trigger state** - RP_TRIG_STATE_TRIGGERED, RP_TRIG_STATE_WAITING\n", 57 | "- **Buffer size** - ADC_BUFFER_SIZE, DAC_BUFFER_SIZE\n", 58 | "- **Fast analog channels** - RP_CH_1, RP_CH_2\n", 59 | "\n", 60 | "SIGNALlab 250-12 only:\n", 61 | "- **Input coupling** - RP_DC, RP_AC\n", 62 | "\n", 63 | "STEMlab 125-14 4-Input only:\n", 64 | "- **Fast analog channels** - RP_CH_3, RP_CH_4\n", 65 | "- **Acquisition trigger** - RP_TRIG_SRC_CHC_PE, RP_TRIG_SRC_CHC_NE, RP_TRIG_SRC_CHD_PE, RP_TRIG_SRC_CHD_NE\n" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "## Instant acquisition\n", 73 | "The only change from the previous example is that we will specify the acquisition trigger as **RP_TRIG_SRC_NOW**, which immediately forces a trigger condition.\n", 74 | "\n", 75 | "Here are the Generation and Acquisition parameters:" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "metadata": { 82 | "collapsed": true 83 | }, 84 | "outputs": [], 85 | "source": [ 86 | "# Generator parameters\n", 87 | "channel = rp.RP_CH_1\n", 88 | "channel2 = rp.RP_CH_2\n", 89 | "waveform = rp.RP_WAVEFORM_SINE\n", 90 | "freq = 100000\n", 91 | "ampl = 1.0\n", 92 | "\n", 93 | "# Acquisition paramters\n", 94 | "dec = rp.RP_DEC_1\n", 95 | "\n", 96 | "trig_lvl = 0.5\n", 97 | "trig_dly = 0\n", 98 | "\n", 99 | "acq_trig_sour = rp.RP_TRIG_SRC_NOW\n", 100 | "N = 16384\n", 101 | "\n", 102 | "rp.rp_GenReset()\n", 103 | "rp.rp_AcqReset()" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "Generator code (if needed):" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "print(\"Gen_start\")\n", 120 | "rp.rp_GenWaveform(channel, waveform)\n", 121 | "rp.rp_GenFreqDirect(channel, freq)\n", 122 | "rp.rp_GenAmp(channel, ampl)\n", 123 | "\n", 124 | "rp.rp_GenWaveform(channel2, waveform)\n", 125 | "rp.rp_GenFreqDirect(channel2, freq)\n", 126 | "rp.rp_GenAmp(channel2, ampl)\n", 127 | "\n", 128 | "rp.rp_GenTriggerSource(channel, rp.RP_GEN_TRIG_SRC_INTERNAL)\n", 129 | "\n", 130 | "rp.rp_GenOutEnableSync(True)\n", 131 | "rp.rp_GenSynchronise()" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "Here is the acquisition code. It is recommended to leave some time between the **rp_AcqStart** and **rp_AcqSetTriggerSrc** so Red Pitaya has enough time to capture the data. Otherwise, we can find inconsistencies in the captured data (especially at higher decimations)." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [ 147 | "# Set Decimation\n", 148 | "rp.rp_AcqSetDecimation(dec)\n", 149 | "\n", 150 | "# Set trigger level and delay\n", 151 | "rp.rp_AcqSetTriggerLevel(rp.RP_T_CH_1, trig_lvl)\n", 152 | "rp.rp_AcqSetTriggerDelay(trig_dly)\n", 153 | "\n", 154 | "# Start Acquisition\n", 155 | "print(\"Acq_start\")\n", 156 | "rp.rp_AcqStart()\n", 157 | "\n", 158 | "time.sleep(0.1)\n", 159 | "\n", 160 | "# Specify trigger - immediately\n", 161 | "rp.rp_AcqSetTriggerSrc(acq_trig_sour)\n", 162 | "\n", 163 | "# Trigger state\n", 164 | "while 1:\n", 165 | " trig_state = rp.rp_AcqGetTriggerState()[1]\n", 166 | " if trig_state == rp.RP_TRIG_STATE_TRIGGERED:\n", 167 | " break\n", 168 | "\n", 169 | "# Fill state\n", 170 | "while 1:\n", 171 | " if rp.rp_AcqGetBufferFillState()[1]:\n", 172 | " break\n", 173 | "\n", 174 | "\n", 175 | "### Get data ###\n", 176 | "# RAW\n", 177 | "ibuff = rp.i16Buffer(N)\n", 178 | "res = rp.rp_AcqGetOldestDataRaw(rp.RP_CH_1, N, ibuff.cast())[1]\n", 179 | "\n", 180 | "# Volts\n", 181 | "fbuff = rp.fBuffer(N)\n", 182 | "res = rp.rp_AcqGetOldestDataV(rp.RP_CH_1, N, fbuff)[1]\n", 183 | "\n", 184 | "data_V = np.zeros(N, dtype = float)\n", 185 | "data_raw = np.zeros(N, dtype = int)\n", 186 | "X = np.arange(0, N, 1)\n", 187 | "\n", 188 | "for i in range(0, N, 1):\n", 189 | " data_V[i] = fbuff[i]\n", 190 | " data_raw[i] = ibuff[i]\n", 191 | "\n", 192 | "figure, axis = plt.subplots(1, 2) \n", 193 | "\n", 194 | "axis[0].plot(X, data_V) \n", 195 | "axis[0].set_title(\"Volts\")\n", 196 | "\n", 197 | "axis[1].plot(X, data_raw) \n", 198 | "axis[1].set_title(\"RAW\") \n", 199 | "\n", 200 | "plt.show()" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": null, 206 | "metadata": {}, 207 | "outputs": [], 208 | "source": [ 209 | "# Release resources\n", 210 | "rp.rp_Release()" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "### Note\n", 218 | "There are a lot of different commands for the Acquisition. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n" 219 | ] 220 | } 221 | ], 222 | "metadata": { 223 | "kernelspec": { 224 | "display_name": "Python 3", 225 | "language": "python", 226 | "name": "python3" 227 | }, 228 | "language_info": { 229 | "codemirror_mode": { 230 | "name": "ipython", 231 | "version": 3 232 | }, 233 | "file_extension": ".py", 234 | "mimetype": "text/x-python", 235 | "name": "python", 236 | "nbconvert_exporter": "python", 237 | "pygments_lexer": "ipython3", 238 | "version": "3.5.2" 239 | } 240 | }, 241 | "nbformat": 4, 242 | "nbformat_minor": 2 243 | } 244 | -------------------------------------------------------------------------------- /examples/analog/analog_output.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Slow Analog Outputs \n", 8 | "\n", 9 | "Slow analog outputs provide a convenient way to generate output voltage from 0 to 1.8 V.\n", 10 | "\n", 11 | "There are four analog outputs on the E2 connector depicted in the picture below.\n", 12 | "\n", 13 | "![alt text](../img/RedPitaya_pinout.jpg \"Red Pitaya pinout.\")" 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "metadata": {}, 19 | "source": [ 20 | "## Libraries and FPGA image\n", 21 | "\n", 22 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": { 29 | "collapsed": true 30 | }, 31 | "outputs": [], 32 | "source": [ 33 | "from rp_overlay import overlay\n", 34 | "import rp\n", 35 | "\n", 36 | "fpga = overlay()\n", 37 | "rp.rp_Init()" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "## Macros\n", 45 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of analog macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 46 | "\n", 47 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 48 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "## Controling Analog Outputs\n", 56 | "The analog outputs can be contolled in two different ways; either specify the value in Volts or the RAW DAC value directly. Analog output numbers range from 0 to 3.\n", 57 | "\n", 58 | "### Setting value in Volts\n", 59 | "- **rp_AOpinSetValue(analog_output_number, value)**\n", 60 | "- **rp_ApinSetValue(analog_output_macro, value)**\n", 61 | "\n", 62 | "### Setting RAW value\n", 63 | "- **rp_AOpinSetValueRaw(analog_output_number, raw_value)**\n", 64 | "- **rp_ApinSetValueRaw(analog_input_macro, raw_value)**\n", 65 | "\n", 66 | "### Getting current output value in Volts\n", 67 | "- **rp_AOpinGetValue(analog_output_number)**\n", 68 | "- **rp_ApinGetValue(analog_output_macro)**\n", 69 | "\n", 70 | "### Getting current output RAW value\n", 71 | "- **rp_AOpinGetValueRaw(analog_output_number)**\n", 72 | "- **rp_ApinGetValueRaw(analog_input_macro)**\n", 73 | "\n", 74 | "### Reading analog output range\n", 75 | "To get the analog output range use the following function:\n", 76 | "- **rp_AOpinGetRange(analog_out_number)**\n", 77 | "- **rp_ApinGetRange(analog_pin_macro)**\n", 78 | "\n", 79 | "### Reseting analog pins\n", 80 | "To reset all analog pins to their default state (output 0 V) use:\n", 81 | "- **rp_AOpinReset()**\n", 82 | "- **rp_ApinReset()**" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "First we will reset all analog pins." 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "rp.rp_ApinReset()" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "Next, lets set *Analog output 0* and *AOUT1* to 1 V and 1.5 V respectively." 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "rp.rp_ApinSetValue(rp.RP_AOUT0, 1)\n", 115 | "rp.rp_AOpinSetValue(1, 1.5)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "Releasing resources:" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "rp.rp_Release()" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "## Analog Signal Generator\n", 139 | "This example is the analog signal generator for the [analog input](analog_input.ipynb) live data plotting.\n", 140 | "\n", 141 | "The measurements on the slow analog inputs are taken every 10 milliseconds. Hence, we need to generate new data samples at the same rate. We will use the *time* module to delay the data generation and import *numpy* to generate a sine wave.\n" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "import time\n", 151 | "import numpy as np\n", 152 | "import rp\n", 153 | "\n", 154 | "rp.rp_Init()" 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "metadata": {}, 160 | "source": [ 161 | "Here, we will configure the number of channels (4) and define the amplitudes. Note that the analog outputs only accept values from 0 to 1.8V, so we have to offset our signals to $\\frac{1.8V} { 2 } = 0.9V $.\n", 162 | "\n", 163 | "Then, we will start an infinite loop that will generate sinuses on the analog outputs. \n", 164 | "To stop execution:\n", 165 | "- Press the (∎) button above or \n", 166 | "- Click outside, to the left of the cell, but inside of the green rectangle, so it turns green, which will invoke Jupyter's command mode and press the *I* key twice." 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": null, 172 | "metadata": {}, 173 | "outputs": [], 174 | "source": [ 175 | "chn = 4\n", 176 | "amp = (0.25, 0.35, 0.4, 0.8)\n", 177 | "\n", 178 | "while True:\n", 179 | " for i in range(40):\n", 180 | " for ch in range(0, chn):\n", 181 | " rp.rp_AOpinSetValue(ch, 0.9 + amp[ch] * np.sin(i * np.pi / 20) )\n", 182 | " time.sleep(0.01)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "Releasing resources:" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "rp.rp_Release()" 199 | ] 200 | } 201 | ], 202 | "metadata": { 203 | "kernelspec": { 204 | "display_name": "Python 3", 205 | "language": "python", 206 | "name": "python3" 207 | }, 208 | "language_info": { 209 | "codemirror_mode": { 210 | "name": "ipython", 211 | "version": 3 212 | }, 213 | "file_extension": ".py", 214 | "mimetype": "text/x-python", 215 | "name": "python", 216 | "nbconvert_exporter": "python", 217 | "pygments_lexer": "ipython3", 218 | "version": "3.5.2" 219 | } 220 | }, 221 | "nbformat": 4, 222 | "nbformat_minor": 2 223 | } 224 | -------------------------------------------------------------------------------- /examples/analog/img/analogLoopBack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/analog/img/analogLoopBack.png -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/basic/buttonG.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# BUTTON G CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# Set the direction of mikrobus pins\n", 84 | "rp.rp_DpinSetDirection(PWM1, rp.RP_OUT)\n", 85 | "rp.rp_DpinSetDirection(PWM2, rp.RP_OUT)\n", 86 | "rp.rp_DpinSetDirection(INT1, rp.RP_IN)\n", 87 | "rp.rp_DpinSetDirection(INT2, rp.RP_IN)" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "If the G button is pressed on the click board, an LED on the Red Pitaya and the LED inside the G button are turned ON." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": {}, 101 | "outputs": [], 102 | "source": [ 103 | "while True:\n", 104 | " state = int(rp.rp_DpinGetState(INT1)[1])\n", 105 | " if state:\n", 106 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_HIGH)\n", 107 | " rp.rp_DpinSetState(PWM1, rp.RP_HIGH)\n", 108 | " else:\n", 109 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_LOW)\n", 110 | " rp.rp_DpinSetState(PWM1, rp.RP_LOW)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "# Release resources\n", 120 | "rp.rp_Release()" 121 | ] 122 | } 123 | ], 124 | "metadata": { 125 | "language_info": { 126 | "name": "python" 127 | }, 128 | "orig_nbformat": 4 129 | }, 130 | "nbformat": 4, 131 | "nbformat_minor": 2 132 | } 133 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/basic/cap_touch.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# CAPACITIVE TOUCH CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N\n", 75 | "\n", 76 | "# Set the direction of mikrobus pins\n", 77 | "rp.rp_DpinSetDirection(INT1, rp.RP_IN)\n", 78 | "rp.rp_DpinSetDirection(INT2, rp.RP_IN)" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "If the capacitor button is pressed on the click board, an LED is turned ON on the Red Pitaya." 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": null, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "while True:\n", 95 | " state = int(rp.rp_DpinGetState(INT1)[1])\n", 96 | " if state:\n", 97 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_HIGH)\n", 98 | " else:\n", 99 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_LOW)" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "# Release resources\n", 109 | "rp.rp_Release()" 110 | ] 111 | } 112 | ], 113 | "metadata": { 114 | "language_info": { 115 | "name": "python" 116 | }, 117 | "orig_nbformat": 4 118 | }, 119 | "nbformat": 4, 120 | "nbformat_minor": 2 121 | } 122 | 123 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/basic/relay.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# RELAY CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": { 18 | "collapsed": true 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "import time\n", 23 | "from rp_overlay import overlay\n", 24 | "import rp\n", 25 | "\n", 26 | "# Initialize the FPGA overlay\n", 27 | "fpga = overlay()\n", 28 | "rp.rp_Init()" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## Macros\n", 36 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 37 | "\n", 38 | "- **States** - RP_LOW, RP_HIGH\n", 39 | "- **Directions** - RP_IN, RP_OUT\n", 40 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 41 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 42 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 43 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 44 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 45 | "\n", 46 | "### Click shield macros\n", 47 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 48 | "\n", 49 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 50 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 51 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 52 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 53 | "- **UART_SW** - RP_DIO5_N\n", 54 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 55 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 56 | "\n", 57 | "Setting up click shield macros:" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "AN1 = rp.RP_AIN0\n", 67 | "AN2 = rp.RP_AIN1\n", 68 | "RST1 = rp.RP_DIO2_N\n", 69 | "RST2 = rp.RP_DIO4_N\n", 70 | "PWM1 = rp.RP_DIO1_P\n", 71 | "PWM2 = rp.RP_DIO3_P\n", 72 | "INT1 = rp.RP_DIO2_P\n", 73 | "INT2 = rp.RP_DIO4_P\n", 74 | "UART_SW = rp.RP_DIO5_N\n", 75 | "SPI_CS1 = rp.RP_DIO1_N\n", 76 | "SPI_CS2 = rp.RP_DIO3_N\n", 77 | "\n", 78 | "# Set the direction of mikrobus pins\n", 79 | "RL1 = SPI_CS1\n", 80 | "RL2 = PWM1\n", 81 | "\n", 82 | "rp.rp_DpinSetDirection(RL1, rp.RP_OUT)\n", 83 | "rp.rp_DpinSetDirection(RL2, rp.RP_OUT)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "The two relays on the click board can be closed on command. Consequently, the LEDs are turned ON on the Red Pitaya." 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": true 98 | }, 99 | "outputs": [], 100 | "source": [ 101 | "while True:\n", 102 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_HIGH)\n", 103 | " rp.rp_DpinSetState(RL1, rp.RP_HIGH)\n", 104 | " rp.rp_DpinSetState(RL2, rp.RP_HIGH)\n", 105 | " time.sleep(1)\n", 106 | " \n", 107 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_LOW)\n", 108 | " rp.rp_DpinSetState(RL1, rp.RP_LOW)\n", 109 | " rp.rp_DpinSetState(RL2, rp.RP_LOW)\n", 110 | " time.sleep(1)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "# Release resources\n", 120 | "rp.rp_Release()" 121 | ] 122 | } 123 | ], 124 | "metadata": { 125 | "kernelspec": { 126 | "display_name": "Python 3", 127 | "language": "python", 128 | "name": "python3" 129 | }, 130 | "language_info": { 131 | "codemirror_mode": { 132 | "name": "ipython", 133 | "version": 3 134 | }, 135 | "file_extension": ".py", 136 | "mimetype": "text/x-python", 137 | "name": "python", 138 | "nbconvert_exporter": "python", 139 | "pygments_lexer": "ipython3", 140 | "version": "3.5.2" 141 | } 142 | }, 143 | "nbformat": 4, 144 | "nbformat_minor": 2 145 | } 146 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/click_board_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "0595ebb4-5223-4f51-9da4-41d443f626d7", 6 | "metadata": {}, 7 | "source": [ 8 | "## JupyterLab Click Board examples for Red Pitaya\n", 9 | "\n", 10 | "Below you can find a few examples of how to control [MirkoE Click Boards](https://www.mikroe.com/) through your Red Pitaya with the [Click Shield](https://redpitaya.readthedocs.io/en/latest/developerGuide/hardware/ext_modules/click_shield.html#click-shield).\n", 11 | "\n", 12 | "To execute a cell click on it to change focus, and press the run button (⏵) above or press the key combination `Shift+Enter`." 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "id": "f462a81a-b397-4976-9340-192770719809", 18 | "metadata": {}, 19 | "source": [ 20 | "1. **Basic:**\n", 21 | " 1. [Button G Click](basic/buttonG.ipynb)\n", 22 | " 0. [Capacitive Touch Click](basic/cap_touch.ipynb)\n", 23 | " 0. [Relay Click](basic/relay.ipynb)\n", 24 | "0. **Sensors:**\n", 25 | " 1. [Current Click](sensor/current.ipynb)\n", 26 | " 0. [Light Click](sensor/light.ipynb)\n", 27 | " 0. [Motion Click](sensor/motion.ipynb)\n", 28 | " 0. [Thermo 16 Click](sensor/thermo16.ipynb)\n", 29 | "0. **Motors:**\n", 30 | " 1. [DC Motor 2 Click](motor/dc_motor2.ipynb)\n", 31 | " 0. [Vibro Motor Click](motor/vibro_motor.ipynb)\n", 32 | "0. **Data:**\n", 33 | " 1. *Under construction...*\n" 34 | ] 35 | } 36 | ], 37 | "metadata": { 38 | "kernelspec": { 39 | "display_name": "Python 3 (ipykernel)", 40 | "language": "python", 41 | "name": "python3" 42 | }, 43 | "language_info": { 44 | "codemirror_mode": { 45 | "name": "ipython", 46 | "version": 3 47 | }, 48 | "file_extension": ".py", 49 | "mimetype": "text/x-python", 50 | "name": "python", 51 | "nbconvert_exporter": "python", 52 | "pygments_lexer": "ipython3", 53 | "version": "3.10.12" 54 | } 55 | }, 56 | "nbformat": 4, 57 | "nbformat_minor": 5 58 | } 59 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/motor/vibro_motor.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# VIBRO MOTOR CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# Define pin directions\n", 84 | "rp.rp_DpinSetDirection(PWM1, rp.RP_OUT)\n", 85 | "rp.rp_DpinSetDirection(PWM2, rp.RP_OUT)\n", 86 | "\n", 87 | "def pwm(pin, duty_cycle, num_seconds):\n", 88 | " period_us = 875\n", 89 | " pulse_us = (duty_cycle * period_us) / 100\n", 90 | " num_periods = 0\n", 91 | " \n", 92 | " while True:\n", 93 | " if num_periods == num_seconds * 1000:\n", 94 | " break\n", 95 | " rp.rp_DpinSetState(pin, rp.RP_HIGH)\n", 96 | " time.sleep(pulse_us / 1000000)\n", 97 | " rp.rp_DpinSetState(pin, rp.RP_HIGH)\n", 98 | " time.sleep((period_us - pulse_us) / 1000000)\n", 99 | " num_periods += 1" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "The example turns on an LED for 3 seconds, then runs the motor connected to the PWM pin at 50% power for 3 seconds." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "# turn on\n", 116 | "rp.rp_DpinSetState(rp.RP_LED0, rp.RP_HIGH)\n", 117 | "\n", 118 | "# run motor at 50% duty cycle for 3 seconds\n", 119 | "pwm(PWM1, 50, 3)\n", 120 | "# the motor doesn't run at less than 30% power\n", 121 | "\n", 122 | "# turn off\n", 123 | "rp.rp_DpinSetState(rp.RP_LED0, rp.RP_LOW)" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "# Release resources\n", 133 | "rp.rp_Release()" 134 | ] 135 | } 136 | ], 137 | "metadata": { 138 | "kernelspec": { 139 | "display_name": "Python 3", 140 | "language": "python", 141 | "name": "python3" 142 | }, 143 | "language_info": { 144 | "codemirror_mode": { 145 | "name": "ipython", 146 | "version": 3 147 | }, 148 | "file_extension": ".py", 149 | "mimetype": "text/x-python", 150 | "name": "python", 151 | "nbconvert_exporter": "python", 152 | "pygments_lexer": "ipython3", 153 | "version": "3.5.2" 154 | } 155 | }, 156 | "nbformat": 4, 157 | "nbformat_minor": 2 158 | } 159 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/sensor/current.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# CURRENT CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N\n", 75 | "\n", 76 | "# Reset analog pins\n", 77 | "rp.rp_ApinReset()\n", 78 | "\n", 79 | "AIN = AN1" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "def convert_to_engineering_unit(number, units):\n", 89 | " magnitude = number\n", 90 | " unit_index = 0\n", 91 | "\n", 92 | " while magnitude <= 1.0 and unit_index < len(units) - 1:\n", 93 | " magnitude *= 1000.0\n", 94 | " unit_index += 1\n", 95 | "\n", 96 | " print(\"Value: {:.4f} {} \\n\".format(magnitude, units[unit_index]))\n", 97 | "\n", 98 | "def get_current(pin, resistor_value):\n", 99 | " # Get ADC value from the specified pin\n", 100 | " value = rp.rp_ApinGetValue(pin)[1]\n", 101 | " max_current = 3.3 / (20.0 * resistor_value)\n", 102 | " print(\"Minimum current is 2mA, maximum is:\")\n", 103 | " convert_to_engineering_unit(max_current, [\"A\", \"mA\", \"μA\", \"nA\"])\n", 104 | "\n", 105 | " # Calculate current\n", 106 | " voltage = value / 20.0\n", 107 | " # gain of circuit is 20\n", 108 | " current = voltage / resistor_value\n", 109 | "\n", 110 | " return current\n", 111 | "\n", 112 | "def recommend_resistor(current):\n", 113 | " if current != 0:\n", 114 | " resistor = 0.075 / current\n", 115 | " print(\"The recommended resistor value for best measurement (R) is {:.4f} ohms.\\n\".format(resistor))\n", 116 | " return resistor\n", 117 | " else:\n", 118 | " print(\"Error: Current (I) cannot be zero.\\n\")\n", 119 | " return -1\n", 120 | " # Return -1 to indicate an error" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "The example shows how to read the current through a shunt resistor. The program, however, does not know how many ohms your shunt resistor has. That is why the shunt resistor value must be input when prompted by the program. Also, the shunt resistor should be accurate to at least three decimals (for example, with a multimeter). That way, the current measurement will be most accurate.\n", 128 | "\n", 129 | "Refrain from going above or below the minimum and maximum current measurement.\n", 130 | "\n", 131 | "For best measurements, please use the recommended resistor." 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "while True:\n", 141 | " print(\"Enter shunt resistor value in Ohms: \")\n", 142 | " # circuit 5 ohms\n", 143 | " resistor_value = float(input())\n", 144 | " current = get_current(AIN, resistor_value)\n", 145 | "\n", 146 | " convert_to_engineering_unit(current, [\"A\", \"mA\", \"μA\", \"nA\"])\n", 147 | " recommend_resistor(current)\n", 148 | " time.sleep(1)" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "# Release resources\n", 158 | "rp.rp_Release()" 159 | ] 160 | } 161 | ], 162 | "metadata": { 163 | "language_info": { 164 | "name": "python" 165 | }, 166 | "orig_nbformat": 4 167 | }, 168 | "nbformat": 4, 169 | "nbformat_minor": 2 170 | } 171 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/sensor/light.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# LIGHT CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N\n", 75 | "\n", 76 | "# Reset analog pins\n", 77 | "rp.rp_ApinReset()\n", 78 | "\n", 79 | "AIN = AN1" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "The example measures light intensity by reading the analog value and displays whether it is light or dark. If the sensor is covered or the light intensity is below the threshold, the program prints that it is dark." 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "while True:\n", 96 | " # Get light value\n", 97 | " value = rp.rp_ApinGetValue(AIN)[1]\n", 98 | " print(\"Measured voltage on AI[{}] = {}V\\n\".format(0, value))\n", 99 | " if value >= 2.0:\n", 100 | " # Turn on light based on read value\n", 101 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_HIGH)\n", 102 | " print(\"It is light\\n\")\n", 103 | " elif value <= 0.5:\n", 104 | " # Turn off light based on read value\n", 105 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_LOW)\n", 106 | " print(\"It is dark\\n\")\n", 107 | " else:\n", 108 | " print(\"It is gloomy\\n\")\n", 109 | "\n", 110 | " time.sleep(1)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "# Release resources\n", 120 | "rp.rp_Release()" 121 | ] 122 | } 123 | ], 124 | "metadata": { 125 | "language_info": { 126 | "name": "python" 127 | }, 128 | "orig_nbformat": 4 129 | }, 130 | "nbformat": 4, 131 | "nbformat_minor": 2 132 | } 133 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/sensor/motion.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# MOTION CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N\n", 75 | "\n", 76 | "\n", 77 | "# Define pin directions\n", 78 | "rp.rp_DpinSetDirection(INT1, rp.RP_IN)\n", 79 | "rp.rp_DpinSetDirection(INT2, rp.RP_IN)" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "Every second, the example program checks if any motion was detected." 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "while True:\n", 96 | " # Get the state of the button\n", 97 | " state = rp.rp_DpinSetState(INT1, rp.RP_HIGH)\n", 98 | "\n", 99 | " # Turn on the LED based on the button state\n", 100 | " if state:\n", 101 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_HIGH) # Turn on LED0\n", 102 | " print(\"Must have been the wind...\\n\")\n", 103 | " else:\n", 104 | " rp.rp_DpinSetState(rp.RP_LED0, rp.RP_LOW) # Turn off LED0\n", 105 | " print(\"Everything is quiet\\n\")\n", 106 | "\n", 107 | " time.sleep(1)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "# Release resources\n", 117 | "rp.rp_Release()" 118 | ] 119 | } 120 | ], 121 | "metadata": { 122 | "kernelspec": { 123 | "display_name": "Python 3", 124 | "language": "python", 125 | "name": "python3" 126 | }, 127 | "language_info": { 128 | "codemirror_mode": { 129 | "name": "ipython", 130 | "version": 3 131 | }, 132 | "file_extension": ".py", 133 | "mimetype": "text/x-python", 134 | "name": "python", 135 | "nbconvert_exporter": "python", 136 | "pygments_lexer": "ipython3", 137 | "version": "3.5.2" 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 2 142 | } 143 | -------------------------------------------------------------------------------- /examples/click_shield_examples/click_board_examples/sensor/thermo16.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# THERMO 16 CLICK \n", 8 | "\n", 9 | "## Libraries and FPGA image\n", 10 | "\n", 11 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "import time\n", 21 | "from rp_overlay import overlay\n", 22 | "import rp\n", 23 | "\n", 24 | "# Initialize the FPGA overlay\n", 25 | "fpga = overlay()\n", 26 | "rp.rp_Init()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Macros\n", 34 | "Here is a complete list of macros that will come in handy when customising this notebook and operating the click shields.\n", 35 | "\n", 36 | "- **States** - RP_LOW, RP_HIGH\n", 37 | "- **Directions** - RP_IN, RP_OUT\n", 38 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7\n", 39 | "- **DIOx_P** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 40 | "- **DIOx_N** - RP_DIO0_N, RP_DIO1_N, ..., RP_DIO7_N    *# Goes up to 9 on SDRlab and STEMlab 4-Input*\n", 41 | "- **Analog outputs** - RP_AOUT0, RP_AOUT1, ..., RP_AOUT3\n", 42 | "- **Analog inputs** - RP_AIN0, RP_AIN1, ..., RP_AIN3\n", 43 | "\n", 44 | "### Click shield macros\n", 45 | "For easier work with the click shields, here are some macro rewrites. Marcos ending in \"1\" are on MicroBus1, and macros ending in \"2\" are on MicroBus2.\n", 46 | "\n", 47 | "- **AN1, AIN2** - RP_AIN0, RP_AIN1\n", 48 | "- **RST1, RST2** - RP_DIO2_N, RP_DIO4_N\n", 49 | "- **PWM1, PWM2** - RP_DIO1_P, RP_DIO3_P\n", 50 | "- **INT1, INT2** - RP_DIO2_P, RP_DIO4_P\n", 51 | "- **UART_SW** - RP_DIO5_N\n", 52 | "- **SPI_CS1, SPI_CS2** - RP_DIO1_N, RP_DIO3_N\n", 53 | "- **Logic analyser** - RP_DIO0_P, RP_DIO1_P, ..., RP_DIO7_P\n", 54 | "\n", 55 | "Setting up click shield macros:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "AN1 = rp.RP_AIN0\n", 65 | "AN2 = rp.RP_AIN1\n", 66 | "RST1 = rp.RP_DIO2_N\n", 67 | "RST2 = rp.RP_DIO4_N\n", 68 | "PWM1 = rp.RP_DIO1_P\n", 69 | "PWM2 = rp.RP_DIO3_P\n", 70 | "INT1 = rp.RP_DIO2_P\n", 71 | "INT2 = rp.RP_DIO4_P\n", 72 | "UART_SW = rp.RP_DIO5_N\n", 73 | "SPI_CS1 = rp.RP_DIO1_N\n", 74 | "SPI_CS2 = rp.RP_DIO3_N\n", 75 | "\n", 76 | "# Reset analog pins\n", 77 | "rp.rp_ApinReset()\n", 78 | "\n", 79 | "AIN = AN1" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "print(f\"Measured voltage on Analog pin is {rp.rp_ApinGetValue(AIN)[1]:.2f} V\\n\")\n", 89 | "\n", 90 | "def get_average_temperature():\n", 91 | " values = []\n", 92 | " sum = 0.0\n", 93 | " for i in range(0, 30):\n", 94 | " # read analog input value from Red Pitaya\n", 95 | " values.append(rp.rp_ApinGetValue(AIN)[1])\n", 96 | " sum += values[i]\n", 97 | " time.sleep(0.05)\n", 98 | " average = sum / 30.0\n", 99 | " return (average -0.53) * 100.0\n", 100 | "\n", 101 | " # TEMP_IN_CELSIUS;\n", 102 | " # standard deviation = ABSOLUTE MISTAKE / Sqrt(3) = 1,25 °C / Sqrt(3) = 0.72 °C\n", 103 | " # with 68% certainty\n", 104 | " # uncertainty due to repeated measurements can be disregarded" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "The example shows how to measure temperature. If the Thermo16 Click Board is too close to the Red Pitaya (directly mounted on the Click Shield), the temperature measurements can be affected by the Red Pitaya's heating." 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "temperature = get_average_temperature()\n", 121 | "correction= -9.0 \n", 122 | "# ADD A DIFFRENT CORRECTION IF NECESSARY;\n", 123 | "temperature = temperature + correction\n", 124 | "\n", 125 | "print(f\"Measured TEMP_IN_KELVIN = {temperature + 273.15:.4f}°C +- 0.72°C \\n\")\n", 126 | "print(f\"Measured TEMP_IN_FARENHEIT = {(temperature * 9.0/5.0) + 32.0:.4f}°F +- 1.3°F \\n\")\n", 127 | "print(f\"Measured TEMP_IN_CELSIUS = {temperature:.4f}°C +- 0.72°C\\n\")" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "# Release resources\n", 137 | "rp.rp_Release()" 138 | ] 139 | } 140 | ], 141 | "metadata": { 142 | "language_info": { 143 | "name": "python" 144 | }, 145 | "orig_nbformat": 4 146 | }, 147 | "nbformat": 4, 148 | "nbformat_minor": 2 149 | } 150 | -------------------------------------------------------------------------------- /examples/digital/led.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Drive LEDs\n", 8 | "\n", 9 | "This example shows how to control LEDs on a Red Pitaya board." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "![led_blink](../img/LED-blink.gif \"Blinking LED on Red Pitaya.\")" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Libraries and FPGA image\n", 24 | "\n", 25 | "The first thing we need to do is import the *time*, *rp* (Red Pitaya), and *rp_overlay* libraries.\n", 26 | "Then, we load the *v0.94* FPGA image into the Xilinx Zynq 7010 SoC and finally initialize the Red Pitaya.\n", 27 | "\n", 28 | "We will do this by clicking on the following cell to select it and pressing the run button (⏵) above or the key combination *Shift+Enter*." 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "import time\n", 38 | "from rp_overlay import overlay\n", 39 | "import rp\n", 40 | "\n", 41 | "fpga = overlay()\n", 42 | "rp.rp_Init()" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "## Macros\n", 50 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of digital macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 51 | "\n", 52 | "- **States** - RP_LOW, RP_HIGH\n", 53 | "- **LEDs** - RP_LED0, RP_LED1, ..., RP_LED7" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "## LEDs" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "There are eight orange LEDs on the Red Pitaya board. We need to tell Python which LED we want to control. Each bit corresponds to an LED; 1st bit (*LSB*) to *LED0*, 2nd bit to *LED1*, ..., and 8th (*MSB*) to *LED7*. If a specific bit is set to 1 (*HIGH*), the LED is turned *on*. Otherwise (the bit is 0 (*LOW*)), the LED is turned *off*. To configure the LED, we can use one of the following functions:\n", 68 | "- **rp_LEDSetState(8-bit_state)**\n", 69 | "\n", 70 | "Alternatively, use LED macros to turn *on*/*off* a specific LED:\n", 71 | "- **rp_DpinSetState(led_macro, led_state)**\n", 72 | "\n", 73 | "Here are examples of how to turn *on LED1*." 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": { 80 | "collapsed": true, 81 | "jupyter": { 82 | "outputs_hidden": true 83 | } 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "led1 = 0b00000010\n", 88 | "rp.rp_LEDSetState(led1)" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "Using macros:" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "rp.rp_DpinSetState(rp.RP_LED1, rp.RP_HIGH)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "To read the LED states use the following functions:\n", 112 | "- **rp_LEDGetState()**\n", 113 | "- **rp_DpinGetState(led_macro)**\n", 114 | "\n", 115 | "When reading the LED states with the first function, we must extract a specific bit. When checking if the LED is *on* we are searching for a result greater than 0 (or comparing it to power of 2). Here is an example:" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "led_values = rp.rp_LEDGetState()[1] # Reading state of all LEDs\n", 125 | "print(f\"LED states: {led_values}\")\n", 126 | "\n", 127 | "led1_state = led_values & led1 # Extracting the 2nd bit\n", 128 | "print(f\"LED1 state: {led1_state}\")\n", 129 | "\n", 130 | "if led1_state > 0: # or led1_state == pow(2,1)\n", 131 | " print(\"LED1 ON\")\n", 132 | "else:\n", 133 | " print(\"LED1 OFF\")" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "Using macros:" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "led1_state = rp.rp_DpinGetState(rp.RP_LED1)[1]\n", 150 | "print(f\"LED1 state: {led1_state}\")" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "To turn all LEDs *off* execute the following cell." 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": { 164 | "collapsed": true, 165 | "jupyter": { 166 | "outputs_hidden": true 167 | } 168 | }, 169 | "outputs": [], 170 | "source": [ 171 | "rp.rp_LEDSetState(0)" 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "Alternatively, all LEDs can be turned *off* one by one using macros." 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "## Blink LED\n", 186 | "\n", 187 | "To make an LED blink, we need to write a loop turning the LED *on* and *off*. We will use the *time* library so we can slow down the execution of the cell so we can see the LED blinking." 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | " 1. Turn the LED *on* and *off* 10 times every half a second." 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": { 201 | "collapsed": true, 202 | "jupyter": { 203 | "outputs_hidden": true 204 | } 205 | }, 206 | "outputs": [], 207 | "source": [ 208 | "for i in range(10):\n", 209 | " rp.rp_LEDSetState(led1)\n", 210 | " time.sleep(0.5)\n", 211 | " rp.rp_LEDSetState(0)\n", 212 | " time.sleep(0.5)" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": null, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "for i in range(10):\n", 222 | " rp.rp_DpinSetState(rp.RP_LED1, rp.RP_HIGH)\n", 223 | " time.sleep(0.5)\n", 224 | " rp.rp_DpinSetState(rp.RP_LED1, rp.RP_LOW)\n", 225 | " time.sleep(0.5)" 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "Finaly, at the end of the program, we should always release the used resources. Execute the following cell." 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": null, 238 | "metadata": { 239 | "collapsed": true, 240 | "jupyter": { 241 | "outputs_hidden": true 242 | } 243 | }, 244 | "outputs": [], 245 | "source": [ 246 | "rp.rp_Release()" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "### Note\n", 254 | "All Python API functions internally call corresponding C functions. Therefore, they always return an integer value depending on their successful execution (**0 - success**, **!=0 - error**). " 255 | ] 256 | } 257 | ], 258 | "metadata": { 259 | "kernelspec": { 260 | "display_name": "Python 3 (ipykernel)", 261 | "language": "python", 262 | "name": "python3" 263 | }, 264 | "language_info": { 265 | "codemirror_mode": { 266 | "name": "ipython", 267 | "version": 3 268 | }, 269 | "file_extension": ".py", 270 | "mimetype": "text/x-python", 271 | "name": "python", 272 | "nbconvert_exporter": "python", 273 | "pygments_lexer": "ipython3", 274 | "version": "3.10.12" 275 | } 276 | }, 277 | "nbformat": 4, 278 | "nbformat_minor": 4 279 | } 280 | -------------------------------------------------------------------------------- /examples/generation/gen_burst_async_signals.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Generate two burst asynced signals\n", 8 | "This example shows how to generate two asynced analog burst signals." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Libraries and FPGA image" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "import time\n", 25 | "from rp_overlay import overlay\n", 26 | "import rp\n", 27 | "\n", 28 | "fpga = overlay()\n", 29 | "rp.rp_Init()" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "## Macros\n", 37 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 38 | "\n", 39 | "- **Waveforms** - RP_WAVEFORM_SINE, RP_WAVEFORM_SQUARE, RP_WAVEFORM_TRIANGLE, RP_WAVEFORM_RAMP_UP, RP_WAVEFORM_RAMP_DOWN, RP_WAVEFORM_DC, RP_WAVEFORM_PWM, RP_WAVEFORM_ARBITRARY, RP_WAVEFORM_DC_NEG, RP_WAVEFORM_SWEEP\n", 40 | "- **Generator modes** - RP_GEN_MODE_CONTINUOUS, RP_GEN_MODE_BURST\n", 41 | "- **Sweep direction** - RP_GEN_SWEEP_DIR_NORMAL, RP_GEN_SWEEP_DIR_UP_DOWN\n", 42 | "- **Sweep mode** - RP_GEN_SWEEP_MODE_LINEAR, RP_GEN_SWEEP_MODE_LOG\n", 43 | "- **Generator trigger source** - RP_GEN_TRIG_SRC_INTERNAL, RP_GEN_TRIG_SRC_EXT_PE, RP_GEN_TRIG_SRC_EXT_NE\n", 44 | "- **Fast analog channels** - RP_CH_1, RP_CH_2\n", 45 | "- **Fast analog triggers** - RP_T_CH_1, RP_T_CH_2, RP_T_CH_EXT\n", 46 | "- **Rise and fall times** - RISE_FALL_MIN_RATIO, RISE_FALL_MAX_RATIO\n", 47 | "\n", 48 | "SIGNALlab 250-12 only:\n", 49 | "- **Generator gain** - RP_GAIN_1X, RP_GAIN_5X\n", 50 | "\n", 51 | "STEMlab 125-14 4-Input only:\n", 52 | "- **Fast analog channels** - RP_CH_3, RP_CH_4\n", 53 | "- **Fast analog triggers** - RP_T_CH_3, RP_T_CH_4\n" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "## Asynchronised signals\n", 61 | "Here is a quick reference guide to the functions used:\n", 62 | "- **rp_GenOutEnable(output_channel)** - supplies voltage on the specified output (voltage set with **rp_GenSetInitGenValue** appears on the output), but does not generate a signal\n", 63 | "- **rp_GenOutEnableSync()** - supplies voltage on both outputs (voltage set with **rp_GenSetInitGenValue** appears on the outputs), but does not generate a signal.\n", 64 | "- **rp_GenTriggerOnly(output_channel)** - triggers signal generation on the specified output\n", 65 | "- **rp_GenSynchronise()** - triggers both signal generators at the same time (sychronised)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "channel = rp.RP_CH_1 # rp.RP_CH_2\n", 75 | "channel2 = rp.RP_CH_2\n", 76 | "waveform = rp.RP_WAVEFORM_SINE\n", 77 | "freq = 10000\n", 78 | "ampl = 1\n", 79 | "\n", 80 | "ncyc = 2\n", 81 | "nor = 1\n", 82 | "period = 50\n", 83 | "\n", 84 | "\n", 85 | "# Reset generator\n", 86 | "rp.rp_GenReset()\n", 87 | "\n", 88 | "###### Generation #####\n", 89 | "# OUT1\n", 90 | "rp.rp_GenWaveform(channel, waveform)\n", 91 | "rp.rp_GenFreqDirect(channel, freq)\n", 92 | "rp.rp_GenAmp(channel, ampl)\n", 93 | "\n", 94 | "# Change to burst mode\n", 95 | "rp.rp_GenMode(channel, rp.RP_GEN_MODE_BURST)\n", 96 | "rp.rp_GenBurstCount(channel, ncyc) # Ncyc\n", 97 | "rp.rp_GenBurstRepetitions(channel, nor) # Nor\n", 98 | "rp.rp_GenBurstPeriod(channel, period) # Period\n", 99 | "\n", 100 | "# OUT2\n", 101 | "rp.rp_GenWaveform(channel2, waveform)\n", 102 | "rp.rp_GenFreqDirect(channel2, freq)\n", 103 | "rp.rp_GenAmp(channel2, ampl)\n", 104 | "\n", 105 | "# Change to burst mode\n", 106 | "rp.rp_GenMode(channel2, rp.RP_GEN_MODE_BURST)\n", 107 | "rp.rp_GenBurstCount(channel2, ncyc) # Ncyc\n", 108 | "rp.rp_GenBurstRepetitions(channel2, nor) # Nor\n", 109 | "rp.rp_GenBurstPeriod(channel2, period) # Period\n", 110 | "\n", 111 | "\n", 112 | "# Specify generator trigger source\n", 113 | "rp.rp_GenTriggerSource(channel, rp.RP_GEN_TRIG_SRC_INTERNAL)\n", 114 | "\n", 115 | "# Enable output synchronisation\n", 116 | "rp.rp_GenOutEnableSync(True)\n", 117 | "time.sleep(0.1)\n", 118 | "\n", 119 | "# Syncronise output channels\n", 120 | "rp.rp_GenTriggerOnly(channel)\n", 121 | "rp.rp_GenTriggerOnly(channel2)\n", 122 | "rp.rp_GenSynchronise()" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "# Release resources\n", 132 | "rp.rp_Release()" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "### Note\n", 140 | "There are a lot of different commands for the Generation. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n" 141 | ] 142 | } 143 | ], 144 | "metadata": { 145 | "language_info": { 146 | "name": "python" 147 | } 148 | }, 149 | "nbformat": 4, 150 | "nbformat_minor": 2 151 | } 152 | -------------------------------------------------------------------------------- /examples/generation/gen_bursts.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Generate signal pulses\n", 8 | "In this example we will learn how to create burst pulses on the fast analog outputs." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Libraries and FPGA image" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": { 22 | "collapsed": true 23 | }, 24 | "outputs": [], 25 | "source": [ 26 | "from rp_overlay import overlay\n", 27 | "import rp\n", 28 | "\n", 29 | "fpga = overlay()\n", 30 | "rp.rp_Init()" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "## Macros\n", 38 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 39 | "\n", 40 | "- **Waveforms** - RP_WAVEFORM_SINE, RP_WAVEFORM_SQUARE, RP_WAVEFORM_TRIANGLE, RP_WAVEFORM_RAMP_UP, RP_WAVEFORM_RAMP_DOWN, RP_WAVEFORM_DC, RP_WAVEFORM_PWM, RP_WAVEFORM_ARBITRARY, RP_WAVEFORM_DC_NEG, RP_WAVEFORM_SWEEP\n", 41 | "- **Generator modes** - RP_GEN_MODE_CONTINUOUS, RP_GEN_MODE_BURST\n", 42 | "- **Sweep direction** - RP_GEN_SWEEP_DIR_NORMAL, RP_GEN_SWEEP_DIR_UP_DOWN\n", 43 | "- **Sweep mode** - RP_GEN_SWEEP_MODE_LINEAR, RP_GEN_SWEEP_MODE_LOG\n", 44 | "- **Generator trigger source** - RP_GEN_TRIG_SRC_INTERNAL, RP_GEN_TRIG_SRC_EXT_PE, RP_GEN_TRIG_SRC_EXT_NE\n", 45 | "- **Fast analog channels** - RP_CH_1, RP_CH_2\n", 46 | "- **Fast analog triggers** - RP_T_CH_1, RP_T_CH_2, RP_T_CH_EXT\n", 47 | "- **Rise and fall times** - RISE_FALL_MIN_RATIO, RISE_FALL_MAX_RATIO\n", 48 | "\n", 49 | "SIGNALlab 250-12 only:\n", 50 | "- **Generator gain** - RP_GAIN_1X, RP_GAIN_5X\n", 51 | "\n", 52 | "STEMlab 125-14 4-Input only:\n", 53 | "- **Fast analog channels** - RP_CH_3, RP_CH_4\n", 54 | "- **Fast analog triggers** - RP_T_CH_3, RP_T_CH_4" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "## Burst signals\n", 62 | "\n", 63 | "Burst signals differ from continuous signals. They are only generated in a short amount of time and do not necessarily repeat. Here are the new parameters that come into play (in addition to the continuous signal parameters):\n", 64 | "\n", 65 | "- **Number of Cycles (NCYC)** - How many periods of our signal are there in a single burst?\n", 66 | "- **Number of Repetitions (NOR)** - How many bursts are there overall (each burst includes NCYC signal periods)?\n", 67 | "- **Burst period (PERIOD)** - The time between the start of one and the start of the next burst (in microseconds). The minimal period is 1 microsecond.\n", 68 | "\n", 69 | "Now that we know the basics, let's start programming." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": { 76 | "collapsed": true 77 | }, 78 | "outputs": [], 79 | "source": [ 80 | "channel = rp.RP_CH_1 # rp.RP_CH_2\n", 81 | "waveform = rp.RP_WAVEFORM_SINE\n", 82 | "freq = 1000\n", 83 | "ampl = 1\n", 84 | "\n", 85 | "# Burst paramteres\n", 86 | "ncyc = 1 # Number of waveform periods in one burst\n", 87 | "nor = 1000 # Number of repeated bursts\n", 88 | "period = 5000 # Delay between start of first burst and start of second burst\n", 89 | " # in mircoseconds" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "By default, Red Pitaya operates generates continuous signals, so we need to change the generation mode to burst." 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "mode = rp.RP_GEN_MODE_BURST\n", 106 | "\n", 107 | "# Reset generator\n", 108 | "rp.rp_GenReset()\n", 109 | "\n", 110 | "#### Generation ####\n", 111 | "rp.rp_GenWaveform(channel, waveform)\n", 112 | "rp.rp_GenFreqDirect(channel, freq)\n", 113 | "rp.rp_GenAmp(channel, ampl)\n", 114 | "\n", 115 | "# Change to burst mode\n", 116 | "rp.rp_GenMode(channel, mode)\n", 117 | "rp.rp_GenBurstCount(channel, ncyc) # Ncyc\n", 118 | "rp.rp_GenBurstRepetitions(channel, nor) # Nor\n", 119 | "rp.rp_GenBurstPeriod(channel, period) # Period" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "One major difference between continuous and burst signals is that you can retrigger burst signals to generate them again. Retriggering a continuous signal does not achieve much beyond resetting the phase." 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "rp.rp_GenOutEnable(channel)\n", 136 | "rp.rp_GenTriggerOnly(channel)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": {}, 142 | "source": [ 143 | "To repeat a burst signal, trigger the generator again." 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "metadata": { 150 | "collapsed": true 151 | }, 152 | "outputs": [], 153 | "source": [ 154 | "rp.rp_GenTriggerOnly(channel)" 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "metadata": {}, 160 | "source": [ 161 | "Finally, release the resources." 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "rp.rp_Release()" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "### Note\n", 178 | "There are a lot of different commands for the Generation. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n" 179 | ] 180 | } 181 | ], 182 | "metadata": { 183 | "kernelspec": { 184 | "display_name": "Python 3", 185 | "language": "python", 186 | "name": "python3" 187 | }, 188 | "language_info": { 189 | "codemirror_mode": { 190 | "name": "ipython", 191 | "version": 3 192 | }, 193 | "file_extension": ".py", 194 | "mimetype": "text/x-python", 195 | "name": "python", 196 | "nbconvert_exporter": "python", 197 | "pygments_lexer": "ipython3", 198 | "version": "3.5.2" 199 | } 200 | }, 201 | "nbformat": 4, 202 | "nbformat_minor": 2 203 | } 204 | -------------------------------------------------------------------------------- /examples/generation/gen_continuous_signal.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Generate Continuous Signal\n", 8 | "\n", 9 | "This example will show how to generate a continuous 2 kHz 1 V sine wave on fast analog outputs." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Libraries and FPGA image\n", 17 | "\n", 18 | "We will start by importing the *rp* (Red Pitaya) and *rp_overlay* libraries, loading the *v0.94* FPGA image, and initializing the Red Pitaya." 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "scrolled": true 26 | }, 27 | "outputs": [], 28 | "source": [ 29 | "from rp_overlay import overlay\n", 30 | "import rp\n", 31 | "\n", 32 | "fpga = overlay()\n", 33 | "rp.rp_Init()" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "## Macros\n", 41 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 42 | "\n", 43 | "- **Waveforms** - RP_WAVEFORM_SINE, RP_WAVEFORM_SQUARE, RP_WAVEFORM_TRIANGLE, RP_WAVEFORM_RAMP_UP, RP_WAVEFORM_RAMP_DOWN, RP_WAVEFORM_DC, RP_WAVEFORM_PWM, RP_WAVEFORM_ARBITRARY, RP_WAVEFORM_DC_NEG, RP_WAVEFORM_SWEEP\n", 44 | "- **Generator modes** - RP_GEN_MODE_CONTINUOUS, RP_GEN_MODE_BURST\n", 45 | "- **Sweep direction** - RP_GEN_SWEEP_DIR_NORMAL, RP_GEN_SWEEP_DIR_UP_DOWN\n", 46 | "- **Sweep mode** - RP_GEN_SWEEP_MODE_LINEAR, RP_GEN_SWEEP_MODE_LOG\n", 47 | "- **Generator trigger source** - RP_GEN_TRIG_SRC_INTERNAL, RP_GEN_TRIG_SRC_EXT_PE, RP_GEN_TRIG_SRC_EXT_NE\n", 48 | "- **Fast analog channels** - RP_CH_1, RP_CH_2\n", 49 | "- **Fast analog triggers** - RP_T_CH_1, RP_T_CH_2, RP_T_CH_EXT\n", 50 | "- **Rise and fall times** - RISE_FALL_MIN_RATIO, RISE_FALL_MAX_RATIO\n", 51 | "\n", 52 | "SIGNALlab 250-12 only:\n", 53 | "- **Generator gain** - RP_GAIN_1X, RP_GAIN_5X\n", 54 | "\n", 55 | "STEMlab 125-14 4-Input only:\n", 56 | "- **Fast analog channels** - RP_CH_3, RP_CH_4\n", 57 | "- **Fast analog triggers** - RP_T_CH_3, RP_T_CH_4" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "## Generation\n", 65 | "\n", 66 | "When generating signals, there are a number of important parameters that we need to define.\n", 67 | "\n", 68 | "- **Channel** - on which of the two output channels do we want to generate a signal\n", 69 | "- **Waveform** - te basic shape of our signal. Some most common examples are sine, square, triangle, etc.\n", 70 | "- **Frequency** - how fast will our signal periods be generated/how much time it takes for one period of our signal to generate. $f = \\frac{1}{T}$, where T is signal period.\n", 71 | "- **Amplitude** - what is the maximum voltage of our output signal. There are multiple different ways to define this, but Red Pitaya uses one-way amplitude referenced towards GND (and not peak-to-peak).\n", 72 | "\n", 73 | "In this example, we will generate a 1 V, 2 kHz sine wave. So, let's define the parameters." 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "channel = rp.RP_CH_1 # rp.RP_CH_2\n", 83 | "waveform = rp.RP_WAVEFORM_SINE\n", 84 | "freq = 2000\n", 85 | "ampl = 1 # One way amplitude (reference to GND)" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "Next, we will reset the generator to default parameters (1 kHz sine wave with amplitude 1 V), as we have no idea what the output was generating before." 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "rp.rp_GenReset()" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "Now that the generator is reset, let us specify our 2 kHz sine signal." 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": true, 116 | "scrolled": true 117 | }, 118 | "outputs": [], 119 | "source": [ 120 | "rp.rp_GenWaveform(channel, waveform)\n", 121 | "rp.rp_GenFreqDirect(channel, freq)\n", 122 | "rp.rp_GenAmp(channel, ampl)" 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": {}, 128 | "source": [ 129 | "To enable the output and trigger the generation execute the following cell." 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "rp.rp_GenOutEnable(channel)\n", 139 | "rp.rp_GenTriggerOnly(channel)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "It is a bit hard to know without using an oscilloscope or external insturument, but OUT1 of our Red Pitaya is now generating a continuous sine wave with the specified parameters.\n", 147 | "\n", 148 | "Once finished, do not forget to release the resources." 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": { 155 | "scrolled": true 156 | }, 157 | "outputs": [], 158 | "source": [ 159 | "rp.rp_Release()" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "### Note\n", 167 | "There are a lot of different commands for the Generation. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n" 168 | ] 169 | } 170 | ], 171 | "metadata": { 172 | "kernelspec": { 173 | "display_name": "Python 3", 174 | "language": "python", 175 | "name": "python3" 176 | }, 177 | "language_info": { 178 | "codemirror_mode": { 179 | "name": "ipython", 180 | "version": 3 181 | }, 182 | "file_extension": ".py", 183 | "mimetype": "text/x-python", 184 | "name": "python", 185 | "nbconvert_exporter": "python", 186 | "pygments_lexer": "ipython3", 187 | "version": "3.5.2" 188 | } 189 | }, 190 | "nbformat": 4, 191 | "nbformat_minor": 2 192 | } 193 | -------------------------------------------------------------------------------- /examples/generation/gen_sync_two_channel.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Generate two synchronous signals\n", 8 | "Here we will learn how to generate two synchronous signals on both fast analog outputs." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Libraries and FPGA image" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": { 22 | "scrolled": true 23 | }, 24 | "outputs": [], 25 | "source": [ 26 | "from rp_overlay import overlay\n", 27 | "import rp\n", 28 | "\n", 29 | "fpga = overlay()\n", 30 | "rp.rp_Init()" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "## Macros\n", 38 | "Throughout this tutorial we will mention macros multiple times. Here is a complete list of macros that will come in handy when customising this notebook. The marcos are a part of the **rp** library.\n", 39 | "\n", 40 | "- **Waveforms** - RP_WAVEFORM_SINE, RP_WAVEFORM_SQUARE, RP_WAVEFORM_TRIANGLE, RP_WAVEFORM_RAMP_UP, RP_WAVEFORM_RAMP_DOWN, RP_WAVEFORM_DC, RP_WAVEFORM_PWM, RP_WAVEFORM_ARBITRARY, RP_WAVEFORM_DC_NEG, RP_WAVEFORM_SWEEP\n", 41 | "- **Generator modes** - RP_GEN_MODE_CONTINUOUS, RP_GEN_MODE_BURST\n", 42 | "- **Sweep direction** - RP_GEN_SWEEP_DIR_NORMAL, RP_GEN_SWEEP_DIR_UP_DOWN\n", 43 | "- **Sweep mode** - RP_GEN_SWEEP_MODE_LINEAR, RP_GEN_SWEEP_MODE_LOG\n", 44 | "- **Generator trigger source** - RP_GEN_TRIG_SRC_INTERNAL, RP_GEN_TRIG_SRC_EXT_PE, RP_GEN_TRIG_SRC_EXT_NE\n", 45 | "- **Fast analog channels** - RP_CH_1, RP_CH_2\n", 46 | "- **Fast analog triggers** - RP_T_CH_1, RP_T_CH_2, RP_T_CH_EXT\n", 47 | "- **Rise and fall times** - RISE_FALL_MIN_RATIO, RISE_FALL_MAX_RATIO\n", 48 | "\n", 49 | "SIGNALlab 250-12 only:\n", 50 | "- **Generator gain** - RP_GAIN_1X, RP_GAIN_5X\n", 51 | "\n", 52 | "STEMlab 125-14 4-Input only:\n", 53 | "- **Fast analog channels** - RP_CH_3, RP_CH_4\n", 54 | "- **Fast analog triggers** - RP_T_CH_3, RP_T_CH_4" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "## Synchronising both outputs\n", 62 | "\n", 63 | "Here is a quick reference guide to the functions used:\n", 64 | "- **rp_GenOutEnable(output_channel)** - supplies voltage on the specified output (voltage set with **rp_GenSetInitGenValue** appears on the output), but does not generate a signal\n", 65 | "- **rp_GenOutEnableSync()** - supplies voltage on both outputs (voltage set with **rp_GenSetInitGenValue** appears on the outputs), but does not generate a signal.\n", 66 | "- **rp_GenTriggerOnly(output_channel)** - triggers signal generation on the specified output\n", 67 | "- **rp_GenSynchronise()** - triggers both signal generators at the same time (sychronised)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": { 74 | "scrolled": true 75 | }, 76 | "outputs": [], 77 | "source": [ 78 | "channel = rp.RP_CH_1\n", 79 | "channel2 = rp.RP_CH_2\n", 80 | "waveform = rp.RP_WAVEFORM_SINE\n", 81 | "freq = 10000\n", 82 | "ampl = 1\n", 83 | "\n", 84 | "gen_trig_sour = rp.RP_GEN_TRIG_SRC_INTERNAL\n", 85 | "\n", 86 | "\n", 87 | "# Reset generator\n", 88 | "rp.rp_GenReset()\n", 89 | "\n", 90 | "###### Generation #####\n", 91 | "# OUT1\n", 92 | "rp.rp_GenWaveform(channel, waveform)\n", 93 | "rp.rp_GenFreqDirect(channel, freq)\n", 94 | "rp.rp_GenAmp(channel, ampl)\n", 95 | "\n", 96 | "# OUT2\n", 97 | "rp.rp_GenWaveform(channel2, waveform)\n", 98 | "rp.rp_GenFreqDirect(channel2, freq)\n", 99 | "rp.rp_GenAmp(channel2, ampl)\n", 100 | "\n", 101 | "# Specify generator trigger source\n", 102 | "rp.rp_GenTriggerSource(channel, gen_trig_sour)\n", 103 | "\n", 104 | "# Enable outputs on both channels synchronuously\n", 105 | "rp.rp_GenOutEnableSync(True)\n", 106 | "\n", 107 | "# Syncronise and trigger output channels\n", 108 | "rp.rp_GenSynchronise()\n" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "# Release resources\n", 118 | "rp.rp_Release()" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "### Note\n", 126 | "There are a lot of different commands for the Generation. The list of available functions is quite an achievement to read through, so from now on, please refer to the *C and Python API section* of the [SCPI & API command list](https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/command_list.html#list-of-supported-scpi-api-commands) for all available commands.\n" 127 | ] 128 | } 129 | ], 130 | "metadata": { 131 | "kernelspec": { 132 | "display_name": "Python 3", 133 | "language": "python", 134 | "name": "python3" 135 | }, 136 | "language_info": { 137 | "codemirror_mode": { 138 | "name": "ipython", 139 | "version": 3 140 | }, 141 | "file_extension": ".py", 142 | "mimetype": "text/x-python", 143 | "name": "python", 144 | "nbconvert_exporter": "python", 145 | "pygments_lexer": "ipython3", 146 | "version": "3.5.2" 147 | } 148 | }, 149 | "nbformat": 4, 150 | "nbformat_minor": 2 151 | } 152 | -------------------------------------------------------------------------------- /examples/hardware/hwid.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Hardware identification" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Import Red Pitaya library." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "import time\n", 24 | "from rp_overlay import overlay\n", 25 | "import rp" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "Load the *v0.94* FPGA image into the Xilinx Zynq SoC." 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "fpga = overlay()" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "Initialize the interface." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "rp.rp_Init()" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "Display the Red Pitaya Version and the Hardware ID. The *hardware identification* register is not very useful, since the number never changes. Red Pitaya *Version* might be relevant to some board-model-specific applications." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "print(f'My Red Pitaya version: {rp.rp_GetVersion()}')\n", 74 | "print(f'My Red Pitaya HWID: {rp.rp_IdGetID()[1]}')" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "Print *Zynq FPGA* **DNA** number." 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "print(f'DNA number: {rp.rp_IdGetDNA()[1]}')" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": { 96 | "collapsed": true, 97 | "jupyter": { 98 | "outputs_hidden": true 99 | } 100 | }, 101 | "source": [ 102 | "Release resources." 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "rp.rp_Release()" 112 | ] 113 | } 114 | ], 115 | "metadata": { 116 | "kernelspec": { 117 | "display_name": "Python 3 (ipykernel)", 118 | "language": "python", 119 | "name": "python3" 120 | }, 121 | "language_info": { 122 | "codemirror_mode": { 123 | "name": "ipython", 124 | "version": 3 125 | }, 126 | "file_extension": ".py", 127 | "mimetype": "text/x-python", 128 | "name": "python", 129 | "nbconvert_exporter": "python", 130 | "pygments_lexer": "ipython3", 131 | "version": "3.10.12" 132 | } 133 | }, 134 | "nbformat": 4, 135 | "nbformat_minor": 4 136 | } 137 | -------------------------------------------------------------------------------- /examples/img/FastIOLoopBack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/img/FastIOLoopBack.png -------------------------------------------------------------------------------- /examples/img/LED-blink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/img/LED-blink.gif -------------------------------------------------------------------------------- /examples/img/RedPitaya_pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/img/RedPitaya_pinout.jpg -------------------------------------------------------------------------------- /examples/img/generate_continous_signal_on_fast_analog_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/img/generate_continous_signal_on_fast_analog_output.png -------------------------------------------------------------------------------- /examples/img/on_given_trigger_acquire_signal_on_fast_analog_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/img/on_given_trigger_acquire_signal_on_fast_analog_input.png -------------------------------------------------------------------------------- /examples/outdated/exam_temp.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Setup\n", 8 | "- Red Pitaya STEMlab board + sensor shield\n", 9 | "- Grove temperature sensor" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Temperature sensor\n", 17 | "The Grove - Temperature Sensor uses a Thermistor to detect the ambient temperature. The resistance of a thermistor will increase when the ambient temperature decreases. It's this characteristic that we use to calculate the ambient temperature. The detectable range of this sensor is -40 - 125ºC, and the accuracy is ±1.5ºC\n", 18 | "Datasheet: [NCP18WF104F03RC](http://wiki.seeed.cc/Grove-Temperature_Sensor_V1.2/) \n", 19 | "![temp_sensor](img/temp_sensor.jpg)\n", 20 | "![temp_sensor_sch](img/temp_sensor_sch.png)" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "from redpitaya.overlay.mercury import mercury as FPGA\n", 30 | "overlay = FPGA()\n", 31 | "ANALOG = FPGA.analog_in(0) # define which pin will be used for temperature sensor" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "# Temperature vs. NTC resistance \n", 41 | "import math\n", 42 | "import matplotlib.pyplot as plt\n", 43 | "import time\n", 44 | "from redpitaya.overlay.mercury import mercury as FPGA\n", 45 | "overlay = FPGA()\n", 46 | "ANALOG = FPGA.analog_in(0) # define which pin will be used for temperature sensor\n", 47 | "\n", 48 | "def res_to_temp(Rntc):\n", 49 | " B = 4275; # B value of the thermistor\n", 50 | " return (1.0/(math.log10(Rntc/100000.0)/B+1/298.15)-273.15) #convert to temperature via datasheet \n", 51 | "temp = [ res_to_temp(R) for R in range(10000,300000,100)]\n", 52 | "plt.plot(range(10000,300000,100), temp)\n", 53 | "plt.xlabel('Rntc[ohm]')\n", 54 | "plt.ylabel('Temperature[*C]')\n", 55 | "plt.show()" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "## Reading temperature sensor\n", 63 | "\n", 64 | "To read the temperature we need to read the voltage value and convert it to temperature." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "def temp():\n", 74 | " Va0=ANALOG.read() # read voltage of sensor\n", 75 | " R0 = 100000; # R0 = 100k\n", 76 | " Rntc = 3.3/(Va0)-1.0 \n", 77 | " Rntc = 100000.0*Rntc # thermistor resistance\n", 78 | " return (res_to_temp(Rntc),Va0);\n", 79 | "r=temp()\n", 80 | "\n", 81 | "print(\"voltage={:.2f}V temp {:.2f}℃\".format(r[1],r[0]) )" 82 | ] 83 | } 84 | ], 85 | "metadata": { 86 | "kernelspec": { 87 | "display_name": "Python 3", 88 | "language": "python", 89 | "name": "python3" 90 | }, 91 | "language_info": { 92 | "codemirror_mode": { 93 | "name": "ipython", 94 | "version": 3 95 | }, 96 | "file_extension": ".py", 97 | "mimetype": "text/x-python", 98 | "name": "python", 99 | "nbconvert_exporter": "python", 100 | "pygments_lexer": "ipython3", 101 | "version": "3.5.2" 102 | } 103 | }, 104 | "nbformat": 4, 105 | "nbformat_minor": 2 106 | } 107 | -------------------------------------------------------------------------------- /examples/outdated/home_automation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Home heating system / temperature regulator\n", 8 | "In this experiment we will present basic heating on/off system regulator with a hysteresis.\n", 9 | "Even very modern thermostats like NEST are still primarly based on old ON/OFF regulaton method. \n", 10 | "![nest](img/nest.jpeg)" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "## Basic principle\n", 18 | "User sets a desired temperature that is compared to measured temperature. If the measured temperature is < set temperature, we turn heater on, but if measured tempreature > set temperature we turn it off.\n", 19 | "![on_off_control](img/on_off_control.png)" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "## Setup\n", 27 | "- Red Pitaya STEMlab board + sensor shield\n", 28 | "- Grove temperature sensor & LED diode for heater states indicator (optional relay that drives heater)\n", 29 | "![temp_reg_setup](img/temp_reg_setup.jpg)" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "## Temperature sensor\n", 37 | "The Grove - Temperature Sensor uses a Thermistor to detect the ambient temperature. The resistance of a thermistor will increase when the ambient temperature decreases. It's this characteristic that we use to calculate the ambient temperature. The detectable range of this sensor is -40 - 125ºC, and the accuracy is ±1.5ºC\n", 38 | "Datasheet: [NCP18WF104F03RC](http://wiki.seeed.cc/Grove-Temperature_Sensor_V1.2/) \n", 39 | "![temp_sensor](img/temp_sensor.jpg)\n", 40 | "![temp_sensor_sch](img/temp_sensor_sch.png)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "# Temperature vs. NTC resistance \n", 50 | "import math\n", 51 | "import matplotlib.pyplot as plt\n", 52 | "import time\n", 53 | "from redpitaya.overlay.mercury import mercury as FPGA\n", 54 | "overlay = FPGA()\n", 55 | "ANALOG = FPGA.analog_in(0) # define which pin will be used for temperature sensor\n", 56 | "\n", 57 | "def res_to_temp(Rntc):\n", 58 | " B = 4275; # B value of the thermistor\n", 59 | " return (1.0/(math.log10(Rntc/100000.0)/B+1/298.15)-273.15) #convert to temperature via datasheet \n", 60 | "temp = [ res_to_temp(R) for R in range(10000,300000,100)]\n", 61 | "plt.plot(range(10000,300000,100), temp)\n", 62 | "plt.xlabel('Rntc[ohm]')\n", 63 | "plt.ylabel('Temperature[*C]')\n", 64 | "plt.show()" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "## Reading temperature sensor\n", 72 | "\n", 73 | "To read the temperature we need to read the voltage value and convert it to temperature." 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "def temp():\n", 83 | " Va0=ANALOG.read() # read voltage of sensor\n", 84 | " R0 = 100000; # R0 = 100k\n", 85 | " Rntc = 3.3/(Va0)-1.0 \n", 86 | " Rntc = 100000.0*Rntc # thermistor resistance\n", 87 | " return (res_to_temp(Rntc),Va0);\n", 88 | "r=temp()\n", 89 | "\n", 90 | "print(\"voltage={:.2f}V temp {:.2f}℃\".format(r[1],r[0]) )" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "## Simple controll of LED\n", 98 | "\n", 99 | "LEDs are controlled with GPIOs." 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": { 106 | "collapsed": true 107 | }, 108 | "outputs": [], 109 | "source": [ 110 | "GPIO = FPGA.gpio\n", 111 | "import time" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "gpio_o = GPIO('p', 0, \"out\")\n", 121 | "gpio_o.write(True)\n", 122 | "time.sleep(1)\n", 123 | "gpio_o.write(False)" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "# Simple Home Heating" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": null, 136 | "metadata": { 137 | "scrolled": true 138 | }, 139 | "outputs": [], 140 | "source": [ 141 | "import time\n", 142 | "\n", 143 | "from bokeh.io import push_notebook, show, output_notebook\n", 144 | "from bokeh.models import HoverTool, Range1d\n", 145 | "from bokeh.plotting import figure\n", 146 | "from bokeh.resources import INLINE \n", 147 | "output_notebook(resources=INLINE)" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": { 154 | "scrolled": false 155 | }, 156 | "outputs": [], 157 | "source": [ 158 | "colors = ('red', 'blue', 'green', 'orange')\n", 159 | "legends = ('temperature', 'setTemp+hysteresis','setTemp-hysteresis', 'heater State')\n", 160 | "hover = HoverTool(mode = 'vline', tooltips=[(\"T\", \"@y\")])\n", 161 | "tools = \"pan,wheel_zoom,box_zoom,reset,crosshair\"\n", 162 | "p = figure(plot_height=400, plot_width=900, title=\"Home heating system\", toolbar_location=\"above\", tools=(tools, hover))\n", 163 | "p.xaxis.axis_label='time [s]'\n", 164 | "p.y_range=Range1d(20, 35)\n", 165 | "p.yaxis.axis_label='temperature [℃]'\n", 166 | "\n", 167 | "# get and explicit handle to update the next show cell with\n", 168 | "# a simple ON/OFF regulator with hysteresis\n", 169 | "target = show(p, notebook_handle=True)" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": null, 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "# a simple ON/OFF regulator with hysteresis\n", 179 | "HYSTERESIS=0.5\n", 180 | "setTemp=28\n", 181 | "heaterState=0\n", 182 | "chn=4\n", 183 | "\n", 184 | "T = 1 # sampling period\n", 185 | "HYST_HI=setTemp+HYSTERESIS\n", 186 | "HYST_LO=setTemp-HYSTERESIS\n", 187 | "\n", 188 | "x=[0]\n", 189 | "y=[ [temp()[0]], [HYST_HI], [HYST_LO], [heaterState] ]\n", 190 | "r = [p.line(x, y[ch], line_width=1, line_alpha=0.7, color=colors[ch],legend=legends[ch]) for ch in range(chn)]\n", 191 | "\n", 192 | "# take 30 samples while simultaneously plotting the plot\n", 193 | "for i in range(30):\n", 194 | " x.append(0) if i == 0 else x.append(x[-1]+T)\n", 195 | " temperature=temp()[0]\n", 196 | " \n", 197 | " # Hysteresis\n", 198 | " if (temperature < HYST_LO): #turn heating ON (LED)\n", 199 | " gpio_o.write(True)\n", 200 | " heaterState=1\n", 201 | " elif (temperature > HYST_HI): #turn heating OFF (LED)\n", 202 | " heaterState=0\n", 203 | " gpio_o.write(False) \n", 204 | " \n", 205 | " r[0].data_source.data['y'].append(temperature) # store temperature\n", 206 | " r[1].data_source.data['y'].append(HYST_HI) # store set temperature + hysteresis\n", 207 | " r[2].data_source.data['y'].append(HYST_LO) # store set temperature - hysteresis\n", 208 | " r[3].data_source.data['y'].append(heaterState*22) # store heater state\n", 209 | " \n", 210 | " # push updates to the plot continuously using the handle (intererrupt the notebook kernel to stop)\n", 211 | " push_notebook(handle=target)\n", 212 | " time.sleep(T)" 213 | ] 214 | } 215 | ], 216 | "metadata": { 217 | "kernelspec": { 218 | "display_name": "Python 3", 219 | "language": "python", 220 | "name": "python3" 221 | }, 222 | "language_info": { 223 | "codemirror_mode": { 224 | "name": "ipython", 225 | "version": 3 226 | }, 227 | "file_extension": ".py", 228 | "mimetype": "text/x-python", 229 | "name": "python", 230 | "nbconvert_exporter": "python", 231 | "pygments_lexer": "ipython3", 232 | "version": "3.5.2" 233 | } 234 | }, 235 | "nbformat": 4, 236 | "nbformat_minor": 2 237 | } 238 | -------------------------------------------------------------------------------- /examples/outdated/img/cable_length.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/outdated/img/cable_length.jpg -------------------------------------------------------------------------------- /examples/outdated/img/nest.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/outdated/img/nest.jpeg -------------------------------------------------------------------------------- /examples/outdated/img/on_off_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/outdated/img/on_off_control.png -------------------------------------------------------------------------------- /examples/outdated/img/temp_reg_setup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/outdated/img/temp_reg_setup.jpg -------------------------------------------------------------------------------- /examples/outdated/img/temp_sensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/outdated/img/temp_sensor.jpg -------------------------------------------------------------------------------- /examples/outdated/img/temp_sensor_sch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPitaya/jupyter/cfc9051d7a3518b2cb987337bc1fc068cd5b6c67/examples/outdated/img/temp_sensor_sch.png -------------------------------------------------------------------------------- /examples/outdated/la_trigger.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Logic analyzer trigger" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "An FPGA overlay must be loaded first." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": { 21 | "collapsed": true, 22 | "scrolled": false 23 | }, 24 | "outputs": [], 25 | "source": [ 26 | "from redpitaya.overlay.mercury import mercury as overlay\n", 27 | "fpga = overlay()" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": { 34 | "collapsed": true 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "la = fpga.la()" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "Logic analyzer is configured in a similar way as the oscilloscope,\n", 46 | "except for trigger settings, which can check for masked values on the bus,\n", 47 | "and or posedge/negedge triggers." 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": { 54 | "collapsed": true 55 | }, 56 | "outputs": [], 57 | "source": [ 58 | "# input mask and polarity\n", 59 | "la.input_mask = 0xffff\n", 60 | "la.input_polarity = 0x0000\n", 61 | "\n", 62 | "# data rate decimation\n", 63 | "la.decimation = 1\n", 64 | "\n", 65 | "# trigger timing [sample periods]\n", 66 | "N = la.buffer_size\n", 67 | "la.trigger_pre = N//4 * 1\n", 68 | "la.trigger_post = N//4 * 3\n", 69 | "\n", 70 | "# trigger bit mask, bit values and edges ['neg', 'pos']\n", 71 | "la.trigger_mask = 0x0000\n", 72 | "la.trigger_value = 0x0000\n", 73 | "la.trigger_edge = [0x0100, 0x0000] # enable trigger on edge [pos, neg]\n", 74 | "\n", 75 | "# trigger source is the level trigger from the same input\n", 76 | "la.trig_src = fpga.trig_src[\"la\"]" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": { 83 | "collapsed": true 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "# reset and start\n", 88 | "la.reset()\n", 89 | "la.start()\n", 90 | "# wait for data\n", 91 | "while (la.status_run()): pass\n", 92 | "\n", 93 | "# show only the part of the buffer requested by pre/post trigger timing\n", 94 | "data = la.data(N)" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "In contrast to oscilloscope, the data is not converted to float signals,\n", 102 | "instead integer values are returned." 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": { 109 | "collapsed": true 110 | }, 111 | "outputs": [], 112 | "source": [ 113 | "for i in range(20):\n", 114 | " print(\"{0:4d} = {0:016b}\".format(data[i]))" 115 | ] 116 | } 117 | ], 118 | "metadata": { 119 | "kernelspec": { 120 | "display_name": "Python 3", 121 | "language": "python", 122 | "name": "python3" 123 | }, 124 | "language_info": { 125 | "codemirror_mode": { 126 | "name": "ipython", 127 | "version": 3 128 | }, 129 | "file_extension": ".py", 130 | "mimetype": "text/x-python", 131 | "name": "python", 132 | "nbconvert_exporter": "python", 133 | "pygments_lexer": "ipython3", 134 | "version": "3.5.2" 135 | } 136 | }, 137 | "nbformat": 4, 138 | "nbformat_minor": 2 139 | } 140 | -------------------------------------------------------------------------------- /examples/outdated/lg_counter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Logic generator (counter signal)" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "An FPGA overlay must be loaded first." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "from redpitaya.overlay.mercury import mercury as overlay\n", 26 | "fpga = overlay()" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "Fpga management is used to configure GPIO pins into logic generator mode, instead of the default PS GPIO mode.\n", 34 | "\n", 35 | "Each bit in `gpio_mode` coresponds to one of the 16 GPIO pins.\n", 36 | "* 0 - PS GPIO mode\n", 37 | "* 1 - Logic generator mode" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": { 44 | "collapsed": true 45 | }, 46 | "outputs": [], 47 | "source": [ 48 | "mgmt = fpga.mgmt()" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": { 55 | "collapsed": true 56 | }, 57 | "outputs": [], 58 | "source": [ 59 | "mgmt.gpio_mode = 0xffff" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "Compared to the arbitrary signal generator, the logic generator only supports burst mode.\n", 67 | "The given example creates a binary counter, which can be used for debugging." 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": { 74 | "collapsed": true 75 | }, 76 | "outputs": [], 77 | "source": [ 78 | "lg = fpga.lg()" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": { 85 | "collapsed": true 86 | }, 87 | "outputs": [], 88 | "source": [ 89 | "# buffer waveform and sample timing\n", 90 | "lg.waveform = range(lg.buffer_size)\n", 91 | "\n", 92 | "# repeat the entire buffere indefinitely\n", 93 | "lg.burst_data_repetitions = 1\n", 94 | "lg.burst_data_length = lg.buffer_size\n", 95 | "lg.burst_period_length = lg.buffer_size\n", 96 | "lg.burst_period_number = 0\n", 97 | "\n", 98 | "# set output amplitude, offset and enable it\n", 99 | "lg.enable = 0xffff # all pins have outputs enabled (for both output values 0/1)\n", 100 | "lg.mask = 0x0000 # all bits come from ASG, none are constants\n", 101 | "lg.value = 0x0000 # the constant pin values are irrelevant since they are not used\n", 102 | "\n", 103 | "# reset, start and trigger generator to get the first burst\n", 104 | "lg.reset()\n", 105 | "lg.start()\n", 106 | "lg.trigger()" 107 | ] 108 | } 109 | ], 110 | "metadata": { 111 | "kernelspec": { 112 | "display_name": "Python 3", 113 | "language": "python", 114 | "name": "python3" 115 | }, 116 | "language_info": { 117 | "codemirror_mode": { 118 | "name": "ipython", 119 | "version": 3 120 | }, 121 | "file_extension": ".py", 122 | "mimetype": "text/x-python", 123 | "name": "python", 124 | "nbconvert_exporter": "python", 125 | "pygments_lexer": "ipython3", 126 | "version": "3.5.2" 127 | } 128 | }, 129 | "nbformat": 4, 130 | "nbformat_minor": 2 131 | } 132 | -------------------------------------------------------------------------------- /experiments/axi4lite_gpio.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "**NOTE: This is experimental code, not intended as an example.**\n", 8 | "\n", 9 | "Verilog RTL code and some block diagram code (AXI3 to AXI4-lite conversion) are in the `fpga/prj/axi4lite` directory.\n", 10 | "\n", 11 | "The FPGA image contains a single slave device connected to GPIO and LED pins.\n", 12 | "The slave system bus was recoded from the previous undocumented bus to a standard *AXI4-Lite* interface.\n", 13 | "The clock for the system bus is derived from the ADC reference oscilator,\n", 14 | "as it should be with hardware synchronous to 125 MHz ADC/DAC.\n", 15 | "\n", 16 | "The Example provides raw Python code for mapping registers, without and C code.\n", 17 | "And would allow developers to write drivers for FPGA HW entirely in Python." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "The first code segment provides register set definition and memory mapping.\n", 25 | "Output, output enable and input registers are all 32bit.\n", 26 | "GPIOs are mapped to bits `[15:0]`and LEDs are mapped to bits `[23:16]`." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": { 33 | "collapsed": false 34 | }, 35 | "outputs": [], 36 | "source": [ 37 | "import os\n", 38 | "import mmap\n", 39 | "import numpy as np\n", 40 | "\n", 41 | "regset_gpio = np.dtype([\n", 42 | " ('o', 'uint32'),\n", 43 | " ('t', 'uint32'),\n", 44 | " ('i', 'uint32')\n", 45 | "])\n", 46 | "\n", 47 | "os.system('cat /opt/redpitaya/fpga/axi4lite/fpga.bit > /dev/xdevcfg')\n", 48 | "\n", 49 | "fd = os.open('/dev/uio/api', os.O_RDWR)\n", 50 | "m = mmap.mmap(fileno=fd, length=mmap.PAGESIZE, offset=0x0)\n", 51 | "gpio_array = np.recarray(1, regset_gpio, buf=m)\n", 52 | "gpio = gpio_array[0]" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "GPIO T signal is inverted output enable, a native notation for Xilinx IOBUF Verilog primitives.\n", 60 | "So to enable an output, the relevant bit in this register should be set to `0`.\n", 61 | "\n", 62 | "The example then alternatively lights up `LED[3:0]` and `LED[7:4]` with a 0.2s delay between them." 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": { 69 | "collapsed": true 70 | }, 71 | "outputs": [], 72 | "source": [ 73 | "import time\n", 74 | "\n", 75 | "# enable output\n", 76 | "gpio.t = 0xffff00\n", 77 | "\n", 78 | "# blink\n", 79 | "for i in range(10):\n", 80 | " gpio.o = 0x0000f0\n", 81 | " time.sleep(0.2)\n", 82 | " gpio.o = 0x00000f\n", 83 | " time.sleep(0.2)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "Reading from the input register should return the value on the pins." 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": false 98 | }, 99 | "outputs": [], 100 | "source": [ 101 | "hex(gpio.i)" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "The next example provides an alternative mapping of the registers.\n", 109 | "It is intended for testing 64 bit read access to registers.\n", 110 | "Although the actual register is 32 bit the AXI interconnect\n", 111 | "should split 64 bit transfers into two 32bit transfers.\n", 112 | "This is usefull for example for 64 bit values like the Zynq DNA code.\n", 113 | "Since the bus is little endian the high part of 64 bit data\n", 114 | "is stored at address `0x0`, while the low part at address `0x4`." 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": { 121 | "collapsed": false 122 | }, 123 | "outputs": [], 124 | "source": [ 125 | "regset_test64 = np.dtype([\n", 126 | " ('ot', 'uint64'),\n", 127 | " ('i', 'uint32')\n", 128 | "])\n", 129 | "\n", 130 | "test64_array = np.recarray(1, regset_test64, buf=m)\n", 131 | "test64 = test64_array[0]\n", 132 | "gpio.t = 0x01234567\n", 133 | "gpio.o = 0x89abcdef\n", 134 | "hex(test64.ot)" 135 | ] 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "metadata": {}, 140 | "source": [ 141 | "Writing 64 bit data and reading it as two 32 bit registers should also work." 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": { 148 | "collapsed": false 149 | }, 150 | "outputs": [], 151 | "source": [ 152 | "test64.ot = 0xfedcba9876543210\n", 153 | "hex(gpio.t), hex(gpio.o)" 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "kernelspec": { 159 | "display_name": "Python 3", 160 | "language": "python", 161 | "name": "python3" 162 | }, 163 | "language_info": { 164 | "codemirror_mode": { 165 | "name": "ipython", 166 | "version": 3 167 | }, 168 | "file_extension": ".py", 169 | "mimetype": "text/x-python", 170 | "name": "python", 171 | "nbconvert_exporter": "python", 172 | "pygments_lexer": "ipython3", 173 | "version": "3.5.2" 174 | } 175 | }, 176 | "nbformat": 4, 177 | "nbformat_minor": 2 178 | } 179 | -------------------------------------------------------------------------------- /experiments/monitor_classic_fpga.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false, 8 | "deletable": true, 9 | "editable": true 10 | }, 11 | "outputs": [], 12 | "source": [ 13 | "from periphery import MMIO\n", 14 | "\n", 15 | "# Open am335x real-time clock subsystem page\n", 16 | "regset_gen = MMIO(0x40200000, 0x30000)\n", 17 | "\n", 18 | "# read control/status registers\n", 19 | "for adr in range(0, 0x44, 0x4):\n", 20 | " print(\"@{adr:08x} = 0x{dat:08x} = {dat:10d} = {dat:032b}\".format(adr=adr, dat=regset_gen.read32(adr)))\n", 21 | "# read the buffer\n", 22 | "for adr in range(0x10000, 0x10040, 0x4):\n", 23 | " print(\"@{adr:08x} = 0x{dat:08x} = {dat:10d} = {dat:032b}\".format(adr=adr, dat=regset_gen.read32(adr)))\n", 24 | "\n", 25 | "regset_gen.close()" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": { 32 | "collapsed": true, 33 | "deletable": true, 34 | "editable": true 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "# just an example on how to write\n", 39 | "#regset_gen.write32(0x0, 0x0080)" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": { 46 | "collapsed": false, 47 | "deletable": true, 48 | "editable": true 49 | }, 50 | "outputs": [], 51 | "source": [ 52 | "from periphery import MMIO\n", 53 | "\n", 54 | "# Open am335x real-time clock subsystem page\n", 55 | "regset_acq = MMIO(0x40100000, 0x30000)\n", 56 | "\n", 57 | "# read control/status registers\n", 58 | "for adr in range(0, 0x100, 0x4):\n", 59 | " print(\"@{adr:08x} = 0x{dat:08x} = {dat:10d} = {dat:032b}\".format(adr=adr, dat=regset_acq.read32(adr)))\n", 60 | "# read the buffer\n", 61 | "for adr in range(0x10000, 0x10040, 0x4):\n", 62 | " print(\"@{adr:08x} = 0x{dat:08x} = {dat:10d} = {dat:032b}\".format(adr=adr, dat=regset_acq.read32(adr)))\n", 63 | "\n", 64 | "regset_acq.close()" 65 | ] 66 | } 67 | ], 68 | "metadata": { 69 | "kernelspec": { 70 | "display_name": "Python 3", 71 | "language": "python", 72 | "name": "python3" 73 | }, 74 | "language_info": { 75 | "codemirror_mode": { 76 | "name": "ipython", 77 | "version": 3 78 | }, 79 | "file_extension": ".py", 80 | "mimetype": "text/x-python", 81 | "name": "python", 82 | "nbconvert_exporter": "python", 83 | "pygments_lexer": "ipython3", 84 | "version": "3.5.2" 85 | } 86 | }, 87 | "nbformat": 4, 88 | "nbformat_minor": 2 89 | } 90 | -------------------------------------------------------------------------------- /experiments/scope_filter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Scope filter\n", 8 | "\n", 9 | "```\n", 10 | "Legend:\n", 11 | "R01, R02, R1, R2, R3, R4, R5 registers\n", 12 | "SHR n - right shift for n bits\n", 13 | "SHL n - left shift for n bits\n", 14 | "BB - zero for FIR part of equalization filter\n", 15 | "AA - pole for IIR part of equalization filter\n", 16 | "PP - pole for IIR part of shaping filter\n", 17 | "KK - gain\n", 18 | "Transfer function:\n", 19 | "H[z]=K*(z-B) / (z^4*(z-P) * (z-A))\n", 20 | "where:\n", 21 | "K=KK/2^24\n", 22 | "B=1-(BB/2^28)\n", 23 | "P=PP/2^16\n", 24 | "A=1-(AA/2^25)\n", 25 | "```\n", 26 | "\n", 27 | "$$ H[z] = \\frac {z K - B K} {z^4*(z^2 - z (P+A) + P A)} $$\n", 28 | "\n", 29 | "$$ H[z] = \\frac {z K - B K} {z^6 - z^5 (P+A) + z^4 P A} $$" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "metadata": { 36 | "collapsed": false 37 | }, 38 | "outputs": [], 39 | "source": [ 40 | "from scipy import signal\n", 41 | "import matplotlib.pyplot as plt\n", 42 | "\n", 43 | "AA = 0x7D93\n", 44 | "BB = 0x437C7\n", 45 | "PP = 0x2666\n", 46 | "KK = 0xd9999a\n", 47 | "\n", 48 | "K=KK/2**24\n", 49 | "B=1-(BB/2**28)\n", 50 | "P=PP/2**16\n", 51 | "A=1-(AA/2**25)\n", 52 | "\n", 53 | "num = [K, -K*B]\n", 54 | "den = [1, -(P+A), P*A, 0, 0, 0, 0]\n", 55 | "\n", 56 | "scope_filter = signal.TransferFunction(num, den, dt=0.000000008)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": { 63 | "collapsed": false 64 | }, 65 | "outputs": [], 66 | "source": [ 67 | "w, mag, phase = signal.dbode(scope_filter)\n", 68 | "\n", 69 | "plt.figure()\n", 70 | "plt.semilogx(w, mag) # Bode magnitude plot\n", 71 | "plt.figure()\n", 72 | "plt.semilogx(w, phase) # Bode phase plot\n", 73 | "plt.show()" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": { 80 | "collapsed": false 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "from scipy import __version__\n", 85 | "__version__" 86 | ] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "Python 3", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.5.2" 106 | } 107 | }, 108 | "nbformat": 4, 109 | "nbformat_minor": 2 110 | } 111 | -------------------------------------------------------------------------------- /redpitaya/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['overlay', 'drv', 'app'] 2 | -------------------------------------------------------------------------------- /redpitaya/app/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['generator', 'oscilloscope'] 2 | -------------------------------------------------------------------------------- /redpitaya/app/generator.py: -------------------------------------------------------------------------------- 1 | # FPGA configuration and API 2 | from redpitaya.overlay.mercury import mercury as overlay 3 | 4 | # system and mathematics libraries 5 | import time 6 | import math 7 | import numpy as np 8 | 9 | # visualization 10 | from bokeh.io import push_notebook, show, output_notebook 11 | from bokeh.models import HoverTool, Range1d 12 | from bokeh.plotting import figure 13 | from bokeh.layouts import widgetbox 14 | from bokeh.resources import INLINE 15 | 16 | # widgets 17 | from IPython.display import display 18 | import ipywidgets as ipw 19 | 20 | class generator (object): 21 | def __init__ (self, channels = [0, 1]): 22 | """Generator application""" 23 | 24 | # instantiate both generators 25 | self.channels = channels 26 | 27 | # this will load the FPGA 28 | try: 29 | self.ovl = overlay() 30 | except ResourceWarning: 31 | print ("FPGA bitstream is already loaded") 32 | # wait a bit for the overlay to be properly applied 33 | # TODO it should be automated in the library 34 | time.sleep(0.5) 35 | 36 | # generators 37 | self.gen = [self.channel(ch) for ch in self.channels] 38 | 39 | # display widgets 40 | for ch in self.channels: 41 | self.gen[ch].display() 42 | 43 | def __del__ (self): 44 | # close widgets 45 | for ch in self.channels: 46 | self.gen[ch].close() 47 | # delete generator and overlay objects 48 | del (self.gen) 49 | # TODO: overlay should not be removed if a different app added it 50 | del (self.ovl) 51 | 52 | class channel (overlay.gen): 53 | # waveform defaults 54 | form = 'sin' 55 | duty = 0.5 56 | 57 | def set_waveform (self): 58 | if self.form == 'sin': 59 | self.waveform = self.sin() 60 | elif self.form == 'square': 61 | self.waveform = self.square(self.duty) 62 | elif self.form == 'sawtooth': 63 | self.waveform = self.sawtooth(self.duty) 64 | 65 | def __init__ (self, ch): 66 | 67 | super().__init__(ch) 68 | 69 | self.reset() 70 | self.sync_src = overlay.sync_src['gen'+str(ch)] 71 | self.trig_src = 0 72 | self.mode = 'PERIODIC' 73 | self.amplitude = 0 74 | self.offset = 0 75 | self.set_waveform() 76 | self.frequency = self._f_one 77 | self.phase = 0 78 | self.start() 79 | self.trigger() 80 | 81 | fl_min = math.log10(self._f_min) 82 | fl_max = math.log10(self._f_max) 83 | fl_one = math.log10(self._f_one) 84 | 85 | # create widgets 86 | self.w_enable = ipw.ToggleButton (value=False, description='output enable') 87 | self.w_waveform = ipw.ToggleButtons(value='sin', options=['sin', 'square', 'sawtooth'], description='waveform') 88 | self.w_duty = ipw.FloatSlider (value=0.5, min=0.0, max=1.0, step=0.01, description='duty') 89 | self.w_amplitude = ipw.FloatSlider (value=0, min=-1.0, max=+1.0, step=0.02, description='amplitude') 90 | self.w_offset = ipw.FloatSlider (value=0, min=-1.0, max=+1.0, step=0.02, description='offset') 91 | self.w_frequency = ipw.FloatSlider (value=fl_one, min=fl_min, max=fl_max, step=0.02, description='frequency') 92 | self.w_phase = ipw.FloatSlider (value=0, min=0, max=360, step=1, description='phase') 93 | 94 | # style widgets 95 | self.w_enable.layout = ipw.Layout(width='100%') 96 | self.w_duty.layout = ipw.Layout(width='100%') 97 | self.w_amplitude.layout = ipw.Layout(width='100%') 98 | self.w_offset.layout = ipw.Layout(width='100%') 99 | self.w_frequency.layout = ipw.Layout(width='100%') 100 | self.w_phase.layout = ipw.Layout(width='100%') 101 | 102 | self.w_enable.observe (self.clb_enable , names='value') 103 | self.w_waveform.observe (self.clb_waveform , names='value') 104 | self.w_duty.observe (self.clb_duty , names='value') 105 | self.w_amplitude.observe(self.clb_amplitude, names='value') 106 | self.w_offset.observe (self.clb_offset , names='value') 107 | self.w_frequency.observe(self.clb_frequency, names='value') 108 | self.w_phase.observe (self.clb_phase , names='value') 109 | 110 | def clb_enable (self, change): 111 | self.enable = change['new'] 112 | 113 | def clb_waveform (self, change): 114 | self.form = change['new'] 115 | self.set_waveform() 116 | 117 | def clb_duty (self, change): 118 | self.duty = change['new'] 119 | self.set_waveform() 120 | 121 | def clb_amplitude (self, change): 122 | self.amplitude = change['new'] 123 | 124 | def clb_offset (self, change): 125 | self.offset = change['new'] 126 | 127 | def clb_frequency (self, change): 128 | self.frequency = math.pow(10, change['new']) 129 | 130 | def clb_phase (self, change): 131 | self.phase = change['new'] 132 | 133 | def display (self): 134 | layout = ipw.Layout(border='solid 2px', margin='2px 2px 2px 2px') 135 | # labels 136 | self.lbl_waveform = ipw.Label(value="waveform shapes" , layout = ipw.Layout(width='100%')) 137 | self.lbl_output = ipw.Label(value="amplitude [V] and offset [V]" , layout = ipw.Layout(width='100%')) 138 | self.lbl_frequency = ipw.Label(value="frequency [Hz] and phase [DEG]", layout = ipw.Layout(width='100%')) 139 | self.lbl_channel = ipw.Label(value="generator" , layout = ipw.Layout(width='100%')) 140 | # boxes 141 | self.box_enable = ipw.VBox([self.w_enable], layout = ipw.Layout(margin='2px 2px 2px 2px')) 142 | self.box_waveform = ipw.VBox([self.lbl_waveform, self.w_waveform, self.w_duty] , layout = layout) 143 | self.box_output = ipw.VBox([self.lbl_output, self.w_amplitude, self.w_offset], layout = layout) 144 | self.box_frequency = ipw.VBox([self.lbl_frequency, self.w_frequency, self.w_phase] , layout = layout) 145 | self.box_channel = ipw.VBox([self.lbl_channel, 146 | self.box_enable, 147 | self.box_waveform, 148 | self.box_output, 149 | self.box_frequency], 150 | layout = ipw.Layout(border='solid 2px', 151 | padding='2px 2px 2px 2px', 152 | margin='4px 0px 4px 0px') ) 153 | display (self.box_channel) 154 | 155 | def close(self): 156 | # boxes 157 | self.box_channel.close() 158 | self.box_enable.close() 159 | self.box_waveform.close() 160 | self.box_output.close() 161 | self.box_frequency.close() 162 | # labels 163 | self.lbl_waveform.close() 164 | self.lbl_output.close() 165 | self.lbl_frequency.close() 166 | self.lbl_channel.close() 167 | # widgets 168 | self.w_enable.close() 169 | self.w_waveform.close() 170 | self.w_duty.close() 171 | self.w_amplitude.close() 172 | self.w_offset.close() 173 | self.w_frequency.close() 174 | self.w_phase.close() 175 | 176 | def __del__ (self): 177 | # widgets 178 | del(w_enable) 179 | del(w_waveform) 180 | del(w_duty) 181 | del(w_amplitude) 182 | del(w_offset) 183 | del(w_frequency) 184 | del(w_phase) 185 | # calling super class 186 | super().__del__() 187 | -------------------------------------------------------------------------------- /redpitaya/drv/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['overlay', 'uio', 'evn', 'hwid', 'mgmt', 'pdm', 'clb', 'wave', 'gen', 'osc', 'lg', 'la'] -------------------------------------------------------------------------------- /redpitaya/drv/acq.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | import math 4 | 5 | 6 | class acq(object): 7 | CW = 31 #: counter size 8 | _CWr = 2**CW 9 | 10 | class _regset_t(Structure): 11 | _fields_ = [('cfg_pre', c_uint32), # configuration pre trigger 12 | ('cfg_pst', c_uint32), # configuration post trigger 13 | ('sts_pre', c_uint32), # status pre trigger 14 | ('sts_pst', c_uint32)] # status post trigger 15 | 16 | def show_regset(self): 17 | """Print FPGA module register set for debugging purposes.""" 18 | print( 19 | "cfg_pre = 0x{reg:08x} = {reg:10d} # delay pre trigger \n".format(reg=self.regset.acq.cfg_pre) + 20 | "cfg_pst = 0x{reg:08x} = {reg:10d} # delay post trigger \n".format(reg=self.regset.acq.cfg_pst) + 21 | "sts_pre = 0x{reg:08x} = {reg:10d} # status pre trigger \n".format(reg=self.regset.acq.sts_pre) + 22 | "sts_pst = 0x{reg:08x} = {reg:10d} # status post trigger \n".format(reg=self.regset.acq.sts_pst) 23 | ) 24 | 25 | def default(self): 26 | """Set registers into default (power-up) state.""" 27 | self.regset.acq.cfg_pre = 0 28 | self.regset.acq.cfg_pst = 0 29 | 30 | @property 31 | def trigger_pre(self) -> int: 32 | """Pre trigger delay. 33 | 34 | Number of samples stored into the buffer 35 | after start() before a trigger event is accepted. 36 | It makes sense for this number to be up to buffer size. 37 | """ 38 | return self.regset.acq.cfg_pre 39 | 40 | @trigger_pre.setter 41 | def trigger_pre(self, value: int): 42 | if (0 <= value < self._CWr): 43 | self.regset.acq.cfg_pre = value 44 | else: 45 | raise ValueError("Pre trigger delay should be positive and less or equal to {}.".format(self._CWr)) 46 | 47 | @property 48 | def trigger_post(self) -> int: 49 | """Post trigger delay. 50 | 51 | Number of samples stored into the buffer 52 | after a trigger, before writing stops automatically. 53 | It makes sense for this number to be up to buffer size. 54 | """ 55 | return self.regset.acq.cfg_pst 56 | 57 | @trigger_post.setter 58 | def trigger_post(self, value: int): 59 | if (0 <= value < self._CWr): 60 | self.regset.acq.cfg_pst = value 61 | else: 62 | raise ValueError("Post trigger delay should be positive and less or equal to {}.".format(self._CWr)) 63 | # TODO check range 64 | 65 | @property 66 | def trigger_pre_status(self) -> int: 67 | """Pre trigger sample counter status.""" 68 | return (self.regset.acq.sts_pre & 0x7fffffff) 69 | 70 | @property 71 | def trigger_post_status(self) -> int: 72 | """Post trigger sample counter status.""" 73 | return (self.regset.acq.sts_pst & 0x7fffffff) 74 | -------------------------------------------------------------------------------- /redpitaya/drv/asg_bst.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class asg_bst (object): 5 | """ 6 | Generator FPGA module driver. 7 | """ 8 | 9 | # burst counter parameters 10 | CWR = 14 #: counter width - burst data repetition 11 | CWL = 32 #: counter width - burst period length 12 | CWN = 16 #: counter width - burst period number 13 | _CWRr = 2**CWR 14 | _CWLr = 2**CWL 15 | _CWNr = 2**CWN 16 | 17 | class _regset_t(Structure): 18 | _fields_ = [('cfg_bdr', c_uint32), # burst data repetitions 19 | ('cfg_bdl', c_uint32), # burst data length 20 | ('cfg_bpl', c_uint32), # burst period length (data+pause) 21 | ('cfg_bpn', c_uint32), # burst period number 22 | ('sts_bln', c_uint32), # length (current position inside burst length) 23 | ('sts_bnm', c_uint32)] # number (current burst counter) 24 | 25 | def default(self): 26 | """Set registers into default (power-up) state.""" 27 | self.regset.bst.cfg_bdr = 0 28 | self.regset.bst.cfg_bdl = 0 29 | self.regset.bst.cfg_bpl = 0 30 | self.regset.bst.cfg_bpn = 0 31 | 32 | def show_regset(self): 33 | """Print FPGA module register set for debugging purposes.""" 34 | print( 35 | "cfg_bdr = 0x{reg:08x} = {reg:10d} # burst data repetition \n".format(reg=self.regset.bst.cfg_bdr) + 36 | "cfg_bdl = 0x{reg:08x} = {reg:10d} # burst data length \n".format(reg=self.regset.bst.cfg_bdl) + 37 | "cfg_bpl = 0x{reg:08x} = {reg:10d} # burst period length \n".format(reg=self.regset.bst.cfg_bpl) + 38 | "cfg_bpn = 0x{reg:08x} = {reg:10d} # burst period number \n".format(reg=self.regset.bst.cfg_bpn) + 39 | "sts_bln = 0x{reg:08x} = {reg:10d} # burst length (current position)\n".format(reg=self.regset.bst.sts_bln) + 40 | "sts_bnm = 0x{reg:08x} = {reg:10d} # burst number (current counter) \n".format(reg=self.regset.bst.sts_bnm) 41 | ) 42 | 43 | @property 44 | def burst_data_repetitions(self) -> int: 45 | """Burst data repetitions, up to 2**`CWR`.""" 46 | return (self.regset.bst.cfg_bdr + 1) 47 | 48 | @burst_data_repetitions.setter 49 | def burst_data_repetitions(self, value: int): 50 | if (0 < value <= self._CWRr): 51 | self.regset.bst.cfg_bdr = value - 1 52 | else: 53 | raise ValueError("Burst data repetitions should be in range from 1 to {}.".format(self._CWRr)) 54 | 55 | @property 56 | def burst_data_length(self) -> int: 57 | """Burst data length, up to waveform array size.""" 58 | return (self.regset.bst.cfg_bdl + 1) 59 | 60 | @burst_data_length.setter 61 | def burst_data_length(self, value: int): 62 | if (0 < value <= self.buffer_size): 63 | self.regset.bst.cfg_bdl = value - 1 64 | else: 65 | raise ValueError("Burst data length should be in range from 1 to {}.".format(self.buffer_size)) 66 | 67 | @property 68 | def burst_period_length(self) -> int: 69 | """Burst period length (data+pause), up to 2**`CWL`.""" 70 | return (self.regset.bst.cfg_bpl + 1) 71 | 72 | @burst_period_length.setter 73 | def burst_period_length(self, value: int): 74 | if (0 < value <= self._CWLr): 75 | self.regset.bst.cfg_bpl = value - 1 76 | else: 77 | raise ValueError("Burst period length should be in range from 1 to {}.".format(self._CWLr)) 78 | 79 | @property 80 | def burst_period_number(self) -> int: 81 | """Number of burst period reperitions, up to 2**`CWN`, value `0` produces infinite repetition.""" 82 | value = self.regset.bst.cfg_bpn 83 | if (value & 0x80000000): 84 | return (0) 85 | else: 86 | return (value + 1) 87 | 88 | @burst_period_number.setter 89 | def burst_period_number(self, value: int): 90 | if (value == 0): 91 | self.regset.bst.cfg_bpn = 0x80000000 92 | elif (0 < value <= self._CWNr): 93 | self.regset.bst.cfg_bpn = value - 1 94 | else: 95 | raise ValueError("Burst period number should be in range from 1 to {}, or 0 for inifinite bursts.".format(self._CWNr)) 96 | -------------------------------------------------------------------------------- /redpitaya/drv/asg_per.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class asg_per(object): 5 | """ 6 | Generator FPGA module driver. 7 | """ 8 | 9 | # buffer parameters (fixed point number uM.F) 10 | CWM = 14 #: counter width - magnitude (fixed point integer) 11 | CWF = 16 #: counter width - fraction (fixed point fraction) 12 | CW = CWM + CWF 13 | # buffer counter ranges 14 | _CWMr = 2**CWM 15 | _CWFr = 2**CWF 16 | 17 | class _regset_t(Structure): 18 | _fields_ = [('cfg_siz', c_uint32), # size 19 | ('cfg_off', c_uint32), # offset 20 | ('cfg_ste', c_uint32)] # step 21 | 22 | def default(self): 23 | """Set registers into default (power-up) state.""" 24 | self.regset.per.cfg_siz = 0 25 | self.regset.per.cfg_ste = 0 26 | self.regset.per.cfg_off = 0 27 | 28 | def show_regset(self): 29 | """Print FPGA module register set for debugging purposes.""" 30 | print( 31 | "cfg_siz = 0x{reg:08x} = {reg:10d} # waveform size \n".format(reg=self.regset.per.cfg_siz) + 32 | "cfg_off = 0x{reg:08x} = {reg:10d} # waveform offset\n".format(reg=self.regset.per.cfg_off) + 33 | "cfg_ste = 0x{reg:08x} = {reg:10d} # waveform step \n".format(reg=self.regset.per.cfg_ste) 34 | ) 35 | 36 | @property 37 | def waveform_size(self) -> int: 38 | """Waveform size.""" 39 | return ((self.regset.per.cfg_siz + 1) >> self.CWF) 40 | 41 | @waveform_size.setter 42 | def waveform_size(self, value: int): 43 | if (0 < value <= self.buffer_size): 44 | self.regset.per.cfg_siz = (value << self.CWF) - 1 45 | else: 46 | raise ValueError("Waveform size should in range from 1 to buffer size. buffer_size = {}".format(self.buffer_size)) 47 | 48 | @property 49 | def frequency(self) -> float: 50 | """Periodic signal frequency up to FS/2""" 51 | siz = self.regset.per.cfg_siz + 1 52 | ste = self.regset.per.cfg_ste + 1 53 | return (ste / siz * self.FS) 54 | 55 | @frequency.setter 56 | def frequency(self, value: float): 57 | if (value < self.FS/2): 58 | siz = self.regset.per.cfg_siz + 1 59 | self.regset.per.cfg_ste = int(siz * (value / self.FS)) - 1 60 | else: 61 | raise ValueError("Frequency should be less then half the sample rate. f < FS/2 = {} Hz".format(self.FS/2)) 62 | 63 | @property 64 | def phase(self) -> float: 65 | """Periodic signal phase in angular degrees""" 66 | siz = self.regset.per.cfg_siz + 1 67 | off = self.regset.per.cfg_off 68 | return (off / siz * 360) 69 | 70 | @phase.setter 71 | def phase(self, value: float): 72 | siz = self.regset.per.cfg_siz + 1 73 | self.regset.per.cfg_off = int(siz * (value % 360) / 360) 74 | -------------------------------------------------------------------------------- /redpitaya/drv/evn.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class evn(): 5 | # control register masks 6 | _CTL_TRG_MASK = 1<<3 # sw trigger bit (sw trigger must be enabled) 7 | _CTL_STP_MASK = 1<<2 # stop/abort; returns 1 when stopped 8 | _CTL_STR_MASK = 1<<1 # start 9 | _CTL_RST_MASK = 1<<0 # reset state machine so that it is in known state 10 | 11 | class _regset_t (Structure): 12 | _fields_ = [('ctl_sts', c_uint32), # control/status register 13 | ('cfg_evn', c_uint32), # software event source select 14 | ('cfg_trg', c_uint32)] # hardware trigger mask 15 | 16 | def default(self): 17 | """Set registers into default (power-up) state.""" 18 | self.regset.evn.cfg_evn = 0 # TODO: it should probably be pointing to itself 19 | self.regset.evn.cfg_trg = 0 20 | 21 | def show_regset(self): 22 | """Print FPGA module register set for debugging purposes.""" 23 | print( 24 | "ctl_sts = 0x{reg:08x} = {reg:10d} # control/status \n".format(reg=self.regset.evn.ctl_sts) + 25 | "cfg_evn = 0x{reg:08x} = {reg:10d} # SW event source select\n".format(reg=self.regset.evn.cfg_evn) + 26 | "cfg_trg = 0x{reg:08x} = {reg:10d} # HW trigger mask \n".format(reg=self.regset.evn.cfg_trg) 27 | ) 28 | 29 | def reset(self): 30 | """Reset state machine, is used to synchronize alwways running streams.""" 31 | self.regset.evn.ctl_sts = self._CTL_RST_MASK 32 | 33 | def start(self): 34 | """Start starte machine.""" 35 | self.regset.evn.ctl_sts = self._CTL_STR_MASK 36 | 37 | def stop(self): 38 | """Stop state machine.""" 39 | self.regset.evn.ctl_sts = self._CTL_STP_MASK 40 | 41 | def trigger(self): 42 | """Activate SW trigger.""" 43 | self.regset.evn.ctl_sts = self._CTL_TRG_MASK 44 | 45 | def start_trigger(self): 46 | """Start state machine and activate SW trigger.""" 47 | self.regset.evn.ctl_sts = self._CTL_TRG_MASK | self._CTL_STR_MASK 48 | 49 | def status_run(self) -> bool: 50 | """Run status.""" 51 | return bool(self.regset.evn.ctl_sts & self._CTL_STR_MASK) 52 | 53 | def status_trigger(self) -> bool: 54 | """Trigger status.""" 55 | return bool(self.regset.evn.ctl_sts & self._CTL_TRG_MASK) 56 | 57 | @property 58 | def sync_src(self) -> int: 59 | """Select for software event sources.""" 60 | return self.regset.evn.cfg_evn 61 | 62 | @sync_src.setter 63 | def sync_src(self, value: int): 64 | self.regset.evn.cfg_evn = value 65 | 66 | @property 67 | def trig_src(self) -> int: 68 | """Enable mask for hardware trigger sources.""" 69 | return self.regset.evn.cfg_trg 70 | 71 | @trig_src.setter 72 | def trig_src(self, value: int): 73 | self.regset.evn.cfg_trg = value 74 | -------------------------------------------------------------------------------- /redpitaya/drv/fixp.py: -------------------------------------------------------------------------------- 1 | class fixp (object): 2 | """Fixed point basic class.""" 3 | __init__(self, s: bool, m: int, f: int): 4 | self.s = s 5 | self.m = m 6 | self.f = f 7 | 8 | @property 9 | def num(self) -> int: 10 | """Number of possible values.""" 11 | return ( (1<<(v.s+v.m+v.f)) ) 12 | 13 | @property 14 | def max(self) -> int: 15 | """Maximum value (positive).""" 16 | return ( (+(1<<( v.m+v.f))-1) ) 17 | 18 | @property 19 | def min(self) -> int: 20 | """Minimum value (nagetive or zero for unsigned).""" 21 | return ((v.s ? (-(1<<( v.m+v.f)) ) : 0)) 22 | 23 | @property 24 | def unit(self) -> int: 25 | """Unit (1) value.""" 26 | return ( (1<<( v.f)) ) 27 | 28 | @property 29 | def bits(self) -> int: 30 | """Number of used bits.""" 31 | return ( (v.s+v.m+v.f) ) 32 | 33 | def float2fixp(self, value: float) -> int: 34 | """Conversion from ``float`` fixed point.""" 35 | if ((not self.s) and (value < 0)): 36 | raise ValueError("This fixed point number is unsigned, so negative values are not supported.") 37 | else: 38 | return int(value*self.unit) 39 | 40 | def fixp2float(self, value: int) -> float: 41 | """Conversion from ``float`` fixed point.""" 42 | return (float(value)/float(self.unit)) 43 | -------------------------------------------------------------------------------- /redpitaya/drv/gen.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | 4 | from enum import Enum 5 | 6 | import mmap 7 | 8 | from .evn import evn 9 | from .asg_per import asg_per 10 | from .asg_bst import asg_bst 11 | from .gen_out import gen_out 12 | from .wave import wave 13 | from .uio import uio 14 | 15 | 16 | class gen(evn, asg_per, asg_bst, gen_out, wave, uio): 17 | """ 18 | Generator FPGA module driver. 19 | """ 20 | 21 | #: sampling frequency 22 | FS = 125000000.0 23 | # linear addition multiplication register width 24 | DW = 14 #: data width - streaming sample 25 | DWM = 14 #: data width - linear gain multiplier 26 | DWS = 14 #: data width - linear offset summand 27 | # fixed point range 28 | _DWr = (1 << (DW -1)) - 1 29 | _DWMr = (1 << (DWM-2)) 30 | _DWSr = (1 << (DWS-1)) - 1 31 | 32 | class _regset_t(Structure): 33 | _fields_ = [('evn', evn._regset_t), 34 | ('rsv_000', c_uint32), 35 | ('cfg_mod', c_uint32), # mode 36 | ('per', asg_per._regset_t), 37 | ('bst', asg_bst._regset_t), 38 | ('rsv_001', c_uint32 * 2), 39 | ('out', gen_out._regset_t)] 40 | 41 | class _buffer_t(Array): 42 | _length_ = 2**14 43 | _type_ = c_int32 44 | 45 | def __init__(self, index: int, uio: str = '/dev/uio/gen'): 46 | """Module instance index should be provided""" 47 | 48 | # use index 49 | uio = uio+str(index) 50 | 51 | # call parent class init to open UIO device and mmap maps 52 | super().__init__(uio) 53 | 54 | # map regset 55 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 56 | # map buffer 57 | self.buffer = self._buffer_t.from_buffer(self.uio_mmaps[1]) 58 | 59 | # calculate constants 60 | self.buffer_size = 2**self.CWM #: buffer size 61 | 62 | # logaritmic scale from 0.116Hz to 62.5Mhz 63 | self._f_min = self.FS / 2**self.CW 64 | self._f_max = self.FS / 2 65 | self._f_one = self.FS / 2**self.CWM 66 | 67 | def __del__(self): 68 | # disable output 69 | self.enable = False 70 | # make sure state machine is not running 71 | self.reset() 72 | # call parent class init to unmap maps and close UIO device 73 | super().__del__() 74 | 75 | def default(self): 76 | """Set registers into default (power-up) state.""" 77 | evn.default(self) 78 | self.regset.cfg_mod = 0 79 | asg_per.default(self) 80 | asg_bst.default(self) 81 | gen_out.default(self) 82 | 83 | def show_regset(self): 84 | """Print FPGA module register set for debugging purposes.""" 85 | evn.show_regset(self) 86 | print( 87 | "cfg_mod = 0x{reg:08x} = {reg:10d} # burst mode\n".format(reg=self.regset.cfg_mod) 88 | ) 89 | asg_per.show_regset(self) 90 | asg_bst.show_regset(self) 91 | gen_out.show_regset(self) 92 | 93 | @property 94 | def waveform(self): 95 | """Waveworm array containing normalized values in the range [-1,1]. 96 | 97 | Array can be up to `buffer_size` samples in length. 98 | """ 99 | scale = float(self._DWr) 100 | # TODO: nparray 101 | return [self.buffer[i] / scale for i in range(self.waveform_size)] 102 | 103 | @waveform.setter 104 | def waveform(self, value): 105 | siz = len(value) 106 | if (siz <= self.buffer_size): 107 | for i in range(siz): 108 | # TODO add saturation 109 | scale = float(self._DWr) 110 | self.buffer[i] = int(value[i] * scale) 111 | self.waveform_size = siz 112 | else: 113 | raise ValueError("Waveform buffer size should not excede buffer size. buffer_size = {}".format(self.buffer_size)) 114 | 115 | class modes(Enum): 116 | PERIODIC = 0x0 117 | BURST = 0x1 118 | 119 | @property 120 | def mode(self) -> str: 121 | """Generator mode: 122 | 123 | * 'PERIODIC' - continuous/periodic signals 124 | * 'BURST' - finite/infinite bursts 125 | """ 126 | return self.modes(self.regset.cfg_mod) 127 | 128 | @mode.setter 129 | def mode(self, value: str): 130 | if isinstance(value, str): 131 | self.regset.cfg_mod = self.modes[value].value 132 | else: 133 | raise ValueError("Generator supports modes ['PERIODIC', 'BURST'].") 134 | -------------------------------------------------------------------------------- /redpitaya/drv/gen_out.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | 4 | 5 | class gen_out(object): 6 | # linear addition multiplication register width 7 | DWM = 14 #: data width - linear gain multiplier 8 | DWS = 14 #: data width - linear offset summand 9 | # fixed point range 10 | _DWMr = (1 << (DWM-2)) 11 | _DWSr = (1 << (DWS-1)) - 1 12 | 13 | class _regset_t(Structure): 14 | _fields_ = [('cfg_mul', c_int32), # multiplier (amplitude) 15 | ('cfg_sum', c_int32), # adder (offset) 16 | ('cfg_ena', c_uint32)] # output enable 17 | 18 | def default(self): 19 | """Set registers into default (power-up) state.""" 20 | self.regset.out.cfg_mul = int(1 * self._DWMr) 21 | self.regset.out.cfg_sum = 0 22 | self.regset.out.cfg_ena = 0 23 | 24 | def show_regset(self): 25 | """Print FPGA module register set for debugging purposes.""" 26 | print( 27 | "cfg_mul = 0x{reg:08x} = {reg:10d} # multiplier (amplitude)\n".format(reg=self.regset.out.cfg_mul) + 28 | "cfg_sum = 0x{reg:08x} = {reg:10d} # adder (offset) \n".format(reg=self.regset.out.cfg_sum) + 29 | "cfg_ena = 0x{reg:08x} = {reg:10d} # output enable \n".format(reg=self.regset.out.cfg_ena) 30 | ) 31 | 32 | @property 33 | def amplitude(self) -> float: 34 | """Output amplitude in range [-1,1] vols.""" 35 | return (self.regset.out.cfg_mul / self._DWMr) 36 | 37 | @amplitude.setter 38 | def amplitude(self, value: float): 39 | if (-1.0 <= value <= 1.0): 40 | self.regset.out.cfg_mul = int(value * self._DWMr) 41 | else: 42 | raise ValueError("Output amplitude should be inside [-1,1] volts.") 43 | 44 | @property 45 | def offset(self) -> float: 46 | """Output offset in range [-1,1] vols.""" 47 | return (self.regset.out.cfg_sum / self._DWSr) 48 | 49 | @offset.setter 50 | def offset(self, value: float): 51 | if (-1.0 <= value <= 1.0): 52 | self.regset.out.cfg_sum = int(value * self._DWSr) 53 | else: 54 | raise ValueError("Output offset should be inside [-1,1] volts.") 55 | 56 | @property 57 | def enable(self) -> bool: 58 | """Output enable boolean value.""" 59 | return bool(self.regset.out.cfg_ena) 60 | 61 | @enable.setter 62 | def enable(self, value: bool): 63 | self.regset.out.cfg_ena = int(value) 64 | -------------------------------------------------------------------------------- /redpitaya/drv/hwid.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | from .uio import uio 4 | 5 | 6 | class hwid(uio): 7 | """Driver for hardware identification module. 8 | 9 | Attributes 10 | ---------- 11 | hwid : int 12 | Red Pitaya FPGA identification number (32bit). 13 | efuse : int 14 | Zynq FPGA efuse (57bit). 15 | dna : int 16 | Zynq FPGA DNA number (57bit). 17 | gith : str 18 | Git hash (160 bits, 40 hex characters) 19 | 20 | .. note:: 21 | 22 | Future releases might provide access to other Zynq FPGA features. 23 | """ 24 | class _regset_t(Structure): 25 | _fields_ = [('hwid' , c_uint32 ), 26 | ('rsv0' , c_uint32 ), # reserved 27 | ('efuse', c_uint32 ), 28 | ('rsv1' , c_uint32 ), # reserved 29 | ('dna' , c_uint32 * 2), 30 | ('rsv3' , c_uint32 * 2), # reserved 31 | ('gith' , c_uint32 * 5)] 32 | 33 | def __init__(self, uio: str = '/dev/uio/hwid'): 34 | super().__init__(uio) 35 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 36 | 37 | def __del__(self): 38 | super().__del__() 39 | 40 | @property 41 | def hwid(self) -> int: 42 | """Red Pitaya FPGA identification number. 43 | 44 | A 32bit read only register defined at FPGA compile time. 45 | """ 46 | return self.regset.hwid 47 | 48 | @property 49 | def efuse(self) -> int: 50 | """Zynq FPGA efuse. 51 | 52 | A 32bit value, read only for now, future versions might provide a convoluted write access scheme. 53 | """ 54 | return self.regset.efuse 55 | 56 | @property 57 | def dna(self) -> int: 58 | """Zynq FPGA DNA number. 59 | 60 | A 57bit read-only value defined in manufacturing. 61 | Can be used as an almost unique device identification. 62 | """ 63 | return ((self.regset.dna[1] << 32) | self.regset.dna[0]) 64 | 65 | @property 66 | def gith(self) -> str: 67 | """Git hash. 68 | 69 | A full SHA-1 hash (160 bits, 40 hex characters) 70 | for the repository from which the FPGA was built. 71 | """ 72 | return (''.join(["{:08x}".format(self.regset.gith[i]) for i in range(5)])) 73 | -------------------------------------------------------------------------------- /redpitaya/drv/la.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | import math 4 | 5 | import mmap 6 | 7 | from .evn import evn 8 | from .acq import acq 9 | from .la_trg import la_trg 10 | from .la_rle import la_rle 11 | from .la_msk import la_msk 12 | from .uio import uio 13 | 14 | 15 | class la(evn, acq, la_trg, la_rle, la_msk, uio): 16 | #: sampling frequency 17 | FS = 125000000.0 18 | #: register width - linear addition multiplication 19 | DW = 16 20 | # fixed point range 21 | _DWr = (1 << (DW-1)) - 1 22 | # buffer parameters 23 | buffer_size = 2**14 #: buffer size 24 | CW = 31 #: counter size 25 | _CWr = 2**CW 26 | 27 | class _regset_t (Structure): 28 | _fields_ = [('evn', evn._regset_t), 29 | ('rsv_000', c_uint32), 30 | ('acq', acq._regset_t), # pre/post trigger counters 31 | ('trg', la_trg._regset_t), # trigger (value, edge) detection 32 | ('rle', la_rle._regset_t), # RLE 33 | ('rsv_001', c_uint32), 34 | ('msk', la_msk._regset_t)] # mask/polarity 35 | 36 | class _buffer_t(Array): 37 | _length_ = 2**14 38 | _type_ = c_int16 39 | 40 | def __init__(self, uio: str = '/dev/uio/la'): 41 | # call parent class init to open UIO device and map regset 42 | super().__init__(uio) 43 | 44 | # map regset 45 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 46 | # map buffer 47 | self.buffer = self._buffer_t.from_buffer(self.uio_mmaps[1]) 48 | 49 | def __del__(self): 50 | # call parent class init to unmap maps and close UIO device 51 | super().__del__() 52 | 53 | def default(self): 54 | """Set registers into default (power-up) state.""" 55 | evn.default(self) 56 | acq.default(self) 57 | la_trg.default(self) 58 | la_rle.default(self) 59 | la_msk.default(self) 60 | 61 | def show_regset(self): 62 | """Print FPGA module register set for debugging purposes.""" 63 | evn.show_regset(self) 64 | acq.show_regset(self) 65 | la_trg.show_regset(self) 66 | la_rle.show_regset(self) 67 | la_msk.show_regset(self) 68 | 69 | @property 70 | def sample_rate(self) -> float: 71 | """Sample rate depending on decimation factor.""" 72 | return (self.FS / self.decimation) 73 | 74 | @property 75 | def sample_period(self) -> float: 76 | """Sample period depending on decimation factor.""" 77 | return (1 / self.sample_rate) 78 | 79 | @property 80 | def pointer(self): 81 | # mask out overflow bit and sum pre and post trigger counters 82 | cnt = self.trigger_pre_status + self.trigger_post_status 83 | adr = cnt % self.buffer_size 84 | return adr 85 | 86 | def data(self, siz: int = buffer_size, ptr: int = None) -> np.array: 87 | """Data. 88 | 89 | Parameters 90 | ---------- 91 | siz : int, optional 92 | Number of data samples to be read from the FPGA buffer. 93 | ptr : int, optional 94 | End of data pointer, only use if you understand 95 | the source code. 96 | 97 | Returns 98 | ------- 99 | array 100 | Array containing binary samples. 101 | The data is alligned at the end to the last sample 102 | stored into the buffer. 103 | """ 104 | if ptr is None: 105 | ptr = int(self.pointer) 106 | adr = (self.buffer_size + ptr - siz) % self.buffer_size 107 | ret = [] 108 | for i in range(siz): 109 | ret.append(self.buffer[(i + ptr) % self.buffer_size]) 110 | return ret 111 | -------------------------------------------------------------------------------- /redpitaya/drv/la_msk.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class la_msk(object): 5 | class _regset_t(Structure): 6 | _fields_ = [('cfg_msk', c_uint32), # input mask 7 | ('cfg_pol', c_uint32), # input polarity 8 | ('cfg_dec', c_uint32)] # decimation factor 9 | 10 | def default(self): 11 | """Set registers into default (power-up) state.""" 12 | self.regset.msk.cfg_msk = 0 13 | self.regset.msk.cfg_pol = 0 14 | self.regset.msk.cfg_dec = 0 15 | 16 | def show_regset(self): 17 | """Print FPGA module register set for debugging purposes.""" 18 | print( 19 | "cfg_msk = 0x{reg:08x} = {reg:10d} # input mask \n".format(reg=self.regset.msk.cfg_msk) + 20 | "cfg_pol = 0x{reg:08x} = {reg:10d} # input polarity \n".format(reg=self.regset.msk.cfg_pol) + 21 | "cfg_dec = 0x{reg:08x} = {reg:10d} # decimation factor\n".format(reg=self.regset.msk.cfg_dec) 22 | ) 23 | 24 | @property 25 | def input_mask(self) -> int: 26 | """Input signal bit mask (can be used to reduce power consumption).""" 27 | return self.regset.msk.cfg_msk 28 | 29 | @input_mask.setter 30 | def input_mask(self, value: int): 31 | self.regset.msk.cfg_msk = value 32 | 33 | @property 34 | def input_polarity(self) -> int: 35 | """Input signal bit polarity.""" 36 | return self.regset.msk.cfg_pol 37 | 38 | @input_polarity.setter 39 | def input_polarity(self, value: int): 40 | self.regset.msk.cfg_pol = value 41 | 42 | @property 43 | def decimation(self) -> int: 44 | """Decimation factor.""" 45 | return (self.regset.cfg_dec + 1) 46 | 47 | @decimation.setter 48 | def decimation(self, value: int): 49 | # TODO check range 50 | self.regset.cfg_dec = value - 1 51 | -------------------------------------------------------------------------------- /redpitaya/drv/la_rle.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class la_rle(object): 5 | class _regset_t(Structure): 6 | _fields_ = [('cfg_rle', c_uint32), # RLE mode 7 | ('sts_cur', c_uint32), # current counter 8 | ('sts_lst', c_uint32)] # last counter 9 | 10 | def default(self): 11 | """Set registers into default (power-up) state.""" 12 | self.regset.rle.cfg_rle = 0 13 | 14 | def show_regset(self): 15 | """Print FPGA module register set for debugging purposes.""" 16 | print( 17 | "cfg_rle = 0x{reg:08x} = {reg:10d} # RLE mode \n".format(reg=self.regset.rle.cfg_rle) + 18 | "sts_cur = 0x{reg:08x} = {reg:10d} # current counter\n".format(reg=self.regset.rle.sts_cur) + 19 | "sts_lst = 0x{reg:08x} = {reg:10d} # last counter\n".format(reg=self.regset.rle.sts_lst) 20 | ) 21 | 22 | @property 23 | def rle(self) -> bool: 24 | """RLE mode enable.""" 25 | return bool(self.regset.rle.cfg_rle) 26 | 27 | @rle.setter 28 | def rle(self, value: bool): 29 | self.regset.rle.cfg_rle = int(value) 30 | 31 | @property 32 | def counter_current(self) -> int: 33 | """Current data stream length counter.""" 34 | return self.regset.rle.sts_cur 35 | 36 | @property 37 | def counter_last(self) -> int: 38 | """Last data stream length counter.""" 39 | return self.regset.rle.sts_lst 40 | -------------------------------------------------------------------------------- /redpitaya/drv/la_trg.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class la_trg(object): 5 | class _regset_t(Structure): 6 | _fields_ = [('cfg_cmp_msk', c_uint32), # comparator mask 7 | ('cfg_cmp_val', c_uint32), # comparator value 8 | ('cfg_edg_pos', c_uint32), # edge positive 9 | ('cfg_edg_neg', c_uint32)] # edge negative 10 | 11 | def show_regset(self): 12 | """Print FPGA module register set for debugging purposes.""" 13 | print( 14 | "cfg_cmp_msk = 0x{reg:08x} = {reg:10d} # comparator mask \n".format(reg=self.regset.trg.cfg_cmp_msk) + 15 | "cfg_cmp_val = 0x{reg:08x} = {reg:10d} # comparator value\n".format(reg=self.regset.trg.cfg_cmp_val) + 16 | "cfg_edg_pos = 0x{reg:08x} = {reg:10d} # edge positive \n".format(reg=self.regset.trg.cfg_edg_pos) + 17 | "cfg_edg_neg = 0x{reg:08x} = {reg:10d} # edge negative \n".format(reg=self.regset.trg.cfg_edg_neg) 18 | ) 19 | 20 | def default(self): 21 | """Set registers into default (power-up) state.""" 22 | self.regset.trg.cfg_cmp_msk = 0 23 | self.regset.trg.cfg_cmp_val = 0 24 | self.regset.trg.cfg_edg_pos = 0 25 | self.regset.trg.cfg_edg_neg = 0 26 | 27 | @property 28 | def trigger_mask(self) -> int: 29 | """Trigger comparator mask.""" 30 | return self.regset.trg.cfg_cmp_msk 31 | 32 | @trigger_mask.setter 33 | def trigger_mask(self, value: tuple): 34 | self.regset.trg.cfg_cmp_msk = value 35 | 36 | @property 37 | def trigger_value(self) -> int: 38 | """Trigger comparator value.""" 39 | return self.regset.trg.cfg_cmp_val 40 | 41 | @trigger_value.setter 42 | def trigger_value(self, value: tuple): 43 | self.regset.trg.cfg_cmp_val = value 44 | 45 | @property 46 | def trigger_edge(self) -> tuple: 47 | """Trigger edge detection mask [pos, neg].""" 48 | return [self.regset.trg.cfg_edg_pos, self.regset.trg.cfg_edg_neg] 49 | 50 | @trigger_edge.setter 51 | def trigger_edge(self, value: tuple): 52 | [self.regset.trg.cfg_edg_pos, self.regset.trg.cfg_edg_neg] = value 53 | -------------------------------------------------------------------------------- /redpitaya/drv/lg.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | 4 | from enum import Enum 5 | 6 | import mmap 7 | 8 | from .evn import evn 9 | from .asg_bst import asg_bst 10 | from .lg_out import lg_out 11 | from .uio import uio 12 | 13 | 14 | class lg(evn, asg_bst, lg_out, uio): 15 | """ 16 | Generator FPGA module driver. 17 | """ 18 | 19 | #: sampling frequency 20 | FS = 125000000.0 21 | # linear addition multiplication register width 22 | DW = 16 #: data width - streaming sample 23 | 24 | CWM = 14 25 | 26 | class _regset_t(Structure): 27 | _fields_ = [('evn', evn._regset_t), 28 | ('rsv_000', c_uint32), 29 | ('cfg_bmd', c_uint32), # mode 30 | ('rsv_001', c_uint32 * 3), 31 | ('bst', asg_bst._regset_t), 32 | ('rsv_002', c_uint32 * 2), 33 | ('out', lg_out._regset_t)] 34 | 35 | class _buffer_t(Array): 36 | _length_ = 2**14 37 | _type_ = c_int32 38 | 39 | def __init__(self, uio: str = '/dev/uio/lg'): 40 | # call parent class init to open UIO device and mmap maps 41 | super().__init__(uio) 42 | 43 | # map regset 44 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 45 | # map buffer 46 | self.buffer = self._buffer_t.from_buffer(self.uio_mmaps[1]) 47 | 48 | # calculate constants 49 | self.buffer_size = 2**self.CWM #: buffer size 50 | 51 | def __del__(self): 52 | # disable output 53 | self.enable = False 54 | # make sure state machine is not running 55 | self.reset() 56 | # call parent class init to unmap maps and close UIO device 57 | super().__del__() 58 | 59 | def default(self): 60 | """Set registers into default (power-up) state.""" 61 | evn.default(self) 62 | asg_bst.default(self) 63 | lg_out.default(self) 64 | 65 | def show_regset(self): 66 | """Print FPGA module register set for debugging purposes.""" 67 | evn.show_regset(self) 68 | asg_bst.show_regset(self) 69 | lg_out.show_regset(self) 70 | 71 | @property 72 | def waveform(self): 73 | """Waveworm array containing normalized values in the range [-1,1]. 74 | 75 | Array can be up to `buffer_size` samples in length. 76 | """ 77 | # TODO: nparray 78 | return [self.buffer[i] for i in range(self.waveform_size)] 79 | 80 | @waveform.setter 81 | def waveform(self, value): 82 | siz = len(value) 83 | if (siz <= self.buffer_size): 84 | for i in range(siz): 85 | self.buffer[i] = value[i] 86 | self.waveform_size = siz 87 | else: 88 | raise ValueError("Waveform table size should not excede buffer size. buffer_size = {}".format(self.buffer_size)) 89 | -------------------------------------------------------------------------------- /redpitaya/drv/lg_out.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | 4 | 5 | class lg_out (object): 6 | """Logic generator output control. 7 | 8 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 9 | | ``cfg_oen[0]`` | ``cfg_oen[1]`` | ``cfg_msk`` | ``cfg_val`` | **output** | **output** | 10 | | out enable 0 | out enable 1 | out mask | value/polarity | **enable** | **equation** | 11 | +================+================+=============+================+=============+===============================+ 12 | | 0 | 0 | x | x | Hi-Z | ``z`` | 13 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 14 | | 0 | 1 | 0 | | open drain | `` cfg_val ? 1 : z`` | 15 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 16 | | 0 | 1 | 1 | | open drain | ``asg_val ^ cfg_val ? 1 : z`` | 17 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 18 | | 1 | 0 | 0 | | open source | `` cfg_val ? z : 0`` | 19 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 20 | | 1 | 0 | 1 | | open source | ``asg_val ^ cfg_val ? z : 0`` | 21 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 22 | | 1 | 1 | 0 | | push-pull | `` cfg_val`` | 23 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 24 | | 1 | 1 | 1 | | push-pull | ``asg_val ^ cfg_val`` | 25 | +----------------+----------------+-------------+----------------+-------------+-------------------------------+ 26 | """ 27 | 28 | class _regset_t (Structure): 29 | _fields_ = [('cfg_oen', c_uint32 *2), # output enable [0,1] 30 | ('cfg_msk', c_uint32 ), # mask 31 | ('cfg_val', c_uint32 )] # value/polarity 32 | 33 | def default(self): 34 | """Set registers into default (power-up) state.""" 35 | self.regset.out.cfg_oen[0] = 0 36 | self.regset.out.cfg_oen[1] = 0 37 | self.regset.out.cfg_msk = 0 38 | self.regset.out.cfg_val = 0 39 | 40 | def show_regset(self): 41 | """Print FPGA module register set for debugging purposes.""" 42 | print( 43 | "cfg_oen[0] = 0x{reg:08x} = {reg:10d} # output enable 0\n".format(reg=self.regset.out.cfg_oen[0]) + 44 | "cfg_oen[1] = 0x{reg:08x} = {reg:10d} # output enable 1\n".format(reg=self.regset.out.cfg_oen[1]) + 45 | "cfg_msk = 0x{reg:08x} = {reg:10d} # output mask \n".format(reg=self.regset.out.cfg_msk) + 46 | "cfg_val = 0x{reg:08x} = {reg:10d} # value/polarity \n".format(reg=self.regset.out.cfg_val) 47 | ) 48 | 49 | @property 50 | def enable(self) -> _regset_t.cfg_oen: 51 | """Output enable [oe0, oe1].""" 52 | return self.regset.out.cfg_oen 53 | 54 | @enable.setter 55 | def enable(self, value: tuple): 56 | if isinstance(value, int): 57 | value = [value]*2 58 | self.regset.out.cfg_oen[0] = value[0] 59 | self.regset.out.cfg_oen[1] = value[1] 60 | 61 | @property 62 | def mask(self) -> int: 63 | """Output mask.""" 64 | return self.regset.out.cfg_msk 65 | 66 | @mask.setter 67 | def mask(self, value: int): 68 | self.regset.out.cfg_msk = value 69 | 70 | @property 71 | def value(self) -> int: 72 | """Output value.""" 73 | return self.regset.out.cfg_val 74 | 75 | @value.setter 76 | def value(self, value: int): 77 | self.regset.out.cfg_val = value 78 | -------------------------------------------------------------------------------- /redpitaya/drv/mgmt.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | from .uio import uio 4 | 5 | 6 | class mgmt(uio): 7 | """Driver for hardware identification module""" 8 | class _regset_t(Structure): 9 | _fields_ = [('cfg_iom' , c_uint32), # GPIO mode (0 - PS GPIO, 1 - Logic generator) 10 | ('cfg_loop', c_uint32)] # enable internal digital loop from gen to osc 11 | 12 | def __init__(self, uio: str = '/dev/uio/mgmt'): 13 | super().__init__(uio) 14 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 15 | 16 | def __del__(self): 17 | super().__del__() 18 | 19 | def default(self): 20 | """Set registers into default (power-up) state.""" 21 | self.regset.cfg_iom = 0x0 22 | self.regset.cfg_loop = 0x0 23 | 24 | def show_regset(self): 25 | """Print FPGA module register set for debugging purposes.""" 26 | print( 27 | "cfg_iom = 0x{reg:08x} = {reg:10d} # GPIO mode \n".format(reg=self.regset.cfg_iom) + 28 | "cfg_loop = 0x{reg:08x} = {reg:10d} # gen->osc loop\n".format(reg=self.regset.cfg_loop) 29 | ) 30 | 31 | @property 32 | def gpio_mode(self) -> int: 33 | """GPIO mode 34 | 35 | Each bit coresponds to one of {exp_n_io[7:0], exp_p_io[7:0]} GPIO pins. 36 | 0 - pin is connected to PS GPIO controller 37 | 1 - pin is connected to Logic generator. 38 | """ 39 | return self.regset.cfg_iom 40 | 41 | @gpio_mode.setter 42 | def gpio_mode(self, value: int): 43 | self.regset.cfg_iom = value 44 | 45 | @property 46 | def loop(self) -> int: 47 | """Digital loopback (for debugging purposes) 48 | 49 | Each bit controls one of the loop paths: 50 | 0 - enable loop: gen0 -> osc0, 51 | 1 - enable loop: gen1 -> osc1. 52 | """ 53 | return self.regset.cfg_loop 54 | 55 | @loop.setter 56 | def loop(self, value: int): 57 | self.regset.cfg_loop = value 58 | -------------------------------------------------------------------------------- /redpitaya/drv/osc.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | import numpy as np 3 | import math 4 | 5 | import mmap 6 | 7 | from .evn import evn 8 | from .acq import acq 9 | from .osc_trg import osc_trg 10 | from .osc_fil import osc_fil 11 | from .uio import uio 12 | 13 | 14 | class osc(evn, acq, osc_trg, osc_fil, uio): 15 | #: sampling frequency 16 | FS = 125000000.0 17 | #: register width - linear addition multiplication 18 | DW = 16 19 | # fixed point range 20 | _DWr = (1 << (DW-1)) - 1 21 | # buffer parameters 22 | buffer_size = 2**14 #: buffer size 23 | CW = 31 #: counter size 24 | _CWr = 2**CW 25 | 26 | #: analog stage range voltages 27 | ranges = (1.0, 20.0) 28 | 29 | class _regset_t(Structure): 30 | _fields_ = [('evn', evn._regset_t), 31 | ('rsv_000', c_uint32), 32 | ('acq', acq._regset_t), # pre/post trigger counters 33 | # edge detection 34 | ('trg', osc_trg._regset_t), 35 | ('rsv_001', c_uint32), 36 | # filter 37 | ('fil', osc_fil._regset_t)] 38 | 39 | class _buffer_t(Array): 40 | _length_ = 2**14 41 | _type_ = c_int16 42 | 43 | def __init__(self, index: int, input_range: float, uio: str = '/dev/uio/osc'): 44 | """Module instance index should be provided""" 45 | 46 | # use index 47 | uio = uio+str(index) 48 | 49 | # call parent class init to open UIO device and map regset 50 | super().__init__(uio) 51 | 52 | # map regset 53 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 54 | # map buffer 55 | self.buffer = self._buffer_t.from_buffer(self.uio_mmaps[1]) 56 | 57 | # set input range (there is no default) 58 | self.input_range = input_range 59 | 60 | def __del__(self): 61 | # call parent class init to unmap maps and close UIO device 62 | super().__del__() 63 | 64 | def default(self): 65 | """Set registers into default (power-up) state.""" 66 | evn.default(self) 67 | acq.default(self) 68 | osc_trg.default(self) 69 | osc_fil.default(self) 70 | self.input_range = self.input_range 71 | 72 | def show_regset(self): 73 | """Print FPGA module register set for debugging purposes.""" 74 | evn.show_regset(self) 75 | acq.show_regset(self) 76 | osc_trg.show_regset(self) 77 | osc_fil.show_regset(self) 78 | 79 | @property 80 | def input_range(self) -> float: 81 | """Input range can be one of the supporte ranges. 82 | 83 | See HW board documentation for details. 84 | """ 85 | return self.__input_range 86 | 87 | @input_range.setter 88 | def input_range(self, value: float): 89 | if value in self.ranges: 90 | self.__input_range = value 91 | self.filter_coeficients = self._filters[value] 92 | else: 93 | raise ValueError("Input range can be one of {} volts.".format(self.ranges)) 94 | 95 | @property 96 | def sample_rate(self) -> float: 97 | """Sample rate depending on decimation factor.""" 98 | return (self.FS / self.decimation) 99 | 100 | @property 101 | def sample_period(self) -> float: 102 | """Sample period depending on decimation factor.""" 103 | return (1 / self.sample_rate) 104 | 105 | @property 106 | def pointer(self): 107 | # mask out overflow bit and sum pre and post trigger counters 108 | cnt = self.trigger_pre_status + self.trigger_post_status 109 | adr = cnt % self.buffer_size 110 | return adr 111 | 112 | 113 | def data(self, siz: int = buffer_size, ptr: int = None) -> np.array: 114 | """Data. 115 | 116 | Parameters 117 | ---------- 118 | siz : int, optional 119 | Number of data samples to be read from the FPGA buffer. 120 | ptr : int, optional 121 | End of data pointer, only use if you understand 122 | the source code. 123 | 124 | Returns 125 | ------- 126 | array 127 | Array containing float samples scaled 128 | to the selected analog range. 129 | The data is alligned at the end to the last sample 130 | stored into the buffer. 131 | """ 132 | if ptr is None: 133 | ptr = int(self.pointer) 134 | scale = self.__input_range / float(self._DWr) 135 | 136 | buffer_np = np.ctypeslib.as_array(self.buffer) 137 | buffer_size = len(self.buffer) 138 | 139 | # get `siz`-segment by start and exlusive-end pointers 140 | start = ptr 141 | end = (ptr + siz) % buffer_size 142 | if start < end: 143 | return scale * buffer_np[start:end] 144 | else: # wrap around 145 | head_length = buffer_size - start 146 | segment = np.empty(head_length + end) 147 | segment[:head_length] = buffer_np[start:] 148 | segment[head_length:] = buffer_np[:end] 149 | return scale * segment 150 | -------------------------------------------------------------------------------- /redpitaya/drv/osc_fil.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class osc_fil(object): 5 | # filter coeficients 6 | _filters = { 1.0: (0x7D93, 0x437C7, 0xd9999a, 0x2666), 7 | 20.0: (0x4C5F, 0x2F38B, 0xd9999a, 0x2666)} 8 | 9 | class _regset_t(Structure): 10 | _fields_ = [('cfg_dec', c_uint32), # decimation factor 11 | ('cfg_shr', c_uint32), # shift right 12 | ('cfg_avg', c_uint32), # average enable 13 | ('cfg_byp', c_uint32), # bypass 14 | ('cfg_faa', c_int32), # AA coeficient 15 | ('cfg_fbb', c_int32), # BB coeficient 16 | ('cfg_fkk', c_int32), # KK coeficient 17 | ('cfg_fpp', c_int32)] # PP coeficient 18 | 19 | def default(self): 20 | self.regset.fil.cfg_dec = 0 21 | self.regset.fil.cfg_shr = 0 22 | self.regset.fil.cfg_avg = 0 23 | 24 | def show_regset(self): 25 | """Print FPGA module register set for debugging purposes.""" 26 | print( 27 | "cfg_dec = 0x{reg:08x} = {reg:10d} # decimation factor\n".format(reg=self.regset.fil.cfg_dec) + 28 | "cfg_shr = 0x{reg:08x} = {reg:10d} # shift right \n".format(reg=self.regset.fil.cfg_shr) + 29 | "cfg_avg = 0x{reg:08x} = {reg:10d} # average enable \n".format(reg=self.regset.fil.cfg_avg) + 30 | "cfg_byp = 0x{reg:08x} = {reg:10d} # bypass \n".format(reg=self.regset.fil.cfg_byp) + 31 | "cfg_faa = 0x{reg:08x} = {reg:10d} # AA coeficient \n".format(reg=self.regset.fil.cfg_faa) + 32 | "cfg_fbb = 0x{reg:08x} = {reg:10d} # BB coeficient \n".format(reg=self.regset.fil.cfg_fbb) + 33 | "cfg_fkk = 0x{reg:08x} = {reg:10d} # KK coeficient \n".format(reg=self.regset.fil.cfg_fkk) + 34 | "cfg_fpp = 0x{reg:08x} = {reg:10d} # PP coeficient \n".format(reg=self.regset.fil.cfg_fpp) 35 | ) 36 | 37 | @property 38 | def decimation(self) -> int: 39 | """Decimation factor.""" 40 | return (self.regset.fil.cfg_dec + 1) 41 | 42 | @decimation.setter 43 | def decimation(self, value: int): 44 | # TODO check range 45 | self.regset.fil.cfg_dec = value - 1 46 | 47 | @property 48 | def average(self) -> bool: 49 | return bool(self.regset.fil.cfg_avg) 50 | 51 | @average.setter 52 | def average(self, value: bool): 53 | # TODO check range, for non 2**n decimation factors, 54 | # scaling should be applied in addition to shift 55 | self.regset.fil.cfg_avg = int(value) 56 | self.regset.fil.cfg_shr = math.ceil(math.log2(self.decimation)) 57 | 58 | @property 59 | def filter_bypass(self) -> bool: 60 | """Bypass digital input filter. 61 | 62 | True filter is not used 63 | False filter is used 64 | """ 65 | return bool(self.regset.fil.cfg_byp) 66 | 67 | @filter_bypass.setter 68 | def filter_bypass(self, value: bool): 69 | self.regset.fil.cfg_byp = int(value) 70 | 71 | @property 72 | def filter_coeficients(self) -> tuple: 73 | return (self.regset.fil.cfg_faa, 74 | self.regset.fil.cfg_fbb, 75 | self.regset.fil.cfg_fkk, 76 | self.regset.fil.cfg_fpp) 77 | 78 | @filter_coeficients.setter 79 | def filter_coeficients(self, value: tuple): 80 | # TODO check range 81 | self.regset.fil.cfg_faa = value[0] 82 | self.regset.fil.cfg_fbb = value[1] 83 | self.regset.fil.cfg_fkk = value[2] 84 | self.regset.fil.cfg_fpp = value[3] 85 | -------------------------------------------------------------------------------- /redpitaya/drv/osc_trg.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | 4 | class osc_trg(object): 5 | # trigger edge dictionary 6 | _edges = {'pos': 0, 'neg': 1} 7 | 8 | class _regset_t(Structure): 9 | _fields_ = [('cfg_neg', c_int32), # negative level 10 | ('cfg_pos', c_int32), # positive level 11 | ('cfg_edg', c_uint32)] # edge (0-pos, 1-neg) 12 | 13 | def default(self): 14 | """Set registers into default (power-up) state.""" 15 | self.regset.trg.cfg_neg = 0 16 | self.regset.trg.cfg_pos = 0 17 | self.regset.trg.cfg_edg = 0 18 | 19 | def show_regset(self): 20 | """Print FPGA module register set for debugging purposes.""" 21 | print( 22 | "cfg_neg = 0x{reg:08x} = {reg:10d} # negative level \n".format(reg=self.regset.trg.cfg_neg) + 23 | "cfg_pos = 0x{reg:08x} = {reg:10d} # positive level \n".format(reg=self.regset.trg.cfg_pos) + 24 | "cfg_edg = 0x{reg:08x} = {reg:10d} # edge (0-pos, 1-neg)\n".format(reg=self.regset.trg.cfg_edg) 25 | ) 26 | 27 | @property 28 | def level(self) -> float: 29 | """Trigger level in vols, or a pair of values [neg, pos] if a hysteresis is desired.""" 30 | scale = self.input_range / self._DWr 31 | return [self.regset.trg.cfg_neg * scale, self.regset.trg.cfg_pos * scale] 32 | 33 | @level.setter 34 | def level(self, value: tuple): 35 | scale = self._DWr / self.input_range 36 | if isinstance(value, float): 37 | value = [value]*2 38 | if (-1.0 <= value[0] <= 1.0): 39 | self.regset.trg.cfg_neg = int(value[0] * scale) 40 | else: 41 | raise ValueError("Trigger negative level should be inside [{},{}]".format(self.input_range)) 42 | if (-1.0 <= value[1] <= 1.0): 43 | self.regset.trg.cfg_pos = int(value[1] * scale) 44 | else: 45 | raise ValueError("Trigger positive level should be inside [{},{}]".format(self.input_range)) 46 | 47 | @property 48 | def edge(self) -> str: 49 | """Trigger edge as a string 'pos'/'neg'""" 50 | return ('pos', 'neg')[self.regset.trg.cfg_edg] 51 | 52 | @edge.setter 53 | def edge(self, value: str): 54 | if (value in self._edges): 55 | self.regset.trg.cfg_edg = self._edges[value] 56 | else: 57 | raise ValueError("Trigger edge should be one of {}".format(list(self._edges.keys()))) 58 | -------------------------------------------------------------------------------- /redpitaya/drv/overlay.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | 5 | class overlay(object): 6 | """Class handling device tree overlays and FPGA bitstreams.""" 7 | overlays = "/sys/kernel/config/device-tree/overlays" 8 | fpgapath = "/opt/redpitaya/fpga" 9 | overlaysh = "/opt/redpitaya/sbin/overlay.sh" 10 | 11 | def __init__(self, overlay: str): 12 | if not isinstance(overlay, str): 13 | raise TypeError("Bitstream name has to be a string.") 14 | 15 | if os.path.isfile(self.overlaysh): 16 | self.overlay = overlay 17 | self.syspath = "{}/{}".format(self.overlays, self.overlay) 18 | 19 | if self.status(): 20 | print('Check FPGA [OK].') 21 | return 22 | 23 | os.system("{} {}".format(self.overlaysh,overlay)) 24 | # this delay makes sure all devices are created before continuing 25 | time.sleep(0.5) 26 | if self.status(): 27 | print('Load overlay [OK].') 28 | else: 29 | print('Load overlay [FAIL].') 30 | 31 | def __del__(self): 32 | print('Overlay __del__ was activated.') 33 | print('But since there are garbage collection ordering issues, this code is commented out.') 34 | # os.system("rmdir {}".format(self.syspath)) 35 | # del(self.syspath) 36 | # del(self.overlay) 37 | 38 | def status(self) -> bool: 39 | """Checking device tree overlay status. 40 | 41 | :returns: device tree overlay 'applied' status 42 | :rtype: bool 43 | """ 44 | if not os.path.isfile('/tmp/loaded_fpga.inf'): 45 | return False 46 | else: 47 | with open('/tmp/loaded_fpga.inf', 'r') as status_file: 48 | status_string = status_file.read() 49 | if (status_string != self.overlay): return False 50 | 51 | if not os.path.isfile('{}/Full/status'.format(self.overlays)): 52 | return False 53 | else: 54 | with open('{}/Full/status'.format(self.overlays), 'r') as status_file: 55 | status_string = status_file.read() 56 | if (status_string == "applied\n"): return True 57 | else: return False 58 | -------------------------------------------------------------------------------- /redpitaya/drv/pdm.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | from .uio import uio 4 | 5 | 6 | class pdm(uio): 7 | 8 | DN = 4 9 | DW = 8 10 | _DWr = 2**DW - 1 11 | 12 | class _regset_t(Structure): 13 | DN = 4 # TODO: the DN value from the 'pdm' class should be used 14 | _fields_ = [('pdm', c_uint32 * DN)] 15 | 16 | def __init__(self, uio: str = '/dev/uio/pdm'): 17 | super().__init__(uio) 18 | self.regset = self._regset_t.from_buffer(self.uio_mmaps[0]) 19 | 20 | def __del__(self): 21 | super().__del__() 22 | 23 | def default(self): 24 | """Set registers into default (power-up) state.""" 25 | for channel in range(self.DN): 26 | self.regset.pdm[channel] = 0 27 | 28 | def read(self, channel: int) -> int: 29 | return self.regset.pdm[channel] 30 | 31 | def write(self, channel: int, value: int): 32 | if (0 <= value <= self._DWr): 33 | self.regset.pdm[channel] = value 34 | else: 35 | raise ValueError("PDM output value should be in range [0,{}]".format(self._DWr)) 36 | -------------------------------------------------------------------------------- /redpitaya/drv/uio.py: -------------------------------------------------------------------------------- 1 | import os 2 | import fcntl 3 | import mmap 4 | import pyudev 5 | from ctypes import c_uint32 6 | 7 | 8 | class _uio_map(object): 9 | def __init__(self, device, index: int): 10 | self.index = index 11 | self.name = device.attributes.asstring('maps/map'+str(index)+'/name') 12 | self.addr = int(device.attributes.asstring('maps/map'+str(index)+'/addr'), 16) 13 | self.offset = int(device.attributes.asstring('maps/map'+str(index)+'/offset'), 16) 14 | self.size = int(device.attributes.asstring('maps/map'+str(index)+'/size'), 16) 15 | 16 | 17 | class uio(object): 18 | """UIO class provides user space access to UIO devices. 19 | 20 | When instantiating this class the next steps are performed: 21 | 22 | 1. The provided UIO device file is first opened. 23 | 2. An attempt is made to exclusively lock the device file. 24 | If another process has already locked this file 25 | an error will be rised. This prevents multiple 26 | applications from accessing the same HW module. 27 | 3. If locking is sucessfull sysfs arguments will be read 28 | to determine the maps listed in the device tree. 29 | All maps will be `mmap`ed into memory and provided 30 | as a tuple. 31 | 32 | When an instance of :class:`uio` is deleted the next steps are performed: 33 | 34 | 1. Close all memory mappings. 35 | 2. Close the UIO device file, which also releases the exclusive lock. 36 | 37 | Parameters 38 | ---------- 39 | uio : :obj:`str` 40 | device node path 41 | 42 | Attributes 43 | ---------- 44 | uio_maps : :obj:`touple` of :class:`mmap` objects 45 | List of all memory maps derived from device tree node for the UIO device. 46 | uio_mmaps : :obj:`touple` of :class:`mmap` objects 47 | List of all mmap-ed memory maps derived from device tree node for the UIO device. 48 | """ 49 | 50 | def __init__(self, uio: str): 51 | # store UIO device node path 52 | self.uio_path = uio 53 | 54 | # open device file 55 | try: 56 | self.uio_dev = open(self.uio_path, 'r+b') 57 | except OSError as e: 58 | raise IOError(e.errno, "Opening {}: {}".format(self.uio_path, e.strerror)) 59 | 60 | # exclusive lock 61 | try: 62 | fcntl.flock(self.uio_dev, fcntl.LOCK_EX | fcntl.LOCK_NB) 63 | except IOError as e: 64 | raise IOError(e.errno, "Locking {}: {}".format(self.uio_path, e.strerror)) 65 | 66 | # UDEV device 67 | device = pyudev.Devices.from_device_file(pyudev.Context(), self.uio_path) 68 | 69 | # create list of UIO maps 70 | self.uio_maps = [_uio_map(device, int(uio_map[3:])) for uio_map in os.listdir(os.path.join(device.sys_path, 'maps'))] 71 | 72 | # mmap all maps listed in device tree 73 | self.uio_mmaps = [self._uio_mmap(uio_map) for uio_map in self.uio_maps] 74 | 75 | def _uio_mmap(self, uio_map: _uio_map): 76 | try: 77 | uio_mmap = mmap.mmap(fileno = self.uio_dev.fileno(), 78 | length = uio_map.size, 79 | offset = uio_map.index * mmap.PAGESIZE, 80 | flags = mmap.MAP_SHARED, 81 | prot = mmap.PROT_READ | mmap.PROT_WRITE) 82 | except OSError as e: 83 | raise IOError(e.errno, "Mapping {} map {} size {}: {}".format(self.uio_path, uio_map.name, uio_map.size, e.strerror)) 84 | return uio_mmap 85 | 86 | def __del__(self): 87 | # print('UIO __del__ was activated.') 88 | # close memory mappings 89 | for uio_mmap in self.uio_mmaps: 90 | uio_mmap.close() 91 | # close uio device (also releases exclusive lock) 92 | try: 93 | self.uio_dev.close() 94 | except OSError as e: 95 | raise IOError(e.errno, "Closing {}: {}".format(self.uio_path, e.strerror)) 96 | 97 | def irq_enable(self): 98 | """Enable interrupt.""" 99 | cnt = c_uint32(1); 100 | try: 101 | self.uio_dev.write(bytearray(cnt)) 102 | except OSError as e: 103 | raise IOError(e.errno, "Enable IRQ {}: {}".format(self.uio_path, e.strerror)); 104 | 105 | def irq_disable(self): 106 | """Disable interrupt.""" 107 | cnt = c_uint32(0); 108 | try: 109 | self.uio_dev.write(bytearray(cnt)) 110 | except OSError as e: 111 | raise IOError(e.errno, "Disable IRQ {}: {}".format(self.uio_path, e.strerror)); 112 | 113 | def irq_wait(self): 114 | """Wait for interrupt.""" 115 | try: 116 | status = self.uio_dev.read(4) 117 | except OSError as e: 118 | raise IOError(e.errno, "Wait for IRQ {}: {}".format(self.uio_path, e.strerror)); 119 | # import sys 120 | # cnt = int.from_bytes(status, byteorder=sys.byteorder) 121 | 122 | def pool(self): 123 | """TODO: implement interrupt support 124 | """ 125 | pass 126 | -------------------------------------------------------------------------------- /redpitaya/drv/wave.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy import signal 3 | 4 | 5 | class wave(): 6 | """Common waveform creation. 7 | 8 | This class provides methods for creating common waveform shapes. 9 | """ 10 | 11 | def _wavetime(self): 12 | return np.linspace(0, 2*np.pi, self.buffer_size, endpoint=False) 13 | 14 | def sin(self, t: np.array = None) -> np.array: 15 | """Sinus waveform. 16 | 17 | Parameters 18 | ---------- 19 | t : array_like, optional 20 | If not time array is provided, a default buffer sized array 21 | with a 2*PI period will be used. 22 | 23 | Returns 24 | ------- 25 | waveform : ndarray 26 | Sinusoidal waveform with samples in the normalized range [-1,+1]. 27 | 28 | References 29 | ---------- 30 | https://docs.scipy.org/doc/numpy/reference/generated/numpy.sin.html 31 | 32 | See Also 33 | -------- 34 | square 35 | sawtooth 36 | """ 37 | if t is None: 38 | t = self._wavetime() 39 | return np.sin(t) 40 | 41 | def square(self, duty: float = 0.5, t: np.array = None) -> np.array: 42 | """Square waveform. 43 | 44 | Parameters 45 | ---------- 46 | duty : float, optional 47 | Duty cycle. 48 | t : array_like, optional 49 | If not time array is provided, a default buffer sized array 50 | with a 2*PI period will be used. 51 | 52 | Returns 53 | ------- 54 | waveform : ndarray 55 | Square waveform with samples in the normalized range [-1,+1] 56 | and given duty cycle. 57 | 58 | References 59 | ---------- 60 | http://scipy.github.io/devdocs/generated/scipy.signal.square.html 61 | 62 | See Also 63 | -------- 64 | sin 65 | sawtooth 66 | """ 67 | if t is None: 68 | t = self._wavetime() 69 | return signal.square(t, duty) 70 | 71 | def sawtooth(self, width: float = 0.5, t: np.array = None) -> np.array: 72 | """Sawtooth waveform. 73 | 74 | Parameters 75 | ---------- 76 | width : float, optional 77 | Width of rising versus the falling sawtooth edge. 78 | t : array_like, optional 79 | If not time array is provided, a default buffer sized array 80 | with a 2*PI period will be used. 81 | 82 | Returns 83 | ------- 84 | waveform : ndarray 85 | Sawtooth waveform with samples in the normalized range [-1,+1] 86 | and given width. 87 | 88 | References 89 | ---------- 90 | http://scipy.github.io/devdocs/generated/scipy.signal.square.html 91 | 92 | See Also 93 | -------- 94 | sin 95 | square 96 | """ 97 | if t is None: 98 | t = self._wavetime() 99 | return signal.sawtooth(t, width) 100 | -------------------------------------------------------------------------------- /redpitaya/overlay/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['mercury'] 2 | -------------------------------------------------------------------------------- /redpitaya/overlay/mercury.py: -------------------------------------------------------------------------------- 1 | from redpitaya.drv.overlay import overlay 2 | 3 | from periphery import LED 4 | from periphery import GPIO 5 | 6 | from redpitaya.drv.hwid import hwid 7 | from redpitaya.drv.mgmt import mgmt 8 | from redpitaya.drv.pdm import pdm 9 | from redpitaya.drv.clb import clb 10 | from redpitaya.drv.gen import gen 11 | from redpitaya.drv.osc import osc 12 | from redpitaya.drv.lg import lg 13 | from redpitaya.drv.la import la 14 | 15 | import iio 16 | 17 | 18 | class mercury(overlay): 19 | 20 | def __init__(self): 21 | super().__init__(overlay='mercury') 22 | 23 | def __del__(self): 24 | super().__del__() 25 | 26 | # module number constants 27 | _MNG = 2 # generators 28 | _MNO = 2 # oscilloscopes 29 | 30 | _modules = tuple(['gen'+str(ch) for ch in range(_MNG)] + ['osc'+str(ch) for ch in range(_MNO)] + ['lg', 'la']) 31 | # TODO: it is unclear why the next line fails 32 | # sync_src = {event_sources[i]: i for i in range(len(_modules))} 33 | # trig_src = {event_sources[i]: 1 << i for i in range(len(_modules))} 34 | sync_src = {'gen0': 0, 35 | 'gen1': 1, 36 | 'osc0': 2, 37 | 'osc1': 3, 38 | 'lg' : 4, 39 | 'la' : 5} 40 | trig_src = {'gen0': 1 << 0, 41 | 'gen1': 1 << 1, 42 | 'osc0': 1 << 2, 43 | 'osc1': 1 << 3, 44 | 'lg' : 1 << 4, 45 | 'la' : 1 << 5} 46 | 47 | class led(LED): 48 | leds = range(8) 49 | 50 | def __init__(self, index, brightness=None): 51 | if index not in self.leds: 52 | raise ValueError("LED index should be one of: {}".format(self.leds)) 53 | else: 54 | super().__init__(name="led"+str(index), brightness=brightness) 55 | 56 | class gpio(): 57 | 58 | def __new__(cls, port, pin, direction="preserve"): 59 | ports = {'p': 968, 'n': 976} 60 | gpios = range(8) 61 | 62 | if port not in ports: 63 | raise ValueError("GPIO port should be one of: {}".format(ports)) 64 | if pin not in gpios: 65 | raise ValueError("GPIO pin should be one of: {}".format(gpios)) 66 | else: 67 | return GPIO(ports[port] + pin,direction) 68 | 69 | class analog_in(): 70 | channels = {0: 'voltage9', 1: 'voltage11', 2: 'voltage10', 3: 'voltage8'} 71 | ctx = iio.Context() 72 | dev = ctx.devices[1] 73 | # resistor divider 74 | resdiv = 4.99 / (30.0 + 4.99) 75 | 76 | def __init__(self, channel): 77 | if channel in range(4): 78 | channel = self.channels[channel] 79 | self.chn = self.dev.find_channel(channel) 80 | self.scale = self.chn.attrs['scale'].value 81 | 82 | def read(self): 83 | raw = self.chn.attrs['raw'].value 84 | return (int(raw)*float(self.scale)/1000 / self.resdiv) 85 | 86 | class hwid(hwid): 87 | pass 88 | 89 | class mgmt(mgmt): 90 | pass 91 | 92 | class analog_out(pdm): 93 | V = 1.8 # voltage 94 | 95 | def read(self, ch: int) -> float: 96 | return (super().read(ch) / super().DWr * self.V) 97 | 98 | def write(self, ch: int, value: float): 99 | if (0 <= value <= self.V): 100 | super().write(ch, int(value / self.V * super()._DWr)) 101 | else: 102 | raise ValueError("Output amplitude should be inside [0,{}] volts.".format(self.V)) 103 | 104 | class clb(clb): 105 | # TODO, add checks 106 | pass 107 | 108 | class gen(gen): 109 | def __init__(self, index: int): 110 | self.calib = clb() 111 | self.eeprom_user = self.calib.eeprom_read() 112 | self.calib_user = self.calib.eeprom_parse(self.eeprom_user) 113 | self.calib.calib_dac_apply(self.calib_user) 114 | del(self.calib) 115 | if index in range(mercury._MNG): 116 | super().__init__(index=index) 117 | self.sync_src = mercury.sync_src['gen'+str(index)] 118 | else: 119 | raise ValueError("Generator index should be one of {}".format(range(mercury._MNG))) 120 | 121 | class osc(osc): 122 | def __init__(self, index: int, input_range: float): 123 | self.calib = clb() 124 | self.eeprom_user = self.calib.eeprom_read() 125 | self.calib_user = self.calib.eeprom_parse(self.eeprom_user) 126 | self.calib.calib_adc_apply(self.calib_user,index,input_range) 127 | #self.calib.calib_show(self.calib_user) 128 | del(self.calib) 129 | if index in range(mercury._MNO): 130 | super().__init__(index=index, input_range=input_range) 131 | self.sync_src = mercury.sync_src['osc'+str(index)] 132 | self.trig_src = mercury.trig_src['osc'+str(index)] 133 | if (input_range == 1.0): 134 | fil_cof = self.calib_user.adc[index].lo 135 | self.filter_coeficients = (fil_cof.fil_aa,fil_cof.fil_bb,fil_cof.fil_kk,fil_cof.fil_pp) 136 | else: 137 | fil_cof = self.calib_user.adc[index].hi 138 | self.filter_coeficients = (fil_cof.fil_aa,fil_cof.fil_bb,fil_cof.fil_kk,fil_cof.fil_pp) 139 | # self.show_regset() 140 | else: 141 | raise ValueError("Oscilloscope index should be one of {}".format(range(mercury._MNO))) 142 | 143 | class lg(lg): 144 | def __init__(self): 145 | super().__init__() 146 | self.sync_src = mercury.sync_src['lg'] 147 | 148 | class la(la): 149 | def __init__(self): 150 | super().__init__() 151 | self.sync_src = mercury.sync_src['la'] 152 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Always prefer setuptools over distutils 2 | from setuptools import setup, find_packages 3 | # To use a consistent encoding 4 | from codecs import open 5 | from os import path 6 | 7 | here = path.abspath(path.dirname(__file__)) 8 | 9 | # Get the long description from the README file 10 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 11 | long_description = f.read() 12 | 13 | setup( 14 | name='redpitaya', 15 | 16 | # Versions should comply with PEP440. For a discussion on single-sourcing 17 | # the version across setup.py and the project code, see 18 | # https://packaging.python.org/en/latest/single_source_version.html 19 | version='2.00', 20 | 21 | description='Red Pitaya Python drivers and Jupyter applications', 22 | long_description=long_description, 23 | 24 | # The project's main homepage. 25 | url='https://github.com/RedPitaya/RedPitaya', 26 | 27 | # Author details 28 | author='Red Pitaya', 29 | author_email='info@redpitaya.com', 30 | 31 | # Choose your license 32 | license='BSD', 33 | 34 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 35 | classifiers=[ 36 | # 3 - Alpha 37 | # 4 - Beta 38 | # 5 - Production/Stable 39 | 'Development Status :: 5 - Stable', 40 | 41 | 'Intended Audience :: Developers', 42 | 'Topic :: Software Development :: Drivers', 43 | 44 | 'License :: OSI Approved :: MIT License', 45 | 46 | 'Programming Language :: Python :: 3.10', 47 | ], 48 | 49 | keywords='signal generation acquisition GPIO control', 50 | packages=['redpitaya'], 51 | install_requires=['numpy', 'scipy', 'bokeh', 'IPython', 'ipywidgets'], 52 | ) 53 | -------------------------------------------------------------------------------- /welcome.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "de4c4d1c-d010-4f1e-b32c-8fdc1f3da56d", 6 | "metadata": { 7 | "collapsed": true, 8 | "jupyter": { 9 | "outputs_hidden": true 10 | } 11 | }, 12 | "source": [ 13 | "## Welcome to the Red Pitaya JupyterLab tutorial\n", 14 | "\n", 15 | "JupyterLab is the latest web-based interactive development environment for notebooks, code, and data. Its flexible interface allows users to configure and arrange workflows in data science, scientific computing, computational journalism, and machine learning. A modular design invites extensions to expand and enrich functionality. Read more about [JupyterLab](https://jupyter.org/).\n", 16 | "\n", 17 | "JupyterLab is available on Red Pitaya with 2.00-23 OS version or higher.\n", 18 | "\n", 19 | "With the upgrade from Jupyter Notebook to JupyterLab, we at Red Pitaya also made a big change: No more obscure documentation and spending hours searching for resources - from now on, JupyterLab uses the Python API commands. Since we now have *One OS to rule all Red Pitaya boards*, the decision has fallen to use the same commands that control your Red Pitaya board across all platforms. \n", 20 | "SCPI commands, once received by the Red Pitaya, are interpreted, and an appropriate C API function is executed. Python API commands, and by extension JupyterLab commands, are also just a mask for C API functions. This means the following:\n", 21 | "- All commands across all platforms are the same\n", 22 | "- The functionality of C API commands is expanded to all other programming languages and platforms.\n", 23 | "\n", 24 | "Enough of the chit-chat! Let's go straight to the fun part!\n", 25 | "\n", 26 | "In case you are new to Python, here is the [Official Python 3 tutorial](https://docs.python.org/3/tutorial/index.html).\n", 27 | "You also can check out the [Whirlwind Python tutorial by Jake Vanderplas on GitHub](https://github.com/jakevdp/WhirlwindTourOfPython), but please note that the Python syntax is outdated.\n", 28 | "\n", 29 | "To execute a cell in JupyterLab, click on it to change focus, and press the run button (⏵) above or press the key combination `Shift+Enter`.\n", 30 | "\n", 31 | "### Note \n", 32 | "We do not recommend running more than 10 JupyterLab kernels simultaneously, as the board can run out of memory and force the shutdown of the JupyterLab application.\n", 33 | "Red Pitaya remembers which Notebooks were opened the last time JupyterLab was used, so exiting the application without closing most of the Notebooks can lead to very long JupyterLab loading times. Therefore, it is inadvisable to exit JupyterLab with more than 5 tabs (Notebooks) open.\n", 34 | "\n" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "9d0a837a-18e9-4ddd-89af-1be4b46d2160", 40 | "metadata": {}, 41 | "source": [ 42 | "### Jupyter API Examples:\n", 43 | "\n", 44 | "1. **Digital:**\n", 45 | " 1. [LED Blink](examples/digital/led.ipynb)\n", 46 | " 2. [Control GPIOs](examples/digital/gpio.ipynb)\n", 47 | "2. **Analog:**\n", 48 | " 1. [Read slow analog I/Os](examples/analog/analog_input.ipynb)\n", 49 | " 2. [Set slow analog I/Os](examples/analog/analog_output.ipynb)\n", 50 | "3. **Generating signals at RF outputs:**\n", 51 | " 1. [Generate continuous signal](examples/generation/gen_continuous_signal.ipynb)\n", 52 | " 2. [Generate signal pulses](examples/generation/gen_bursts.ipynb)\n", 53 | " 3. [Generate a signal on external trigger](examples/generation/gen_ext_trigger.ipynb)\n", 54 | " 4. [Custom waveform signal generation](examples/generation/gen_arbitrary_signal.ipynb)\n", 55 | " 5. [Generate two synchronous signals](examples/generation/gen_sync_two_channel.ipynb)\n", 56 | " 6. [Generate two burst asynced signals](examples/generation/gen_burst_async_signals.ipynb)\n", 57 | "4. **Acquiring signals at RF inputs:**\n", 58 | " 1. [Triggering with a threshold on channel](examples/acquisition/acq_trigger_level.ipynb)\n", 59 | " 2. [Instant signal acquisition](examples/acquisition/acq_instant.ipynb)\n", 60 | " 3. [Triggering on external trigger](examples/acquisition/acq_ext_trig.ipynb)\n", 61 | "5. **Generating and Acquiring signals at RF inputs/outputs:**\n", 62 | " 1. [Synchronised one-pulse signal generation and acquisition](examples/acquisition_generation/acq_gen_synced_pulse.ipynb)\n", 63 | "6. **Multi-board signal acquisition and generation:**\n", 64 | " 1. [Daisy chain generation and acquisition](examples/multiboard_sync/daisy_chain_1.ipynb)\n", 65 | " 2. [Synchronised Click Shield generation and acquisition](examples/multiboard_sync/click_shield_1.ipynb)\n", 66 | "7. **Deep Memory Acquisition:**\n", 67 | " 1. [Deep Memory Acquisition](examples/dma/dma.ipynb)\n", 68 | "8. **Digital communication interfaces (Under construction):**\n", 69 | " 1. *I2C:*\n", 70 | "\n", 71 | " 2. *SPI:*\n", 72 | "\n", 73 | " 3. *UART:*\n", 74 | "\n", 75 | "### System Tools:\n", 76 | "1. [Hardware ID](examples/hardware/hwid.ipynb)\n", 77 | "2. [Calibration](examples/hardware/calibration.ipynb)\n", 78 | "\n", 79 | "### Click Shield Examples\n", 80 | "1. [Click Board Examples](examples/click_shield_examples/click_board_examples/click_board_examples.ipynb)\n", 81 | "\n", 82 | "\n", 83 | "## Outdated\n", 84 | "The code here is outdated and must be updated to work with the Red Pitaya JupyterLab. The examples here will be brought up-to-date in the future.\n", 85 | "\n", 86 | "1. **Sensor:**\n", 87 | " 1. [Home heating automation](examples/outdated/home_automation.ipynb)\n", 88 | " 2. [Temperature sensor (GROVE sensors)](examples/outdated/exam_temp.ipynb)\n", 89 | "2. **Other:**\n", 90 | " 1. [Cable Length measurement using TDR](examples/outdated/cable_length.ipynb)" 91 | ] 92 | } 93 | ], 94 | "metadata": { 95 | "kernelspec": { 96 | "display_name": "Python 3 (ipykernel)", 97 | "language": "python", 98 | "name": "python3" 99 | }, 100 | "language_info": { 101 | "codemirror_mode": { 102 | "name": "ipython", 103 | "version": 3 104 | }, 105 | "file_extension": ".py", 106 | "mimetype": "text/x-python", 107 | "name": "python", 108 | "nbconvert_exporter": "python", 109 | "pygments_lexer": "ipython3", 110 | "version": "3.10.12" 111 | } 112 | }, 113 | "nbformat": 4, 114 | "nbformat_minor": 5 115 | } 116 | --------------------------------------------------------------------------------