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++;
}