ADC driver task safety

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

ADC driver task safety

1,990 Views
mehmetekici
Contributor II

Hi All,

Is ADC driver in MQX thread safe ? I mean if can we open adc0 from a task and adc1 from another task ?

Regards,

Tags (3)
0 Kudos
14 Replies

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehmet,

Yes you can do that.  It is thread safe.

Regards,

David

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi David,

I have been experimenting with it but there is a problem with it. I am registering lwevent object from each process, the recently registered event gets triggered but the other one is not triggered to indicate the completion of the convertion.

Regards,

Mehmet

0 Kudos

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehmet,

What version of MQX are you using?

Which device?

Are you doing this on a Tower kit or your product?

Are the lwevent objects globally defined?

Are you setting the lwevent in the ADC isr?

How are the ADC's being triggered?

Are you using debugger for this test?  If yes I have seen where the ADC trigger gets lost because of using debugger.

Any additional information on your application implementations is appreciated.

Regards,

David

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi,

MQX4.0  on  PK60DN512VLQ10

We are testing on a custom board based on TWRK60N512.

Yes, lwevents are defined globally.

I am not setting the lwevent objects. Actually I expect it to be triggered by driver as it triggers one of the event objects.

ADCs are hardware triggered.

Yes , I am using debugger for the test.  I might try it without debugger that requires some time to code a test.

Our application is a welding control card. We measure line voltage with one ADC and  trigger a thyristor using PWM funtionality at a specified angle of line voltage and measure current using another ADC.

Regards,

0 Kudos

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehmet,

Thank you for all the information.  It is helpful.

Testing without debugger when doing ADC with hardware trigger is recommended.

So it is the lwevent defined in the MQX ADC "ADC_INIT_CHANNEL_STRUCT adc_channel_param1" that you are looking at.  Correct?

#if MQX_USE_LWEVENTS

    &evn,

    0x01            /* mask of event to be set */

#endif

One other observation:  The TWR-K60N512 has revision 1.0 silicon.  The PK60DN512VLQ10 device you have is revision 2.0 silicon and corresponds to the TWR-K60D100M MQX RTOS components.

Regards,

David

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi David,

Yes , you are right we are registering event object per ADC. Two different evn objects are registered like the one you shown. I think the driver is able to only trig one event per driver. I would expect it to do it per channel.


Bye the way I tried to use TWR-K60D100M bsp as my base bsp but I am having strange issue: printed messages are not printed on the console even though I enabled uart0 and choos ttya as default IO channel. this works when we take  TWRK60N512  as base bsp. You might help us to quickly solve the issue.

regards,

Mehmet

0 Kudos

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehmet,

WRT the TWR-K60D100M, I have that and have successfully used the serial ports ttyd and ttyf but not ttya since it is not directly accessible on the tower kit.

Please check the following:

In user_config.h  set #define BSPCFG_ENABLE_TTYA 1   //DES default is 0

For the other BSPCFG_ENABLE_TTYx devices if you are not going to use them set to "0".

In twrk60d100m.h:

ScreenHunter_13 Mar. 27 12.53.gif

Regards,

David

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi David,

I have been working on the issue I have come to the conclusion of adc stops after PDB sequencing error occurs.

"Sequence error detected on PDB channel's corresponding pre-trigger. ADCn block can be triggered

for a conversion by one pre-trigger from PDB channel n. When one conversion, which is triggered by

one of the pre-triggers from PDB channel n, is in progress, new trigger from PDB channel's

corresponding pre-trigger m cannot be accepted by ADCn, and ERR[m] is set. Writing 0’s to clear the

sequence error flags."

Documentation doesn't tell what will happen if sequencing error occurs. I don't understand why it stops I would expect the ADC to continueu its operation after next trigger arrives.

I hope you can clear what documentation does not .

Regards,

Mehmet

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi David,

I searched the forum  there are some other people face the same problem as I do.

Re: K60 PDB problem with error clearing.

Can you tell us if there is a way detecting and recovering way when the problem occures ?

Is it possible to reach the fellow wrote the adc driver ? He can give us some deeper understanding.

regards,

Mehmet

0 Kudos

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehet,

Please check the following setting:

Sequence error is typically happened because the delay m is set too short and the pre-trigger m asserts before the previous triggered ADC conversion is completed.

Regards,

David

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi,

I have did a test as follows. I run  ADC0 with  a config runs without any problem when configured to run alone. I run ADC1 as well alone with a configuration.  When I configured them to run together one of them does not run.

I think there might be an errata with pdb.

Can freescale supply us a test suite? I can use it to prove K60 ADCs can be used at the same time.

pdbConfig.jpg

0 Kudos

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehmet,

Two suggestions:

1- post your example code for the Community to help with

2- Review the many Application Notes. Some have code too.

I recommend the following:

AN4410 - FlexTimer and ADC Synchronization for Field Oriented Control on Kinetis

AN4407 - Dual Motor Control for PMSM with the Kinetis K70

Also the KQRUG.pdf Chapter 19 Using Peripheral Delay Block (PDB) to Schedule Analog to Digital Converter (ADC) Conversions

Sorry for the trouble.

Regards,

David

0 Kudos

1,159 Views
mehmetekici
Contributor II

Hi,

I have gone through the examples mentioned. When a squence error happens it does not recover by clearing the error bit. ADC or PDB does not work I can not identify which one. You can also test it using the adc_demo in KINETIS512_SC. You just need to generate squencing error. An easy way to generate squencing error is to break point while running under JTAG and continueu after a while.

Anyway here is the code I am using. The following code measures voltage and current of a 50 hz power line. I is based on 3 phase meter project supplied by freescale.

/**HEADER********************************************************************

*

* $FileName: LVDTask.h$

* $Version : $

* $Date    : 03 02 2013$

*

* Comments:

*

*END************************************************************************/

#ifndef __LVDTask_H__

    #define __LVDTask_H__

/*

**  Define line frequency which can be 50 or 60 Hz

*/

#define LINE_FREQUENCY          (50)

/*

**  Define number of samples per line period

**  It affects the size of buffers used for sampling

**  The valid values are 32, 64, 128

*/

#define SAMPLES_PER_PERIOD      (32)

/*

* Number of RMS calculations to be remembered

*

*/

#define MAX_RMS_HISTORY         (12)

#define ADC_REF_VOLTAGE (3.3f)

#define ADC_BITS_PER_SAMPLE (65535)

/* Allocate ADC sample buffers */

#define SAMPLE_BUFFER           (SAMPLES_PER_PERIOD + 256)

/* Sampling period in microseconds */

#define ADC_SAMPLING_PERIOD     (1000000 / (LINE_FREQUENCY) / (SAMPLES_PER_PERIOD))

#define ADC_IDELAY              (ADC_SAMPLING_PERIOD - 20)  

#define ADC_HARDWARE_AVERAGING  (0)

#define ADC_LONG_SAMPLE         (2)

#define ADC_RESULT_RANGE_SCALE  0xFFFF  /* not implemented in ADC driver */

/* Delay voltage sampling from trigger point in microseconds */

#define ADC_VOLTAGE_DELAY       (0)

#define ADC_CURRENT_DELAY       (ADC_SAMPLING_PERIOD /5)

/* LWEVENT masks for meter_shared_event */

#define ADC_DATA_READY_MASK     (1 << 0)

extern LWEVENT_STRUCT           LVDEvent;

extern LWEVENT_STRUCT           CurrEvent;

/* Buffers used for calculation */

extern ADC_RESULT_STRUCT                 LVDBuff[SAMPLES_PER_PERIOD];

extern ADC_RESULT_STRUCT                 CurrBuff[SAMPLES_PER_PERIOD];

/*

* Global functions

*/

extern void adc_task (uint_32 initial_data);

#endif /* __LVDTask_H__ */

/**HEADER********************************************************************

*

* Copyright (c) 2008-2009 Freescale Semiconductor;

* All Rights Reserved                     

*

***************************************************************************

*

* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR

* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,

* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING

* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

* THE POSSIBILITY OF SUCH DAMAGE.

*

**************************************************************************

*

* $FileName: adc_task.c$

*

* Comments:

*

*   This file contains the source for the ADC example program.

*   Two channels are running, one is running in loop, the second one

*   only once.

*

*END************************************************************************/

#include <mqx.h>

#include <bsp.h>

#include <string.h>

#include <time.h>

#include <math.h>

#include <stdlib.h>

#include "LVDTask.h"

#include "RMSCalculations.h"

#if ! BSPCFG_ENABLE_IO_SUBSYSTEM

#error This application requires BSPCFG_ENABLE_IO_SUBSYSTEM defined non-zero in user_config.h. Please recompile BSP with this option.

#endif

#ifndef BSP_DEFAULT_IO_CHANNEL_DEFINED

#error This application requires BSP_DEFAULT_IO_CHANNEL to be not NULL. Please set corresponding BSPCFG_ENABLE_TTYx to non-zero in user_config.h and recompile BSP with this option.

#endif

/* Function prototypes */

extern void process_calculation(void);

static void adc_init(void);

static void adc_init_redo(void);

static _mqx_int adc_calibrate(void);

static _mqx_int adc_save_calibration_data(void);

static _mqx_int adc_restore_calibration_data(void);

static void adc_channel_init(void);

static void adc_start_measuring(void);

static void adc_idelay_callback(void);

static void adc_error_callback(void);

static void curr_adc_init(void);

static void curr_adc_init_redo(void);

static _mqx_int curr_adc_calibrate(void);

static _mqx_int curr_adc_save_calibration_data(void);

static _mqx_int curr_adc_restore_calibration_data(void);

static void curr_adc_channel_init(void);

static void curr_adc_start_measuring(void);

static void curr_adc_idelay_callback(void);

static void curr_adc_error_callback(void);

/* ADC device init struct string definitions */

const ADC_INIT_STRUCT adc_init_param = {

  ADC_RESOLUTION_16BIT,     /* resolution */

};

/*

** Line voltage - logical channel init structures

*/

#define LVD_ADC_STR         "adc1:"

#define LVD_ADC_CHNLSTR     "adc1:LVD"

#define CURR_ADC_STR        "adc0:"

#define CURR_ADC_CHNLSTR    "adc0:Curr"

const ADC_INIT_CHANNEL_STRUCT     LVDChannelParam =

{

/* physical ADC channel                  */ ADC1_SOURCE_AD3,   

/* runs continuously after PDB trigger   */ (ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED),

/* number of samples in one run sequence */ SAMPLES_PER_PERIOD,           

/* time offset from trigger point in us  */ ADC_VOLTAGE_DELAY,            

/* period in us                          */ ADC_SAMPLING_PERIOD,          

/* scale range of result (not used now)  */ ADC_RESULT_RANGE_SCALE,       

/* circular buffer size (sample count)   */ SAMPLE_BUFFER,           

/* adc trigger                           */ ADC_PDB_TRIGGER,

/* lwevent object                        */ &LVDEvent,

/* lwevent mask                          */ ADC_DATA_READY_MASK,

};

const ADC_INIT_CHANNEL_STRUCT     CurrChannelParam =

{

/* physical ADC channel                  */ ADC0_SOURCE_AD3,   

/* runs continuously after PDB trigger   */ (ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED),

/* number of samples in one run sequence */ SAMPLES_PER_PERIOD,           

/* time offset from trigger point in us  */ ADC_CURRENT_DELAY,            

/* period in us                          */ ADC_SAMPLING_PERIOD,          

/* scale range of result (not used now)  */ ADC_RESULT_RANGE_SCALE,       

/* circular buffer size (sample count)   */ SAMPLE_BUFFER,           

/* adc trigger                           */ ADC_PDB_TRIGGER,

/* lwevent object                        */ &CurrEvent,

/* lwevent mask                          */ ADC_DATA_READY_MASK,

};

/* ADC file pointers */

MQX_FILE_PTR         fLVD;   /* File for line voltage detect ADC */

MQX_FILE_PTR         fCurr;  /* File for line voltage detect ADC */

/* Calculation buffer */

ADC_RESULT_STRUCT               LVDBuff[SAMPLES_PER_PERIOD];

ADC_RESULT_STRUCT               CurrBuff[SAMPLES_PER_PERIOD];

/*

* history of RMS values of line voltage

* These buffers keep recent RMS values of the cycles

* */

uint_16 RMSLVDHistory[MAX_RMS_HISTORY];

uint_16 RMSCurrHistory[MAX_RMS_HISTORY];

/* Number of ADC results read in a cycle */

uint_32             LVDReadNum;

/* Number of ADC results read in a cycle */

uint_32             CurrReadNum;

/* Event structure used between process and ADC driver to signal a period completion */

LWEVENT_STRUCT      LVDEvent;

LWEVENT_STRUCT      CurrEvent;

/* Global variables */

/* This lwsem is trigger on zero crossing of LVD */

LWSEM_STRUCT ZClwsem;

float voltagePerBit =  ADC_REF_VOLTAGE / ADC_BITS_PER_SAMPLE;

char floatPrintBuf[256];

/*ISR*-----------------------------------------------------

*

* Task Name    : int_service_routine

* Comments     : This interrupt service called on zero

* crossing of line voltage

*

*END*-----------------------------------------------------*/

void ZC_int_service_routine(void *pin)

{

    lwgpio_int_clear_flag((LWGPIO_STRUCT_PTR) pin);

    _lwsem_post(&ZClwsem);

}

/*TASK******************************************************

**

** Task Name    : adc_task

** Comments     :

**

*END*******************************************************/

void adc_task

   (

      uint_32 initial_data

   )

{

    int i;

    unsigned int tdiff;

  

    boolean overflow = FALSE;

    MQX_TICK_STRUCT ticks;

    MQX_TICK_STRUCT dticks;

  

    LWGPIO_STRUCT led1, led2, led3, btn1;

    MQX_TICK_STRUCT  time1, time2, diff;

  

    LWGPIO_STRUCT zcpzt, zcneg;

    _mqx_uint counter = 0;

    int usecs;

    boolean overlap;

  

    _mqx_uint result;

    float rmsVoltage;

    float rmsCurrent;

  

     

    puts("\n\n*****************************\n");

    puts("ADC task is running\n");

    /* opening pins for input */

    if (!lwgpio_init(&zcpzt, LVD_ZEROCROSS_TO_PZT, LWGPIO_DIR_INPUT, LWGPIO_VALUE_NOCHANGE))

    {

        printf("Initializing button GPIO as input failed.\n");

        _task_block();

    }

  

    lwgpio_set_functionality(&zcpzt, BSP_ZCPZT_MUX_GPIO);

    lwgpio_set_attribute(&zcpzt, LWGPIO_ATTR_OPEN_DRAIN, LWGPIO_AVAL_ENABLE);

    /* enable gpio functionality for given pin, react on falling edge */

    if (!lwgpio_int_init(&zcpzt, LWGPIO_INT_MODE_RISING))

    {

        printf("Initializing button GPIO for interrupt failed.\n");

        _task_block();

    }

    /* install gpio interrupt service routine */

    _int_install_isr(lwgpio_int_get_vector(&zcpzt), ZC_int_service_routine, (void *) &zcpzt);

    /* set the interrupt level, and unmask the interrupt in interrupt controller*/

    _bsp_int_init(lwgpio_int_get_vector(&zcpzt), 3, 0, TRUE);

    /* enable interrupt on GPIO peripheral module*/

  

    adc_init();

    curr_adc_init();

  

    /* Calibrate ADC devices used in 3-phase meter */

    printf("Calibrating ADC devices... ");  

    if (MQX_OK == adc_calibrate())  {

        puts("done\n");

    }

    else {

        puts("failed\n");

    }

  

    if (MQX_OK == curr_adc_calibrate())  {

        puts("done\n");

    }

    else {

        puts("failed\n");

    }

  

    /* Create the event object */

    if (_lwevent_create(&LVDEvent, 0) != MQX_OK) {

        puts("\nLVDEvent event failed!\n");

        _task_block();

    }

  

    _lwevent_set_auto_clear( &LVDEvent, ADC_DATA_READY_MASK);

  

    /* Create the event object */

    if (_lwevent_create(&CurrEvent, 0) != MQX_OK) {

        puts("\nLVDEvent event failed!\n");

        _task_block();

    }

  

    _lwevent_set_auto_clear( &CurrEvent, ADC_DATA_READY_MASK);

   

    /* Initialize ADC channel */

  

    curr_adc_channel_init();

    adc_channel_init();

    lwgpio_int_enable(&zcpzt, TRUE);

  

    /* Trigger ADC measurements */

    adc_start_measuring();

    ioctl (fLVD, ADC_IOCTL_PAUSE_CHANNEL, NULL);

    ioctl (fCurr, ADC_IOCTL_PAUSE_CHANNEL, NULL);

  

    i = 0;

    while(1)

    {

 

    LVDReadNum = read(fLVD, LVDBuff, SAMPLES_PER_PERIOD * sizeof(LVDBuff[0].result));

    CurrReadNum = read(fCurr, CurrBuff, SAMPLES_PER_PERIOD * sizeof(CurrBuff[0].result));

 

    _lwsem_wait(&ZClwsem);

        _time_get_elapsed_ticks(&ticks);

    ioctl (fLVD, ADC_IOCTL_RESUME_CHANNEL, NULL);

    ioctl (fCurr, ADC_IOCTL_RESUME_CHANNEL, NULL);

 

        /* Wait for adc data ready event */

        if (_lwevent_wait_ticks (&LVDEvent, ADC_DATA_READY_MASK, TRUE, 0) == MQX_OK)

        {

     

        ioctl (fLVD, ADC_IOCTL_PAUSE_CHANNEL, NULL);

            LVDReadNum  = read(fLVD, LVDBuff, SAMPLES_PER_PERIOD * sizeof(LVDBuff[0].result));

                 

        //_lwevent_wait_ticks (&LVDEvent, ADC_DATA_READY_MASK, TRUE, 0);

            ioctl (fCurr, ADC_IOCTL_PAUSE_CHANNEL, NULL);

            CurrReadNum = read(fCurr, CurrBuff, SAMPLES_PER_PERIOD * sizeof(CurrBuff[0].result));

          

            /* Process metering algorithms */

            //process_calculation();

          

          

          

             //i = Average(&LVDBuff[0]);

          

            _time_get_elapsed_ticks(&dticks);

          

          

            tdiff = _time_diff_microseconds(&dticks, &ticks, &overflow);

            RMSLVDHistory[i]  = RMS(LVDBuff);

            RMSCurrHistory[i] = RMS(CurrBuff);

          

            rmsVoltage = voltagePerBit * RMSLVDHistory[i];

            rmsCurrent = voltagePerBit * RMSCurrHistory[i];

          

            //printf("%d , %.4f\n", tdiff, rmsVoltage );

  printf("%d , %.4f    - %.4f \n", tdiff, rmsVoltage, rmsCurrent );

  //_time_delay(300);

/*

        for (i = 0; i<SAMPLES_PER_PERIOD; i++ )

        {

        printf("%d  =  %d\n", i, LVDBuff[i].result);

        }*/

        }

        //_lwsem_wait(&ZClwsem);

        if (i++ >= MAX_RMS_HISTORY) i = 0;

    }

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_init

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

static void adc_init(void)

{

    _mqx_uint      error_code = 0;

    /* Opening ADC devices */

    puts("Opening ADC devices for measurement\n");

    fLVD   = fopen(LVD_ADC_STR, (const char*)&adc_init_param);

    if(fLVD  != NULL)  

    {  

        /* Set long sample time */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_LONG_SAMPLE, (pointer)ADC_LONG_SAMPLE);  

        /* Set hardware averaging to be taken from 16 samples */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_HW_AVERAGING,(pointer)ADC_HARDWARE_AVERAGING);  

        /* Set low conversion speed */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_HIGH_SPEED,   NULL);  

        /* Set common sampling period for all ADC channels */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_BASE_PERIOD, (pointer)ADC_SAMPLING_PERIOD);  

        /*Set idelay function call back */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_IDELAY_FCN, &adc_idelay_callback);  

      

      

        error_code += ioctl(fLVD, ADC_IOCTL_SET_IDELAY, (pointer)(ADC_IDELAY));  

        /* Set ADC error call back function for capturing triggering errors */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_ERROR_FCN, &adc_error_callback);

    }

    else  {  

        error_code++;

    }

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_channel_init

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

static void adc_channel_init(void)

{

    _mqx_uint      error_code = 0;

    puts("Opening ADC channels ..LVD . measurement\n");

    /* Opening ADC channels for L1 voltage and current measurements */

    puts("LVD voltage channel...");

  

    fLVD  = fopen(LVD_ADC_CHNLSTR, (const char*)&LVDChannelParam);

    if(fLVD != NULL)

    {  

        /* Force L1 voltage channel data to be processed in PDB interrupt */

        error_code += ioctl(fLVD, ADC_IOCTL_SET_IDELAY_PROCESS, NULL);  

        puts("opened\n");

    }

    else

    {  

        puts("failed\n");

        _task_block();

    }

    puts("\n LVD channel is waiting for trigger\n");

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_calibrate

* Returned Value   : _mqx_int

* Comments         :

*

*END*********************************************************************/

static _mqx_int adc_calibrate(void)

{

    _mqx_int   error_code = MQX_OK;

    /* ADC calibration */  

    error_code = ioctl(fLVD, ADC_IOCTL_CALIBRATE, NULL);

  

    if (error_code != MQX_OK)    {

        return error_code;

    }

    return  error_code; 

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_start_measuring

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

static void adc_start_measuring(void)

{

    /* Triggering */

    puts("Starting measurement..LVD.\n");

    ioctl(fCurr, ADC_IOCTL_FIRE_TRIGGER, (pointer) ADC_PDB_TRIGGER);

    ioctl(fLVD, ADC_IOCTL_FIRE_TRIGGER, (pointer) ADC_PDB_TRIGGER);  

  

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_idelay_callback

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

volatile uint_32 adc_idelay_count = 0;

static void adc_idelay_callback(void)

{

    adc_idelay_count++;

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_error_callback

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

volatile uint_32 adc_error_count = 0;

static void adc_error_callback(void)

{

    adc_error_count++;

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_init

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

static void curr_adc_init(void)

{

    _mqx_uint      error_code = 0;

    /* Opening ADC devices */

    puts("Opening ADC devices for measurement CURR\n");

    fCurr   = fopen(CURR_ADC_STR, (const char*)&adc_init_param);

    if(fCurr  != NULL)  

    {  

        /* Set long sample time */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_LONG_SAMPLE, (pointer)ADC_LONG_SAMPLE);  

        /* Set hardware averaging to be taken from 16 samples */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_HW_AVERAGING,(pointer)ADC_HARDWARE_AVERAGING);  

        /* Set low conversion speed */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_HIGH_SPEED,   NULL);  

        /* Set common sampling period for all ADC channels */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_BASE_PERIOD, (pointer)ADC_SAMPLING_PERIOD);  

        /* Set idelay function call back */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_IDELAY_FCN, &curr_adc_idelay_callback);  

      

      

        error_code += ioctl(fCurr, ADC_IOCTL_SET_IDELAY, (pointer)(ADC_IDELAY));  

        /*Set ADC error call back function for capturing triggering errors */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_ERROR_FCN, &curr_adc_error_callback);

    }

    else  {  

        error_code++;

    }

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_channel_init

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

static void curr_adc_channel_init(void)

{

    _mqx_uint      error_code = 0;

    puts("Opening ADC channels ..CURR. measurement\n");

    /* Opening ADC channels for L1 voltage and current measurements */

    puts("CURR voltage channel...");

  

    fCurr  = fopen(CURR_ADC_CHNLSTR, (const char*)&CurrChannelParam);

    if(fCurr != NULL)

    {  

        /* Force L1 voltage channel data to be processed in PDB interrupt */

        error_code += ioctl(fCurr, ADC_IOCTL_SET_IDELAY_PROCESS, NULL);  

        puts("opened\n");

    }

    else

    {  

        puts("failed\n");

        _task_block();

    }

    puts("\n CURR channel is waiting for trigger\n");

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_calibrate

* Returned Value   : _mqx_int

* Comments         :

*

*END*********************************************************************/

static _mqx_int curr_adc_calibrate(void)

{

    _mqx_int   error_code = MQX_OK;

    /* ADC calibration */  

    error_code = ioctl(fCurr, ADC_IOCTL_CALIBRATE, NULL);

  

    if (error_code != MQX_OK)    {

        return error_code;

    }

    return  error_code; 

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_start_measuring

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

static void curr_adc_start_measuring(void)

{

    /* Triggering */

    puts("Starting measurement...\n");

    ioctl(fCurr, ADC_IOCTL_FIRE_TRIGGER, (pointer) ADC_PDB_TRIGGER);

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_idelay_callback

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

volatile uint_32 curr_adc_idelay_count = 0;

static void curr_adc_idelay_callback(void)

{

    curr_adc_idelay_count++;

}

/*FUNCTION****************************************************************

*

* Function Name    : adc_error_callback

* Returned Value   : void

* Comments         :

*

*END*********************************************************************/

volatile uint_32 curr_adc_error_count = 0;

static void curr_adc_error_callback(void)

{

    curr_adc_error_count++;

}

Regards,

Mehmet

0 Kudos

1,159 Views
DavidS
NXP Employee
NXP Employee

Hi Mehet,

Sorry for delayed response. I was trying to confirm my reply.

My reply is follows:

“if you have a sequencing error, it really is
an indication of a configuration issue rather than a need to just clear the
error flag.  With error interrupt, I think the solution is to disable
ADC/PDB, re-initialize, and change timing/delay values to re-test.”

Response from our MQX Development team:

"You must reinit the ADC in order to make it work. The error flag
is there to indicate some discrepancies in the configuration.

At the present we do not have any example that would do reinit
of the ADC.

The overly complex ADC driver in Kinetis is to be replaced by LWADC in future MQX release"

Regards,

David

PS for future please attach source file rather than pasting it.

0 Kudos