EdgePi-Cloud / edgepi-python-sdk

Python SDK to control EdgePi, an industrial PC/PLC/IoT device powered by Raspberry Pi CM4
MIT License
5 stars 3 forks source link

ADC User Interface #88

Closed sjpark608 closed 1 year ago

sjpark608 commented 2 years ago

ADC

By importing edgepi_adc module, the user should be able to measure input voltage in the form of digitized code, 24 or 32 bit, from an input terminal specified by the user and convert the measurement into a human-readable voltage value. The user should be able to change some high level configurations regarding the reading of the input.

Voltage Reading functionality

Specify the following parameters before perform reading command

Voltage Data representation

provide processed data

Configuration

There are configuration registers affecting the performance of the module. Most of the registers should be set during the module instantiation. The user only interacts with a limited configuration to perform the measurements.

Default Setting

User setting

Note: MODE0~2 registers are related to the data rates. This still needs some research on how these registers affect the data sampling rate. In the future, users will just provide a sampling rate of interest, and a function will configure these registers in order to meet the provided rate.

flavius-t commented 1 year ago

ADC

By importing edgepi_adc module, the user should be able to measure input voltage in the form of digitized code, 24 or 32 bit, from an input terminal specified by the user and convert the measurement into a human-readable voltage value. The user should be able to change some high level configurations regarding the reading of the input.

Voltage Reading functionality

Specify the following parameters before perform reading command

* [ ]  Specify Channel to read

  * [ ]  ch0~7 when RTD_EN is False
  * [ ]  ch0~3 when RTD_EN is True

* [ ]  Specify ADC

  * [ ]  ADC 1 32bit long
  * [ ]  ADC 2 24bit long

* [ ]  sampling rate / data rate

* [ ]  Instantaneous / set_number of samples

* [ ]  code to voltage conversion

Voltage Data representation

provide processed data

* [ ]  statistic data

  * [ ]  mean
  * [ ]  stdev
  * [ ]  median
  * [ ]  min
  * [ ]  max

Configuration

There are configuration registers affecting the performance of the module. Most of the registers should be set during the module instantiation. The user only interacts with a limited configuration to perform the measurements.

Default Setting

* [ ]  POWER: Reset bit needs to be cleared on reset/powerup, rest of the bits stay in the default condition

* [ ]  INTERFACE: All bits stay in the default state, Checksum calculation implemented done in the test script. Let me know if you need help @flavius-t

* [ ]  MODE0: All bits in the default state

* [ ]  MODE1: All bits in the default state

* [ ]  MODE2: All bits in the default state

* [ ]  INPMUX: set MUXP = 0xF (Float), set MUXN = 0xA (AINCOM)

* [ ]  IDACMUX: All bits in the default state

* [ ]  IDACMAG: All bits in the default state

* [ ]  REFMUX: All bits in the default state

User setting

* [ ]  INTERFACE: CRC bits can be changed, we need to provide them with CRC and checksum function

* [ ]  MODE0: rum mode can be selected between continuous or pulse conversion

* [ ]  MODE1: filter mode can be selected

* [ ]  MODE2: Data rate bits can be selected

* [ ]  INPMUX: MUXN is fixed with AINCOM, MUXP is selected according to the channel that the user provides

Note: MODE0~2 registers are related to the data rates. This still needs some research on how these registers affect the data sampling rate. In the future, users will just provide a sampling rate of interest, and a function will configure these registers in order to meet the provided rate.


Based on this, my understanding of the high level interface we need to provide to users is as follows:

  1. read_input_voltage(channel, adc)
  2. set_config
    • crc_mode: CRC or checksum
    • conversion_mode: continuous or pulse
    • filter_mode
    • data_rate
  3. adc_status

    • read conversion data STATUS byte for adc1 output faults


    • [ ] Instantaneous / set_number of samples

    • [ ] code to voltage conversion Does the first refer to data_rate? I am not sure what code to voltage conversion refers to.


    • [ ] Specify Channel to read

      • [ ] ch0~7 when RTD_EN is False
      • [ ] ch0~3 when RTD_EN is True

When is RTD_EN expected to be False? Is the user in control of setting this pin?


Voltage Data representation

provide processed data

* [ ]  statistic data

  * [ ]  mean
  * [ ]  stdev
  * [ ]  median
  * [ ]  min
  * [ ]  max

We will need to decide on whether to provide a set time frame for these statistics (i.e. the past hour, day, month, etc), or accept a time frame as an argument.


* [ ]  INPMUX: MUXN is fixed with AINCOM, MUXP is selected according to the channel that the user provides

We do not want to also allow users to select ADC2 multiplexer?


Note: MODE0~2 registers are related to the data rates. This still needs some research on how these registers affect the data sampling rate. In the future, users will just provide a sampling rate of interest, and a function will configure these registers in order to meet the provided rate.

The thermocouple module had a similar averaging mode setting. The high level approach we took was to offer the available averaging modes (in this case data_rate) as Enums. It seems there are a finite set of configurable data rates in the MODE2 register. I think this approach would be ideal rather than mapping a user input sampling rate.

farzadpanahi commented 1 year ago

@flavius-t could also list the proposed high level function signatures we discussed in our meeting?

flavius-t commented 1 year ago

@flavius-t could also list the proposed high level function signatures we discussed in our meeting?

@farzadpanahi

Based on this, my understanding of the high level interface we need to provide to users is as follows:

1. `read_input_voltage`(`channel`, `adc`)

2. `set_config`

   * `crc_mode`: CRC or checksum
   * `conversion_mode`: continuous or pulse
   * `filter_mode`
   * `data_rate`

3. `adc_status`

   * read conversion data `STATUS` byte for `adc1` output faults
farzadpanahi commented 1 year ago
  1. set_config

    • crc_mode: CRC or checksum
    • conversion_mode: continuous or pulse
    • filter_mode
    • data_rate

I don't think this is what we discussed in the meeting. can you take another look at your notes?

flavius-t commented 1 year ago
  1. set_config

    • crc_mode: CRC or checksum
    • conversion_mode: continuous or pulse
    • filter_mode
    • data_rate

I don't think this is what we discussed in the meeting. can you take another look at your notes?

@farzadpanahi For the set_config I believe we discussed the exact settings we wanted users to be able to configure would be determined later, after @sjpark608 determined which were essential settings. From the meeting notes, I have recorded that input voltage reading, configuration setting, and a fault reading system for the STATUS byte is required. Am I missing anything else?

sjpark608 commented 1 year ago

@flavius-t

Based on this, my understanding of the high level interface we need to provide to users is as follows:

read_input_voltage(channel, adc)
set_config
crc_mode: CRC or checksum
conversion_mode: continuous or pulse
filter_mode
data_rate
adc_status
read conversion data STATUS byte for adc1 output faults

This is correct

* [ ]  Instantaneous / set_number of samples

* [ ]  code to voltage conversion

Does the first refer to data_rate? I am not sure what code to voltage conversion refers to.

Instantaneous reading means it will read only one sample at that instance. The data/sampling rate is how fast the ADC chip convert the signal. So the first setting configures whether to do a single read or set number of reading.

The code to voltage conversion is just a function name, it shouldn't be a parameter to specify. Sorry for the confusion

When is RTD_EN expected to be False? Is the user in control of setting this pin?

This can be done by reading pininfo dataclass. The GPIO pin should be set when RTD module is instantiated.

Regarding ADC2, I'd like to verify the functionality and how to use them first before implementing it, since it has a possibility to collide with ADC1 operation.

flavius-t commented 1 year ago

Based on today's meeting, here is the updated high level interface for ADC: 74cf0f26cafb0fc9af864dc83938e015ff076740

The interface is in edgepi_adc.py

@sjpark608 @farzadpanahi

farzadpanahi commented 1 year ago

Just to make sure we are using the right terminology, I think instead of ADCChannel we can use something else, maybe ADCInput? @sjpark608 what is the right terminology to use here?

sjpark608 commented 1 year ago

Just to make sure we are using the right terminology, I think instead of ADCChannel we can use something else, maybe ADCInput? @sjpark608 what is the right terminology to use here?

ADC channel is better in my opinion since it is common to call it input channel or channel x. Reference image

image

However, I think it is also important to use a unified naming on both hardware and software. Right now, our label on the product say A/DINx

flavius-t commented 1 year ago

For DAC we used analog_out in the user interface, maybe analog_in would work here?

flavius-t commented 1 year ago

image

@sjpark is it important to have any settings that users can configure without having an ADC restart conversions? I'm wondering because for the settings that do restart conversions, it is advised to update these as a group (single write). However, it looks like this might not be very efficient in some cases. For example, when updating Group 1 registers together, it's possible we might have to update the intervening non-Group 1 registers as well.

If we want to update Group 1, Group 2, and other registers this would mean at least 3 separate writes. Unless we chose to include the intervening registers, in which case this becomes a single write operation including nearly all registers. So I am thinking it may be more efficient to update all registers at once, unless there are concerns about restarting conversions every time the ADC configuration is changed.

i.e. given the list of updated register values, writing to the groups individually would be something along these lines (Group 3 registers are those not in Groups 1 or 2):

# for each updated register

    # if updated register belongs to GROUP1 add to list of GROUP1 register updates.

    # else if updated register belongs to GROUP2, add to list of GROUP2 register updates

    # else if GROUP3 and addx is between the addxs of any two in GROUP1, add to GROUP1 update list
        # can be implemented by checking if GROUP3 entry is not either at beginning or end of GROUP1 list
        # sorted by addx, then it must be between the GROUP1 blocks

    # else write the GROUP3 update directly

# if GROUP1 or GROUP2 update lists not empty write each as block
sjpark608 commented 1 year ago

image

@sjpark is it important to have any settings that users can configure without having an ADC restart conversions? I'm wondering because for the settings that do restart conversions, it is advised to update these as a group (single write). However, it looks like this might not be very efficient in some cases. For example, when updating Group 1 registers together, it's possible we might have to update the intervening non-Group 1 registers as well.

If we want to update Group 1, Group 2, and other registers this would mean at least 3 separate writes. Unless we chose to include the intervening registers, in which case this becomes a single write operation including nearly all registers. So I am thinking it may be more efficient to update all registers at once, unless there are concerns about restarting conversions every time the ADC configuration is changed.

i.e. given the list of updated register values, writing to the groups individually would be something along these lines (Group 3 registers are those not in Groups 1 or 2):

# for each updated register

    # if updated register belongs to GROUP1 add to list of GROUP1 register updates.

    # else if updated register belongs to GROUP2, add to list of GROUP2 register updates

    # else if GROUP3 and addx is between the addxs of any two in GROUP1, add to GROUP1 update list
        # can be implemented by checking if GROUP3 entry is not either at beginning or end of GROUP1 list
        # sorted by addx, then it must be between the GROUP1 blocks

    # else write the GROUP3 update directly

# if GROUP1 or GROUP2 update lists not empty write each as block

I agree with the idea of updating all registers and re-starting the conversion. In most cases that the user wants to change the configuration, the configs are related to the conversion data or ADC configs. Selecting/filtering registers to be changed and writing them separately will add more complexity to the use case and to implementation.

sjpark608 commented 1 year ago

image

It turns out we actually have 1262 instead which doesn't have ADC2.

I am waiting on TI engineer's reply to my question regarding the correlation between Data rate and the digital filter for ADC. However, it looks like by setting the DR bits in Mode2 register, we can achieve the maximum data rate of 38400SPS. image

The first stage filter is always on, but the second stage filter is configurable.

image

When conversion first starts, there is a conversion latency according to the filter settings. The above table shows the conversion latencies. After the first conversion, the subsequent conversion rate will correspond to the data rate. This assumes the input voltage is settled.

When the INPMUX register changes, the conversion will automatically restart and the first conversion will have the conversion latency.

farzadpanahi commented 1 year ago

@sjpark608 did we have the wrong part number in the schematic file?

sjpark608 commented 1 year ago

@sjpark608 did we have the wrong part number in the schematic file?

yes, the schematic has 1263, but the actual chip we have on board is 1262

sjpark608 commented 1 year ago

@farzadpanahi @flavius-t TI engineer confirmed regarding the data rate of the ADC. Regardless of the setting of Filter Bits in MODE1 Register, DR bits in MODE2 Register overrides the sampling rate. Ex) if you want the maximum data rate of 38400SPS, set DR bits to 1111 in MODE2 Register.

flavius-t commented 1 year ago

It turns out we actually have 1262 instead which doesn't have ADC2.

I will remove ADC2 specific code from the implementation, unless I should leave it there in case we get the 1263 in the future?

@sjpark608 @farzadpanahi

farzadpanahi commented 1 year ago

@sjpark608 are we considering 1263 at all? can you confirm w/ Colin. If we are not going to use 1263 we should remove all the related code and simplify the interface.

sjpark608 commented 1 year ago

@farzadpanahi @flavius-t Colin mentioned that we have both 1262 and 1263 at the moment. There was a shortage of 1263 and he got both chips. Colin suggested focusing on the common functionality of these two chips for now until we resolve the supply issue with 1263 chip. I partially agree with Colin, since ADC2 requires more testing regarding concurrency with ADC1 and calibrations.

farzadpanahi commented 1 year ago

OK, in that case, let's implement with one ADC but let's have two ADCs in mind in the design. So, for naming keep ADC1, remove ADC2, but keep the design such that we can add ADC2 without structural change later.

flavius-t commented 1 year ago

@farzadpanahi I will keep both ADC1 and ADC2 functionality in the lower level __config method that handles the updates, but only offer ADC1 in the higher level set_config method users will call. That way we can easily add ADC2 functionality for users in the future.

flavius-t commented 1 year ago

image

When conversion first starts, there is a conversion latency according to the filter settings. The above table shows the conversion latencies. After the first conversion, the subsequent conversion rate will correspond to the data rate. This assumes the input voltage is settled.

I ran some tests to see how these numbers line up with the actual conversion latency we see: image

Conversions were performed in Pulse mode. Time was measured with perf_counter_ns from after sending the READ_DATA command up until the STATUS byte of a voltage read indicated new data was available. Mean time in milliseconds after x trials is shown in each cell.

@farzadpanahi @sjpark608

sjpark608 commented 1 year ago

@flavius-t this is related to the SPI issue I'm currently investigating refer to #89

I made a new spi6-4cs.dtbo in dt_src repo. please replace the overlay file on your test device and perform the test again.

flavius-t commented 1 year ago

@flavius-t this is related to the SPI issue I'm currently investigating refer to #89

I made a new spi6-4cs.dtbo in dt_src repo. please replace the overlay file on your test device and perform the test again.

@sjpark608 the data with the new overlay added: image

Edit: this data represents the initial conversion delay time

flavius-t commented 1 year ago

I repeated the above tests in continuous sampling mode:

image

Description

Mean conversion delay in milliseconds after x trials is shown in each cell. For each cell, representing a unique configuration of data_rate and filter_mode, conversion delay was computed by sending a START command and then continuously sending a READ command and checking whether the STATUS bit indicated new data. Only a single START command was sent before measuring conversion delay for all x trials. The time taken until new data was indicated is represented as the conversion delay above. The first two conversion delays recorded for each cell were not included in the mean conversion delay, as these were extreme outliers caused by the immediate commencement of conversions upon sending the START command in continuous sampling mode (i.e. the STATUS bit indicated new data was available almost immediately upon the first two reads).

Edit: I increased the number of trials for the higher data rates, so the mean delays are different from what we saw in the meeting today.

@farzadpanahi @sjpark608

sjpark608 commented 1 year ago

@flavius-t this is related to the SPI issue I'm currently investigating refer to #89 I made a new spi6-4cs.dtbo in dt_src repo. please replace the overlay file on your test device and perform the test again.

@sjpark608 the data with the new overlay added: image

Edit: this data represents the initial conversion delay time

now it make sense why some of the high data rates are saturating around 100us, I should be related to the SPI transaction issue I just posted in #89, also posted in rpi-forum