├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── beaglebone_pru_adc ├── __init__.py └── firmware │ └── firmware.bin ├── distribute_setup.py ├── examples ├── basic.py ├── encoders.py ├── encoders_test.py ├── oscilloscope.py ├── speed.py ├── speed_control.py └── thresholds.py ├── prussdrv ├── __prussdrv.h ├── pruss_intc_mapping.h ├── prussdrv.c └── prussdrv.h ├── setup.py ├── src ├── README.md ├── firmware.h ├── firmware.p └── pru_adc.c └── test ├── grab_enc0_values.py ├── test_enc.py ├── test_oscilloscope.py ├── test_smoke.py └── test_start.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mike Kroutikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PASM = ../pypruss/PASM/pasm 2 | 3 | all: 4 | $(PASM) -b src/firmware.p beaglebone_pru_adc/firmware/firmware 5 | #python setup.py build_ext --inplace 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # beaglebone_pru_adc 2 | 3 | Fast analog sensor capture for [Beaglebone Black](http://beaglebone.org). 4 | 5 | Please note that this repo is for old Angstrom OS. You may want to check 6 | https://github.com/pgmmpk/bbb_pru_adc for Debian 10 version. 7 | 8 | ## Introduction 9 | 10 | Beaglebone Black processor has built-in ADC unit, that is technically called "Touchscreen/ADC subsystem" in documentation. 11 | It can be used to capture analog signals and digitize them. Unit supports up to 8 inputs. (Incidentally, there 12 | is just a single ADC chip and capture from 8 inputs happens sequentially by multiplexing pins. This means that 13 | capturing a single pin is faster than capturing several pins.) 14 | 15 | Another cool feature of BBB processor is that it has two "Programmable Real-time Units", or PRUs. These are 16 | just two small RISC processors that run at 200Mhz independently from the main CPU. They have access to everything 17 | on the board. 18 | 19 | ## What is it? 20 | This is a Python module that captures ADC signals by utilizing PRU. The capture is very fast, because it happens 21 | in parallel to the main CPU work. User can query signals at any time. This is as fast as a memory read operation. 22 | 23 | In addition to just presenting the current ADC values to the user, this driver can perform some useful data 24 | processing: 25 | 26 | 1. It can apply EMA-filtering (Exponential moving average) with pre-configured smoothing factor. This is useful 27 | for smoothening noisy signals (e.g. IR sensors). 28 | 29 | 2. Up to two inputs can be configured as "wheel encoders". Then driver will not do any EMA filtering, but 30 | instead apply Schmitt-filtering to these signals and compute ticks and distance between encoder ticks (which 31 | is a measure of wheel speed). 32 | 33 | 3. Driver can be configured to perform "oscilloscope capture", i.e. capture any of the computed value in real time 34 | and store the result in memory for subsequent analysis. This is useful for researching analog input shape and tuning 35 | smoothing parameters and Schmitt filter threshold. 36 | 37 | 4. User can configure `cap_delay` parameter to run at lower capture speed than the maximum. Capture delay introduces some delay at every capture cycle resulting in speed slowdown. This allows one to configure ADC capture frequency. 38 | 39 | ## Installation 40 | 41 | Assume Angstrom distribution with kernel 3.8.13: 42 | ```bash 43 | # uname -a 44 | Linux beaglebone 3.8.13 #1 SMP Wed Sep 4 09:09:32 CEST 2013 armv7l GNU/Linux 45 | ``` 46 | 47 | ```bash 48 | # cat /etc/angstrom-version 49 | Angstrom v2012.12 (Core edition) 50 | Built from branch: angstrom-staging-yocto1.3 51 | Revision: 2ac8ed60f1c4152577f334b223b9203f57ed1722 52 | Target system: arm-angstrom-linux-gnueabi 53 | ``` 54 | 55 | 1. Install pre-requisites: 56 | ```bash 57 | opkg update && opkg install python-pip python-setuptools python-smbus 58 | ``` 59 | 60 | 2. Clone GIT repository 61 | ```bash 62 | git clone https://github.com/pgmmpk/beaglebone_pru_adc.git 63 | ``` 64 | 65 | Note: if GIT refuses to clone, this might help (warning: disabling GIT SSL verification may pose a security risk) 66 | ```bash 67 | git config --global http.sslVerify false 68 | ``` 69 | 70 | 3. Build and install python package 71 | ```bash 72 | cd beaglebone_pru_adc 73 | 74 | python setup.py install 75 | ``` 76 | 77 | 4. See it working 78 | ```bash 79 | python examples/basic.py 80 | ``` 81 | 82 | ## Basic usage 83 | 84 | [examples/basic.py](https://github.com/pgmmpk/beaglebone_pru_adc/tree/master/examples/basic.py) 85 | ```python 86 | import beaglebone_pru_adc as adc 87 | 88 | capture = adc.Capture() 89 | 90 | capture.start() 91 | 92 | for _ in range(1000): 93 | print capture.timer, capture.values 94 | 95 | capture.stop() 96 | capture.wait() 97 | capture.close() 98 | ``` 99 | 100 | ## Slowing down capture speed 101 | [examples/speed_control.py](https://github.com/pgmmpk/beaglebone_pru_adc/tree/master/examples/speed_control.py) 102 | ```python 103 | import beaglebone_pru_adc as adc 104 | 105 | capture = adc.Capture() 106 | 107 | # the bigger the delay the slower capture is 108 | capture.cap_delay = 2000 109 | ... 110 | 111 | capture.start() 112 | ... 113 | ``` 114 | 115 | 116 | ## Using encoders 117 | 118 | [examples/encoders.py](https://github.com/pgmmpk/beaglebone_pru_adc/tree/master/examples/encoders.py) 119 | ```python 120 | import beaglebone_pru_adc as adc 121 | 122 | capture = adc.Capture() 123 | capture.encoder0_pin = 0 # AIN0, aka P9_39 124 | capture.encoder1_pin = 2 # AIN2, aka P9_37 125 | capture.encoder0_threshold = 3000 # you will want to adjust this 126 | capture.encoder1_thredhold = 3000 # and this... 127 | capture.encoder0_delay = 100 # prevents "ringing", adjust if needed 128 | capture.encoder1_delay = 100 # ... same 129 | capture.start() 130 | 131 | for _ in range(1000): 132 | print capture.timer, capture.encoder0_values, capture.encoder1_values 133 | 134 | capture.stop() 135 | capture.wait() 136 | capture.close() 137 | ``` 138 | 139 | ## Advanced: oscilloscope mode 140 | 141 | [examples/oscilloscope.py](https://github.com/pgmmpk/beaglebone_pru_adc/tree/master/examples/oscilloscope.py) 142 | ```python 143 | import beaglebone_pru_adc as adc 144 | import time 145 | 146 | numsamples = 10000 # how many samples to capture 147 | 148 | capture = adc.Capture() 149 | 150 | capture.oscilloscope_init(adc.OFF_VALUES, numsamples) # captures AIN0 - the first elt in AIN array 151 | #capture.oscilloscope_init(adc.OFF_VALUES+8, numsamples) # captures AIN2 - the third elt in AIN array 152 | capture.start() 153 | 154 | for _ in range(10): 155 | if capture.oscilloscope_is_complete(): 156 | break 157 | print '.' 158 | time.sleep(0.1) 159 | 160 | capture.stop() 161 | capture.wait() 162 | 163 | print 'Saving oscilloscope values to "data.csv"' 164 | 165 | with open('data.csv', 'w') as f: 166 | for x in capture.oscilloscope_data(numsamples): 167 | f.write(str(x) + '\n') 168 | 169 | print 'done' 170 | 171 | capture.close() 172 | ``` 173 | 174 | ## Choosing encoder threshold 175 | Life is random and no two encoders are the same. Therefore, to get the best out of your wheel 176 | encoder you need to adjust the threshold. Here is a simple method for doing this: 177 | 178 | * Configure encoder pins 179 | * Set encoder threshold to a very high number (e.g. any number higher than 4095 will guarantee that encoder tick will never fire) 180 | * Start capture 181 | * Rotate each wheel few times while capturing 182 | * Examine encoder values. We are interested in min/max pair for each encoder. It will tell us what the actual signal range is for each 183 | wheel encoder 184 | * Choose threshold which is 5-10% lower than the range seen. 185 | 186 | Here is the code that does it (except for the wheel rotation which need to be done manually): 187 | 188 | [examples/thresholds.py](https://github.com/pgmmpk/beaglebone_pru_adc/tree/master/examples/thresholds.py) 189 | 190 | ```python 191 | import beaglebone_pru_adc as adc 192 | import time 193 | 194 | capture = adc.Capture() 195 | capture.encoder0_pin = 0 # AIN0 196 | capture.encoder1_pin = 2 # AIN2 197 | 198 | # set threshold such that encoders never fire any ticks 199 | capture.encoder0_threshold=4096 200 | capture.encoder1_threshold=4096 201 | 202 | capture.start() 203 | 204 | print 'Now you have 10 seconds to rotate each wheel...' 205 | time.sleep(10) 206 | 207 | capture.stop() 208 | capture.wait() 209 | 210 | _, min0, max0, _, _ = capture.encoder0_values 211 | _, min1, max1, _, _ = capture.encoder1_values 212 | 213 | capture.close() 214 | 215 | print 'Range for the Encoder0:', min0, '-', max0 216 | print 'Recommended threshold value for encoder 0 is:', int(0.9*(max0-min0)) 217 | 218 | print 'Range for the Encoder1:', min1, '-', max1 219 | print 'Recommended threshold value for encoder 1 is:', int(0.9*(max1-min1))``` 220 | ``` 221 | ## Choosing encoder delay 222 | 223 | Encoders seem to be not very sensitive to this value. Try `100` that may work just fine for you. 224 | 225 | `delay` supresses noise and prevents it from registering a tick. When `delay` is zero, Schmitt software filtering works in a standard way: 226 | whenever signal exceeds `min+threshold` uptick is registered, and whenever signal becomes less than `max-threshold` a downtick is registered. 227 | 228 | With non-zero `delay` we require signal to overcome threshold for that many consequtive readings. Therefore, small random peaks are just ignored. 229 | 230 | If you make `delay` too low, you may suffer spurious ticks triggered by signal noise. If you make it too high, and your robot goes very fast, 231 | you risk genuine tick to be considered a "noise" and hence ignored. Typical period of a tick for fast-moving wheels is around 1000 time units 232 | (reminder: time unit is one ADC read operation). Therefore, `delay` values of up to 250 seem still reasonable. 233 | 234 | 235 | 236 | ## Reference 237 | ADC input pins are named AIN0-AIN7 (there are 8 of them). They are located on P9 header and mapped to the header pins as follows: 238 | ``` 239 | AIN0: P9_39 240 | AIN1: P9_40 241 | AIN2: P9_37 242 | AIN3: P9_38 243 | AIN4: P9_35 244 | AIN5: P9_36 245 | AIN6: P9_33 246 | AIN7: ????? 247 | ``` 248 | Digital capture produces an integer in the range 0-4095 (inclusively) for each analog input. 249 | 250 | Driver lifetime is 251 | 252 | * `Capture` object is constructed 253 | * Optionally configure driver by setting properties 254 | * `Capture.start()` - driver started 255 | * Main processing is happening here. Read IR and encoder values 256 | * `Capture.stop()` - request sent to the driver to stop capturing and exit 257 | * `Capture.wait()` - wait for driver exit 258 | * `Capture.close()` - releases all resources 259 | 260 | Methods and properties of `Capture` object: 261 | 262 | ### Capture.start() 263 | Starts capture driver. 264 | 265 | ### Capture.stop() 266 | Sets flag signaling driver to exit exit capture loop and halt. 267 | 268 | ### Capture.wait() 269 | Blocks caller until driver halts. 270 | 271 | ### Capture.close() 272 | Releases all driver resources. 273 | 274 | ### Capture.timer 275 | Read-only property. Contains the number of ADC reads since the start of the driver. 276 | 277 | ### Capture.ema_pow 278 | EMA smoothening factor. Smoothening is performed according to the formula: 279 | ``` 280 | ema += (value - ema / 2^ema_pow) 281 | ``` 282 | Therefore, `2^ema_pow` gives the smoothening size. 283 | 284 | Valid range: 0-31 285 | 286 | Default value is `ema_pow=0` which degenerates to no smoothening. 287 | 288 | ### Capture.values 289 | Read-only properties. Returns the tuple of 8 ADC pin values: (AIN0, AIN1, AIN2, AIN3, AIN4, AIN5, AIN6, AIN7). 290 | 291 | If EMA smoothening 292 | was set, these values will represent the result of EMA filtering. Note that due to the way driver applies the EMA smoothening, the values will 293 | be scaled up. To bring them back into the 0-4095 range, divide them by `2^ema_pow` (or shift values right by `ema_pow` bits). 294 | 295 | If some pins were declared as encoder pins, the corresponding slots in the tuple will stay zero. Use `Capture.encoder0_values` 296 | and `Capture.encoder1_values` to read encoder pin values. 297 | 298 | ### Capture.encoder0_pin, Capture.encoder1_pin 299 | Setting this property to value in range 0-7 enables corresponding encoder and makes it use this pin. 300 | Setting it to any other value disables corresponding encoder. 301 | 302 | Default value is `0xff` (disabled). 303 | 304 | ### Capture.encoder0_threshold, Capture.encoder1_threshold 305 | 306 | Threshold value for Schmitt filtering of encoder. Setting this value too high will have an effect of encoder never producing any ticks. 307 | Setting it too low opens possibility of spurious ticks triggered by random analog noise. 308 | 309 | ### Capture.encoder0_delay, Capture.encoder1_delay 310 | 311 | Delay value to filter out noise. Default value is `0` (no filtering). Reasonable value is `100` which requires signal to stay high 312 | for 100 timer units before uptick is registered, and stay low for 100 timer units before downtick is registered. 313 | 314 | ### Capture.encoder0_values, Capture.encoder1_values 315 | Read-only property that returns a 5-tuple describing the state of the encoder. Values are: (raw, min, max, ticks, speed). 316 | 317 | * `raw` is the latest raw value for the encoder pin (for internal use and debugging) 318 | * `min` is the minimum value seen during the current tick window (for internal use and debugging) 319 | * `max` is the maximum value seen during the current tick window (for internal use and debugging) 320 | * `ticks` is the number of encoder ticks seen since the start of the driver. Ticks are counted on the falling edge of the signal. 321 | This value can also be retrieved with a helper property `encoder0_ticks`, `encoder1_ticks`. 322 | * `speed` is the width of the last encoder tick in `timer` units. Its inverse provides a measure of speed. 323 | This value can also be retrieved with `encoder0_speed`, `encoder1_speed` 324 | 325 | ### Capture.encoder0_ticks, Capture.encoder1_ticks 326 | Read-only property that returns number of ticks registered for the corresponding encoder. 327 | Same value is returned as 4-th element of tuple retrieved by `encoder0_values`, `encoder1_values`. 328 | 329 | 330 | ### Capture.encoder0_speed, Capture.encoder1_speed 331 | Read-only property that returns inverse speed of the last registered tick. 332 | Same value is returned as 5-th element of tuple retrieved by `encoder0_values`, `encoder1_values`. 333 | 334 | Note that name is a misnomer. Bigger values mean smaller speed. Actual speed of rotation for 16-teeth encoder can be 335 | computed as 336 | ``` 337 | radians_per_sec = (PI / 8) * 122000 / encoder_speed 338 | ``` 339 | Here PI/8 is the 1/16 of a circle - how many radians one tick represents, 122000 is (approximate) capture speed, 340 | and encoder_speed is teh value returned by the driver (which is the width in timer units of the tick). 341 | 342 | ### Capture.cap_delay 343 | Extra delay to be introduced in the main capture loop for the purpose of slowing down the capture speed. Default value is 0, which means "no delay". Play with the code in `examples/speed_control.py` to choose the correct delay value for the desired speed. Try values of 100, 1000, 10000 to see the difference. 344 | 345 | ### Capture.oscilloscope_init(offset, numsamples) 346 | Sets up driver for "oscilloscope" mode. In this mode on every ADC capture a value from driver local memory will be written 347 | out to a memory buffer. The content of this buffer can later be analyzed (e.g. written to a CSV file and plotted out). 348 | 349 | Parameters: 350 | 351 | * `offset` - offset into local memory where the value of interest is located. Some important offsets are: 352 | * `OFF_VALUES` - offset to the beginning of AIN values array. Use `OFF_VALUES` to examine AIN0, `OFF_VALUES+4` to examine 353 | AIN1, etc. 354 | * `OFF_ENC0_VALUES` - offset to the beginning of encoder0 values. Use `OFF_ENC0_VALUES` to examine raw value of encoder0, 355 | use `OFF_ENC0_VALUES+4` to examine `max` variable of encoder0, etc. 356 | * `OFF_ENC1_VALUES` - offset to the beginning of encoder1 values. 357 | 358 | For the complete list of local memory variables and their offset values see 359 | [src/firmware.h](https://github.com/pgmmpk/beaglebone_pru_adc/blob/master/src/firmware.h) and 360 | [src/README.md](https://github.com/pgmmpk/beaglebone_pru_adc/blob/master/src/README.md). 361 | 362 | * `numsamples` - number of samples to record. This is limited by the size of the DDR memory allocated to the `uio_pruss` device driver. It 363 | is typically 0x40000, which allows recording of up to 64K oscilloscope values. This amounts to about 0.5 sec in time units. 364 | 365 | ### Capture.oscilloscope_is_complete() 366 | Returns `True` if capture was finished (i.e. the required number of samples was recorded and is ready for retrieval). 367 | 368 | ### Capture.oscilloscope_data(numsamples) 369 | Retrieves `numsamples` of data from driver DDR memory. Before calling this its a good idea to verify that oscilloscope indeed 370 | finished capturing all samples by calling `oscilloscope_is_complete()` (or you might read some garbage from not yet initialized memory). 371 | Of course, `numsamples` should be the same value as used in `oscilloscope._init()`. 372 | 373 | Returns an array of integers representing time evolution of the value of interest as determined by `offset` in `oscilloscope_init()` call. 374 | 375 | ## Resources 376 | 377 | 1. [AM335x Technical Reference Manual](http://www.phytec.com/wiki/images/7/72/AM335x_techincal_reference_manual.pdf). Older revision where PRU section is not deleted is [here](http://elinux.org/images/6/65/Spruh73c.pdf). 378 | 2. [How to control ADC (see comments by Lenny and Abd)](http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc) 379 | 3. Hipstercircuits blog and [this](http://hipstercircuits.com/beaglebone-pru-ddr-memory-access-the-right-way) post in particular (how to communicate with DDR memory). 380 | 4. Excellent [PyPRUSS](https://bitbucket.org/intelligentagent/pypruss) library. 381 | 6. [prussdrv.c source](https://github.com/beagleboard/am335x_pru_package/blob/master/pru_sw/app_loader/interface/prussdrv.c) by Texas Instruments. 382 | 7. [PRU assembly reference](http://processors.wiki.ti.com/index.php/PRU_Assembly_Instructions). 383 | 8. [PRU docs on TI wiki](http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem). Includes [list of Open Source PRU projects](http://processors.wiki.ti.com/index.php/PRU_Projects). 384 | 9. [Derek Molloy's BeagleBone website](http://derekmolloy.ie/beaglebone/). 385 | 10. [Ultrasound sensors with PRU](https://github.com/Teknoman117/beaglebot) by Teknoman. 386 | 387 | 388 | ## License 389 | MIT 390 | -------------------------------------------------------------------------------- /beaglebone_pru_adc/__init__.py: -------------------------------------------------------------------------------- 1 | import _pru_adc 2 | import glob 3 | import re 4 | import os 5 | import mmap 6 | import struct 7 | import time 8 | import array 9 | 10 | 11 | SLOTS = glob.glob('/sys/devices/bone_capemgr.*/slots')[0] 12 | 13 | 14 | def _is_pru_loaded(): 15 | with open(SLOTS, 'r') as f: 16 | for line in f: 17 | if re.search(r'BB-BONE-PRU-01', line): 18 | return True 19 | 20 | return False 21 | 22 | def _is_adc_loaded(): 23 | with open(SLOTS, 'r') as f: 24 | for line in f: 25 | if re.search(r'BB-ADC', line): 26 | return True 27 | 28 | return False 29 | 30 | def _ensure_pru_loaded(): 31 | if _is_pru_loaded(): 32 | return 33 | 34 | with open(SLOTS, 'w') as f: 35 | f.write('BB-BONE-PRU-01') 36 | time.sleep(0.2) # let things settle before using this driver 37 | 38 | def _ensure_adc_loaded(): 39 | if _is_adc_loaded(): 40 | return 41 | 42 | with open(SLOTS, 'w') as f: 43 | f.write('BB-ADC') 44 | time.sleep(0.2) # let things settle before using this driver 45 | 46 | _ensure_pru_loaded() 47 | _ensure_adc_loaded() 48 | 49 | # Useful offsets from firmware.h 50 | OFF_FLAG = 0x0008 51 | OFF_TIMER = 0x0004 52 | OFF_EMA_POW = 0x001c 53 | OFF_VALUES = 0x0020 54 | OFF_ENC0_PIN = 0x0040 55 | OFF_ENC1_PIN = 0x0041 56 | OFF_ENC0_THRESH = 0x0044 57 | OFF_ENC1_THRESH = 0x0084 58 | OFF_ENC0_VALUES = 0x0048 59 | OFF_ENC1_VALUES = 0x0088 60 | OFF_ENC0_TICKS = 0x0054 61 | OFF_ENC1_TICKS = 0x0094 62 | OFF_ENC0_SPEED = 0x0058 63 | OFF_ENC1_SPEED = 0x0098 64 | OFF_ENC0_DELAY = 0x0060 65 | OFF_ENC1_DELAY = 0x00a0 66 | OFF_SCOPE_ADDR = 0x000c 67 | OFF_SCOPE_OFFSET= 0x0010 68 | OFF_SCOPE_SIZE = 0x0014 69 | OFF_DEBUG = 0x0018 70 | OFF_CAP_DELAY = 0x00c4 71 | 72 | 73 | class Capture(_pru_adc.Capture): 74 | 75 | def __init__(self): 76 | self._mem = None 77 | _pru_adc.Capture.__init__(self) 78 | 79 | with open('/sys/class/uio/uio0/maps/map0/addr') as f: 80 | self._mem_addr = int(f.read().strip(), 16) 81 | 82 | with open('/sys/class/uio/uio0/maps/map0/size') as f: 83 | self._mem_size = int(f.read().strip(), 16) 84 | 85 | with open('/sys/class/uio/uio0/maps/map1/addr') as f: 86 | self._ddr_addr = int(f.read().strip(), 16) 87 | 88 | with open('/sys/class/uio/uio0/maps/map1/size') as f: 89 | self._ddr_size = int(f.read().strip(), 16) 90 | 91 | with open("/dev/mem", 'r+b') as f1: 92 | self._mem = mmap.mmap(f1.fileno(), self._mem_size, offset=self._mem_addr) 93 | 94 | def __del__(self): 95 | if self._mem: 96 | self._mem.close() 97 | 98 | def start(self): 99 | firmware = os.path.dirname(__file__) + '/firmware/firmware.bin' 100 | _pru_adc.Capture.start(self, firmware) 101 | 102 | def stop(self): 103 | self._set_word(OFF_FLAG, 1) # exit flag 104 | 105 | def close(self): 106 | _pru_adc.Capture.close(self) 107 | self._mem.close() 108 | self._mem = None 109 | 110 | @property 111 | def timer(self): 112 | """ 113 | Returns ADC timer value. This is the number of ADC capture cycles since driver start 114 | """ 115 | return self._get_word(OFF_TIMER) 116 | 117 | @property 118 | def ema_pow(self): 119 | """ 120 | Returns EMA exponent. If zero, no EMA averaging 121 | """ 122 | return self._get_word(OFF_EMA_POW) 123 | 124 | @ema_pow.setter 125 | def ema_pow(self, value): 126 | if 0 <= value <= 31: 127 | self._set_word(OFF_EMA_POW, value) 128 | else: 129 | raise ValueError("ema_pow must be in range 0-31") 130 | 131 | @property 132 | def values(self): 133 | return struct.unpack("LLLLLLLL", self._mem[OFF_VALUES:OFF_VALUES+8*4]) 134 | 135 | @property 136 | def encoder0_pin(self): 137 | return struct.unpack("b", self._mem[OFF_ENC0_PIN:OFF_ENC0_PIN+1])[0] 138 | 139 | @encoder0_pin.setter 140 | def encoder0_pin(self, value): 141 | struct.pack_into('b', self._mem, OFF_ENC0_PIN, value) 142 | 143 | @property 144 | def encoder1_pin(self): 145 | return struct.unpack("b", self._mem[OFF_ENC1_PIN:OFF_ENC1_PIN+1])[0] 146 | 147 | @encoder1_pin.setter 148 | def encoder1_pin(self, value): 149 | struct.pack_into('b', self._mem, OFF_ENC1_PIN, value) 150 | 151 | @property 152 | def encoder0_threshold(self): 153 | return self._get_word(OFF_ENC0_THRESH) 154 | 155 | @encoder0_threshold.setter 156 | def encoder0_threshold(self, value): 157 | self._set_word(OFF_ENC0_THRESH, value) 158 | 159 | @property 160 | def encoder1_threshold(self): 161 | return self._get_word(OFF_ENC1_THRESH) 162 | 163 | @encoder1_threshold.setter 164 | def encoder1_threshold(self, value): 165 | self._set_word(OFF_ENC1_THRESH, value) 166 | 167 | @property 168 | def encoder0_values(self): 169 | return struct.unpack("LLLLL", self._mem[OFF_ENC0_VALUES:OFF_ENC0_VALUES+5*4]) 170 | 171 | @property 172 | def encoder1_values(self): 173 | return struct.unpack("LLLLL", self._mem[OFF_ENC1_VALUES:OFF_ENC1_VALUES+5*4]) 174 | 175 | @property 176 | def encoder0_delay(self): 177 | return self._get_word(OFF_ENC0_DELAY) 178 | 179 | @encoder0_delay.setter 180 | def encoder0_delay(self, value): 181 | self._set_word(OFF_ENC0_DELAY, value) 182 | 183 | @property 184 | def encoder1_delay(self): 185 | return self._get_word(OFF_ENC1_DELAY) 186 | 187 | @encoder1_delay.setter 188 | def encoder1_delay(self, value): 189 | self._set_word(OFF_ENC1_DELAY, value) 190 | 191 | @property 192 | def encoder0_ticks(self): 193 | return self._get_word(OFF_ENC0_TICKS) 194 | 195 | @property 196 | def encoder1_ticks(self): 197 | return self._get_word(OFF_ENC1_TICKS) 198 | 199 | @property 200 | def encoder0_speed(self): 201 | return self._get_word(OFF_ENC0_SPEED) 202 | 203 | @property 204 | def encoder1_speed(self): 205 | return self._get_word(OFF_ENC1_SPEED) 206 | 207 | @property 208 | def debug_value(self): 209 | return self._get_word(OFF_DEBUG) 210 | 211 | @property 212 | def cap_delay(self): 213 | return self._get_word(OFF_CAP_DELAY) 214 | 215 | @cap_delay.setter 216 | def cap_delay(self, value): 217 | self._set_word(OFF_CAP_DELAY, value) 218 | 219 | def _set_word(self, byte_offset, value): 220 | struct.pack_into('L', self._mem, byte_offset, value) 221 | 222 | def _get_word(self, byte_offset): 223 | return struct.unpack("L", self._mem[byte_offset:byte_offset+4])[0] 224 | 225 | def oscilloscope_init(self, offset, numsamples): 226 | if numsamples * 4 > self._ddr_size: 227 | raise ValueError("numsamples is too large. Limit is (determined by DDR memory size): " + str(self._ddr_size//4)) 228 | self._set_word(OFF_SCOPE_ADDR, self._ddr_addr) 229 | self._set_word(OFF_SCOPE_OFFSET, offset) 230 | self._set_word(OFF_SCOPE_SIZE, numsamples * 4) 231 | 232 | def oscilloscope_is_complete(self): 233 | return self._get_word(OFF_SCOPE_SIZE) == 0 234 | 235 | def oscilloscope_data(self, numsamples): 236 | out = array.array('L') 237 | with open("/dev/mem", 'r+b') as f1: 238 | ddr_offset = 0 239 | ddr_addr = self._ddr_addr 240 | if ddr_addr >= 0x80000000: # workaround of mmap bug 241 | ddr_offset = 0x70000000 242 | ddr_addr -= ddr_offset 243 | ddr = mmap.mmap(f1.fileno(), self._ddr_size + ddr_offset, offset=ddr_addr) 244 | out.fromstring(ddr[ddr_offset:ddr_offset + 4*numsamples]) 245 | ddr.close() 246 | return out 247 | -------------------------------------------------------------------------------- /beaglebone_pru_adc/firmware/firmware.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgmmpk/beaglebone_pru_adc/1128d37df2507addee3c0237a9958add882438b3/beaglebone_pru_adc/firmware/firmware.bin -------------------------------------------------------------------------------- /distribute_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap distribute installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from distribute_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import os 17 | import shutil 18 | import sys 19 | import time 20 | import fnmatch 21 | import tempfile 22 | import tarfile 23 | import optparse 24 | 25 | from distutils import log 26 | 27 | try: 28 | from site import USER_SITE 29 | except ImportError: 30 | USER_SITE = None 31 | 32 | try: 33 | import subprocess 34 | 35 | def _python_cmd(*args): 36 | args = (sys.executable,) + args 37 | return subprocess.call(args) == 0 38 | 39 | except ImportError: 40 | # will be used for python 2.3 41 | def _python_cmd(*args): 42 | args = (sys.executable,) + args 43 | # quoting arguments if windows 44 | if sys.platform == 'win32': 45 | def quote(arg): 46 | if ' ' in arg: 47 | return '"%s"' % arg 48 | return arg 49 | args = [quote(arg) for arg in args] 50 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 51 | 52 | DEFAULT_VERSION = "0.6.45" 53 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" 54 | SETUPTOOLS_FAKED_VERSION = "0.6c11" 55 | 56 | SETUPTOOLS_PKG_INFO = """\ 57 | Metadata-Version: 1.0 58 | Name: setuptools 59 | Version: %s 60 | Summary: xxxx 61 | Home-page: xxx 62 | Author: xxx 63 | Author-email: xxx 64 | License: xxx 65 | Description: xxx 66 | """ % SETUPTOOLS_FAKED_VERSION 67 | 68 | 69 | def _install(tarball, install_args=()): 70 | # extracting the tarball 71 | tmpdir = tempfile.mkdtemp() 72 | log.warn('Extracting in %s', tmpdir) 73 | old_wd = os.getcwd() 74 | try: 75 | os.chdir(tmpdir) 76 | tar = tarfile.open(tarball) 77 | _extractall(tar) 78 | tar.close() 79 | 80 | # going in the directory 81 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 82 | os.chdir(subdir) 83 | log.warn('Now working in %s', subdir) 84 | 85 | # installing 86 | log.warn('Installing Distribute') 87 | if not _python_cmd('setup.py', 'install', *install_args): 88 | log.warn('Something went wrong during the installation.') 89 | log.warn('See the error message above.') 90 | # exitcode will be 2 91 | return 2 92 | finally: 93 | os.chdir(old_wd) 94 | shutil.rmtree(tmpdir) 95 | 96 | 97 | def _build_egg(egg, tarball, to_dir): 98 | # extracting the tarball 99 | tmpdir = tempfile.mkdtemp() 100 | log.warn('Extracting in %s', tmpdir) 101 | old_wd = os.getcwd() 102 | try: 103 | os.chdir(tmpdir) 104 | tar = tarfile.open(tarball) 105 | _extractall(tar) 106 | tar.close() 107 | 108 | # going in the directory 109 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 110 | os.chdir(subdir) 111 | log.warn('Now working in %s', subdir) 112 | 113 | # building an egg 114 | log.warn('Building a Distribute egg in %s', to_dir) 115 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 116 | 117 | finally: 118 | os.chdir(old_wd) 119 | shutil.rmtree(tmpdir) 120 | # returning the result 121 | log.warn(egg) 122 | if not os.path.exists(egg): 123 | raise IOError('Could not build the egg.') 124 | 125 | 126 | def _do_download(version, download_base, to_dir, download_delay): 127 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' 128 | % (version, sys.version_info[0], sys.version_info[1])) 129 | if not os.path.exists(egg): 130 | tarball = download_setuptools(version, download_base, 131 | to_dir, download_delay) 132 | _build_egg(egg, tarball, to_dir) 133 | sys.path.insert(0, egg) 134 | import setuptools 135 | setuptools.bootstrap_install_from = egg 136 | 137 | 138 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 139 | to_dir=os.curdir, download_delay=15, no_fake=True): 140 | # making sure we use the absolute path 141 | to_dir = os.path.abspath(to_dir) 142 | was_imported = 'pkg_resources' in sys.modules or \ 143 | 'setuptools' in sys.modules 144 | try: 145 | try: 146 | import pkg_resources 147 | 148 | # Setuptools 0.7b and later is a suitable (and preferable) 149 | # substitute for any Distribute version. 150 | try: 151 | pkg_resources.require("setuptools>=0.7b") 152 | return 153 | except (pkg_resources.DistributionNotFound, 154 | pkg_resources.VersionConflict): 155 | pass 156 | 157 | if not hasattr(pkg_resources, '_distribute'): 158 | if not no_fake: 159 | _fake_setuptools() 160 | raise ImportError 161 | except ImportError: 162 | return _do_download(version, download_base, to_dir, download_delay) 163 | try: 164 | pkg_resources.require("distribute>=" + version) 165 | return 166 | except pkg_resources.VersionConflict: 167 | e = sys.exc_info()[1] 168 | if was_imported: 169 | sys.stderr.write( 170 | "The required version of distribute (>=%s) is not available,\n" 171 | "and can't be installed while this script is running. Please\n" 172 | "install a more recent version first, using\n" 173 | "'easy_install -U distribute'." 174 | "\n\n(Currently using %r)\n" % (version, e.args[0])) 175 | sys.exit(2) 176 | else: 177 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 178 | return _do_download(version, download_base, to_dir, 179 | download_delay) 180 | except pkg_resources.DistributionNotFound: 181 | return _do_download(version, download_base, to_dir, 182 | download_delay) 183 | finally: 184 | if not no_fake: 185 | _create_fake_setuptools_pkg_info(to_dir) 186 | 187 | 188 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 189 | to_dir=os.curdir, delay=15): 190 | """Download distribute from a specified location and return its filename 191 | 192 | `version` should be a valid distribute version number that is available 193 | as an egg for download under the `download_base` URL (which should end 194 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 195 | `delay` is the number of seconds to pause before an actual download 196 | attempt. 197 | """ 198 | # making sure we use the absolute path 199 | to_dir = os.path.abspath(to_dir) 200 | try: 201 | from urllib.request import urlopen 202 | except ImportError: 203 | from urllib2 import urlopen 204 | tgz_name = "distribute-%s.tar.gz" % version 205 | url = download_base + tgz_name 206 | saveto = os.path.join(to_dir, tgz_name) 207 | src = dst = None 208 | if not os.path.exists(saveto): # Avoid repeated downloads 209 | try: 210 | log.warn("Downloading %s", url) 211 | src = urlopen(url) 212 | # Read/write all in one block, so we don't create a corrupt file 213 | # if the download is interrupted. 214 | data = src.read() 215 | dst = open(saveto, "wb") 216 | dst.write(data) 217 | finally: 218 | if src: 219 | src.close() 220 | if dst: 221 | dst.close() 222 | return os.path.realpath(saveto) 223 | 224 | 225 | def _no_sandbox(function): 226 | def __no_sandbox(*args, **kw): 227 | try: 228 | from setuptools.sandbox import DirectorySandbox 229 | if not hasattr(DirectorySandbox, '_old'): 230 | def violation(*args): 231 | pass 232 | DirectorySandbox._old = DirectorySandbox._violation 233 | DirectorySandbox._violation = violation 234 | patched = True 235 | else: 236 | patched = False 237 | except ImportError: 238 | patched = False 239 | 240 | try: 241 | return function(*args, **kw) 242 | finally: 243 | if patched: 244 | DirectorySandbox._violation = DirectorySandbox._old 245 | del DirectorySandbox._old 246 | 247 | return __no_sandbox 248 | 249 | 250 | def _patch_file(path, content): 251 | """Will backup the file then patch it""" 252 | f = open(path) 253 | existing_content = f.read() 254 | f.close() 255 | if existing_content == content: 256 | # already patched 257 | log.warn('Already patched.') 258 | return False 259 | log.warn('Patching...') 260 | _rename_path(path) 261 | f = open(path, 'w') 262 | try: 263 | f.write(content) 264 | finally: 265 | f.close() 266 | return True 267 | 268 | _patch_file = _no_sandbox(_patch_file) 269 | 270 | 271 | def _same_content(path, content): 272 | f = open(path) 273 | existing_content = f.read() 274 | f.close() 275 | return existing_content == content 276 | 277 | 278 | def _rename_path(path): 279 | new_name = path + '.OLD.%s' % time.time() 280 | log.warn('Renaming %s to %s', path, new_name) 281 | os.rename(path, new_name) 282 | return new_name 283 | 284 | 285 | def _remove_flat_installation(placeholder): 286 | if not os.path.isdir(placeholder): 287 | log.warn('Unkown installation at %s', placeholder) 288 | return False 289 | found = False 290 | for file in os.listdir(placeholder): 291 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'): 292 | found = True 293 | break 294 | if not found: 295 | log.warn('Could not locate setuptools*.egg-info') 296 | return 297 | 298 | log.warn('Moving elements out of the way...') 299 | pkg_info = os.path.join(placeholder, file) 300 | if os.path.isdir(pkg_info): 301 | patched = _patch_egg_dir(pkg_info) 302 | else: 303 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) 304 | 305 | if not patched: 306 | log.warn('%s already patched.', pkg_info) 307 | return False 308 | # now let's move the files out of the way 309 | for element in ('setuptools', 'pkg_resources.py', 'site.py'): 310 | element = os.path.join(placeholder, element) 311 | if os.path.exists(element): 312 | _rename_path(element) 313 | else: 314 | log.warn('Could not find the %s element of the ' 315 | 'Setuptools distribution', element) 316 | return True 317 | 318 | _remove_flat_installation = _no_sandbox(_remove_flat_installation) 319 | 320 | 321 | def _after_install(dist): 322 | log.warn('After install bootstrap.') 323 | placeholder = dist.get_command_obj('install').install_purelib 324 | _create_fake_setuptools_pkg_info(placeholder) 325 | 326 | 327 | def _create_fake_setuptools_pkg_info(placeholder): 328 | if not placeholder or not os.path.exists(placeholder): 329 | log.warn('Could not find the install location') 330 | return 331 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) 332 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \ 333 | (SETUPTOOLS_FAKED_VERSION, pyver) 334 | pkg_info = os.path.join(placeholder, setuptools_file) 335 | if os.path.exists(pkg_info): 336 | log.warn('%s already exists', pkg_info) 337 | return 338 | 339 | log.warn('Creating %s', pkg_info) 340 | try: 341 | f = open(pkg_info, 'w') 342 | except EnvironmentError: 343 | log.warn("Don't have permissions to write %s, skipping", pkg_info) 344 | return 345 | try: 346 | f.write(SETUPTOOLS_PKG_INFO) 347 | finally: 348 | f.close() 349 | 350 | pth_file = os.path.join(placeholder, 'setuptools.pth') 351 | log.warn('Creating %s', pth_file) 352 | f = open(pth_file, 'w') 353 | try: 354 | f.write(os.path.join(os.curdir, setuptools_file)) 355 | finally: 356 | f.close() 357 | 358 | _create_fake_setuptools_pkg_info = _no_sandbox( 359 | _create_fake_setuptools_pkg_info 360 | ) 361 | 362 | 363 | def _patch_egg_dir(path): 364 | # let's check if it's already patched 365 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 366 | if os.path.exists(pkg_info): 367 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): 368 | log.warn('%s already patched.', pkg_info) 369 | return False 370 | _rename_path(path) 371 | os.mkdir(path) 372 | os.mkdir(os.path.join(path, 'EGG-INFO')) 373 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 374 | f = open(pkg_info, 'w') 375 | try: 376 | f.write(SETUPTOOLS_PKG_INFO) 377 | finally: 378 | f.close() 379 | return True 380 | 381 | _patch_egg_dir = _no_sandbox(_patch_egg_dir) 382 | 383 | 384 | def _before_install(): 385 | log.warn('Before install bootstrap.') 386 | _fake_setuptools() 387 | 388 | 389 | def _under_prefix(location): 390 | if 'install' not in sys.argv: 391 | return True 392 | args = sys.argv[sys.argv.index('install') + 1:] 393 | for index, arg in enumerate(args): 394 | for option in ('--root', '--prefix'): 395 | if arg.startswith('%s=' % option): 396 | top_dir = arg.split('root=')[-1] 397 | return location.startswith(top_dir) 398 | elif arg == option: 399 | if len(args) > index: 400 | top_dir = args[index + 1] 401 | return location.startswith(top_dir) 402 | if arg == '--user' and USER_SITE is not None: 403 | return location.startswith(USER_SITE) 404 | return True 405 | 406 | 407 | def _fake_setuptools(): 408 | log.warn('Scanning installed packages') 409 | try: 410 | import pkg_resources 411 | except ImportError: 412 | # we're cool 413 | log.warn('Setuptools or Distribute does not seem to be installed.') 414 | return 415 | ws = pkg_resources.working_set 416 | try: 417 | setuptools_dist = ws.find( 418 | pkg_resources.Requirement.parse('setuptools', replacement=False) 419 | ) 420 | except TypeError: 421 | # old distribute API 422 | setuptools_dist = ws.find( 423 | pkg_resources.Requirement.parse('setuptools') 424 | ) 425 | 426 | if setuptools_dist is None: 427 | log.warn('No setuptools distribution found') 428 | return 429 | # detecting if it was already faked 430 | setuptools_location = setuptools_dist.location 431 | log.warn('Setuptools installation detected at %s', setuptools_location) 432 | 433 | # if --root or --preix was provided, and if 434 | # setuptools is not located in them, we don't patch it 435 | if not _under_prefix(setuptools_location): 436 | log.warn('Not patching, --root or --prefix is installing Distribute' 437 | ' in another location') 438 | return 439 | 440 | # let's see if its an egg 441 | if not setuptools_location.endswith('.egg'): 442 | log.warn('Non-egg installation') 443 | res = _remove_flat_installation(setuptools_location) 444 | if not res: 445 | return 446 | else: 447 | log.warn('Egg installation') 448 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') 449 | if (os.path.exists(pkg_info) and 450 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): 451 | log.warn('Already patched.') 452 | return 453 | log.warn('Patching...') 454 | # let's create a fake egg replacing setuptools one 455 | res = _patch_egg_dir(setuptools_location) 456 | if not res: 457 | return 458 | log.warn('Patching complete.') 459 | _relaunch() 460 | 461 | 462 | def _relaunch(): 463 | log.warn('Relaunching...') 464 | # we have to relaunch the process 465 | # pip marker to avoid a relaunch bug 466 | _cmd1 = ['-c', 'install', '--single-version-externally-managed'] 467 | _cmd2 = ['-c', 'install', '--record'] 468 | if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2: 469 | sys.argv[0] = 'setup.py' 470 | args = [sys.executable] + sys.argv 471 | sys.exit(subprocess.call(args)) 472 | 473 | 474 | def _extractall(self, path=".", members=None): 475 | """Extract all members from the archive to the current working 476 | directory and set owner, modification time and permissions on 477 | directories afterwards. `path' specifies a different directory 478 | to extract to. `members' is optional and must be a subset of the 479 | list returned by getmembers(). 480 | """ 481 | import copy 482 | import operator 483 | from tarfile import ExtractError 484 | directories = [] 485 | 486 | if members is None: 487 | members = self 488 | 489 | for tarinfo in members: 490 | if tarinfo.isdir(): 491 | # Extract directories with a safe mode. 492 | directories.append(tarinfo) 493 | tarinfo = copy.copy(tarinfo) 494 | tarinfo.mode = 448 # decimal for oct 0700 495 | self.extract(tarinfo, path) 496 | 497 | # Reverse sort directories. 498 | if sys.version_info < (2, 4): 499 | def sorter(dir1, dir2): 500 | return cmp(dir1.name, dir2.name) 501 | directories.sort(sorter) 502 | directories.reverse() 503 | else: 504 | directories.sort(key=operator.attrgetter('name'), reverse=True) 505 | 506 | # Set correct owner, mtime and filemode on directories. 507 | for tarinfo in directories: 508 | dirpath = os.path.join(path, tarinfo.name) 509 | try: 510 | self.chown(tarinfo, dirpath) 511 | self.utime(tarinfo, dirpath) 512 | self.chmod(tarinfo, dirpath) 513 | except ExtractError: 514 | e = sys.exc_info()[1] 515 | if self.errorlevel > 1: 516 | raise 517 | else: 518 | self._dbg(1, "tarfile: %s" % e) 519 | 520 | 521 | def _build_install_args(options): 522 | """ 523 | Build the arguments to 'python setup.py install' on the distribute package 524 | """ 525 | install_args = [] 526 | if options.user_install: 527 | if sys.version_info < (2, 6): 528 | log.warn("--user requires Python 2.6 or later") 529 | raise SystemExit(1) 530 | install_args.append('--user') 531 | return install_args 532 | 533 | def _parse_args(): 534 | """ 535 | Parse the command line for options 536 | """ 537 | parser = optparse.OptionParser() 538 | parser.add_option( 539 | '--user', dest='user_install', action='store_true', default=False, 540 | help='install in user site package (requires Python 2.6 or later)') 541 | parser.add_option( 542 | '--download-base', dest='download_base', metavar="URL", 543 | default=DEFAULT_URL, 544 | help='alternative URL from where to download the distribute package') 545 | options, args = parser.parse_args() 546 | # positional arguments are ignored 547 | return options 548 | 549 | def main(version=DEFAULT_VERSION): 550 | """Install or upgrade setuptools and EasyInstall""" 551 | options = _parse_args() 552 | tarball = download_setuptools(download_base=options.download_base) 553 | return _install(tarball, _build_install_args(options)) 554 | 555 | if __name__ == '__main__': 556 | sys.exit(main()) -------------------------------------------------------------------------------- /examples/basic.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | 3 | capture = adc.Capture() 4 | 5 | capture.start() 6 | 7 | for _ in range(1000): 8 | print capture.timer, capture.values 9 | 10 | capture.stop() # ask driver to stop 11 | capture.wait() # wait for graceful exit 12 | capture.close() 13 | -------------------------------------------------------------------------------- /examples/encoders.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | 3 | capture = adc.Capture() 4 | capture.encoder0_pin = 0 # AIN0, aka P9_39 5 | capture.encoder1_pin = 2 # AIN2, aka P9_37 6 | capture.encoder0_threshold = 3000 # you will want to adjust this 7 | capture.encoder1_thredhold = 3000 # and this... 8 | capture.encoder0_delay = 100 # prevents "ringing", adjust if needed 9 | capture.encoder1_delay = 100 # ... same 10 | 11 | capture.start() 12 | 13 | for _ in range(1000): 14 | print capture.timer, capture.encoder0_values, capture.encoder1_values 15 | 16 | capture.stop() 17 | capture.wait() 18 | capture.close() -------------------------------------------------------------------------------- /examples/encoders_test.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import contextlib 3 | import time 4 | 5 | @contextlib.contextmanager 6 | def init_capture(threshold0, threshold1, delay=0): 7 | 8 | capture = adc.Capture() 9 | capture.encoder0_pin = 0 # AIN0, aka P9_39 10 | capture.encoder1_pin = 2 # AIN2, aka P9_37 11 | capture.encoder0_threshold = threshold0 12 | capture.encoder1_thredhold = threshold1 13 | capture.encoder0_delay = delay 14 | capture.encoder1_delay = delay 15 | capture.start() 16 | 17 | yield capture 18 | 19 | capture.stop() 20 | capture.wait() 21 | capture.close() 22 | 23 | with init_capture(2000, 2000, 200) as c: 24 | 25 | enc0_ticks = c.encoder0_ticks 26 | enc1_ticks = c.encoder1_ticks 27 | 28 | while True: 29 | v0 = c.encoder0_ticks 30 | v1 = c.encoder1_ticks 31 | 32 | if v0 != enc0_ticks or v1 != enc1_ticks: 33 | enc0_ticks = v0 34 | enc1_ticks = v1 35 | enc0_speed = 10000. / c.encoder0_speed 36 | enc1_speed = 10000. / c.encoder1_speed 37 | 38 | print '%8d[%4.2lf] %8d[%4.2lf]' % (enc0_ticks, enc0_speed, enc1_ticks, enc1_speed) 39 | 40 | time.sleep(0.001) 41 | -------------------------------------------------------------------------------- /examples/oscilloscope.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | 4 | numsamples = 10000 # how many samples to capture 5 | 6 | capture = adc.Capture() 7 | 8 | capture.oscilloscope_init(adc.OFF_VALUES, numsamples) # captures AIN0 - the first elt in AIN array 9 | #capture.oscilloscope_init(adc.OFF_VALUES+8, numsamples) # captures AIN2 - the third elt in AIN array 10 | capture.start() 11 | 12 | for _ in range(10): 13 | if capture.oscilloscope_is_complete(): 14 | break 15 | print '.' 16 | time.sleep(0.1) 17 | 18 | capture.stop() 19 | capture.wait() 20 | 21 | print 'Saving oscilloscope values to "data.csv"' 22 | 23 | with open('data.csv', 'w') as f: 24 | for x in capture.oscilloscope_data(numsamples): 25 | f.write(str(x) + '\n') 26 | 27 | print 'done' 28 | 29 | capture.close() -------------------------------------------------------------------------------- /examples/speed.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | 4 | print 'Will start capture, keep it running for 10 seconds, then get timer value' 5 | print 'This is used to compute the capture speed (time value of one timer unit)' 6 | print 'Please wait...' 7 | 8 | capture = adc.Capture() 9 | 10 | capture.encoder0_pin = 0 # AIN0, aka P9_39 11 | capture.encoder1_pin = 2 # AIN2, aka P9_37 12 | capture.encoder0_threshold = 3000 # you will want to adjust this 13 | capture.encoder1_thredhold = 3000 # and this... 14 | capture.encoder0_delay = 100 # prevents "ringing", adjust if needed 15 | capture.encoder1_delay = 100 # ... same 16 | capture.start() 17 | 18 | time.sleep(10) 19 | 20 | timer = capture.timer 21 | 22 | capture.stop() 23 | capture.wait() 24 | capture.close() 25 | 26 | print 'Capture runs at %d readings per second' % (timer // 10) 27 | print 'Time value of one timer unit is %d nanosec' % (1000000000 // timer) 28 | -------------------------------------------------------------------------------- /examples/speed_control.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | 4 | print 'Will start capture, keep it running for 10 seconds, then get timer value' 5 | print 'This is used to compute the capture speed (time value of one timer unit)' 6 | print 'Please wait...' 7 | 8 | capture = adc.Capture() 9 | 10 | capture.encoder0_pin = 0 # AIN0, aka P9_39 11 | capture.encoder1_pin = 2 # AIN2, aka P9_37 12 | capture.encoder0_threshold = 3000 # you will want to adjust this 13 | capture.encoder1_thredhold = 3000 # and this... 14 | capture.encoder0_delay = 100 # prevents "ringing", adjust if needed 15 | capture.encoder1_delay = 100 # ... same 16 | 17 | capture.cap_delay = 10000 18 | capture.start() 19 | 20 | time.sleep(10) 21 | 22 | timer = capture.timer 23 | 24 | capture.stop() 25 | capture.wait() 26 | capture.close() 27 | 28 | print 'Capture runs at %d readings per second' % (timer // 10) 29 | print 'Time value of one timer unit is %d nanosec' % (1000000000 // timer) 30 | -------------------------------------------------------------------------------- /examples/thresholds.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | 4 | capture = adc.Capture() 5 | capture.encoder0_pin = 0 # AIN0 6 | capture.encoder1_pin = 2 # AIN2 7 | 8 | # set threshold such that encoders never fire any ticks 9 | capture.encoder0_threshold=4096 10 | capture.encoder1_threshold=4096 11 | 12 | capture.start() 13 | 14 | print 'Now you have 10 seconds to rotate each wheel...' 15 | time.sleep(10) 16 | 17 | capture.stop() 18 | capture.wait() 19 | 20 | _, min0, max0, _, _ = capture.encoder0_values 21 | _, min1, max1, _, _ = capture.encoder1_values 22 | 23 | capture.close() 24 | 25 | print 'Range for the Encoder0:', min0, '-', max0 26 | print 'Recommended threshold value for encoder 0 is:', int(0.9*(max0-min0)) 27 | 28 | print 'Range for the Encoder1:', min1, '-', max1 29 | print 'Recommended threshold value for encoder 1 is:', int(0.9*(max1-min1)) 30 | -------------------------------------------------------------------------------- /prussdrv/__prussdrv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * __prussdrv.h 3 | * 4 | * 5 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 6 | * 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the 18 | * distribution. 19 | * 20 | * Neither the name of Texas Instruments Incorporated nor the names of 21 | * its contributors may be used to endorse or promote products derived 22 | * from this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | /* 39 | * ============================================================================ 40 | * Copyright (c) Texas Instruments Inc 2010-12 41 | * 42 | * Use of this software is controlled by the terms and conditions found in the 43 | * license agreement under which this software has been supplied or provided. 44 | * ============================================================================ 45 | */ 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | #include 63 | 64 | #define DISABLE_L3RAM_SUPPORT 65 | 66 | #define PAGE_SIZE 4096 67 | 68 | #define PRUSS_V1_STR "AM18XX" 69 | #define PRUSS_V2_STR "AM33XX" 70 | #define PRUSS_UNKNOWN_STR "UNKNOWN" 71 | 72 | #define AM33XX_PRUSS_INTC_REV 0x4E82A900 73 | #define AM18XX_PRUSS_INTC_REV 0x4E825900 74 | 75 | #define PRUSS_MAX_IRAM_SIZE 8192 76 | 77 | #define AM33XX_PRUSS_IRAM_SIZE 8192 78 | #define AM33XX_PRUSS_MMAP_SIZE 0x40000 79 | #define AM33XX_DATARAM0_PHYS_BASE 0x4a300000 80 | #define AM33XX_DATARAM1_PHYS_BASE 0x4a302000 81 | #define AM33XX_INTC_PHYS_BASE 0x4a320000 82 | #define AM33XX_PRU0CONTROL_PHYS_BASE 0x4a322000 83 | #define AM33XX_PRU0DEBUG_PHYS_BASE 0x4a322400 84 | #define AM33XX_PRU1CONTROL_PHYS_BASE 0x4a324000 85 | #define AM33XX_PRU1DEBUG_PHYS_BASE 0x4a324400 86 | #define AM33XX_PRU0IRAM_PHYS_BASE 0x4a334000 87 | #define AM33XX_PRU1IRAM_PHYS_BASE 0x4a338000 88 | #define AM33XX_PRUSS_SHAREDRAM_BASE 0x4a310000 89 | #define AM33XX_PRUSS_CFG_BASE 0x4a326000 90 | #define AM33XX_PRUSS_UART_BASE 0x4a328000 91 | #define AM33XX_PRUSS_IEP_BASE 0x4a32e000 92 | #define AM33XX_PRUSS_ECAP_BASE 0x4a330000 93 | #define AM33XX_PRUSS_MIIRT_BASE 0x4a332000 94 | #define AM33XX_PRUSS_MDIO_BASE 0x4a332400 95 | 96 | #define AM18XX_PRUSS_IRAM_SIZE 4096 97 | #define AM18XX_PRUSS_MMAP_SIZE 0x7C00 98 | #define AM18XX_DATARAM0_PHYS_BASE 0x01C30000 99 | #define AM18XX_DATARAM1_PHYS_BASE 0x01C32000 100 | #define AM18XX_INTC_PHYS_BASE 0x01C34000 101 | #define AM18XX_PRU0CONTROL_PHYS_BASE 0x01C37000 102 | #define AM18XX_PRU0DEBUG_PHYS_BASE 0x01C37400 103 | #define AM18XX_PRU1CONTROL_PHYS_BASE 0x01C37800 104 | #define AM18XX_PRU1DEBUG_PHYS_BASE 0x01C37C00 105 | #define AM18XX_PRU0IRAM_PHYS_BASE 0x01C38000 106 | #define AM18XX_PRU1IRAM_PHYS_BASE 0x01C3C000 107 | 108 | //PRUSS INTC register offsets 109 | #define PRU_INTC_REVID_REG 0x000 110 | #define PRU_INTC_CR_REG 0x004 111 | #define PRU_INTC_HCR_REG 0x00C 112 | #define PRU_INTC_GER_REG 0x010 113 | #define PRU_INTC_GNLR_REG 0x01C 114 | #define PRU_INTC_SISR_REG 0x020 115 | #define PRU_INTC_SICR_REG 0x024 116 | #define PRU_INTC_EISR_REG 0x028 117 | #define PRU_INTC_EICR_REG 0x02C 118 | #define PRU_INTC_HIEISR_REG 0x034 119 | #define PRU_INTC_HIDISR_REG 0x038 120 | #define PRU_INTC_GPIR_REG 0x080 121 | 122 | #define PRU_INTC_SRSR1_REG 0x200 123 | #define PRU_INTC_SRSR2_REG 0x204 124 | 125 | #define PRU_INTC_SECR1_REG 0x280 126 | #define PRU_INTC_SECR2_REG 0x284 127 | 128 | #define PRU_INTC_ESR1_REG 0x300 129 | #define PRU_INTC_ESR2_REG 0x304 130 | 131 | #define PRU_INTC_ECR1_REG 0x380 132 | #define PRU_INTC_ECR2_REG 0x384 133 | 134 | #define PRU_INTC_CMR1_REG 0x400 135 | #define PRU_INTC_CMR2_REG 0x404 136 | #define PRU_INTC_CMR3_REG 0x408 137 | #define PRU_INTC_CMR4_REG 0x40C 138 | #define PRU_INTC_CMR5_REG 0x410 139 | #define PRU_INTC_CMR6_REG 0x414 140 | #define PRU_INTC_CMR7_REG 0x418 141 | #define PRU_INTC_CMR8_REG 0x41C 142 | #define PRU_INTC_CMR9_REG 0x420 143 | #define PRU_INTC_CMR10_REG 0x424 144 | #define PRU_INTC_CMR11_REG 0x428 145 | #define PRU_INTC_CMR12_REG 0x42C 146 | #define PRU_INTC_CMR13_REG 0x430 147 | #define PRU_INTC_CMR14_REG 0x434 148 | #define PRU_INTC_CMR15_REG 0x438 149 | #define PRU_INTC_CMR16_REG 0x43C 150 | 151 | #define PRU_INTC_HMR1_REG 0x800 152 | #define PRU_INTC_HMR2_REG 0x804 153 | #define PRU_INTC_HMR3_REG 0x808 154 | 155 | #define PRU_INTC_SIPR1_REG 0xD00 156 | #define PRU_INTC_SIPR2_REG 0xD04 157 | 158 | #define PRU_INTC_SITR1_REG 0xD80 159 | #define PRU_INTC_SITR2_REG 0xD84 160 | 161 | #define PRU_INTC_HIER_REG 0x1500 162 | 163 | 164 | #define MAX_HOSTS_SUPPORTED 10 165 | 166 | //UIO driver expects user space to map PRUSS_UIO_MAP_OFFSET_XXX to 167 | //access corresponding memory regions - region offset is N*PAGE_SIZE 168 | 169 | #define PRUSS_UIO_MAP_OFFSET_PRUSS 0*PAGE_SIZE 170 | #define PRUSS_UIO_DRV_PRUSS_BASE "/sys/class/uio/uio0/maps/map0/addr" 171 | #define PRUSS_UIO_DRV_PRUSS_SIZE "/sys/class/uio/uio0/maps/map0/size" 172 | 173 | #ifndef DISABLE_L3RAM_SUPPORT 174 | 175 | #define PRUSS_UIO_MAP_OFFSET_L3RAM 1*PAGE_SIZE 176 | #define PRUSS_UIO_DRV_L3RAM_BASE "/sys/class/uio/uio0/maps/map1/addr" 177 | #define PRUSS_UIO_DRV_L3RAM_SIZE "/sys/class/uio/uio0/maps/map1/size" 178 | 179 | #define PRUSS_UIO_MAP_OFFSET_EXTRAM 2*PAGE_SIZE 180 | #define PRUSS_UIO_DRV_EXTRAM_BASE "/sys/class/uio/uio0/maps/map2/addr" 181 | #define PRUSS_UIO_DRV_EXTRAM_SIZE "/sys/class/uio/uio0/maps/map2/size" 182 | 183 | #else 184 | 185 | #define PRUSS_UIO_MAP_OFFSET_EXTRAM 1*PAGE_SIZE 186 | #define PRUSS_UIO_DRV_EXTRAM_BASE "/sys/class/uio/uio0/maps/map1/addr" 187 | #define PRUSS_UIO_DRV_EXTRAM_SIZE "/sys/class/uio/uio0/maps/map1/size" 188 | 189 | 190 | #endif 191 | 192 | 193 | typedef struct __prussdrv { 194 | int version; 195 | int fd[NUM_PRU_HOSTIRQS]; 196 | void *pru0_dataram_base; 197 | void *pru1_dataram_base; 198 | void *intc_base; 199 | void *pru0_control_base; 200 | void *pru0_debug_base; 201 | void *pru1_control_base; 202 | void *pru1_debug_base; 203 | void *pru0_iram_base; 204 | void *pru1_iram_base; 205 | void *l3ram_base; 206 | void *extram_base; 207 | int mmap_fd; 208 | void *pruss_sharedram_base; 209 | void *pruss_cfg_base; 210 | void *pruss_uart_base; 211 | void *pruss_iep_base; 212 | void *pruss_ecap_base; 213 | void *pruss_miirt_base; 214 | void *pruss_mdio_base; 215 | unsigned int pru0_dataram_phy_base; 216 | unsigned int pru1_dataram_phy_base; 217 | unsigned int intc_phy_base; 218 | unsigned int pru0_control_phy_base; 219 | unsigned int pru0_debug_phy_base; 220 | unsigned int pru1_control_phy_base; 221 | unsigned int pru1_debug_phy_base; 222 | unsigned int pru0_iram_phy_base; 223 | unsigned int pru1_iram_phy_base; 224 | unsigned int l3ram_phy_base; 225 | unsigned int extram_phy_base; 226 | unsigned int pruss_sharedram_phy_base; 227 | unsigned int pruss_cfg_phy_base; 228 | unsigned int pruss_uart_phy_base; 229 | unsigned int pruss_iep_phy_base; 230 | unsigned int pruss_ecap_phy_base; 231 | unsigned int pruss_miirt_phy_base; 232 | unsigned int pruss_mdio_phy_base; 233 | unsigned int pruss_phys_base; 234 | unsigned int pruss_map_size; 235 | unsigned int l3ram_phys_base; 236 | unsigned int l3ram_map_size; 237 | unsigned int extram_phys_base; 238 | unsigned int extram_map_size; 239 | tpruss_intc_initdata intc_data; 240 | } tprussdrv; 241 | 242 | 243 | int __pruss_detect_hw_version(unsigned int *pruss_io) 244 | { 245 | 246 | if (pruss_io[(AM18XX_INTC_PHYS_BASE - AM18XX_DATARAM0_PHYS_BASE) >> 2] 247 | == AM18XX_PRUSS_INTC_REV) 248 | return PRUSS_V1; 249 | else { 250 | if (pruss_io 251 | [(AM33XX_INTC_PHYS_BASE - AM33XX_DATARAM0_PHYS_BASE) >> 2] == 252 | AM33XX_PRUSS_INTC_REV) 253 | return PRUSS_V2; 254 | else 255 | return -1; 256 | } 257 | } 258 | 259 | void __prussintc_set_cmr(unsigned int *pruintc_io, unsigned short sysevt, 260 | unsigned short channel) 261 | { 262 | pruintc_io[(PRU_INTC_CMR1_REG + (sysevt & ~(0x3))) >> 2] |= 263 | ((channel & 0xF) << ((sysevt & 0x3) << 3)); 264 | 265 | } 266 | 267 | 268 | void __prussintc_set_hmr(unsigned int *pruintc_io, unsigned short channel, 269 | unsigned short host) 270 | { 271 | pruintc_io[(PRU_INTC_HMR1_REG + (channel & ~(0x3))) >> 2] = 272 | pruintc_io[(PRU_INTC_HMR1_REG + 273 | (channel & ~(0x3))) >> 2] | (((host) & 0xF) << 274 | (((channel) & 0x3) << 3)); 275 | 276 | } -------------------------------------------------------------------------------- /prussdrv/pruss_intc_mapping.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pruss_intc_mapping.h 3 | * 4 | * Example PRUSS INTC mapping for the application 5 | * 6 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 7 | * 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 13 | * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 16 | * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the 19 | * distribution. 20 | * 21 | * Neither the name of Texas Instruments Incorporated nor the names of 22 | * its contributors may be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | /* 40 | * ============================================================================ 41 | * Copyright (c) Texas Instruments Inc 2010-11 42 | * 43 | * Use of this software is controlled by the terms and conditions found in the 44 | * license agreement under which this software has been supplied or provided. 45 | * ============================================================================ 46 | */ 47 | 48 | #define AM33XX 49 | #ifdef AM33XX 50 | #define PRU0_PRU1_INTERRUPT 17 51 | #define PRU1_PRU0_INTERRUPT 18 52 | #define PRU0_ARM_INTERRUPT 19 53 | #define PRU1_ARM_INTERRUPT 20 54 | #define ARM_PRU0_INTERRUPT 21 55 | #define ARM_PRU1_INTERRUPT 22 56 | #else 57 | #define PRU0_PRU1_INTERRUPT 32 58 | #define PRU1_PRU0_INTERRUPT 33 59 | #define PRU0_ARM_INTERRUPT 34 60 | #define PRU1_ARM_INTERRUPT 35 61 | #define ARM_PRU0_INTERRUPT 36 62 | #define ARM_PRU1_INTERRUPT 37 63 | #endif 64 | #define CHANNEL0 0 65 | #define CHANNEL1 1 66 | #define CHANNEL2 2 67 | #define CHANNEL3 3 68 | #define CHANNEL4 4 69 | #define CHANNEL5 5 70 | #define CHANNEL6 6 71 | #define CHANNEL7 7 72 | #define CHANNEL8 8 73 | #define CHANNEL9 9 74 | 75 | #define PRU0 0 76 | #define PRU1 1 77 | #define PRU_EVTOUT0 2 78 | #define PRU_EVTOUT1 3 79 | #define PRU_EVTOUT2 4 80 | #define PRU_EVTOUT3 5 81 | #define PRU_EVTOUT4 6 82 | #define PRU_EVTOUT5 7 83 | #define PRU_EVTOUT6 8 84 | #define PRU_EVTOUT7 9 85 | 86 | #define PRU0_HOSTEN_MASK 0x0001 87 | #define PRU1_HOSTEN_MASK 0x0002 88 | #define PRU_EVTOUT0_HOSTEN_MASK 0x0004 89 | #define PRU_EVTOUT1_HOSTEN_MASK 0x0008 90 | #define PRU_EVTOUT2_HOSTEN_MASK 0x0010 91 | #define PRU_EVTOUT3_HOSTEN_MASK 0x0020 92 | #define PRU_EVTOUT4_HOSTEN_MASK 0x0040 93 | #define PRU_EVTOUT5_HOSTEN_MASK 0x0080 94 | #define PRU_EVTOUT6_HOSTEN_MASK 0x0100 95 | #define PRU_EVTOUT7_HOSTEN_MASK 0x0200 96 | 97 | 98 | #define PRUSS_INTC_INITDATA { \ 99 | { PRU0_PRU1_INTERRUPT, PRU1_PRU0_INTERRUPT, PRU0_ARM_INTERRUPT, PRU1_ARM_INTERRUPT, ARM_PRU0_INTERRUPT, ARM_PRU1_INTERRUPT, -1 }, \ 100 | { {PRU0_PRU1_INTERRUPT,CHANNEL1}, {PRU1_PRU0_INTERRUPT, CHANNEL0}, {PRU0_ARM_INTERRUPT,CHANNEL2}, {PRU1_ARM_INTERRUPT, CHANNEL3}, {ARM_PRU0_INTERRUPT, CHANNEL0}, {ARM_PRU1_INTERRUPT, CHANNEL1}, {-1,-1}}, \ 101 | { {CHANNEL0,PRU0}, {CHANNEL1, PRU1}, {CHANNEL2, PRU_EVTOUT0}, {CHANNEL3, PRU_EVTOUT1}, {-1,-1} }, \ 102 | (PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK | PRU_EVTOUT1_HOSTEN_MASK) /*Enable PRU0, PRU1, PRU_EVTOUT0 */ \ 103 | } \ 104 | 105 | -------------------------------------------------------------------------------- /prussdrv/prussdrv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * prussdrv.c 3 | * 4 | * User space driver for PRUSS 5 | * 6 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 7 | * 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 13 | * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 16 | * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the 19 | * distribution. 20 | * 21 | * Neither the name of Texas Instruments Incorporated nor the names of 22 | * its contributors may be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | 40 | /* 41 | * ============================================================================ 42 | * Copyright (c) Texas Instruments Inc 2010-12 43 | * 44 | * Use of this software is controlled by the terms and conditions found in the 45 | * license agreement under which this software has been supplied or provided. 46 | * ============================================================================ 47 | */ 48 | 49 | 50 | #include 51 | #include "__prussdrv.h" 52 | #include 53 | 54 | #ifdef __DEBUG 55 | #define DEBUG_PRINTF(FORMAT, ...) fprintf(stderr, FORMAT, ## __VA_ARGS__) 56 | #else 57 | #define DEBUG_PRINTF(FORMAT, ...) 58 | #endif 59 | 60 | #define PRUSS_UIO_PRAM_PATH_LEN 128 61 | #define PRUSS_UIO_PARAM_VAL_LEN 20 62 | #define HEXA_DECIMAL_BASE 16 63 | 64 | static tprussdrv prussdrv; 65 | 66 | int __prussdrv_memmap_init(void) 67 | { 68 | int i, fd; 69 | char hexstring[PRUSS_UIO_PARAM_VAL_LEN]; 70 | 71 | if (prussdrv.mmap_fd == 0) { 72 | for (i = 0; i < NUM_PRU_HOSTIRQS; i++) { 73 | if (prussdrv.fd[i]) 74 | break; 75 | } 76 | if (i == NUM_PRU_HOSTIRQS) 77 | return -1; 78 | else 79 | prussdrv.mmap_fd = prussdrv.fd[i]; 80 | } 81 | fd = open(PRUSS_UIO_DRV_PRUSS_BASE, O_RDONLY); 82 | if (fd >= 0) { 83 | read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); 84 | prussdrv.pruss_phys_base = 85 | strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); 86 | close(fd); 87 | } else 88 | return -1; 89 | fd = open(PRUSS_UIO_DRV_PRUSS_SIZE, O_RDONLY); 90 | if (fd >= 0) { 91 | read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); 92 | prussdrv.pruss_map_size = 93 | strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); 94 | close(fd); 95 | } else 96 | return -1; 97 | 98 | prussdrv.pru0_dataram_base = 99 | mmap(0, prussdrv.pruss_map_size, PROT_READ | PROT_WRITE, 100 | MAP_SHARED, prussdrv.mmap_fd, PRUSS_UIO_MAP_OFFSET_PRUSS); 101 | prussdrv.version = 102 | __pruss_detect_hw_version(prussdrv.pru0_dataram_base); 103 | 104 | switch (prussdrv.version) { 105 | case PRUSS_V1: 106 | { 107 | DEBUG_PRINTF(PRUSS_V1_STR "\n"); 108 | prussdrv.pru0_dataram_phy_base = AM18XX_DATARAM0_PHYS_BASE; 109 | prussdrv.pru1_dataram_phy_base = AM18XX_DATARAM1_PHYS_BASE; 110 | prussdrv.intc_phy_base = AM18XX_INTC_PHYS_BASE; 111 | prussdrv.pru0_control_phy_base = AM18XX_PRU0CONTROL_PHYS_BASE; 112 | prussdrv.pru0_debug_phy_base = AM18XX_PRU0DEBUG_PHYS_BASE; 113 | prussdrv.pru1_control_phy_base = AM18XX_PRU1CONTROL_PHYS_BASE; 114 | prussdrv.pru1_debug_phy_base = AM18XX_PRU1DEBUG_PHYS_BASE; 115 | prussdrv.pru0_iram_phy_base = AM18XX_PRU0IRAM_PHYS_BASE; 116 | prussdrv.pru1_iram_phy_base = AM18XX_PRU1IRAM_PHYS_BASE; 117 | } 118 | break; 119 | case PRUSS_V2: 120 | { 121 | DEBUG_PRINTF(PRUSS_V2_STR "\n"); 122 | prussdrv.pru0_dataram_phy_base = AM33XX_DATARAM0_PHYS_BASE; 123 | prussdrv.pru1_dataram_phy_base = AM33XX_DATARAM1_PHYS_BASE; 124 | prussdrv.intc_phy_base = AM33XX_INTC_PHYS_BASE; 125 | prussdrv.pru0_control_phy_base = AM33XX_PRU0CONTROL_PHYS_BASE; 126 | prussdrv.pru0_debug_phy_base = AM33XX_PRU0DEBUG_PHYS_BASE; 127 | prussdrv.pru1_control_phy_base = AM33XX_PRU1CONTROL_PHYS_BASE; 128 | prussdrv.pru1_debug_phy_base = AM33XX_PRU1DEBUG_PHYS_BASE; 129 | prussdrv.pru0_iram_phy_base = AM33XX_PRU0IRAM_PHYS_BASE; 130 | prussdrv.pru1_iram_phy_base = AM33XX_PRU1IRAM_PHYS_BASE; 131 | prussdrv.pruss_sharedram_phy_base = 132 | AM33XX_PRUSS_SHAREDRAM_BASE; 133 | prussdrv.pruss_cfg_phy_base = AM33XX_PRUSS_CFG_BASE; 134 | prussdrv.pruss_uart_phy_base = AM33XX_PRUSS_UART_BASE; 135 | prussdrv.pruss_iep_phy_base = AM33XX_PRUSS_IEP_BASE; 136 | prussdrv.pruss_ecap_phy_base = AM33XX_PRUSS_ECAP_BASE; 137 | prussdrv.pruss_miirt_phy_base = AM33XX_PRUSS_MIIRT_BASE; 138 | prussdrv.pruss_mdio_phy_base = AM33XX_PRUSS_MDIO_BASE; 139 | } 140 | break; 141 | default: 142 | DEBUG_PRINTF(PRUSS_UNKNOWN_STR "\n"); 143 | } 144 | 145 | prussdrv.pru1_dataram_base = 146 | prussdrv.pru0_dataram_base + prussdrv.pru1_dataram_phy_base - 147 | prussdrv.pru0_dataram_phy_base; 148 | prussdrv.intc_base = 149 | prussdrv.pru0_dataram_base + prussdrv.intc_phy_base - 150 | prussdrv.pru0_dataram_phy_base; 151 | prussdrv.pru0_control_base = 152 | prussdrv.pru0_dataram_base + prussdrv.pru0_control_phy_base - 153 | prussdrv.pru0_dataram_phy_base; 154 | prussdrv.pru0_debug_base = 155 | prussdrv.pru0_dataram_base + prussdrv.pru0_debug_phy_base - 156 | prussdrv.pru0_dataram_phy_base; 157 | prussdrv.pru1_control_base = 158 | prussdrv.pru0_dataram_base + prussdrv.pru1_control_phy_base - 159 | prussdrv.pru0_dataram_phy_base; 160 | prussdrv.pru1_debug_base = 161 | prussdrv.pru0_dataram_base + prussdrv.pru1_debug_phy_base - 162 | prussdrv.pru0_dataram_phy_base; 163 | prussdrv.pru0_iram_base = 164 | prussdrv.pru0_dataram_base + prussdrv.pru0_iram_phy_base - 165 | prussdrv.pru0_dataram_phy_base; 166 | prussdrv.pru1_iram_base = 167 | prussdrv.pru0_dataram_base + prussdrv.pru1_iram_phy_base - 168 | prussdrv.pru0_dataram_phy_base; 169 | if (prussdrv.version == PRUSS_V2) { 170 | prussdrv.pruss_sharedram_base = 171 | prussdrv.pru0_dataram_base + 172 | prussdrv.pruss_sharedram_phy_base - 173 | prussdrv.pru0_dataram_phy_base; 174 | prussdrv.pruss_cfg_base = 175 | prussdrv.pru0_dataram_base + prussdrv.pruss_cfg_phy_base - 176 | prussdrv.pru0_dataram_phy_base; 177 | prussdrv.pruss_uart_base = 178 | prussdrv.pru0_dataram_base + prussdrv.pruss_uart_phy_base - 179 | prussdrv.pru0_dataram_phy_base; 180 | prussdrv.pruss_iep_base = 181 | prussdrv.pru0_dataram_base + prussdrv.pruss_iep_phy_base - 182 | prussdrv.pru0_dataram_phy_base; 183 | prussdrv.pruss_ecap_base = 184 | prussdrv.pru0_dataram_base + prussdrv.pruss_ecap_phy_base - 185 | prussdrv.pru0_dataram_phy_base; 186 | prussdrv.pruss_miirt_base = 187 | prussdrv.pru0_dataram_base + prussdrv.pruss_miirt_phy_base - 188 | prussdrv.pru0_dataram_phy_base; 189 | prussdrv.pruss_mdio_base = 190 | prussdrv.pru0_dataram_base + prussdrv.pruss_mdio_phy_base - 191 | prussdrv.pru0_dataram_phy_base; 192 | } 193 | #ifndef DISABLE_L3RAM_SUPPORT 194 | fd = open(PRUSS_UIO_DRV_L3RAM_BASE, O_RDONLY); 195 | if (fd >= 0) { 196 | read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); 197 | prussdrv.l3ram_phys_base = 198 | strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); 199 | close(fd); 200 | } else 201 | return -1; 202 | 203 | 204 | fd = open(PRUSS_UIO_DRV_L3RAM_SIZE, O_RDONLY); 205 | if (fd >= 0) { 206 | read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); 207 | prussdrv.l3ram_map_size = 208 | strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); 209 | close(fd); 210 | } else 211 | return -1; 212 | 213 | prussdrv.l3ram_base = 214 | mmap(0, prussdrv.l3ram_map_size, PROT_READ | PROT_WRITE, 215 | MAP_SHARED, prussdrv.mmap_fd, PRUSS_UIO_MAP_OFFSET_L3RAM); 216 | #endif 217 | 218 | fd = open(PRUSS_UIO_DRV_EXTRAM_BASE, O_RDONLY); 219 | if (fd >= 0) { 220 | read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); 221 | prussdrv.extram_phys_base = 222 | strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); 223 | close(fd); 224 | } else 225 | return -1; 226 | 227 | fd = open(PRUSS_UIO_DRV_EXTRAM_SIZE, O_RDONLY); 228 | if (fd >= 0) { 229 | read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); 230 | prussdrv.extram_map_size = 231 | strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); 232 | close(fd); 233 | } else 234 | return -1; 235 | 236 | 237 | prussdrv.extram_base = 238 | mmap(0, prussdrv.extram_map_size, PROT_READ | PROT_WRITE, 239 | MAP_SHARED, prussdrv.mmap_fd, PRUSS_UIO_MAP_OFFSET_EXTRAM); 240 | 241 | return 0; 242 | 243 | } 244 | 245 | int prussdrv_init(void) 246 | { 247 | memset(&prussdrv, 0, sizeof(prussdrv)); 248 | return 0; 249 | 250 | } 251 | 252 | int prussdrv_open(unsigned int host_interrupt) 253 | { 254 | char name[PRUSS_UIO_PRAM_PATH_LEN]; 255 | if (!prussdrv.fd[host_interrupt]) { 256 | sprintf(name, "/dev/uio%d", host_interrupt); 257 | prussdrv.fd[host_interrupt] = open(name, O_RDWR | O_SYNC); 258 | return __prussdrv_memmap_init(); 259 | } else { 260 | return -1; 261 | 262 | } 263 | } 264 | 265 | int prussdrv_version() { 266 | return prussdrv.version; 267 | } 268 | 269 | const char * prussdrv_strversion(int version) { 270 | switch (version) { 271 | case PRUSS_V1: 272 | return PRUSS_V1_STR; 273 | case PRUSS_V2: 274 | return PRUSS_V2_STR; 275 | default: 276 | return PRUSS_UNKNOWN_STR; 277 | } 278 | } 279 | 280 | int prussdrv_pru_reset(unsigned int prunum) 281 | { 282 | unsigned int *prucontrolregs; 283 | if (prunum == 0) 284 | prucontrolregs = (unsigned int *) prussdrv.pru0_control_base; 285 | else if (prunum == 1) 286 | prucontrolregs = (unsigned int *) prussdrv.pru1_control_base; 287 | else 288 | return -1; 289 | *prucontrolregs = 0; 290 | return 0; 291 | } 292 | 293 | int prussdrv_pru_enable(unsigned int prunum) 294 | { 295 | unsigned int *prucontrolregs; 296 | if (prunum == 0) 297 | prucontrolregs = (unsigned int *) prussdrv.pru0_control_base; 298 | else if (prunum == 1) 299 | prucontrolregs = (unsigned int *) prussdrv.pru1_control_base; 300 | else 301 | return -1; 302 | 303 | *prucontrolregs = 2; 304 | return 0; 305 | 306 | } 307 | 308 | int prussdrv_pru_disable(unsigned int prunum) 309 | { 310 | unsigned int *prucontrolregs; 311 | if (prunum == 0) 312 | prucontrolregs = (unsigned int *) prussdrv.pru0_control_base; 313 | else if (prunum == 1) 314 | prucontrolregs = (unsigned int *) prussdrv.pru1_control_base; 315 | else 316 | return -1; 317 | *prucontrolregs = 1; 318 | return 0; 319 | 320 | } 321 | 322 | int prussdrv_pru_write_memory(unsigned int pru_ram_id, 323 | unsigned int wordoffset, 324 | const unsigned int *memarea, 325 | unsigned int bytelength) 326 | { 327 | unsigned int *pruramarea, i, wordlength; 328 | switch (pru_ram_id) { 329 | case PRUSS0_PRU0_IRAM: 330 | pruramarea = (unsigned int *) prussdrv.pru0_iram_base; 331 | break; 332 | case PRUSS0_PRU1_IRAM: 333 | pruramarea = (unsigned int *) prussdrv.pru1_iram_base; 334 | break; 335 | case PRUSS0_PRU0_DATARAM: 336 | pruramarea = (unsigned int *) prussdrv.pru0_dataram_base; 337 | break; 338 | case PRUSS0_PRU1_DATARAM: 339 | pruramarea = (unsigned int *) prussdrv.pru1_dataram_base; 340 | break; 341 | case PRUSS0_SHARED_DATARAM: 342 | if (prussdrv.version != PRUSS_V2) 343 | return -1; 344 | pruramarea = (unsigned int *) prussdrv.pruss_sharedram_base; 345 | break; 346 | default: 347 | return -1; 348 | } 349 | 350 | 351 | wordlength = (bytelength + 3) >> 2; //Adjust length as multiple of 4 bytes 352 | for (i = 0; i < wordlength; i++) { 353 | *(pruramarea + i + wordoffset) = *(memarea + i); 354 | } 355 | return wordlength; 356 | 357 | } 358 | 359 | 360 | int prussdrv_pruintc_init(const tpruss_intc_initdata *prussintc_init_data) 361 | { 362 | unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; 363 | unsigned int i, mask1, mask2; 364 | 365 | pruintc_io[PRU_INTC_SIPR1_REG >> 2] = 0xFFFFFFFF; 366 | pruintc_io[PRU_INTC_SIPR2_REG >> 2] = 0xFFFFFFFF; 367 | 368 | for (i = 0; i < (NUM_PRU_SYS_EVTS + 3) >> 2; i++) 369 | pruintc_io[(PRU_INTC_CMR1_REG >> 2) + i] = 0; 370 | for (i = 0; 371 | ((prussintc_init_data->sysevt_to_channel_map[i].sysevt != -1) 372 | && (prussintc_init_data->sysevt_to_channel_map[i].channel != 373 | -1)); i++) { 374 | __prussintc_set_cmr(pruintc_io, 375 | prussintc_init_data->sysevt_to_channel_map[i]. 376 | sysevt, 377 | prussintc_init_data->sysevt_to_channel_map[i]. 378 | channel); 379 | } 380 | for (i = 0; i < (NUM_PRU_HOSTS + 3) >> 2; i++) 381 | pruintc_io[(PRU_INTC_HMR1_REG >> 2) + i] = 0; 382 | for (i = 0; 383 | ((prussintc_init_data->channel_to_host_map[i].channel != -1) 384 | && (prussintc_init_data->channel_to_host_map[i].host != -1)); 385 | i++) { 386 | 387 | __prussintc_set_hmr(pruintc_io, 388 | prussintc_init_data->channel_to_host_map[i]. 389 | channel, 390 | prussintc_init_data->channel_to_host_map[i]. 391 | host); 392 | } 393 | 394 | pruintc_io[PRU_INTC_SITR1_REG >> 2] = 0x0; 395 | pruintc_io[PRU_INTC_SITR2_REG >> 2] = 0x0; 396 | 397 | 398 | mask1 = mask2 = 0; 399 | for (i = 0; prussintc_init_data->sysevts_enabled[i] != 255; i++) { 400 | if (prussintc_init_data->sysevts_enabled[i] < 32) { 401 | mask1 = 402 | mask1 + (1 << (prussintc_init_data->sysevts_enabled[i])); 403 | } else if (prussintc_init_data->sysevts_enabled[i] < 64) { 404 | mask2 = 405 | mask2 + 406 | (1 << (prussintc_init_data->sysevts_enabled[i] - 32)); 407 | } else { 408 | DEBUG_PRINTF("Error: SYS_EVT%d out of range\n", 409 | prussintc_init_data->sysevts_enabled[i]); 410 | return -1; 411 | } 412 | } 413 | pruintc_io[PRU_INTC_ESR1_REG >> 2] = mask1; 414 | pruintc_io[PRU_INTC_SECR1_REG >> 2] = mask1; 415 | pruintc_io[PRU_INTC_ESR2_REG >> 2] = mask2; 416 | pruintc_io[PRU_INTC_SECR2_REG >> 2] = mask2; 417 | 418 | for (i = 0; i < MAX_HOSTS_SUPPORTED; i++) 419 | if (prussintc_init_data->host_enable_bitmask & (1 << i)) { 420 | pruintc_io[PRU_INTC_HIEISR_REG >> 2] = i; 421 | } 422 | 423 | pruintc_io[PRU_INTC_GER_REG >> 2] = 0x1; 424 | 425 | // Stash a copy of the intc settings 426 | memcpy( &prussdrv.intc_data, prussintc_init_data, 427 | sizeof(prussdrv.intc_data) ); 428 | 429 | return 0; 430 | } 431 | 432 | short prussdrv_get_event_to_channel_map( unsigned int eventnum ) 433 | { 434 | unsigned int i; 435 | for (i = 0; i < NUM_PRU_SYS_EVTS && 436 | prussdrv.intc_data.sysevt_to_channel_map[i].sysevt !=-1 && 437 | prussdrv.intc_data.sysevt_to_channel_map[i].channel !=-1; ++i) { 438 | if ( eventnum == prussdrv.intc_data.sysevt_to_channel_map[i].sysevt ) 439 | return prussdrv.intc_data.sysevt_to_channel_map[i].channel; 440 | } 441 | return -1; 442 | } 443 | 444 | short prussdrv_get_channel_to_host_map( unsigned int channel ) 445 | { 446 | unsigned int i; 447 | for (i = 0; i < NUM_PRU_CHANNELS && 448 | prussdrv.intc_data.channel_to_host_map[i].channel != -1 && 449 | prussdrv.intc_data.channel_to_host_map[i].host != -1; ++i) { 450 | if ( channel == prussdrv.intc_data.channel_to_host_map[i].channel ) 451 | /** -2 is because first two host interrupts are reserved 452 | * for PRU0 and PRU1 */ 453 | return prussdrv.intc_data.channel_to_host_map[i].host - 2; 454 | } 455 | return -1; 456 | } 457 | 458 | short prussdrv_get_event_to_host_map( unsigned int eventnum ) 459 | { 460 | short ans = prussdrv_get_event_to_channel_map( eventnum ); 461 | if (ans < 0) return ans; 462 | return prussdrv_get_channel_to_host_map( ans ); 463 | } 464 | 465 | int prussdrv_pru_send_event(unsigned int eventnum) 466 | { 467 | unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; 468 | if (eventnum < 32) 469 | pruintc_io[PRU_INTC_SRSR1_REG >> 2] = 1 << eventnum; 470 | else 471 | pruintc_io[PRU_INTC_SRSR2_REG >> 2] = 1 << (eventnum - 32); 472 | return 0; 473 | } 474 | 475 | unsigned int prussdrv_pru_wait_event(unsigned int host_interrupt) 476 | { 477 | unsigned int event_count; 478 | read(prussdrv.fd[host_interrupt], &event_count, sizeof(int)); 479 | return event_count; 480 | } 481 | 482 | int prussdrv_pru_event_fd(unsigned int host_interrupt) 483 | { 484 | if (host_interrupt < NUM_PRU_HOSTIRQS) 485 | return prussdrv.fd[host_interrupt]; 486 | else 487 | return -1; 488 | } 489 | 490 | int prussdrv_pru_clear_event(unsigned int host_interrupt, unsigned int sysevent) 491 | { 492 | unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; 493 | if (sysevent < 32) 494 | pruintc_io[PRU_INTC_SECR1_REG >> 2] = 1 << sysevent; 495 | else 496 | pruintc_io[PRU_INTC_SECR2_REG >> 2] = 1 << (sysevent - 32); 497 | 498 | // Re-enable the host interrupt. Note that we must do this _after_ the 499 | // system event has been cleared so as to not re-tigger the interrupt line. 500 | // See Section 6.4.9 of Reference manual about HIEISR register. 501 | // The +2 is because the first two host interrupts are reserved for 502 | // PRU0 and PRU1. 503 | pruintc_io[PRU_INTC_HIEISR_REG >> 2] = host_interrupt+2; 504 | return 0; 505 | } 506 | 507 | int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum, 508 | unsigned int host_interrupt, 509 | unsigned int ack_eventnum) 510 | { 511 | prussdrv_pru_send_event(send_eventnum); 512 | prussdrv_pru_wait_event(host_interrupt); 513 | prussdrv_pru_clear_event(host_interrupt, ack_eventnum); 514 | return 0; 515 | 516 | } 517 | 518 | 519 | int prussdrv_map_l3mem(void **address) 520 | { 521 | *address = prussdrv.l3ram_base; 522 | return 0; 523 | } 524 | 525 | 526 | 527 | int prussdrv_map_extmem(void **address) 528 | { 529 | 530 | *address = prussdrv.extram_base; 531 | return 0; 532 | 533 | } 534 | 535 | unsigned int prussdrv_extmem_size(void) 536 | { 537 | return prussdrv.extram_map_size; 538 | } 539 | 540 | int prussdrv_map_prumem(unsigned int pru_ram_id, void **address) 541 | { 542 | switch (pru_ram_id) { 543 | case PRUSS0_PRU0_DATARAM: 544 | *address = prussdrv.pru0_dataram_base; 545 | break; 546 | case PRUSS0_PRU1_DATARAM: 547 | *address = prussdrv.pru1_dataram_base; 548 | break; 549 | case PRUSS0_SHARED_DATARAM: 550 | if (prussdrv.version != PRUSS_V2) 551 | return -1; 552 | *address = prussdrv.pruss_sharedram_base; 553 | break; 554 | default: 555 | *address = 0; 556 | return -1; 557 | } 558 | return 0; 559 | } 560 | 561 | int prussdrv_map_peripheral_io(unsigned int per_id, void **address) 562 | { 563 | if (prussdrv.version != PRUSS_V2) 564 | return -1; 565 | 566 | switch (per_id) { 567 | case PRUSS0_CFG: 568 | *address = prussdrv.pruss_cfg_base; 569 | break; 570 | case PRUSS0_UART: 571 | *address = prussdrv.pruss_uart_base; 572 | break; 573 | case PRUSS0_IEP: 574 | *address = prussdrv.pruss_iep_base; 575 | break; 576 | case PRUSS0_ECAP: 577 | *address = prussdrv.pruss_ecap_base; 578 | break; 579 | case PRUSS0_MII_RT: 580 | *address = prussdrv.pruss_miirt_base; 581 | break; 582 | case PRUSS0_MDIO: 583 | *address = prussdrv.pruss_mdio_base; 584 | break; 585 | default: 586 | *address = 0; 587 | return -1; 588 | } 589 | return 0; 590 | } 591 | 592 | unsigned int prussdrv_get_phys_addr(const void *address) 593 | { 594 | unsigned int retaddr = 0; 595 | if ((address >= prussdrv.pru0_dataram_base) 596 | && (address < 597 | prussdrv.pru0_dataram_base + prussdrv.pruss_map_size)) { 598 | retaddr = 599 | ((unsigned int) (address - prussdrv.pru0_dataram_base) + 600 | prussdrv.pru0_dataram_phy_base); 601 | } else if ((address >= prussdrv.l3ram_base) 602 | && (address < 603 | prussdrv.l3ram_base + prussdrv.l3ram_map_size)) { 604 | retaddr = 605 | ((unsigned int) (address - prussdrv.l3ram_base) + 606 | prussdrv.l3ram_phys_base); 607 | } else if ((address >= prussdrv.extram_base) 608 | && (address < 609 | prussdrv.extram_base + prussdrv.extram_map_size)) { 610 | retaddr = 611 | ((unsigned int) (address - prussdrv.extram_base) + 612 | prussdrv.extram_phys_base); 613 | } 614 | return retaddr; 615 | 616 | } 617 | 618 | void *prussdrv_get_virt_addr(unsigned int phyaddr) 619 | { 620 | void *address = 0; 621 | if ((phyaddr >= prussdrv.pru0_dataram_phy_base) 622 | && (phyaddr < 623 | prussdrv.pru0_dataram_phy_base + prussdrv.pruss_map_size)) { 624 | address = 625 | (void *) ((unsigned int) prussdrv.pru0_dataram_base + 626 | (phyaddr - prussdrv.pru0_dataram_phy_base)); 627 | } else if ((phyaddr >= prussdrv.l3ram_phys_base) 628 | && (phyaddr < 629 | prussdrv.l3ram_phys_base + prussdrv.l3ram_map_size)) { 630 | address = 631 | (void *) ((unsigned int) prussdrv.l3ram_base + 632 | (phyaddr - prussdrv.l3ram_phys_base)); 633 | } else if ((phyaddr >= prussdrv.extram_phys_base) 634 | && (phyaddr < 635 | prussdrv.extram_phys_base + prussdrv.extram_map_size)) { 636 | address = 637 | (void *) ((unsigned int) prussdrv.extram_base + 638 | (phyaddr - prussdrv.extram_phys_base)); 639 | } 640 | return address; 641 | 642 | } 643 | 644 | 645 | int prussdrv_exit() 646 | { 647 | int i; 648 | munmap(prussdrv.pru0_dataram_base, prussdrv.pruss_map_size); 649 | munmap(prussdrv.l3ram_base, prussdrv.l3ram_map_size); 650 | munmap(prussdrv.extram_base, prussdrv.extram_map_size); 651 | for (i = 0; i < NUM_PRU_HOSTIRQS; i++) { 652 | if (prussdrv.fd[i]) 653 | close(prussdrv.fd[i]); 654 | } 655 | return 0; 656 | } 657 | 658 | int prussdrv_exec_program(int prunum, const char *filename) 659 | { 660 | FILE *fPtr; 661 | unsigned char fileDataArray[PRUSS_MAX_IRAM_SIZE]; 662 | int fileSize = 0; 663 | 664 | // Open an File from the hard drive 665 | fPtr = fopen(filename, "rb"); 666 | if (fPtr == NULL) { 667 | DEBUG_PRINTF("File %s open failed\n", filename); 668 | return -1; 669 | } else { 670 | DEBUG_PRINTF("File %s open passed\n", filename); 671 | } 672 | // Read file size 673 | fseek(fPtr, 0, SEEK_END); 674 | fileSize = ftell(fPtr); 675 | 676 | if (fileSize == 0) { 677 | DEBUG_PRINTF("File read failed.. Closing program\n"); 678 | fclose(fPtr); 679 | return -1; 680 | } 681 | 682 | fseek(fPtr, 0, SEEK_SET); 683 | 684 | if (fileSize != 685 | fread((unsigned char *) fileDataArray, 1, fileSize, fPtr)) { 686 | DEBUG_PRINTF("WARNING: File Size mismatch\n"); 687 | fclose(fPtr); 688 | return -1; 689 | } 690 | 691 | fclose(fPtr); 692 | 693 | return prussdrv_exec_code(prunum, (const unsigned int *) fileDataArray, fileSize); 694 | } 695 | 696 | int prussdrv_exec_code(int prunum, const unsigned int *code, int codelen) 697 | { 698 | unsigned int pru_ram_id; 699 | 700 | if (prunum == 0) 701 | pru_ram_id = PRUSS0_PRU0_IRAM; 702 | else if (prunum == 1) 703 | pru_ram_id = PRUSS0_PRU1_IRAM; 704 | else 705 | return -1; 706 | 707 | // Make sure PRU sub system is first disabled/reset 708 | prussdrv_pru_disable(prunum); 709 | prussdrv_pru_write_memory(pru_ram_id, 0, code, codelen); 710 | prussdrv_pru_enable(prunum); 711 | 712 | return 0; 713 | } -------------------------------------------------------------------------------- /prussdrv/prussdrv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * prussdrv.h 3 | * 4 | * Describes PRUSS userspace driver for Industrial Communications 5 | * 6 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 7 | * 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 13 | * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 16 | * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the 19 | * distribution. 20 | * 21 | * Neither the name of Texas Instruments Incorporated nor the names of 22 | * its contributors may be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | /* 40 | * ============================================================================ 41 | * Copyright (c) Texas Instruments Inc 2010-11 42 | * 43 | * Use of this software is controlled by the terms and conditions found in the 44 | * license agreement under which this software has been supplied or provided. 45 | * ============================================================================ 46 | */ 47 | 48 | #ifndef _PRUSSDRV_H 49 | #define _PRUSSDRV_H 50 | 51 | #include 52 | 53 | #if defined (__cplusplus) 54 | extern "C" { 55 | #endif 56 | 57 | #define NUM_PRU_HOSTIRQS 8 58 | #define NUM_PRU_HOSTS 10 59 | #define NUM_PRU_CHANNELS 10 60 | #define NUM_PRU_SYS_EVTS 64 61 | 62 | #define PRUSS0_PRU0_DATARAM 0 63 | #define PRUSS0_PRU1_DATARAM 1 64 | #define PRUSS0_PRU0_IRAM 2 65 | #define PRUSS0_PRU1_IRAM 3 66 | 67 | #define PRUSS_V1 1 // AM18XX 68 | #define PRUSS_V2 2 // AM33XX 69 | 70 | //Available in AM33xx series - begin 71 | #define PRUSS0_SHARED_DATARAM 4 72 | #define PRUSS0_CFG 5 73 | #define PRUSS0_UART 6 74 | #define PRUSS0_IEP 7 75 | #define PRUSS0_ECAP 8 76 | #define PRUSS0_MII_RT 9 77 | #define PRUSS0_MDIO 10 78 | //Available in AM33xx series - end 79 | 80 | #define PRU_EVTOUT_0 0 81 | #define PRU_EVTOUT_1 1 82 | #define PRU_EVTOUT_2 2 83 | #define PRU_EVTOUT_3 3 84 | #define PRU_EVTOUT_4 4 85 | #define PRU_EVTOUT_5 5 86 | #define PRU_EVTOUT_6 6 87 | #define PRU_EVTOUT_7 7 88 | 89 | typedef struct __sysevt_to_channel_map { 90 | short sysevt; 91 | short channel; 92 | } tsysevt_to_channel_map; 93 | typedef struct __channel_to_host_map { 94 | short channel; 95 | short host; 96 | } tchannel_to_host_map; 97 | typedef struct __pruss_intc_initdata { 98 | //Enabled SYSEVTs - Range:0..63 99 | //{-1} indicates end of list 100 | char sysevts_enabled[NUM_PRU_SYS_EVTS]; 101 | //SysEvt to Channel map. SYSEVTs - Range:0..63 Channels -Range: 0..9 102 | //{-1, -1} indicates end of list 103 | tsysevt_to_channel_map sysevt_to_channel_map[NUM_PRU_SYS_EVTS]; 104 | //Channel to Host map.Channels -Range: 0..9 HOSTs - Range:0..9 105 | //{-1, -1} indicates end of list 106 | tchannel_to_host_map channel_to_host_map[NUM_PRU_CHANNELS]; 107 | //10-bit mask - Enable Host0-Host9 {Host0/1:PRU0/1, Host2..9 : PRUEVT_OUT0..7} 108 | unsigned int host_enable_bitmask; 109 | } tpruss_intc_initdata; 110 | 111 | int prussdrv_init(void); 112 | 113 | int prussdrv_open(unsigned int host_interrupt); 114 | 115 | /** Return version of PRU. This must be called after prussdrv_open. */ 116 | int prussdrv_version(); 117 | 118 | /** Return string description of PRU version. */ 119 | const char* prussdrv_strversion(int version); 120 | 121 | int prussdrv_pru_reset(unsigned int prunum); 122 | 123 | int prussdrv_pru_disable(unsigned int prunum); 124 | 125 | int prussdrv_pru_enable(unsigned int prunum); 126 | 127 | int prussdrv_pru_write_memory(unsigned int pru_ram_id, 128 | unsigned int wordoffset, 129 | const unsigned int *memarea, 130 | unsigned int bytelength); 131 | 132 | int prussdrv_pruintc_init(const tpruss_intc_initdata *prussintc_init_data); 133 | 134 | /** Find and return the channel a specified event is mapped to. 135 | * Note that this only searches for the first channel mapped and will not 136 | * detect error cases where an event is mapped erroneously to multiple 137 | * channels. 138 | * @return channel-number to which a system event is mapped. 139 | * @return -1 for no mapping found 140 | */ 141 | short prussdrv_get_event_to_channel_map( unsigned int eventnum ); 142 | 143 | /** Find and return the host interrupt line a specified channel is mapped 144 | * to. Note that this only searches for the first host interrupt line 145 | * mapped and will not detect error cases where a channel is mapped 146 | * erroneously to multiple host interrupt lines. 147 | * @return host-interrupt-line to which a channel is mapped. 148 | * @return -1 for no mapping found 149 | */ 150 | short prussdrv_get_channel_to_host_map( unsigned int channel ); 151 | 152 | /** Find and return the host interrupt line a specified event is mapped 153 | * to. This first finds the intermediate channel and then the host. 154 | * @return host-interrupt-line to which a system event is mapped. 155 | * @return -1 for no mapping found 156 | */ 157 | short prussdrv_get_event_to_host_map( unsigned int eventnum ); 158 | 159 | int prussdrv_map_l3mem(void **address); 160 | 161 | int prussdrv_map_extmem(void **address); 162 | 163 | unsigned int prussdrv_extmem_size(void); 164 | 165 | int prussdrv_map_prumem(unsigned int pru_ram_id, void **address); 166 | 167 | int prussdrv_map_peripheral_io(unsigned int per_id, void **address); 168 | 169 | unsigned int prussdrv_get_phys_addr(const void *address); 170 | 171 | void *prussdrv_get_virt_addr(unsigned int phyaddr); 172 | 173 | /** Wait for the specified host interrupt. 174 | * @return the number of times the event has happened. */ 175 | unsigned int prussdrv_pru_wait_event(unsigned int host_interrupt); 176 | 177 | int prussdrv_pru_event_fd(unsigned int host_interrupt); 178 | 179 | int prussdrv_pru_send_event(unsigned int eventnum); 180 | 181 | /** Clear the specified event and re-enable the host interrupt. */ 182 | int prussdrv_pru_clear_event(unsigned int host_interrupt, 183 | unsigned int sysevent); 184 | 185 | int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum, 186 | unsigned int host_interrupt, 187 | unsigned int ack_eventnum); 188 | 189 | int prussdrv_exit(void); 190 | 191 | int prussdrv_exec_program(int prunum, const char *filename); 192 | 193 | int prussdrv_exec_code(int prunum, const unsigned int *code, int codelen); 194 | 195 | #if defined (__cplusplus) 196 | } 197 | #endif 198 | #endif -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import distribute_setup 2 | distribute_setup.use_setuptools() 3 | 4 | from setuptools import setup, Extension, find_packages 5 | 6 | classifiers = ['Development Status :: 3 - Alpha', 7 | 'Operating System :: POSIX :: Linux', 8 | 'License :: OSI Approved :: MIT License', 9 | 'Intended Audience :: Developers', 10 | 'Programming Language :: Python :: 2.6', 11 | 'Programming Language :: Python :: 2.7', 12 | 'Programming Language :: Python :: 3', 13 | 'Topic :: Software Development', 14 | 'Topic :: Home Automation', 15 | 'Topic :: System :: Hardware'] 16 | 17 | setup(name = 'beaglebone_pru_adc', 18 | version = '0.0.3', 19 | author = 'Mike Kroutikov', 20 | author_email = 'pgmmpk@gmail.com', 21 | description = 'Fast analog sensor capture for Beaglebone Black', 22 | long_description = open('README.md').read(), 23 | license = 'MIT', 24 | keywords = 'BeagleBone PRU ADC', 25 | url = 'https://github.com/pgmmpk/beaglebone_pru_adc/', 26 | classifiers = classifiers, 27 | packages = find_packages(), 28 | py_modules = ['beaglebone_pru_adc'], 29 | package_data = {'beaglebone_pru_adc': ['firmware/*.bin']}, 30 | ext_modules = [ 31 | Extension('beaglebone_pru_adc._pru_adc', 32 | ['src/pru_adc.c', 'prussdrv/prussdrv.c'], 33 | include_dirs = ['prussdrv', 'src'] 34 | ) 35 | ] 36 | ) 37 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | ## Driver memory map 2 | 3 | This is the structure of local PRU0 memory. There are 512 bytes available (128 fullwords) 4 | 5 | ``` 6 | Offset Length Value Name Description 7 | ------ ------ ----- ---- ----------- 8 | 0x0000 4 0xbeef1965 EYE Eyecatcher constant 0xbeef1965 9 | 0x0004 4 0x00000000 TICKS Number of capture ticks. Incremented each time ADC capture runs (200K times per sec, approx) 10 | 0x0008 4 0x00000000 FLAGS Execution flags (bit mapped) 11 | 0x000c 4 0x00000000 SCOPE_OUT Address of the DDR memory buffer where to store OSCILLOSCOPE captured values 12 | 0x0010 4 0x00000000 SCHOPE_OFF Offset to use for OSCILLOSCOPE capture 13 | 0x0014 4 0x00000000 SCOPE_LEN How many values to capture in OSCILLOSCOPE mode 14 | 0x0018 4 0x00000000 DEBUG_VAL Value to be stored for debugging purpose 15 | 0x001c 4 0x00000000 EMA_POW Exponent to use for EMA-averaging: ema_value += (value - ema_value / 2^EMA_POW) 16 | 0x0020 4 0x00000000 AIN0_EMA Value (optionally smoothened via EMA) of the channel AIN0 17 | 0x0024 4 0x00000000 AIN1_EMA Value (optionally smoothened via EMA) of the channel AIN1 18 | 0x0028 4 0x00000000 AIN2_EMA Value (optionally smoothened via EMA) of the channel AIN2 19 | 0x002c 4 0x00000000 AIN3_EMA Value (optionally smoothened via EMA) of the channel AIN3 20 | 0x0030 4 0x00000000 AIN4_EMA Value (optionally smoothened via EMA) of the channel AIN4 21 | 0x0034 4 0x00000000 AIN5_EMA Value (optionally smoothened via EMA) of the channel AIN5 22 | 0x0038 4 0x00000000 AIN6_EMA Value (optionally smoothened via EMA) of the channel AIN6 23 | 0x003c 4 0x00000000 AIN7_EMA Value (optionally smoothened via EMA) of the channel AIN7 24 | 0x0040 4 0x00000000 ENC_CHNLS Encoder channels 25 | 0x0044 4 0x00000800 ENC_THRSH Schmitt trigger threshold for encoder values 26 | 0x0048 4 0x00000000 ENC0_RAW Raw value last captured for ENC0 27 | 0x004c 4 0x00000000 ENC0_MIN Running min (see Scmitt trigger filtering algo) 28 | 0x0050 4 0x00000000 ENC0_MAX Running max (see Scmitt trigger filtering algo) 29 | 0x0054 4 0x00000000 ENC0_TICK Number of ticks for encoder 0 30 | 0x0058 4 0x00000000 ENC0_SPD Speed for the encoder 0 31 | 0x005c 4 0x00000000 ENC0_ACC Accumulator for computing encoder speed 32 | 0x0060 4 0x00000000 ENC0_DELAY Signal must exceed threshold for at least this value to be registered 33 | 0x0064 4 0x00000000 ENC0_UP Counts how many timer units signal is over the threshold 34 | 0x0068 4 0x00000000 ENC0_DOWN Counts how many timer units signal is below the threshold 35 | 0x006c 4 Reserved 36 | 0x0070 4 Reserved 37 | 0x0074 4 Reserved 38 | 0x0078 4 Reserved 39 | 0x007c 4 Reserved 40 | 0x0080 4 Reserved 41 | 0x0084 4 0x00000800 ENC_THRSH Schmitt trigger threshold for encoder values 42 | 0x0088 4 0x00000000 ENC1_RAW Raw value last captured for ENC1 43 | 0x008c 4 0x00000000 ENC1_MIN Running min (see Scmitt trigger filtering algo) 44 | 0x0090 4 0x00000000 ENC1_MAX Running max (see Scmitt trigger filtering algo) 45 | 0x0094 4 0x00000000 ENC1_TICK Number of ticks for encoder 1 46 | 0x0098 4 0x00000000 ENC1_SPD Speed for the encoder 1 47 | 0x009c 4 0x00000000 ENC1_ACC Accumulator for computing encoder speed 48 | 0x00a0 4 0x00000000 ENC1_DELAY Signal must exceed threshold for at least this value to be registered 49 | 0x00a4 4 0x00000000 ENC1_UP Counts how many timer units signal is over the threshold 50 | 0x00a8 4 0x00000000 ENC1_DOWN Counts how many timer units signal is below the threshold 51 | 0x00ac 4 Reserved 52 | 0x00b0 4 Reserved 53 | 0x00b4 4 Reserved 54 | 0x00b8 4 Reserved 55 | 0x00bc 4 Reserved 56 | 0x00c0 4 Reserved 57 | 0x00c4 4 0x00000000 CAP_DELAY Extra delay to control capture frequency 58 | ``` 59 | -------------------------------------------------------------------------------- /src/firmware.h: -------------------------------------------------------------------------------- 1 | #ifndef _FIRMWARE_H 2 | #define _FIRMWARE_H 3 | 4 | typedef unsigned int word; 5 | typedef unsigned short halfword; 6 | typedef unsigned char byte; 7 | 8 | typedef struct { 9 | word threshold; // threshold used for detecting wheel encoder ticks 10 | word raw; // raw value of encoder 11 | word min; // min value for current half-tick 12 | word max; // max value for current half-tick 13 | word ticks; // count of encoder ticks 14 | word speed; // width of last encoder tick in "timer" units, aka inverse speed 15 | #define INITIAL_ACC_VAL (0x7fffffff) 16 | word acc; // work area for speed computation 17 | word delay; // activation delay, in timer units. 18 | word uptick_time; // work area for computing uptick delay 19 | word downtick_time; // work area for computing downtick delay 20 | word reserved[6]; 21 | } enc_local_t; 22 | 23 | /* 24 | * Local memory of the firmware 25 | */ 26 | typedef struct { 27 | #define EYECATCHER (0xbeef1965) 28 | word eyecatcher; // eyecacher (for sanity checks) 29 | word timer; // timer: counts number of ADC reads 30 | word flags; // runtime flags. write 1 to exit capture loop 31 | 32 | struct { 33 | word addr; // address of DDR memory bank 34 | word offset; // byte offset into local memory to capture for `scope mode 35 | word length; // byte size of available DDR mem bank (non-zero triggers `scope capture) 36 | } scope; 37 | 38 | word reserved0; 39 | 40 | word ema_pow; // exponent for EMA averaging: ema += (value - ema/2^ema_pow) 41 | 42 | word ain_ema[8]; // captured and EMA-averaged values of all 8 ADC pins 43 | 44 | struct { 45 | byte encoder0; // pin number of first wheel encoder ENC0 (0-7) 46 | byte encoder1; // pin number of second wheel encoder ENC1 (0-7) 47 | byte reserved[2]; 48 | } enc; 49 | 50 | enc_local_t enc_local[2]; // local work memory for each wheel encoder 51 | word cap_delay; // extra delay to control capture frequency 52 | 53 | } locals_t; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/firmware.p: -------------------------------------------------------------------------------- 1 | // (C) 2014 Mike Kroutikov 2 | 3 | #define PRU0_ARM_INTERRUPT 19 4 | 5 | #define ADC_BASE 0x44e0d000 6 | 7 | #define CONTROL 0x0040 8 | #define SPEED 0x004c 9 | #define STEP1 0x0064 10 | #define DELAY1 0x0068 11 | #define STATUS 0x0044 12 | #define STEPCONFIG 0x0054 13 | #define FIFO0COUNT 0x00e4 14 | 15 | #define ADC_FIFO0DATA (ADC_BASE + 0x0100) 16 | 17 | // Register allocations 18 | #define adc_ r6 19 | #define fifo0data r7 20 | #define out_buff r8 21 | #define locals r9 22 | 23 | #define value r10 24 | #define channel r11 25 | #define ema r12 26 | #define encoders r13 27 | #define cap_delay r14 28 | 29 | #define tmp0 r1 30 | #define tmp1 r2 31 | #define tmp2 r3 32 | #define tmp3 r4 33 | #define tmp4 r5 34 | 35 | .origin 0 36 | .entrypoint START 37 | 38 | START: 39 | LBCO r0, C4, 4, 4 // Load Bytes Constant Offset (?) 40 | CLR r0, r0, 4 // Clear bit 4 in reg 0 41 | SBCO r0, C4, 4, 4 // Store Bytes Constant Offset 42 | 43 | MOV adc_, ADC_BASE 44 | MOV fifo0data, ADC_FIFO0DATA 45 | MOV locals, 0 46 | 47 | LBBO tmp0, locals, 0, 4 // check eyecatcher 48 | MOV tmp1, 0xbeef1965 // 49 | QBNE QUIT, tmp0, tmp1 // bail out if does not match 50 | 51 | LBBO out_buff, locals, 0x0c, 4 52 | LBBO ema, locals, 0x1c, 4 53 | LBBO encoders, locals, 0x40, 4 54 | 55 | // Read CAP_DELAY value into the register for convenience 56 | LBBO cap_delay, locals, 0xc4, 4 57 | 58 | // Disable ADC 59 | LBBO tmp0, adc_, CONTROL, 4 60 | MOV tmp1, 0x1 61 | NOT tmp1, tmp1 62 | AND tmp0, tmp0, tmp1 63 | SBBO tmp0, adc_, CONTROL, 4 64 | 65 | // Put ADC capture to its full speed 66 | MOV tmp0, 0 67 | SBBO tmp0, adc_, SPEED, 4 68 | 69 | // Configure STEPCONFIG registers for all 8 channels 70 | MOV tmp0, STEP1 71 | MOV tmp1, 0 72 | MOV tmp2, 0 73 | 74 | FILL_STEPS: 75 | LSL tmp3, tmp1, 19 76 | SBBO tmp3, adc_, tmp0, 4 77 | ADD tmp0, tmp0, 4 78 | SBBO tmp2, adc_, tmp0, 4 79 | ADD tmp1, tmp1, 1 80 | ADD tmp0, tmp0, 4 81 | QBNE FILL_STEPS, tmp1, 8 82 | 83 | // Enable ADC with the desired mode (make STEPCONFIG registers writable, use tags, enable) 84 | LBBO tmp0, adc_, CONTROL, 4 85 | OR tmp0, tmp0, 0x7 86 | SBBO tmp0, adc_, CONTROL, 4 87 | 88 | CAPTURE: 89 | // check if we need to delay our main loop (to control capture frequency) 90 | QBNE CAPTURE_DELAY, cap_delay, 0 91 | NO_DELAY: 92 | 93 | MOV tmp0, 0x1fe 94 | SBBO tmp0, adc_, STEPCONFIG, 4 // write STEPCONFIG register (this triggers capture) 95 | 96 | // check for exit flag 97 | LBBO tmp0, locals, 0x08, 4 // read runtime flags 98 | QBNE QUIT, tmp0.b0, 0 99 | 100 | 101 | // check for oscilloscope mode 102 | LBBO tmp0, locals, 0x14, 4 103 | QBEQ NO_SCOPE, tmp0, 0 104 | 105 | SUB tmp0, tmp0, 4 106 | SBBO tmp0, locals, 0x14, 4 107 | LBBO tmp0, locals, 0x10, 4 108 | LBBO tmp0, locals, tmp0, 4 109 | SBBO tmp0, out_buff, 0, 4 110 | ADD out_buff, out_buff, 4 111 | 112 | NO_SCOPE: 113 | 114 | // increment ticks 115 | LBBO tmp0, locals, 0x04, 4 116 | ADD tmp0, tmp0, 1 117 | SBBO tmp0, locals, 0x04, 4 118 | 119 | // increment encoder ticks 120 | LBBO tmp0, locals, 0x58, 8 121 | ADD tmp1, tmp1, 1 122 | MAX tmp0, tmp1, tmp0 123 | SBBO tmp0, locals, 0x58, 8 124 | 125 | LBBO tmp0, locals, 0x98, 8 126 | ADD tmp1, tmp1, 1 127 | MAX tmp0, tmp1, tmp0 128 | SBBO tmp0, locals, 0x98, 8 129 | SBBO tmp0, locals, 0x98, 8 130 | 131 | WAIT_FOR_FIFO0: 132 | LBBO tmp0, adc_, FIFO0COUNT, 4 133 | QBNE WAIT_FOR_FIFO0, tmp0, 8 134 | 135 | READ_ALL_FIFO0: // lets read all fifo content and dispatch depending on pin type 136 | LBBO value, fifo0data, 0, 4 137 | LSR channel, value, 16 138 | AND channel, channel, 0xf 139 | MOV tmp1, 0xfff 140 | AND value, value, tmp1 141 | 142 | // here we have true captured value and channel 143 | QBNE NOT_ENC0, encoders.b0, channel 144 | MOV channel, 0 145 | CALL PROCESS 146 | JMP NEXT_CHANNEL 147 | 148 | NOT_ENC0: 149 | QBNE NOT_ENC1, encoders.b1, channel 150 | MOV channel, 1 151 | CALL PROCESS 152 | JMP NEXT_CHANNEL 153 | 154 | NOT_ENC1: 155 | LSL tmp1, channel, 2 // to byte offset 156 | ADD tmp1, tmp1, 0x20 // base of the EMA values 157 | LBBO tmp2, locals, tmp1, 4 158 | LSR tmp3, tmp2, ema 159 | SUB tmp3, value, tmp3 160 | ADD tmp2, tmp2, tmp3 161 | SBBO tmp2, locals, tmp1, 4 162 | 163 | NEXT_CHANNEL: 164 | SUB tmp0, tmp0, 1 165 | QBNE READ_ALL_FIFO0, tmp0, 0 166 | 167 | JMP CAPTURE 168 | 169 | QUIT: 170 | MOV R31.b0, PRU0_ARM_INTERRUPT+16 // Send notification to Host for program completion 171 | HALT 172 | 173 | CAPTURE_DELAY: 174 | MOV tmp0, cap_delay 175 | DELAY_LOOP: 176 | SUB tmp0, tmp0, 1 177 | QBNE DELAY_LOOP, tmp0, 0 178 | JMP NO_DELAY 179 | 180 | PROCESS: // lets process wheel encoder value 181 | LSL channel, channel, 6 182 | ADD channel, channel, 0x44 183 | LBBO &tmp1, locals, channel, 16 // load tmp1-tmp4 (threshold, raw, min, max) 184 | MOV tmp2, value 185 | MIN tmp3, tmp3, value 186 | MAX tmp4, tmp4, value 187 | SBBO &tmp1, locals, channel, 16 // store min/max etc 188 | ADD tmp2, tmp3, tmp1 // tmp2 = min + threshold 189 | QBLT MAYBE_TOHIGH, value, tmp2 190 | ADD tmp2, value, tmp1 // tmp2 = value + threshold 191 | QBLT MAYBE_TOLOW, tmp4, tmp2 192 | 193 | // zero out delays 194 | ADD channel, channel, 32 195 | MOV tmp1, 0 196 | MOV tmp2, 0 197 | SBBO &tmp1, locals, channel, 8 198 | 199 | RET 200 | 201 | MAYBE_TOHIGH: 202 | ADD channel, channel, 28 203 | LBBO &tmp1, locals, channel, 12 // load tmp1-tmp3 with (delay, up_count, down_count) 204 | ADD tmp2, tmp2, 1 // up_count++ 205 | MOV tmp3, 0 // down_count=0 206 | SBBO &tmp1, locals, channel, 12 207 | QBLT TOHIGH, tmp2, tmp1 208 | 209 | RET 210 | 211 | MAYBE_TOLOW: 212 | ADD channel, channel, 28 213 | LBBO &tmp1, locals, channel, 12 // load tmp1-tmp3 with (delay, up_count, down_count) 214 | ADD tmp3, tmp3, 1 // down_count++ 215 | MOV tmp2, 0 // up_count=0 216 | SBBO &tmp1, locals, channel, 12 217 | QBLT TOLOW, tmp3, tmp1 218 | 219 | RET 220 | 221 | TOLOW: 222 | MOV tmp3, 0 223 | MOV tmp2, 0 224 | SBBO &tmp1, locals, channel, 12 // up_count = down_count = 0 225 | 226 | SUB channel, channel, 20 227 | MOV tmp2, value // min = max = value 228 | MOV tmp3, value 229 | SBBO &tmp2, locals, channel, 8 230 | 231 | ADD channel, channel, 8 232 | LBBO &tmp2, locals, channel, 12 // ticks, speed, acc 233 | ADD tmp2, tmp2, 1 // ticks++ 234 | MOV tmp3, tmp4 // speed = acc 235 | MOV tmp4, 0 // acc = 0 236 | SBBO &tmp2, locals, channel, 12 237 | RET 238 | 239 | TOHIGH: 240 | MOV tmp3, 0 241 | MOV tmp2, 0 242 | SBBO &tmp1, locals, channel, 12 // up_count=0, down_count=0 243 | 244 | SUB channel, channel, 20 245 | MOV tmp2, value // min = max = value 246 | MOV tmp3, value 247 | SBBO &tmp2, locals, channel, 8 248 | RET 249 | 250 | -------------------------------------------------------------------------------- /src/pru_adc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * beaglebone_pru_adc - fast analog sensor capture for BeagleBone Black 3 | * 4 | * @author Mike Kroutikov 5 | * @email: pgmmpk@gmail.com 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "prussdrv.h" 12 | #include "pruss_intc_mapping.h" 13 | #include "firmware.h" 14 | 15 | typedef struct { 16 | PyObject_HEAD 17 | 18 | locals_t locals; 19 | 20 | int started; 21 | int closed; 22 | 23 | } Capture; 24 | 25 | static void Capture_dealloc(Capture *self) { 26 | if (!self->closed) { 27 | self->closed = 1; 28 | 29 | prussdrv_exit(); 30 | } 31 | 32 | Py_TYPE(self)->tp_free((PyObject*)self); 33 | } 34 | 35 | static int Capture_init(Capture *self, PyObject *args, PyObject *kwds) { 36 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 37 | int rc; 38 | 39 | self->closed = 1; // consider closed unless successfully init everything 40 | 41 | rc = prussdrv_init (); 42 | if (rc != 0) { 43 | PyErr_SetString(PyExc_IOError, "Failed to init PRUSSDRV driver"); 44 | return -1; 45 | } 46 | 47 | rc = prussdrv_open(0); 48 | if (rc != 0) { 49 | PyErr_SetString(PyExc_IOError, "Failed to open PRU 0"); 50 | prussdrv_exit(); 51 | return -1; 52 | } 53 | 54 | rc = prussdrv_pruintc_init(&pruss_intc_initdata); // Get the interrupt initialized 55 | if (rc != 0) { 56 | PyErr_SetString(PyExc_IOError, "Failed to initialize interrupts"); 57 | prussdrv_exit(); 58 | return -1; 59 | } 60 | 61 | memset(&self->locals, 0, sizeof(self->locals)); 62 | self->locals.eyecatcher = EYECATCHER; 63 | self->locals.enc.encoder0 = 0xff; // assigning out-of-range pin number disables encoder logic 64 | self->locals.enc.encoder1 = 0xff; // ditto 65 | 66 | self->locals.enc_local[0].threshold = 2000; 67 | self->locals.enc_local[0].speed = INITIAL_ACC_VAL; 68 | self->locals.enc_local[0].acc = INITIAL_ACC_VAL; 69 | 70 | self->locals.enc_local[1].threshold = 2000; 71 | self->locals.enc_local[1].speed = INITIAL_ACC_VAL; 72 | self->locals.enc_local[1].acc = INITIAL_ACC_VAL; 73 | 74 | rc = prussdrv_pru_write_memory(0, 0, (unsigned int *) &self->locals, sizeof(self->locals)); 75 | if (rc < 0) { 76 | PyErr_SetString(PyExc_IOError, "Failed to write local memory block"); 77 | prussdrv_exit(); 78 | return -1; 79 | } 80 | 81 | self->closed = 0; 82 | 83 | return 0; 84 | } 85 | 86 | static PyObject *Capture_start(Capture *self, PyObject *args, PyObject *kwds) { 87 | int rc; 88 | char *filename = NULL; 89 | 90 | if (!PyArg_ParseTuple(args, "s", &filename)) { // Parse the PRU number 91 | return NULL; 92 | } 93 | 94 | if (self->started) { 95 | PyErr_SetString(PyExc_IOError, "Already started"); 96 | return NULL; 97 | } 98 | 99 | rc = prussdrv_exec_program (0, filename); // Load and execute the program 100 | if (rc != 0) { 101 | PyErr_SetString(PyExc_IOError, "Failed to exec firmware"); 102 | return NULL; 103 | } 104 | 105 | self->started = 1; // true 106 | 107 | Py_RETURN_NONE; 108 | } 109 | 110 | static PyObject *Capture_wait(Capture *self) { 111 | 112 | if (!self->started) { 113 | PyErr_SetString(PyExc_IOError, "Not started"); 114 | return NULL; 115 | } 116 | 117 | prussdrv_pru_wait_event(0); // Wait for the event. This blocks the thread. 118 | prussdrv_pru_clear_event(0, 0); // Clear the event. FIXME: parameter meaning??? 119 | 120 | Py_RETURN_NONE; 121 | } 122 | 123 | static PyObject *Capture_close(Capture *self, PyObject *args, PyObject *kwds) { 124 | if (!self->closed) { 125 | self->closed = 1; // true 126 | 127 | prussdrv_exit(); 128 | } 129 | 130 | Py_RETURN_NONE; 131 | } 132 | 133 | static PyMethodDef Capture_methods[] = { 134 | {"start", (PyCFunction) Capture_start, METH_VARARGS, "Starts capturing ADC data"}, 135 | {"wait", (PyCFunction) Capture_wait, METH_NOARGS, "Waits for PRU0 interrupt"}, 136 | {"close", (PyCFunction) Capture_close, METH_NOARGS, "closes Capture object"}, 137 | {NULL} /* Sentinel */ 138 | }; 139 | 140 | static PyTypeObject CaptureType = { 141 | PyObject_HEAD_INIT(NULL) 142 | 0, /*ob_size*/ 143 | "_pru_adc.Capture", /*tp_name*/ 144 | sizeof(Capture), /*tp_basicsize*/ 145 | 0, /*tp_itemsize*/ 146 | (destructor)Capture_dealloc, /*tp_dealloc*/ 147 | 0, /*tp_print*/ 148 | 0, /*tp_getattr*/ 149 | 0, /*tp_setattr*/ 150 | 0, /*tp_compare*/ 151 | 0, /*tp_repr*/ 152 | 0, /*tp_as_number*/ 153 | 0, /*tp_as_sequence*/ 154 | 0, /*tp_as_mapping*/ 155 | 0, /*tp_hash */ 156 | 0, /*tp_call*/ 157 | 0, /*tp_str*/ 158 | 0, /*tp_getattro*/ 159 | 0, /*tp_setattro*/ 160 | 0, /*tp_as_buffer*/ 161 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 162 | "fast ADC capture object", /* tp_doc */ 163 | 0, /* tp_traverse */ 164 | 0, /* tp_clear */ 165 | 0, /* tp_richcompare */ 166 | 0, /* tp_weaklistoffset */ 167 | 0, /* tp_iter */ 168 | 0, /* tp_iternext */ 169 | Capture_methods, /* tp_methods */ 170 | 0, /* tp_members */ 171 | 0, /* tp_getset */ 172 | 0, /* tp_base */ 173 | 0, /* tp_dict */ 174 | 0, /* tp_descr_get */ 175 | 0, /* tp_descr_set */ 176 | 0, /* tp_dictoffset */ 177 | (initproc) Capture_init, /* tp_init */ 178 | 0, /* tp_alloc */ 179 | 0, /* tp_new */ 180 | }; 181 | 182 | static PyMethodDef module_methods[] = { 183 | { NULL, NULL, 0, NULL } 184 | }; 185 | 186 | PyMODINIT_FUNC init_pru_adc() { 187 | PyObject *module = NULL; 188 | 189 | 190 | CaptureType.tp_new = PyType_GenericNew; 191 | if (PyType_Ready(&CaptureType) < 0) 192 | return; 193 | 194 | module = Py_InitModule3("_pru_adc", module_methods, ""); 195 | if (module == NULL) { 196 | return; 197 | } 198 | 199 | Py_INCREF(&CaptureType); 200 | PyModule_AddObject(module, "Capture", (PyObject *) &CaptureType); 201 | } 202 | -------------------------------------------------------------------------------- /test/grab_enc0_values.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | import mmap 4 | import struct 5 | 6 | numsamples = 64000 7 | 8 | capture = adc.Capture() 9 | 10 | capture.oscilloscope_capture_init(capture.OFF_VALUES, numsamples) 11 | 12 | capture.start() 13 | 14 | print 'Oscilloscope capture started' 15 | while not capture.oscilloscope_capture_complete(): 16 | print '...' 17 | time.sleep(0.2) 18 | 19 | capture.stop() 20 | capture.wait() 21 | 22 | print 'timer:', capture.timer 23 | print 'ema_pow:', capture.ema_pow 24 | print 'values:', capture.values 25 | print 'enc pins:', capture.encoder0_pin, capture.encoder1_pin 26 | print 'encoder0_values:', capture.encoder0_values 27 | print 'encoder1_values:', capture.encoder1_values 28 | 29 | print 'encoder0_threshold:', capture.encoder0_threshold 30 | print 'encoder1_threshold:', capture.encoder1_threshold 31 | 32 | with open('data.csv', 'w') as f: 33 | for x in capture.oscilloscope_capture_data(numsamples): 34 | f.write(str(x) + '\n') 35 | print 'File "data.csv" saved, exiting' 36 | 37 | capture.close() 38 | -------------------------------------------------------------------------------- /test/test_enc.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | import mmap 4 | import struct 5 | 6 | with open("/dev/uio0", 'r+b') as f1: 7 | pru0_mem = mmap.mmap(f1.fileno(), 0x200, offset=0) 8 | 9 | capture = adc.Capture() 10 | 11 | capture.encoder0_pin=0 12 | capture.encoder1_pin=2 13 | capture.encoder0_threshold = 3000 14 | capture.encoder1_threshold = 2400 15 | capture.start() 16 | 17 | time.sleep(1.0) 18 | 19 | capture.stop() 20 | 21 | capture.wait() 22 | 23 | for off in range(0, 0x81, 4): 24 | read_back = struct.unpack("L", pru0_mem[off:off+4])[0] 25 | print hex(off), ':', hex(read_back) 26 | 27 | print 'timer:', capture.timer 28 | print 'ema_pow:', capture.ema_pow 29 | print 'values:', capture.values 30 | print 'enc pins:', capture.encoder0_pin, capture.encoder1_pin 31 | print 'encoder0_values:', capture.encoder0_values 32 | print 'encoder1_values:', capture.encoder1_values 33 | 34 | print 'encoder0_threshold:', capture.encoder0_threshold 35 | print 'encoder1_threshold:', capture.encoder1_threshold 36 | 37 | 38 | pru0_mem.close() 39 | capture.close() 40 | -------------------------------------------------------------------------------- /test/test_oscilloscope.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | import mmap 4 | import struct 5 | 6 | capture = adc.Capture() 7 | 8 | capture.oscilloscope_init(4, 10) 9 | 10 | capture.start() 11 | 12 | time.sleep(1.0) 13 | 14 | capture.stop() 15 | capture.wait() 16 | 17 | print 'timer:', capture.timer 18 | print 'ema_pow:', capture.ema_pow 19 | print 'values:', capture.values 20 | print 'enc pins:', capture.encoder0_pin, capture.encoder1_pin 21 | print 'encoder0_values:', capture.encoder0_values 22 | print 'encoder1_values:', capture.encoder1_values 23 | 24 | print 'encoder0_threshold:', capture.encoder0_threshold 25 | print 'encoder1_threshold:', capture.encoder1_threshold 26 | 27 | for x in capture.oscilloscope_data(10): 28 | print x 29 | 30 | capture.close() 31 | -------------------------------------------------------------------------------- /test/test_smoke.py: -------------------------------------------------------------------------------- 1 | 2 | import beaglebone_pru_adc as adc 3 | 4 | capture = adc.Capture() 5 | 6 | print capture 7 | -------------------------------------------------------------------------------- /test/test_start.py: -------------------------------------------------------------------------------- 1 | import beaglebone_pru_adc as adc 2 | import time 3 | import mmap 4 | import struct 5 | 6 | with open("/dev/uio0", 'r+b') as f1: 7 | pru0_mem = mmap.mmap(f1.fileno(), 0x200, offset=0) 8 | 9 | capture = adc.Capture() 10 | 11 | capture.start() 12 | 13 | time.sleep(1.0) 14 | #struct.pack_into('L', pru0_mem, 0x0008, 1) # exit flag 15 | 16 | capture.stop() 17 | 18 | for off in range(0, 0x81, 4): 19 | read_back = struct.unpack("L", pru0_mem[off:off+4])[0] 20 | print hex(off), ':', hex(read_back) 21 | 22 | print 'timer:', capture.timer 23 | print 'ema_pow:', capture.ema_pow 24 | print 'values:', capture.values 25 | print 'enc pins:', capture.encoder0_pin, capture.encoder1_pin 26 | print 'encoder0_values:', capture.encoder0_values 27 | print 'encoder1_values:', capture.encoder1_values 28 | 29 | print 'encoder0_threshold:', capture.encoder0_threshold 30 | print 'encoder1_threshold:', capture.encoder1_threshold 31 | 32 | capture.wait() 33 | 34 | pru0_mem.close() 35 | capture.close() 36 | --------------------------------------------------------------------------------