multiple ADC channels with MQX

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

multiple ADC channels with MQX

Jump to solution
1,606 Views
khoanguyen
Contributor I

Hi,

I'm trying to modify the adc example to work with more than 2 channels. I am using MQX 3.8.1, codewarrior 10.2, and the kinetis k60 tower kit. I've already read through this reference https://community.freescale.com/message/95236#95236  because he posed the same question but the solution confused me. I'm trying to read from ADC1 channels 11,12, and 13

So far I've modified the adc example for mqx to contain 3 channels. 2 work perfectly and I know that is the max amount of channels allowed to be open. So in my code below the flow is:

open/trigger channel 1;

open/trigger channel 2;

while(1)

{

read ch1 and ch2

          close ch1

open/trigger ch3

          read ch3

close ch3

open/trigger ch1

}

For some reason this causes my program to have all channels outputting the same value for ch2, so is it something with the hardware still or am i opening and closing the channels incorrectly. I also add some printf statements showing each channel be closed or open and the output shows each channel opening and closing correctly.

thanks,

Khoa Nguyen

void GPIOinit_task(uint_32 initial_data)

{

    float tmp = 0.0;

   ADC_RESULT_STRUCT data;

       _mqx_int i;

       MQX_FILE_PTR f, f_ch1;

    #if ADC_MAX_MODULES > 1

       MQX_FILE_PTR f_2, f_ch2;

       MQX_FILE_PTR f_3, f_ch3; 

     #endif

    printf("Opening ADC device ...");

    f = fopen(MY_ADC, (const char*)&adc_init);

    if(f != NULL)

        {   

            printf("done\n");

        }

    else

        {   

            printf("failed\n");

            _task_block();

        }

   

    printf("Opening channel #1 ...");

    f_ch1 = fopen(MY_ADC "first", (const char*)&adc_channel_param1);

    if(f_ch1 != NULL)

        {   

            printf("done, prepared to start by trigger\n");

        }

    else

    {   

        printf("Channel 1 failed\n");

        //_task_block();

    }

   

#if ADC_MAX_MODULES > 1

    printf("Opening channel #2 ...");

        f_ch2 = fopen(MY_ADC "second", (const char*)&adc_channel_param2); /* adc:2 is running now */

        if(f_ch2 != NULL)

        {   

            printf("done, one sequence started automatically\n");

        }

        else

        {   

            printf("Channel 2 failed\n");

        }

       

#endif

        _time_delay(500);

    printf("Triggering channel #1...");

    ioctl(f, ADC_IOCTL_FIRE_TRIGGER, (pointer) MY_TRIGGER);

    printf("Channel 1 triggered!\n");

   

    printf("Triggering channel #2...");

    ioctl(f_2, ADC_IOCTL_FIRE_TRIGGER, (pointer) MY_TRIGGER);

    printf("Channel 2 triggered!\n");

   

    while(1)

        {

        gResult = 0;

        read(f_ch1, &data, sizeof(data) );

        gResult = data.result;

        _time_delay(100);

       

        tmp = ((float)gResult / 65535.0)* 3.3;

        printf("ADC ch 12: %4.5f \n", tmp);

        _time_delay(1500);

       

       

       

#if ADC_MAX_MODULES > 1

        gResult2 = 0;

        /*

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

            {   

                read(f_ch2, &data, sizeof(data) );

                //data.result = (data.result / 65535) * 3.3;

                gResult += data.result;

                _time_delay(50);

            }

        */

        read(f_ch2, &data, sizeof(data) );

        gResult2 = data.result;

        _time_delay(100);

        tmp = ((float)gResult2 / 65535.0)* 3.3;

        printf("        ADC ch 13: %4.5f \n", tmp);

        _time_delay(1500);

       

                fclose(f_ch1);

                f_ch3 = fopen(MY_ADC "third", (const char*)&adc_channel_param3); /* adc:2 is running now */

                if(f_ch3 != NULL)

                    {   

                        printf("done, one sequence started automatically\n");

                    }

                else

                    {   

                        printf("Channel 3 failed\n");

                    }

                    printf("Triggering channel #3...");

                    ioctl(f_3, ADC_IOCTL_FIRE_TRIGGER, (pointer) MY_TRIGGER);

                    printf("Channel 3 triggered!\n");

                                

        gResult3 = 0;

        read(f_ch3, &data, sizeof(data) );

        gResult3 = data.result;

        _time_delay(100);

        tmp = ((float)gResult3 / 65535.0)* 3.3;

        printf("                ADC ch 11: %4.5f \n", tmp);

        _time_delay(1500);

       

        fclose(f_ch3);

        printf("Opening channel #1 ...");

        f_ch1 = fopen(MY_ADC "first", (const char*)&adc_channel_param1);

        if(f_ch1 != NULL)

            {   

                printf("done, prepared to start by trigger\n");

            }

        else

        {   

            printf("Channel 1 failed\n");

        }

        printf("Triggering channel #1...");

        ioctl(f, ADC_IOCTL_FIRE_TRIGGER, (pointer) MY_TRIGGER);

        printf("Channel 1 triggered!\n");

#endif   

        }

}

/* ADC device init struct */

const ADC_INIT_STRUCT adc_init = {

    ADC_RESOLUTION_DEFAULT,     /* resolution */

};

#if MQX_USE_LWEVENTS

static LWEVENT_STRUCT evn;

#endif

/* Logical channel #12 init struct */

const ADC_INIT_CHANNEL_STRUCT adc_channel_param1 =

{

#if   defined(BSP_TWR_K70F120M) || (BSP_TWR_K60N512) || defined(BSP_TWR_K40X256) ||\

        defined(BSP_TWR_K40D100M) || defined(BSP_TWR_K53N512) || defined(BSP_TWR_K60D100M)

    ADC1_SOURCE_AD12, /* physical ADC channel */

#endif

    ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED, /* runs continuously after IOCTL trigger */

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

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

    300000,         /* period in us (= 0.3 sec) */

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

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

    MY_TRIGGER,     /* logical trigger ID that starts this ADC channel */

#if MQX_USE_LWEVENTS

    &evn,

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

#endif

};

/* Logical channel #13 init struct */

const ADC_INIT_CHANNEL_STRUCT adc_channel_param2 =

{

#if   defined(BSP_TWR_K70F120M) || (BSP_TWR_K60N512) || defined(BSP_TWR_K40X256) || defined(BSP_TWR_K40D100M) ||\

        defined(BSP_TWR_K53N512) || defined(BSP_TWR_K20D72M) || defined(BSP_TWR_K60F120M) || defined(BSP_TWR_K60D100M)

    ADC1_SOURCE_AD13,

#endif

    ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED, /* one sequence is sampled after fopen */

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

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

    600000,         /* period in us (= 0.6 sec) */

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

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

    MY_TRIGGER,     /* logical trigger ID that starts this ADC channel */

#if MQX_USE_LWEVENTS

    NULL

#endif

};

/* Logical channel #11 init struct */

const ADC_INIT_CHANNEL_STRUCT adc_channel_param3 =

{

#if   defined(BSP_TWR_K70F120M) || (BSP_TWR_K60N512) || defined(BSP_TWR_K40X256) ||\

        defined(BSP_TWR_K40D100M) || defined(BSP_TWR_K53N512) || defined(BSP_TWR_K60D100M)

    ADC1_SOURCE_ADPM1, /* physical ADC channel */

#endif

    ADC_CHANNEL_MEASURE_LOOP | ADC_CHANNEL_START_TRIGGERED, /* runs continuously after IOCTL trigger */

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

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

    300000,         /* period in us (= 0.3 sec) */

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

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

    MY_TRIGGER,     /* logical trigger ID that starts this ADC channel */

#if MQX_USE_LWEVENTS

    &evn,

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

#endif

};





Tags (4)
0 Kudos
1 Solution
500 Views
rolandmk
Contributor II

Hello Khoa,

I had the same problem and found some bugs in the adt_period_prescaler() function in the adt_kpdb.c file. The changes are underlined and commented with 'RMK'. I hope that will help.

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

*

* Function Name    : adt_period_prescaler

* Returned Value   : IO_OK or IO_ERROR

* Comments         :

*    Finds the best prescaler for given period

*

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

static _mqx_int adt_period_prescaler(uint_32 period)

{

    volatile uint_32 pdb_prescaler1, pdb_prescaler, pdb_period1, pdb_period = 0, pdb_period_test;

    uint_8 mult = 0; /* assume that we will not use MULT field */

    /* In the first step, we want to find for given a prescaler, which meets following criteria:

    ** considering MOD field = 65535 and, find a combination of (found_prescaler, found_period), in which found_period

    ** is minimal (so the found_prescaler is also lowest possible one), but found_period must be still higher

    ** than given period.

    ** We compute for 2 cases: MULT field is 0 and MULT field is not 0 and after that we compare those 2 results and we

    ** choose the better one (the one with valid lower found_period).

    ** At the end, we reduce MOD, to set given period for PDB. With this approach, MOD field gets the highest possible value.

    */

#define PDB_MAX_PERIOD1 (uint_32) ((uint_64) 8388608000000L / BSP_BUS_CLOCK)   /*  1 * 128 * 65536 * 1000000 = 8388608000000 */

#define PDB_MAX_PERIOD  (uint_32) ((uint_64) 335544320000000L / BSP_BUS_CLOCK) /* 40 * 128 * 65536 * 1000000 = 335544320000000 */

    /* PDB was not run till yet... so setup period */

    if (pdb_external.prescaler == -1) {

        /* PDB prescaler was not set yet */

        pdb_period_test = PDB_MAX_PERIOD1;

        pdb_prescaler1 = 7;

        while ((pdb_prescaler1 != (uint_32)-1) && (period < pdb_period_test)) {

            pdb_prescaler1--;

            pdb_period1 = pdb_period_test;

            pdb_period_test >>= 1;

        }

        pdb_prescaler1++;

        /* now, in pdb_prescaler1, we have prescaler as if there was

        ** no additional division factor (MULT field equivalent to 1) and in

        ** pdb_period1 we have related period in microseconds

        */

        pdb_period_test = PDB_MAX_PERIOD;

        pdb_prescaler = 9; /* we got 2 next bits from MULT field, because MULT can have values of 10, 20, 40 */

        while ((pdb_prescaler != (uint_32)-1) && (period < pdb_period_test)) {

            pdb_prescaler--;

            pdb_period = pdb_period_test;

            pdb_period_test >>= 1;

        }

        pdb_prescaler++;

        /* now, in pdb_prescaler, we have prescaler as if there was

        ** additional division factor (MULT field equivalent to 10) and in

        ** pdb_period we have related period in microseconds

        */

        if ((pdb_prescaler1 == 8) && (pdb_prescaler == 10)) {

                /* cannot set period with pdb_prescaler */

                return ADC_ERROR_BAD_PARAM;

        }

        /* Compare both values of pdb_period1 and pdb_period - the smaller one wins */

        if ((pdb_period1 < pdb_period) && (pdb_prescaler1 != 8)) {

            /* use values of pdb_period1 => copy them to the result; MULT field remains zero */

            pdb_period = pdb_period1;

            pdb_prescaler = pdb_prescaler1;

        }

        else {

            /* compute pdb_period and pdb_prescaler plus compute MULT field */

            if (pdb_prescaler > 7) {

                /* move additional bits from pdb_prescaler to MULT field */

                mult = pdb_prescaler - 6;

                /* and saturate pdb_prescaler to maximum */

                pdb_prescaler = 7;

            }

            else

                mult = 1;

        }

         pdb_external.prescaler = (int_8) pdb_prescaler; //RMK

    }

    else {

        /* compute PDB period with prescaler already set */

        switch (PDB0_BASE_PTR->SC & PDB_SC_MULT_MASK) {

            case PDB_SC_MULT(0): /* 0 in the mask means that divider is 1 */

                pdb_period = PDB_MAX_PERIOD1 >> (7 - pdb_external.prescaler);

                mult = 0;    //RMK

                break;

            case PDB_SC_MULT(1): /* 1 in the mask means that divider is 10 */

                pdb_period = PDB_MAX_PERIOD >> (7 - pdb_external.prescaler + 2);

                mult = 1;    //RMK

                break;

            case PDB_SC_MULT(2): /* 2 in the mask means that divider is 20 */

                pdb_period = PDB_MAX_PERIOD >> (7 - pdb_external.prescaler + 1);

               mult = 2;    //RMK

                break;

            case PDB_SC_MULT(3): /* 3 in the mask means that divider is 40 */

                pdb_period = PDB_MAX_PERIOD >> (7 - pdb_external.prescaler + 0);

               mult = 3;    //RMK

                break;

        }

        if (period > pdb_period)

            return ADC_ERROR_BAD_PARAM; /* cannot set period */

    }

    //RMK pdb_external.prescaler = (int_8) pdb_prescaler;

    pdb_period1 = ((uint_64) period << 16) / pdb_period;

    if (pdb_period1 > 0xFFFF)

        return ADC_ERROR_BAD_PARAM; /* cannot set period */

    PDB0_BASE_PTR->MOD =  pdb_period1 - 1;

    PDB0_BASE_PTR->SC &= ~PDB_SC_MULT_MASK;

    PDB0_BASE_PTR->SC |= PDB_SC_MULT(mult);

    PDB0_BASE_PTR->SC |= PDB_SC_LDOK_MASK;

    pdb_internal.period = period;

    /* set prescaler and enable module with interrupts */

    PDB0_BASE_PTR->SC &= ~PDB_SC_PRESCALER_MASK;

    PDB0_BASE_PTR->SC |= (pdb_prescaler << PDB_SC_PRESCALER_SHIFT);

    PDB0_BASE_PTR->SC |= PDB_SC_PDBIE_MASK | PDB_SC_CONT_MASK | PDB_SC_LDOK_MASK;

    return ADC_OK;

}


View solution in original post

0 Kudos
3 Replies
501 Views
rolandmk
Contributor II

Hello Khoa,

I had the same problem and found some bugs in the adt_period_prescaler() function in the adt_kpdb.c file. The changes are underlined and commented with 'RMK'. I hope that will help.

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

*

* Function Name    : adt_period_prescaler

* Returned Value   : IO_OK or IO_ERROR

* Comments         :

*    Finds the best prescaler for given period

*

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

static _mqx_int adt_period_prescaler(uint_32 period)

{

    volatile uint_32 pdb_prescaler1, pdb_prescaler, pdb_period1, pdb_period = 0, pdb_period_test;

    uint_8 mult = 0; /* assume that we will not use MULT field */

    /* In the first step, we want to find for given a prescaler, which meets following criteria:

    ** considering MOD field = 65535 and, find a combination of (found_prescaler, found_period), in which found_period

    ** is minimal (so the found_prescaler is also lowest possible one), but found_period must be still higher

    ** than given period.

    ** We compute for 2 cases: MULT field is 0 and MULT field is not 0 and after that we compare those 2 results and we

    ** choose the better one (the one with valid lower found_period).

    ** At the end, we reduce MOD, to set given period for PDB. With this approach, MOD field gets the highest possible value.

    */

#define PDB_MAX_PERIOD1 (uint_32) ((uint_64) 8388608000000L / BSP_BUS_CLOCK)   /*  1 * 128 * 65536 * 1000000 = 8388608000000 */

#define PDB_MAX_PERIOD  (uint_32) ((uint_64) 335544320000000L / BSP_BUS_CLOCK) /* 40 * 128 * 65536 * 1000000 = 335544320000000 */

    /* PDB was not run till yet... so setup period */

    if (pdb_external.prescaler == -1) {

        /* PDB prescaler was not set yet */

        pdb_period_test = PDB_MAX_PERIOD1;

        pdb_prescaler1 = 7;

        while ((pdb_prescaler1 != (uint_32)-1) && (period < pdb_period_test)) {

            pdb_prescaler1--;

            pdb_period1 = pdb_period_test;

            pdb_period_test >>= 1;

        }

        pdb_prescaler1++;

        /* now, in pdb_prescaler1, we have prescaler as if there was

        ** no additional division factor (MULT field equivalent to 1) and in

        ** pdb_period1 we have related period in microseconds

        */

        pdb_period_test = PDB_MAX_PERIOD;

        pdb_prescaler = 9; /* we got 2 next bits from MULT field, because MULT can have values of 10, 20, 40 */

        while ((pdb_prescaler != (uint_32)-1) && (period < pdb_period_test)) {

            pdb_prescaler--;

            pdb_period = pdb_period_test;

            pdb_period_test >>= 1;

        }

        pdb_prescaler++;

        /* now, in pdb_prescaler, we have prescaler as if there was

        ** additional division factor (MULT field equivalent to 10) and in

        ** pdb_period we have related period in microseconds

        */

        if ((pdb_prescaler1 == 8) && (pdb_prescaler == 10)) {

                /* cannot set period with pdb_prescaler */

                return ADC_ERROR_BAD_PARAM;

        }

        /* Compare both values of pdb_period1 and pdb_period - the smaller one wins */

        if ((pdb_period1 < pdb_period) && (pdb_prescaler1 != 8)) {

            /* use values of pdb_period1 => copy them to the result; MULT field remains zero */

            pdb_period = pdb_period1;

            pdb_prescaler = pdb_prescaler1;

        }

        else {

            /* compute pdb_period and pdb_prescaler plus compute MULT field */

            if (pdb_prescaler > 7) {

                /* move additional bits from pdb_prescaler to MULT field */

                mult = pdb_prescaler - 6;

                /* and saturate pdb_prescaler to maximum */

                pdb_prescaler = 7;

            }

            else

                mult = 1;

        }

         pdb_external.prescaler = (int_8) pdb_prescaler; //RMK

    }

    else {

        /* compute PDB period with prescaler already set */

        switch (PDB0_BASE_PTR->SC & PDB_SC_MULT_MASK) {

            case PDB_SC_MULT(0): /* 0 in the mask means that divider is 1 */

                pdb_period = PDB_MAX_PERIOD1 >> (7 - pdb_external.prescaler);

                mult = 0;    //RMK

                break;

            case PDB_SC_MULT(1): /* 1 in the mask means that divider is 10 */

                pdb_period = PDB_MAX_PERIOD >> (7 - pdb_external.prescaler + 2);

                mult = 1;    //RMK

                break;

            case PDB_SC_MULT(2): /* 2 in the mask means that divider is 20 */

                pdb_period = PDB_MAX_PERIOD >> (7 - pdb_external.prescaler + 1);

               mult = 2;    //RMK

                break;

            case PDB_SC_MULT(3): /* 3 in the mask means that divider is 40 */

                pdb_period = PDB_MAX_PERIOD >> (7 - pdb_external.prescaler + 0);

               mult = 3;    //RMK

                break;

        }

        if (period > pdb_period)

            return ADC_ERROR_BAD_PARAM; /* cannot set period */

    }

    //RMK pdb_external.prescaler = (int_8) pdb_prescaler;

    pdb_period1 = ((uint_64) period << 16) / pdb_period;

    if (pdb_period1 > 0xFFFF)

        return ADC_ERROR_BAD_PARAM; /* cannot set period */

    PDB0_BASE_PTR->MOD =  pdb_period1 - 1;

    PDB0_BASE_PTR->SC &= ~PDB_SC_MULT_MASK;

    PDB0_BASE_PTR->SC |= PDB_SC_MULT(mult);

    PDB0_BASE_PTR->SC |= PDB_SC_LDOK_MASK;

    pdb_internal.period = period;

    /* set prescaler and enable module with interrupts */

    PDB0_BASE_PTR->SC &= ~PDB_SC_PRESCALER_MASK;

    PDB0_BASE_PTR->SC |= (pdb_prescaler << PDB_SC_PRESCALER_SHIFT);

    PDB0_BASE_PTR->SC |= PDB_SC_PDBIE_MASK | PDB_SC_CONT_MASK | PDB_SC_LDOK_MASK;

    return ADC_OK;

}


0 Kudos
500 Views
c0170
Senior Contributor III

Thank you for sharing the code. We had checked the code and it was corrected.

Regards,

MartinK

0 Kudos
500 Views
JuroV
NXP Employee
NXP Employee

Hello Khoa, did you make a progress with this issue?

0 Kudos