Author Topic: SP7 and ADC  (Read 22196 times)

Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
SP7 and ADC
« on: May 20, 2008, 04:39:05 PM »
Hello

It's possible to use the adc function to do a single ended convertion withou interupt ?

You do no have a simple example of utilisation of the ADC function ?

Thank's a lot !

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: SP7 and ADC
« Reply #1 on: May 20, 2008, 11:19:36 PM »
Hi

ADC interrupts are most useful when monitoring trigger levels, zero crossings or external SYNC started scans. To simply read a value no interrupts need to be activated, instead the conversion can be started (or left running in free-run mode) and simply read the value whenever required.

There are some examples of using the ADC interface in the demo project as follows:
"ADC: enable HW support using SUPPORT_ADC in app_hw_m5223x.h and the demo TEST_ADC in application.c. This will show the module being configured to generate interrupts when the input signal leaves a defined voltage range. A second input will be configired with an offset and interrupt on zero-crossing. The code can be changed (using examples there) to test differential inputs and the use of the SYNC to activate a conversion scan with interrupt on completion."

To configure a free-running ADC on channel 0 without interrupt do the following:

Code: [Select]
static void fnConfigureADC(void)
{
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;                                           // ADC channel 0
    adc_setup.int_adc_mode = (ADC_CONFIGURE_ADC | ADC_CONFIGURE_CHANNEL | ADC_SEQUENTIAL_MODE | ADC_SINGLE_ENDED | ADC_LOOP_MODE | ADC_START_OPERATION); // single ended configuration in loop mode
    adc_setup.int_adc_speed = (unsigned char)(BUS_CLOCK/5000000);        // 5MHz sampling (must be between 100kHz and 5MHz)
    adc_setup.int_adc_int_type = 0;                                      // no interrupt
    fnConfigureInterrupt((void *)&adc_setup);                            // configure and start operation
}

To subsequently read the present sample:

Code: [Select]
static void fnReadRes(void)
{
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    ADC_RESULTS results;
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;
    adc_setup.int_adc_result = &results;
    adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT);
    fnConfigureInterrupt((void *)&adc_setup);                            // get result

    if (results.ucADC_status[0] != ADC_RESULT_NOT_READY) {
      //results.sADC_value[0];                                           // result here
    }
}


This is a bit of overkill to read just a single register and can of course be performed by direct register accesses if required:
ADC_ADSTAT contains the status of the ADC (the RDY_CHANNEL0 should be set) and the result is in ADC_ADRSLT0.

If you configure multiple channels the parameter ADC_ALL_RESULTS will return all channel values in ADC_RESULTS results.

Regards

Mark



Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #2 on: May 21, 2008, 07:16:46 AM »
This work fine !
thank's a lot mark.

Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #3 on: May 21, 2008, 11:09:52 AM »
Excuse me again but I have another little probleme
ADC_RESULT_NOT_READY stay to 0 and the  result was never available

I inser the code
Code: [Select]
ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    ADC_RESULTS results;
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;
    adc_setup.int_adc_result = &results;
    adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT);
    fnConfigureInterrupt((void *)&adc_setup);                            // get result

    if (results.ucADC_status[0] != ADC_RESULT_NOT_READY) {
      //results.sADC_value[0];                                           // result here
    }


in a test task that I have build and I remplace the TEST_ADC configuration by your's

But that don't work, I probably do a mistake in the utilisation of the function but were ?

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: SP7 and ADC
« Reply #4 on: May 21, 2008, 02:39:25 PM »
Hi

I think that the problem that you are seeing is due to the fact that the ADC requires some conversion time (that is why it is often used in conjunction with an interrupt to signal that it can be read). If you call the initialisation and immediately the read it will not yet be ready with the first conversion value.

Here is a slightly modified version of the read which I have tested. I have found that the ADC has to be read three times before it actually returns the value - this is because the Coldfire CPU is executing its instructions faster than the ADC can complete, so results in a short wait until it is finally ready.

Code: [Select]
static void fnReadRes(void)
{
    int iADC_delay = -1;
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    ADC_RESULTS results;
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;
    adc_setup.int_adc_result = &results;
    adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT);
    do {
        fnConfigureInterrupt((void *)&adc_setup);                        // get result
        iADC_delay++;
    } while (results.ucADC_status[0] == ADC_RESULT_NOT_READY);           // 'poll until the result is ready

    if (results.ucADC_status[0] != ADC_RESULT_NOT_READY) {
        fnDebugMsg("ADC value = ");
        fnDebugHex(results.sADC_value[0], 2);                           
        fnDebugMsg("\r\n");
        fnDebugMsg("Wait = ");
        fnDebugDec(iADC_delay, 0, 0);                                    // display the wait count value
        fnDebugMsg("\r\n");
    }
    else {
        fnDebugMsg("ADC not ready\r\n");
    }
}

The serial output looks like this:
ADC value = 34a8
Wait = 3


Alternatively you can schedule the reading task to start after a short software delay so that it is sure that the result is ready when it actually reads.

Regards

Mark
« Last Edit: June 02, 2008, 10:45:25 PM by mark »

Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #5 on: May 21, 2008, 03:51:30 PM »
Ok and you put them two task in the application task or in two separates task ?
Because if y put them in two separated task I stay blocked In the DO .

Thank's

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: SP7 and ADC
« Reply #6 on: May 21, 2008, 08:25:09 PM »
Hi

In my test I call fnReadRes() in the configuration routine as follows:

static void fnConfigureADC(void)
{
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;                                           // ADC channel 0
    adc_setup.int_adc_mode = (ADC_CONFIGURE_ADC | ADC_CONFIGURE_CHANNEL | ADC_SEQUENTIAL_MODE | ADC_SINGLE_ENDED | ADC_LOOP_MODE | ADC_START_OPERATION); // single ended configuration in loop mode
    adc_setup.int_adc_speed = (unsigned char)(BUS_CLOCK/5000000);        // 5MHz sampling (must be between 100kHz and 5MHz)
    adc_setup.int_adc_int_type = 0;                                      // no interrupt
    fnConfigureInterrupt((void *)&adc_setup);                            // configure and start operation
    fnReadRes();
}


If you are configuring in one task and reading in another be careful that the reading task is not started before the configuration task otherwise it will read before the ADC has been configured and subsequently never be able to complete the read.

Regards

Mark

Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #7 on: May 29, 2008, 07:26:44 AM »
Hello mark

Your example function for the channel 0 work perfectly but when I trie to change the channel they won't work.

For exemple if y want to use the channel 7

did i need to put :

adc_setup.int_adc_bit = 7;

or

adc_setup.int_adc_bit = 0x80;


Thank's

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: SP7 and ADC
« Reply #8 on: May 29, 2008, 11:07:24 AM »
Hi

The channels are numbered 0..7

Regards

Mark

Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #9 on: May 30, 2008, 10:32:51 AM »
Hello

I try again the adc adc 0 to 3 work but to 4 to 7 they stay blocked in :

while (results.ucADC_status[4] == ADC_RESULT_NOT_READY);


I don't understand why they work for the 4 first and no for the 4 last ?

Thank's




Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: SP7 and ADC
« Reply #10 on: May 30, 2008, 11:37:47 AM »
Hi

The ADC in the Coldfire is made up of 2 ADC modules. Channels 0..3 are served by the first one and channels 4..7 by the second one.

Each of the two ADCmodules can be powered up seperately but there are a few dependencies on the scanning. The ADC interface attempts to optimise the settings so that only the parts which are used are actually powered and also only the channels configured are scanned.

Since this interface is new there are possibilities that there is a configuration which is not correct - therefore I wil have to test your configuration to see whether there is a problem with the interface.

Generally it has to be noted that when only one channel of the ADC is required it is best to use channel 0. This allows maximum efficience. If channel 1 alone is used, the ADC still has to scan channel 0..1 (and so can not scan as fast). In the case of channel 3 alone the ADC has to scan channels 0..3 to get the result, so again is even slower.
The case is similar for channels 4..7 (on the second ADC) but it may be that some modes also need channels 0..4 to be scanned.

In the mean time you may like to experiment with configuring also channel 0 to ensure that the first ADC is also powered up. Or seeing if the result is different between configuring for ADC_PARALLEL_MODE and ADC_SEQUENTIAL_MODE.

Regards

Mark


Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #11 on: May 30, 2008, 12:48:58 PM »
Thank's oki
in fact in my personal board AN0 TO AN3 are analogique input AN4 to AN6 are digital input and AN7 is an analogique inupt.

When i try to use AN7 alone the soft crash, may be if i configure the all analog input they will work i will try it .

Thank's again

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: SP7 and ADC
« Reply #12 on: June 01, 2008, 12:32:20 AM »
Hi

I have made some tests with just configuring channel 7. I too found that the result would never be ready so the software continued polling the ready bit forever.

Further tests showed the following:
- if channel 4..7 are being used alone (none from channels 0..3) and the ADC is not operating in parallel mode (that is, the two ADCs are working in a sequential manor) the first ADC must to be powered up as well as the second ADC.
To read channel 7, a sequence scan of all channels up to this are required (in this case channels 0...7).
- if the ADCs are operating in parallel mode (ADC_PARALLEL_MODE set in adc_setup.int_adc_mode) the two ADCs work in parallel and independently. Channel 7 can now be read without having the first ADC powered up. The scan sequence is 4,5,6,7. Since there are less channels in the scan, it is also faster.

If only channels between 4..7 are used I would suggest operating in parallel mode since it is then more efficient. If only channels 0..3 are used it is not relevant since the second ADC doesn't need to be powered to acheive the scan sequence.

I have made the following change to automate this depending on the channel and the mode. Only ADC modules needed for by the present configuration are powered and only channels needed in the sequence are scanned.

In m5223x.c in the ADC configuration:

                    if (ucADC_bit < (ADC_CHANNELS/2)) {
                        usModulePower = (PD0 | PD2);                     // first ADC module
                        usModulePowerCheck = (PSTS0 | PSTS2);
                    }
                    else {
                        usModulePower = (PD1 | PD2);                     // second ADC module
                        usModulePowerCheck = (PSTS1 | PSTS2);
                        if (ptrADC_settings->int_adc_mode & ADC_PARALLEL_MODE) { // {53}
                            usEnableBit = DISABLE_CH4;
                        }
                        else {
                            usModulePower |= PD0;                        // when not operating in parallel, also first ACC module must be powered
                            usModulePowerCheck |= PSTS0;
                        }

                    }


If you add the bold lines to this function (with change reference {53}) you will then have the new code and can verify that it fulfils your requirements.

Regards

Mark

Offline Kuroro

  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: SP7 and ADC
« Reply #13 on: June 03, 2008, 03:19:07 PM »
They work's fine thank's a lot mark

Offline Raffaele

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Re: SP7 and ADC
« Reply #14 on: June 03, 2018, 02:28:06 PM »
Hi

ADC interrupts are most useful when monitoring trigger levels, zero crossings or external SYNC started scans. To simply read a value no interrupts need to be activated, instead the conversion can be started (or left running in free-run mode) and simply read the value whenever required.

There are some examples of using the ADC interface in the demo project as follows:
"ADC: enable HW support using SUPPORT_ADC in app_hw_m5223x.h and the demo TEST_ADC in application.c. This will show the module being configured to generate interrupts when the input signal leaves a defined voltage range. A second input will be configired with an offset and interrupt on zero-crossing. The code can be changed (using examples there) to test differential inputs and the use of the SYNC to activate a conversion scan with interrupt on completion."

To configure a free-running ADC on channel 0 without interrupt do the following:

Code: [Select]
static void fnConfigureADC(void)
{
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;                                           // ADC channel 0
    adc_setup.int_adc_mode = (ADC_CONFIGURE_ADC | ADC_CONFIGURE_CHANNEL | ADC_SEQUENTIAL_MODE | ADC_SINGLE_ENDED | ADC_LOOP_MODE | ADC_START_OPERATION); // single ended configuration in loop mode
    adc_setup.int_adc_speed = (unsigned char)(BUS_CLOCK/5000000);        // 5MHz sampling (must be between 100kHz and 5MHz)
    adc_setup.int_adc_int_type = 0;                                      // no interrupt
    fnConfigureInterrupt((void *)&adc_setup);                            // configure and start operation
}

To subsequently read the present sample:

Code: [Select]
static void fnReadRes(void)
{
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    ADC_RESULTS results;
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_adc_bit = 0;
    adc_setup.int_adc_result = &results;
    adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT);
    fnConfigureInterrupt((void *)&adc_setup);                            // get result

    if (results.ucADC_status[0] != ADC_RESULT_NOT_READY) {
      //results.sADC_value[0];                                           // result here
    }
}


This is a bit of overkill to read just a single register and can of course be performed by direct register accesses if required:
ADC_ADSTAT contains the status of the ADC (the RDY_CHANNEL0 should be set) and the result is in ADC_ADRSLT0.

If you configure multiple channels the parameter ADC_ALL_RESULTS will return all channel values in ADC_RESULTS results.

Regards

Mark
Hi,
doesn't the ADC need a calibration? Is it in this piece of code, or is it done somewhere else?

Thank you