FTDI ADC Device

pybarst.ftdi.adc

FTDI ADC device

The FTDI ADC module controls an CPL ADC device connected to the FTDI channel’s digital pins. You can connect multiple ADC devices in parallel to different pins, and they can be configured to be connected to a variable number of channel pins.

class pybarst.ftdi.adc.ADCSettings(clock_bit, lowest_bit, num_bits, sampling_rate=None, chan1=False, chan2=False, hw_buff_size=25, transfer_size=100, chop=True, input_range='-10, 10', data_width=16, reverse=False, rate_filter=None, double crystal_freq=6000000.0, **kwargs)

Bases: pybarst.ftdi.FTDISettings

The settings for a CPL ADC device connected to the the FTDI channel.

When an instance of this class is passed to a FTDIChannel in the channels parameter, it will create a FTDIADC in devices.

This settings class indicates and controls how the device is connected to the FTDI bus as well as the settings used to configure the ADC device.

Parameters:
hw_buff_size: float

The buffer size of the USB device. See hw_buff_size. Defaults to 25.

transfer_size: int

The number of data points for the server to accumulate before sending it to the client. See transfer_size. Effectively this controls how often data is sent to the client. E.g. if the sampling rate is 1000Hz and this value is 500, then 500 data point will be sent at once, or data will be sent to the client twice per second. Defaults to 100.

clock_bit: int

The pin connected to the ADC clock pin. Ssee clock_bit.

lowest_bit: int

The lowest data pin connected to the ADC device. See lowest_bit.

num_bits: int

The number of data pins connected to the ADC device. See num_bits.

chop: bool

Whether chopping (hardware sampling smoothing) is enabled. See chop. Defaults to True.

chan1: bool

Whether channel 1 of the ADC device is enabled and sampled. Each ADC device has two channels, either or both of which can be enabled. See chan1. Defaults to False.

chan2: bool

Whether channel 2 of the ADC device is enabled and sampled. Each ADC device has two channels, either or both of which can be enabled. See chan2. Defaults to False.

input_range: str

The voltage input range supported by the ADC device. See input_range. Defaults to ‘-10, 10’.

data_width: int

The bit depth of the ADC data points; either 16 or 24. See data_width. Defaults to 16.

reverse: bool

Whether the data pins of the ADC device are connected in the reverse order compared to the FTDI USB bus. See reverse. Defaults to False.

sampling_rate: float

The sampling rate that should be used by the ADC device for each channel. See sampling_rate. If None, it’ll use rate_filter filter instead. Defaults to None. Note, the device will try to find to closest sampling rate possible, which is not likely to be equal to sampling_rate.

rate_filter: int

The sampling rate code used by the device to set the sampling rate. See rate_filter. If None, it’ll use sampling_rate filter instead. Defaults to None. This controls the actual sampling rate, and the sampling_rate parameter, if supplied, gets first converted to rate_filter internally.

crystal_freq: float

The frequency of the crystal on the ADC device. Defaults to 6000000.

Note

The settings can not be changed after they have been passed to the constructor. I.e. setting the properties directly might result in incorrect states.

chan1

chan1: ‘unsigned char’

Indicates whether channel 1 should be active and read and send back data.

chan2

chan2: ‘unsigned char’

Indicates whether channel 2 should be active and read and send back data.

chop

chop: ‘unsigned char’

Indicates whether chopping mode (noise reduction) should be active on the ADC device. It typically lowers the sampling rate when enabled.

clock_bit

clock_bit: ‘unsigned char’

The pin to which the clock line of the ADC device is connected at the FTDI channel. Typically between 0 - 7.

data_width

data_width: ‘unsigned char’

The bit depth of each data point read by the ADC device. Acceptable values are either 16, or 24.

hw_buff_size

hw_buff_size: ‘float’

When The FTDI channel is communicating with the peripheral ADC device we continuously read/write to it. The larger the buffer we write/read at once the faster it performs. For instance, for fastest communication we would write in buffer multiples of the maximum buffer size. Because each FTDI channel can be used for multiple peripherals devices, if we were to write in multiples of the maximum buffer size then although it’d be most efficient for the ADC device, during this write/read other devices of this channel will have to wait until we are finished writing the buffer and before move on to the next buffer to be able to update their device. This means, the larger the buffer the more we have to wait between writes to other devices and the longer we have to wait between to update a device. hw_buff_size tells us the percentage (0-100) of the maximum buffer to use for ADC read / write. The smaller this is, the faster other devices will be able to update, but might reduce the ADC bit rate which could be unsuited at higher ADC sampling rates.

input_range

input_range: ‘unsigned char’

The internal Barst code the correspond to the input_range_str string.

input_range_str

input_range_str: str

The voltage input range that the device should accept. Can be one of 4 strings: ‘0, 5’, ‘0, 10’, ‘-5, 5’, or ‘-10, 10’. For a particular setting, voltage outside its range will show as error.

lowest_bit

lowest_bit: ‘unsigned char’

Defines which pins on the FTDI USB bus are data pins. The data pins are connected to the FTDI bus starting from pin number lowest_bit until lowest_bit + num_bits.

max_rate

max_rate: ‘double’

Indicates the highest possible sampling rate possible for the current device settings.

min_rate

min_rate: ‘double’

Indicates the lowest possible sampling rate possible for the current device settings.

num_bits

num_bits: ‘unsigned char’

Indicates the number of pins on the FTDI bus that are connected to the ADC data port. Range is [2, 8]. See lowest_bit.

rate_filter

rate_filter: ‘unsigned char’

The internal code indicating the current sampling rate of the device. sampling_rate gets converted to the closest rate_filter value which controls the final sampling rate of the device.

Following, is the meaning of rate_filter:

  • If chop is True, rate_filter can range between 2-127, inclusive. Therefore:
    • If only one of chan1, chan2 is enabled then the sampling rate is Freq / (rate_filter * 128 + 248).
    • If both chan1 and chan2 are enabled then the sampling rate is Freq / (rate_filter * 128 + 249).
  • If chop is False, rate_filter can range between 3-127, inclusive. Therefore:
    • If only one of chan1, chan2 is enabled then the sampling rate is Freq / (rate_filter * 64 + 206).
    • If both chan1 and chan2 are enabled then the sampling rate is Freq / (rate_filter * 64 + 207).

In all cases, if both channels are enabled, the sampling rate above is for both channels, therefore the sampling rate per channel is half the rate quoted above. Also, Freq is the crystal frequency of the ADC board. This is controlled by the crystal_freq parameter. The resulting sampling rate is expressed in Hz.

reverse

reverse: ‘unsigned char’

Indicates how the ADC is connected to the FTDI USB bus. If True, indicates that the data pins on the USB bus are flipped relative to the pins on the ADC device; e.g. pin 7 connects to pin 0 etc. If False the pins on the USB bus and ADC device go in the same direction; e.g. pin 2 is connected to pin 5, pin 3 to pin 6 etc.

sampling_rate

sampling_rate: ‘double’

The sampling rate used by the ADC device for each channel. The value controls both channels. The available sampling rates is a function of all the other device options.

transfer_size

transfer_size: ‘DWORD’

This parameter allows you to control over how often the ADC sends data read back to the client. The server will wait until transfer_size data points for each channel (if two channels are active) has been accumulated and than sends transfer_size (for each channel) data points to the client.

class pybarst.ftdi.adc.ADCData

Bases: object

A data object returned by the ADC client after a read from the server. Each instance holds the most recently read data from the server for both channel 1 and / or 2. The class returns both the raw and actual voltage data points as well other information about the data. See the class attributes.

This class is not instantiated by the user, but is returned by FTDIADC.read().

bad_count

bad_count: ‘short’

A value indicating the number of times for this packet that invalid data was read by the USB from the ADC device. None-zero values might indicate connection or hardware issues.

chan1_data

chan1_data: array.array

An array of doubles containing the scaled data from channel 1. Each data point is the actual voltage sampled at the ADC channel port and has been scaled appropriately to be within the ADCSettings.input_range_str range.

For example:

>>> print data.chan1_data
array('d', [-0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625])
chan1_oor

chan1_oor: ‘char’

A bool indicating whether the voltage sensed on channel 1 is outside the range defined when creating the channel, ADCSettings.input_range_str.

chan1_raw

chan1_raw: array.array

An array containing the raw un-scaled 16 or 24 bit raw unsigned int data acquired for channel 1. If this channel is disabled, it defaults to None.

For example:

>>> print data.chan1_raw
array('L', [32763L, 32763L, 32763L, 32763L, 32763L, 32763L, 32763L, 32763L, 32763L, 32763L])
chan1_ts_idx

chan1_ts_idx: ‘DWORD’

Each read operation by the USB from the ADC device gets time stamped after the read (uncertainty of the time stamp is a few ms, depending on the USB communication uncertainty). The time stamp is associated with a particular data point within the array since that data point would have been the first data point read in the next USB read. This time stamp is recorded in ts. This parameter tells you the index of this data point within chan1_raw and chan1_data for channel 1. E.g. a value of 10 indicates that data point 10 in chan1_data was taken at about ts.

Because the data in one USB read can be broken down and sent in multiple packets based on the ADCSettings.transfer_size setting. If this packet doesn’t have a data point that was time stamped, ts is zero.

Because data points are time stamped by the system clock regularly, it can be used to compare with the ADC clock (which is the number of data points of this channel received, multiplied by the sampling rate).

For example:

>>> print data.chan1_ts_idx
10
chan2_data

chan2_data: array.array

An array of doubles containing the scaled data from channel 2. Each data point is the actual voltage sampled at the ADC channel port and has been scaled appropriately to be within the ADCSettings.input_range_str range.

For example:

>>> print data.chan2_data
array('d', [-0.001220703125, -0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375])
chan2_oor

chan2_oor: ‘char’

A bool indicating whether the voltage sensed on channel 2 is outside the range defined when creating the channel, ADCSettings.input_range_str.

chan2_raw

chan2_raw: array.array

An array containing the raw un-scaled 16 or 24 bit raw unsigned int data acquired for channel 2. If this channel is disabled, it defaults to None.

For example:

>>> print data.chan2_raw
array('L', [32764L, 32765L, 32765L, 32765L, 32765L, 32765L, 32765L, 32765L, 32765L])
chan2_ts_idx

chan2_ts_idx: ‘DWORD’

The index in chan2_data that approximately corresponds with ts. See chan1_ts_idx.

For example:

>>> print data.chan2_ts_idx
9
count

count: ‘DWORD’

The packet number of this instance. Everytime the server sends data to the client (every time FTDIADC.read() is called) the internal index gets incremented and stored here. This allows us to recognize if a data packet is missing, since this index should be a continuous value.

For example:

>>> print data.count
44
fullness

fullness: ‘float’

As mentioned in ADCSettings.hw_buff_size, we can select different sizes for the buffer length that is written to the FTDI USB device at once. If it is too small, than most of the buffer read would be full with ADC data. If it’s very large, then it should be mostly empty because it’s more efficient. This parameter tells you the percentage of the read buffer that was filled with ADC data.

If this parameter is close to 100, that means the device is close to losing data because the buffer might be too small or the USB clock too slow to be able to read the data fast enough. So you should increase the buffer size or set a smaller sampling rate.

For example:

>>> print data.fullness
0.0122897801921
noref

noref: ‘char’

A bool indicating whether the hardware voltage reference on the ADC device is not detected. A value of True indicates a hardware error.

overflow_count

overflow_count: ‘short’

Indicates the number of times data was skipped while reading the ADC device. For example, if the ADC is operating at a very high sampling rate and the FTDI USB channel is too slow, then data might simply be lost. If none-zero, this indicates the number of times it happened.

rate

rate: ‘float’

Debug information. With every packet, the server also computes the estimated sampling rate at which the data was taken. It should be close to ADCSettings.sampling_rate.

For example, the sampling rate was set to 1000Hz:

>>> print data.rate
1187.5
ts

ts: ‘double’

The time stamp, in server time clock() that the chan1_ts_idx and chan2_ts_idx data points were approximately taken. See chan1_ts_idx.

For example:

>>> print data.ts
5.7277356845
class pybarst.ftdi.adc.FTDIADC

Bases: pybarst.ftdi.FTDIDevice

Controls an ADC device connected to the FTDIChannel. See ADCSettings for details on this device type.

For example:

>>> # create a adc device with clock connected to pin 7, and 4 data
>>> # lines at pins 3 - 6. The sampling rate is 1kHz. Both channels are
>>> # active. Send back data to client at every 100 data points (10Hz)
>>> settings = ADCSettings(clock_bit=7, lowest_bit=3, num_bits=4, sampling_rate=1000, chan1=True, chan2=True, hw_buff_size=25,transfer_size=100)
>>> # create and open the channel
>>> ft = FTDIChannel(channels=[settings], server=server, desc='Birch Board rev1 B')
>>> adc = ft.open_channel(alloc=True)[0]
>>> print adc
<pybarst.ftdi.adc.FTDIADC object at 0x027984C8>
>>> adc.open_channel()
>>> adc.set_state(True)
>>> data = adc.read()
>>> print data
<pybarst.ftdi.adc.ADCData object at 0x0278C6B8>
>>> print data.chan1_data
array('d', [-0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, -0.00152587890625, ..., -0.00152587890625])
>>> print data.chan2_data
array('d', [-0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375, -0.00091552734375, ..., -0.00091552734375])
>>> # the channel time stamp of the the data point at data.chan1_ts_idx
>>> print data.ts
7.34521248027
>>> # the rate should be approximately at 1kHz +/ a few hundred Hz.
>>> print data.rate
1058.51062012
get_conversion_factors(self)

Returns the factors used to scale the raw data into floating points.

Returns a 3-tuple of bit-depth, multiplier, and subtractend.

The formula is float = (raw / 2 ** bit_depth) * multiplier - subtractend.

open_channel(self)

See open_channel() for details.

read(self)

Requests the server to read and send the next available data from the ADC. This method will wait until the server sends data, or an error message, thereby tying up this thread. Depending on how often data is sent, this might take a while under error conditions.

After the first call to read() the server will continuously read from the device and send the results back to the client. This means that if the client doesn’t call read() frequently enough data will accumulate in the pipe.

To cancel a read request while the read is still waiting, from another thread you must call close_channel_client(), or close_channel_server(), or just delete the server, which will cause this method to return with an error.

A more gentle way of canceling a read request while not currently waiting in read(), is to call set_state() to set it inactive, which will cause the next read operation to return with an error, but will not delete/close the channel. See that methods for more details.

Returns:Each call to this method returns the next data read from the active channels in a ADCData instance. As long as data points are not missing, the data returned from subsequent reads can be concatenated to get a continuous data stream at the device’s sampling rate.

Warning

Before this method can be called, open_channel() must be called and then device must be set to active using set_state().

read() may/should be called immediately after set_state() is called activating this device. When the state is activated, the device immediately starts sampling the ADC port, however, data only begins to be sent back to the client after read() is called the first time. So any data sampled before read() is called for the first time is lost. Once read() is called, if read() is not called frequently enough, it just accumulates in the pipe, but does not get discarded.

Note

The error attributes of ADCData (ADCData.chan1_oor, ADCData.chan2_oor, ADCData.noref, ADCData.bad_count, ADCData.overflow_count) should be checked for every returned instance to detect errors with the ADC device.

Note

Although multiple clients can simultaneously connect to the same FTDI channel, and FTDI peripheral devices; e.g. 2 clients instances can open the same ADC channel at the same time. Only one client is allowed to read at any time. That is after activation, once a client has called read(), no other client is allowed to call read() until the initial client set the state to inactive with set_state(). After that, any client can activate the state and call read() again.