Author Topic: Set up for ADC on i.MX RT... not getting it.  (Read 13468 times)

Offline jackking

  • Newbie
  • *
  • Posts: 34
    • View Profile
Set up for ADC on i.MX RT... not getting it.
« on: March 21, 2024, 05:24:10 PM »
I am trying to do some extra credit in my SerialLoader and have a test routine that reads ADC inputs, but I'm not having much luck.

I see various other posts about the ADC, I have checked ADC_Timers.h for example config as well as the pdf on ADC usage, but I still get no reading.

I have two inputs on the i.MX RT (1062), GPIO_AD_B1_04 and GPIO_AD_B1_05. which have the analog voltage coming in.  Using the NXP MCUXpresso SDK, I am able to set up ADC_ETC and the ADC channels 1 and 2 with chaining to successfully read both inputs after a chained conversion is triggered by a PIT.

Using uTasker, I don't really have a clue where to start...

I don't know how to understand the mapping of the actual pins applies to the ADC_SETUP.  I assume that the int_adc_bit should define this using one of the ADC_SE defines in iMX.h:
Code: [Select]
#define ADC_SE0_SINGLE          0
#define ADC_SE1_SINGLE          1
#define ADC_SE2_SINGLE          2
#define ADC_SE3_SINGLE          3
#define ADC_SE4_SINGLE          4
#define ADC_SE5_SINGLE          5
#define ADC_SE6_SINGLE          6
#define ADC_SE7_SINGLE          7
#define ADC_SE8_SINGLE          8
#define ADC_SE9_SINGLE          9
#define ADC_SE10_SINGLE         10
#define ADC_SE11_SINGLE         11
#define ADC_SE12_SINGLE         12
#define ADC_SE13_SINGLE         13
#define ADC_SE14_SINGLE         14
#define ADC_SE15_SINGLE         15
#define ADC_ETC_SINGLE          16

But it also mentions these should map to inputs 0...31 (?). and I see ADC_ETC as well, but I don't see how to set that up.

I also see some of the examples seem to set the int_handler multiple times before setting the actual interrupt, wouldn't this just overwrite the previous value and have no effect?
For example in the ADC pdf it has:
Code: [Select]
ADC_SETUP adc_setup; // interrupt configuration parameters
adc_setup.int_type = ADC_INTERRUPT; // identifier when configuring
adc_setup.pga_gain = PGA_GAIN_OFF; // PGA gain can be specified for certain inputs
adc_setup.int_handler = fnRangeInterrupt; // handling function
adc_setup.int_priority = PRIORITY_ADC; // ADC interrupt priority
adc_setup.int_adc_controller = 1; // ADC controller 1
adc_setup.int_adc_offset = 0; // no offset
adc_setup.int_adc_mode = (ADC_CALIBRATE | ADC_SELECT_INPUTS_A | ADC_CLOCK_BUS_DIV_2 |
ADC_CLOCK_DIVIDE_8 | ADC_SAMPLE_ACTIVATE_LONG | ADC_CONFIGURE_ADC | ADC_REFERENCE_VREF |
ADC_CONFIGURE_CHANNEL | ADC_SINGLE_ENDED | ADC_SINGLE_SHOT_MODE | ADC_12_BIT_MODE |
ADC_SW_TRIGGERED); // calibrate the ADC - single shot with interrupt on completion
adc_setup.int_adc_sample = (ADC_SAMPLE_LONG_PLUS_12 | ADC_SAMPLE_AVERAGING_32);
// additional sampling clocks
adc_setup.int_adc_result = 0; // no result is requested
adc_setup.int_adc_bit = ADC_DM1_SINGLE; // ADC DM1 single-ended
adc_setup.int_adc_bit_b = ADC_DISABLED; // channel B only valid in HW triggered mode
adc_setup.int_adc_int_type = (ADC_LOW_LIMIT_INT);
// interrupt type (trigger only when lower than the defined level)
adc_setup.int_low_level_trigger = (unsigned short)(ADC_VOLT * 1.3);
// the low level trigger threshold represented as input voltage
adc_setup.int_handler = adc_ready_1; // handling function

Which sets the int_handler twice, once to fnRangeInterrupt and then to adc_ready_1 at the end. How is this supposed to work?

Here is the code I have been trying to get working as a test on the iMX:

Code: [Select]
ADC_RESULTS  samples;

void fnADCresult()
{
// get the sample
fnDebugMsg("ADC SAMPLE: ");
fnDebugHex((unsigned short) samples.sADC_value[0], (sizeof(unsigned short) | WITH_LEADIN | WITH_CR_LF));

        // set up for the next sample (after we get this working once)
}

void fnInitializePots(void)
{
fnDebugMsg("INIT ADC\r\n");

    // set the ADC input pins?
    _CONFIG_PORT_INPUT(6, PIN_GPIO_AD_B1_04_GPIO6_IO20, (0));
    _CONFIG_PORT_INPUT(6, PIN_GPIO_AD_B1_05_GPIO6_IO21, (0));

    // now we need to set up the ADC to read the pot values
    ADC_SETUP adc_setup; // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT; // identifier when configuring
    adc_setup.pga_gain = PGA_GAIN_OFF; // PGA gain can be specified for certain inputs
    adc_setup.int_priority = PRIORITY_ADC; // ADC interrupt priority
    adc_setup.int_adc_controller = iMX_ADC_1;                            // first i.MX RT ADC
    adc_setup.int_handler = 0; // handling function, removed for now
    adc_setup.int_adc_bit = ADC_SE10_SINGLE;                              // which pin is this?
    adc_setup.int_adc_offset = 0; // no offset
    adc_setup.int_adc_mode = (ADC_CALIBRATE | ADC_SELECT_INPUTS_A | ADC_CLOCK_BUS_DIV_2 | ADC_CLOCK_DIVIDE_8 | ADC_SAMPLE_ACTIVATE_LONG | ADC_CONFIGURE_ADC | ADC_REFERENCE_VREF | ADC_CONFIGURE_CHANNEL | ADC_SINGLE_ENDED_INPUT | ADC_SINGLE_SHOT_MODE | ADC_12_BIT_MODE | ADC_SW_TRIGGERED); // note that the first configuration should calibrate the ADC - single shot with interrupt on completion {12}
    adc_setup.int_adc_sample = (ADC_SAMPLE_LONG_PLUS_12 | ADC_SAMPLE_AVERAGING_32);
    // additional sampling clocks
    adc_setup.int_adc_result = &samples;
    adc_setup.int_adc_bit_b = ADC_DISABLED; // channel B only valid in HW triggered mode
    adc_setup.int_adc_int_type = (ADC_END_OF_SCAN_INT);


    fnConfigureInterrupt((void *)&adc_setup);                            // configure and start next sequence
    fnADCresult();

}

This results in a value of 0x0000. from the result (which isn't correct).

After/if I get this working, I definitely wouldn't know how to get chaining to work for using both inputs at the same time!

Thanks




Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3243
    • View Profile
    • uTasker
Re: Set up for ADC on i.MX RT... not getting it.
« Reply #1 on: March 21, 2024, 06:38:03 PM »
Hi

The ADC pins are found here: https://www.utasker.com/iMX/iMXRT1060/iMX_RT_1060.xls

To select ADC1_IN9 use
adc_setup.int_adc_controller = iMX_ADC_1;                            // first i.MX RT ADC
adc_setup.int_adc_bit = ADC_SE9_SINGLE;

Optionally pullup/down can also be defined using ADC_INPUT_PULL_DOWN, ADC_INPUT_PULL_UP or ADC_INPUT_PULL_UP_WEAK to the adc_setup.int_adc_mode details.

which causes the configuration (in the ADC driver) with

_CONFIG_PORT_INPUT(1, ADC1_IN9_GPIO_AD_B1_04_GPIO1_IO20, ulPinCharacteristic);


For ADC1_IN10 change adc_setup.int_adc_bit to ADC_SE10_SINGLE.


Presently your code is configuring but not converting (default is to use a conversion interrupt, which you have disabled).
Add ADC_GET_RESULT so that it will do a blocking conversion and return the value.
Note that samples.ucADC_status will then contain ADC_RESULT_VALID, indicating that the result is valid (presently you will find that it is not the case).

Note that I haven't a great many features in the present ADC driver version for the i.MX RT and so HW trigger modes and chaining are not integrated. If you tell me which STK reference contains the method that you would like to use I can add that to the interface.
The HW triggering levels do work well since I have used these successfully in some products.

Regards

Mark





Offline jackking

  • Newbie
  • *
  • Posts: 34
    • View Profile
Re: Set up for ADC on i.MX RT... not getting it.
« Reply #2 on: March 21, 2024, 09:19:42 PM »
ah, thanks!  That is working now.  I may forgo the chaining for this test, I am just trying to understand the ADC setup.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3243
    • View Profile
    • uTasker
Re: Set up for ADC on i.MX RT... not getting it.
« Reply #3 on: March 21, 2024, 10:41:59 PM »
The ADC interface 'attempts' to be compatible across processors and ADC types so some of the values will not do anything but can be left so that the interface remains operational with those that need them, or react to them.

The calibration flag should only be set once, the first time the interface is called (for each ADC).

The easiest way to learn the interface is to run the main application in Visual Studio and step through the code so that the effect of flags can be seen. The idea is to start with a basic interface that has a certain amount of features, and basic compatibility although the internal workings may not be highly efficient due to this. One can see which paths are used (and needed) and take these into a custom function if speed is important.

Regards

Mark