Author Topic: Setting up ADC  (Read 16085 times)

Offline kyoniori

  • Newbie
  • *
  • Posts: 3
    • View Profile
Setting up ADC
« on: April 06, 2010, 05:31:17 AM »
hi, im a newbie to MCU, this is my 1st project using uTasker wif Freescale MCF52235...
i wan to setup ADC for my analog input, but i have no idea how to start the coding because its not available in the TaskConfig.h
it seems like the only code in the demo regarding to ADC is the ADC_timer.h...
any idea??
thanks in advance

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Setting up ADC
« Reply #1 on: April 06, 2010, 01:07:50 PM »
Hi

There are a few discussions of the use of the ADC with the M522XX project in the forum - start here: http://www.utasker.com/forum/index.php?topic=680.0

It is correct that the demonstration has all ADC code in the file ADC_timer.h. There are a few options, depending on the type of processor used, but the M522XX demo makes use of threshold values to cause interrupts to be triggered when signals pass certain levels or change across the zero crossing threshold. These are interesting functions supported by the device since the application code doesn't need to actually read the ADC but can still monitor threshold levels.

There are however various usages of the ADC so this may not match your requirement. In the case of simply sampling values the interface supports calling this function (it is used to read the value when there was a trigger, so this is a valid reference - see the configuration adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT);).

There is no task used which samples input values so if you would like such a task you will need to add one (eg., one that is executed periodically) - there is an introduction to adding new tasks in http://www.utasker.com/docs/uTasker/uTaskerV1.4_user_guide.PDF

Regards

Mark

Offline kyoniori

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Setting up ADC
« Reply #2 on: April 07, 2010, 02:17:44 AM »
Thank you Mark...
At least I have some guides on how to start...

Offline kyoniori

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Setting up ADC
« Reply #3 on: April 15, 2010, 05:01:20 AM »
Hi Mark,

Referring to this post, http://www.utasker.com/forum/index.php?topic=280.0
I am trying to create a task that run ADC, read the result and display it through UART
I tried to create a "run and read" task in TaskConfig.h and call from application.c, some how I got some error for fnConfigureADC()...
Should my read function create only in ADC_Timers.h??
What do you suggest?

Thanks in advance.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Setting up ADC
« Reply #4 on: April 15, 2010, 02:31:50 PM »
Hi

From the description I don't see the exact problem. It may however be that you are calling fnConfigureADC() from another file (whereby it is local to application.c file).

I would suggest that you disable the demo ADC code. Then copy the parts of the ADC code that you need to your new task - this would make things easier.

Regards

Mark

Offline ukit

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Setting up ADC
« Reply #5 on: April 25, 2010, 03:49:12 PM »
hi mark,

i am having problem with my ADC. i configure my ADC and my fnReadRes() in ADC_Timers.h for free run and get result. however i can't get the result display on my serial port.

my configuration is following this post http://www.utasker.com/forum/index.php?topic=280.0 except i am using fnWrite() to display the message on my hyper terminal. i can read any character and message  but i can't get the "results.sADC_value[0]" to display. is there any solution? or is it because of HEX format??

i just want to make free run and read result. the reason i do not use fnDebugMsg() is because it has been disabled for other purpose. my functions are all in the section "#if defined _ADC_TIMER_ROUTINES && defined TEST_ADC".

do "adc_level_change_high" and "adc_level_change_low" involve in free run?? what is the reason of using this: "adc_setup.int_handler = adc_level_change_high;"

one more question, does free run involve _ADC_TIMER_INT_EVENTS_1 and _ADC_TIMER_INT_EVENTS_2 ?? what is the purpose of the events??

hope that you can clarify me as i am a beginner... thanks.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Setting up ADC
« Reply #6 on: April 25, 2010, 07:44:13 PM »
Hi

1) Serial port. The function fnDebugMsg() calls fnWrite() so there should be no reason why you can't use fnWrite() as long as the serial port has been opened (takes place in application.c - see fnSetNewSerialMode()). This means you need to use the serial handle SerialPortID and pass a pointer to the string to be sent, plus the length of the string. If you need to add hex values to the string you can use fnBufferHex().

2) The ADC in the M522XX has a function which allows it to automatically monitor two threshold levels. It will do this in free run mode. The demo configuration shows two interrupt handlers which get called when the programmed thresholds are reached. To disable these, remove the configuration when fnConfigureInterrupt() is called by removing the flags adc_setup.int_adc_int_type = (ADC_HIGH_LIMIT_INT) and adc_setup.int_adc_int_type = (ADC_LOW_LIMIT_INT)
Without these entries it will not enable this monitoring and no interrupt handlers are needed.

3) _ADC_TIMER_INT_EVENTS_1 is not used by the ADC demo - it is used by the general purpose timer demo.

_ADC_TIMER_INT_EVENTS_2 is used by the M522XX ADC demo. There are several events handled:
- ADC_HIGH_0..ADC_LOW_7: these are the various threshold trigger events which are then displayed on the debug output. New thresholds are also programmed.
- ADC_ZERO_CROSS_0..ADC_ZERO_CROSS_7 These are similar to the threshold events but are for zero crossings.
- ADC_TRIGGER is called when a single shot conversion has completed.

Regards

Mark



Offline ukit

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Setting up ADC
« Reply #7 on: April 27, 2010, 05:36:06 PM »
hi mark,

thank you for your clarification. i am using fnWrite to output message to my serial for debugging. i modified my ADC in free run mode as mentioned above in ADC_Timers.h, and the code is working except for the part below:

Code: [Select]
#ifdef _ADC_TIMER_INT_EVENTS_2                                           // interrupt range event handling
    fnWrite(SerialPort1, (unsigned char *)"\r\nEVENTS 2\r\n", 13);
    #if defined TEST_ADC                                                 // {17}
fnWrite(SerialPort1, (unsigned char *)"\r\nTEST ADC\r\n", 13);
        #if defined _M5223X                                              // {30}
              if ((ADC_LOW_7 >= ucInputMessage[MSG_INTERRUPT_EVENT]) && (ADC_HIGH_0 <= ucInputMessage[MSG_INTERRUPT_EVENT])) {
                    ADC_SETUP adc_setup;                                 // interrupt configuration parameters
                    ADC_RESULTS results;
                    adc_setup.int_type = ADC_INTERRUPT;                  // identifier
                    adc_setup.int_priority = ADC_ERR_PRIORITY;           // port interrupt priority
                    adc_setup.int_adc_result = &results;
                    if (ucInputMessage[MSG_INTERRUPT_EVENT] < ADC_LOW_0) {
                        adc_setup.int_adc_bit = (ucInputMessage[MSG_INTERRUPT_EVENT] - ADC_HIGH_0);             // ADC bit 0
                        //fnDebugMsg("ADC change high: ");
                        fnWrite(SerialPort1, (unsigned char *)"ADC change high: ", 23);
                        adc_setup.int_handler = adc_level_change_low;
                        adc_setup.int_adc_int_type = (ADC_LOW_LIMIT_INT);// interrupt types
                        adc_setup.int_low_level_trigger = (unsigned short)(ADC_VOLT * 1.5);
                    }
                    else  {
                        adc_setup.int_adc_bit = (ucInputMessage[MSG_INTERRUPT_EVENT] - ADC_LOW_0);
                        //fnDebugMsg("ADC change low: ");
                        fnWrite(SerialPort1, (unsigned char *)"ADC change low: ", 23);
                        adc_setup.int_handler = adc_level_change_high;
                        adc_setup.int_high_level_trigger = (unsigned short)(ADC_VOLT * 2);
                        adc_setup.int_adc_int_type = (ADC_HIGH_LIMIT_INT); // interrupt types
                    }
                    adc_setup.int_adc_mode = (ADC_START_OPERATION | ADC_GET_RESULT);// start operation now and return the present result
                    fnConfigureInterrupt((void *)&adc_setup);            // enter interrupt for low level trigger
                    fnDebugDec(adc_setup.int_adc_bit, 0);                // {44}
                    fnDebugHex(results.sADC_value[adc_setup.int_adc_bit], (WITH_SPACE | WITH_LEADIN | WITH_CR_LF | 2));
                }
                else if ((ADC_ZERO_CROSS_7 >= ucInputMessage[MSG_INTERRUPT_EVENT]) && (ADC_ZERO_CROSS_0 <= ucInputMessage[MSG_INTERRUPT_EVENT])) {
                    //fnDebugMsg("Zero Crossing - channel ");
                    fnWrite(SerialPort1, (unsigned char *)"Zero Crossing - channel ", 23);
                    fnDebugDec((ucInputMessage[MSG_INTERRUPT_EVENT] - ADC_ZERO_CROSS_0), WITH_CR_LF); // {44}
                }
                else if (ADC_TRIGGER == ucInputMessage[MSG_INTERRUPT_EVENT]) {
                    ADC_SETUP adc_setup;                                 // interrupt configuration parameters
                    ADC_RESULTS results;
                    adc_setup.int_type = ADC_INTERRUPT;                  // identifier
                    adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT);
                    adc_setup.int_adc_bit = 0;
                    adc_setup.int_adc_result = &results;
                    fnConfigureInterrupt((void *)&adc_setup);
                    //fnDebugMsg("ADC triggered:");
                    fnWrite(SerialPort1, (unsigned char *)"Zero Crossing - channel ", 23);
                    fnDebugHex(results.sADC_value[0], (WITH_SPACE | WITH_LEADIN | WITH_CR_LF | 2));
                }

it seems the program does not enter _ADC_TIMER_INT_EVENTS_2. is this because of free run mode?

i am using fnWrite because somehow fnDebugMsg does not work. therefore i am also having problem for displaying the "results.sADC_value[0]" using fnWrite due to incompatible type. is there other way to display the value from fnBufferHex using fnWrite ??

in free run mode, does it mean adc_level_change_high or adc_level_change_low conditions are not met? because using fnWrite to check line by line message like the quote above, no message is sent to serial.

please advise as i am still a beginner. thanks.
« Last Edit: April 28, 2010, 05:45:30 PM by ukit »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Setting up ADC
« Reply #8 on: April 28, 2010, 10:16:58 PM »
Hi

I would expect trigger threshold interrupts to result in the event being called as long as the threshold has been programmed:

    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_handler = adc_level_change_high;                       // handling function
    adc_setup.int_priority = ADC_ERR_PRIORITY;                           // ADC interrupt priority
    adc_setup.int_adc_bit = 0;                                           // ADC bit 0
    adc_setup.int_adc_int_type = (ADC_HIGH_LIMIT_INT);                   // interrupt types
    adc_setup.int_adc_offset = 0;                                        // no offset
    adc_setup.int_high_level_trigger = (unsigned short)(ADC_VOLT * 2);
    adc_setup.int_adc_mode = (ADC_CONFIGURE_ADC | ADC_CONFIGURE_CHANNEL | ADC_SEQUENTIAL_MODE | ADC_SINGLE_ENDED | ADC_LOOP_MODE); // use to test single ended
    adc_setup.int_adc_speed = (unsigned char)(ADC_SAMPLING_SPEED(5000000));// 5MHz sampling (must be between 100kHz and 5MHz)
    adc_setup.int_adc_result = 0;                                        // no result is requested
    fnConfigureInterrupt((void *)&adc_setup);                            // configure test interrupt on high level trigger


This is the standard setup which includes setting the interrupt type (high limit interrupt) which will call the interrupt handler adc_level_change_high. This handler then sends the event to the task: fnInterruptMessage(OWN_TASK, (unsigned char)(ADC_TRIGGER));


I don't understand why fnDebugMsg() is not working. This will normally result in the output going to the UART (check that you are connected to the right UART). Alternatively, when you connect to the board via TELNET, the output will be redirected there - often I find this the simplest general test method because it removes the need to connect a COM port to the board. (If USB is enabled - and supported by the chip - the output can also be sent there).

If you want to use fnWrite(); to send data to the UART you can also format values by calling fnBufferHex(). This routine accepts the value to be converted and converts it into a given buffer. The buffer is usually declared as CHAR cBuffer[100]; - make sure that its length is suitable so that it can't overrun - but not unnecessarily long. Then pass cBuffer to fnWrite(), with a casting (unsigned char *)cBuffer.

In free run mode the level triggers should work normally.

Regards

Mark

Offline ukit

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Setting up ADC
« Reply #9 on: May 02, 2010, 11:38:58 AM »
hi mark,

thanks for your prompt reply. i have tried many times on ADC settings, unfortunately i can't make it work. my objective is very simple, to create 4 channels of ADC to AN0, AN1, AN2, AN3. my reference voltage is 2.5V.

below is all my codes for a single channel, in most simplified form. all these codes are modified based on TEST_ADC in ADC_Timers.h only, without creating any new task, which i think easier to make it work. i followed the instructions given referring to your posts,

in my fnConfigureADC()
Code: [Select]
static void fnConfigureADC(void) //M5223X
{
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.int_handler = adc_level_change_high;                       // handling function
    adc_setup.int_priority = ADC_ERR_PRIORITY;                           // ADC interrupt priority
    adc_setup.int_adc_bit = 1;                                           // ADC bit 0
    adc_setup.int_adc_int_type = (ADC_HIGH_LIMIT_INT);                   // interrupt types
    adc_setup.int_adc_offset = 0;                                        // no offset
    adc_setup.int_high_level_trigger = (unsigned short)(ADC_VOLT * 2);
    adc_setup.int_adc_mode = (ADC_CONFIGURE_ADC | ADC_CONFIGURE_CHANNEL | ADC_SEQUENTIAL_MODE | ADC_SINGLE_ENDED | ADC_LOOP_MODE | ADC_START_OPERATION);         // use to test single ended
    adc_setup.int_adc_speed = (unsigned char)(ADC_SAMPLING_SPEED(100000));        // {29} 5MHz sampling (must be between 100kHz and 5MHz)
    adc_setup.int_adc_result = 0;                                        // no result is requested
    fnConfigureInterrupt((void *)&adc_setup);                    // configure test interrupt on high level trigger
    fnResult();                                                              //my result reading function
}

subsequently my fnResult()
Code: [Select]
static void fnResult(void)
{
int iADC_delay = -1;
        CHAR *cBuffer[100];
ADC_SETUP adc_setup;
ADC_RESULTS results;
adc_setup.int_type = ADC_INTERRUPT;
adc_setup.int_adc_bit = 1;
adc_setup.int_adc_result = &results;
adc_setup.int_adc_mode = (ADC_READ_ONLY | ADC_GET_RESULT); //ADC_ALL_RESULTS
do {
fnConfigureInterrupt((void *)&adc_setup);
iADC_delay++;
} while (results.ucADC_status[1] == ADC_RESULT_NOT_READY);
if (results.ucADC_status[1] != ADC_RESULT_NOT_READY) {
fnWrite(SerialPort1, (unsigned char *)"\r\nResult = \r\n", 16); //result ready
fnBufferHex(results.sADC_value[1], (unsigned char)(4 | NO_LEADIN | WITH_TERMINATOR), cBuffer[100]);
fnWrite(SerialPort1, (unsigned char *)cBuffer, 10); //display the value
}
else {
fnWrite(SerialPort1, (unsigned char *)"\r\nResult = NA\r\n", 16);
}
}

my configuration for channel 1 is exactly like above. it's actually free running, and when i inject a low voltage, say 1.5V or 2V, it proceeds to the line fnWrite "Result = ", without showing any value.

after this it will stuck at the handling function adc_level_change_high. by adding a line message fnWrite "lvl high" in adc_level_change_high, what i get in serial output is "Result = ", then "lvl high" and it keeps repeating until i remove the input voltage. i really have no idea which part i make mistake because i follow all the steps, and i presume EVENT 2 has nothing to do with this.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Setting up ADC
« Reply #10 on: May 02, 2010, 11:16:53 PM »
Hi

The use of fnBufferHex() looks fine to me. Perhaps it is not printing more out due to the threshold interrupt. If the threshold interrupt is getting stuck (or keeps getting called infinitely) it will block the UART transmission interrupt and maybe this stops it before you start seeing the converted value coming out.

I would disable the threshold interrupt so that it can't disturb.

Also try simulating this with the uTasker simulator since this should do pretty much the same - you can test reading values - by clicking on the ADC port input you can change the analog value upwards in steps - by holding CTR (or maybe SHIFT) it reduces the value on each clock. This is easier to test code and it will also simulate the threshold interrupt.

Regards

Mark

Offline ukit

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Setting up ADC
« Reply #11 on: May 13, 2010, 04:01:34 PM »
hi mark,

thank you for your idea of disable the threshold interrupt, it works!!! i can see raw hex values with threshold interrupt disabled. does this mean the threshold interrupt and output of the ADC value can't work together? if i enable the threshold interrupt, it is stuck at the handling function adc_level_change_high and can't see the value.

secondly, if i want to include adc_level_change_high and adc_level_change_low both in fnConfigureADC() can i just add this:
Code: [Select]
       
    adc_setup.int_handler = adc_level_change_high;
    adc_setup.int_handler = adc_level_change_low;                           
    adc_setup.int_adc_int_type = (ADC_HIGH_LIMIT_INT | ADC_LOW_LIMIT_INT);                   
    adc_setup.int_low_level_trigger = (unsigned short)(ADC_VOLT * 1.5);                                     
    adc_setup.int_high_level_trigger = (unsigned short)(ADC_VOLT * 2);

which i can't make it work actually.