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
};
Solved! Go to Solution.
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;
}
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;
}
Thank you for sharing the code. We had checked the code and it was corrected.
Regards,
MartinK
Hello Khoa, did you make a progress with this issue?