KL25Z ADC triggering PIT with KSDK 2.0

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

KL25Z ADC triggering PIT with KSDK 2.0

1,992 Views
gustavsl
Contributor III

I'm using a custom board with KL25Z and trying to convert a single ADC input using the ADC interrupt.

Starting from the KSDK 2.0 ADC low power example, I have tried to convert it from using LPTMR to use PIT.

However, it seems that even after setting the SIM->SOPT7 register, the interrupt won't trigger. I never see the toggling LED and the ADC doesn't convert.

 

How do I implement this?

 

Here's my code:

 

/*******************************************************************************
* Definitions
******************************************************************************/
#define PIT_LED_HANDLER PIT_IRQHandler
#define PIT_IRQ_ID PIT_IRQn
/* Get source clock for PIT driver */
#define PIT_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_BusClk)
#define ADC_BASE_ADDR ADC0
#define ADC_CHANNEL_GROUP 0U
#define ADC_USER_CHANNEL 0U

#define ADC_IRQ_ID ADC0_IRQn
#define ADC_IRQ_HANDLER_FUNC ADC0_IRQHandler


/*******************************************************************************
* Variables
******************************************************************************/
volatile static uint32_t adcValue = 0; /*! ADC value */
volatile bool conversionCompleted = false; /*! Conversion is completed Flag */
volatile bool pitIsrFlag = false;
volatile static uint16_t samplesCounter = 0;


/*******************************************************************************
* Code
******************************************************************************/

void BOARD_ConfigTriggerSource(void)
{
/* Configure SIM for ADC hw trigger source selection */
SIM->SOPT7 |= (SIM_SOPT7_ADC0ALTTRGEN(1) | SIM_SOPT7_ADC0PRETRGSEL(0) | SIM_SOPT7_ADC0TRGSEL(0x4));
}

 

void PIT_InitADCTriggerSource(void)
{
// Initialise PIT0 module and enable run in debug
pit_config_t pitConfig =
{
.enableRunInDebug = true
};
/* Init PIT */
PIT_Init(PIT,&pitConfig);


/* Set 62us interrupt */
PIT_SetTimerPeriod(PIT,kPIT_Chnl_0, USEC_TO_COUNT(62U, PIT_SOURCE_CLOCK));


/* Start counting on channel 0 */
PIT_StartTimer(PIT, kPIT_Chnl_0);


/* Configure SIM for ADC hw trigger source selection */
BOARD_ConfigTriggerSource();
}

static void ADC16_PauseConversion(ADC_Type *base)
{
adc16_channel_config_t adcChnConfig;
adcChnConfig.channelNumber = 0U; /*!< AD0 channel */
adcChnConfig.enableInterruptOnConversionCompleted = false;
adcChnConfig.enableDifferentialConversion = false;
ADC16_SetChannelConfig(base, ADC_CHANNEL_GROUP, &adcChnConfig);
}


static void ADC16_CalibrateParams(ADC_Type *base)
{
adc16_config_t adcUserConfig;
adc16_channel_config_t adcChnConfig;

ADC16_GetDefaultConfig(&adcUserConfig);
adcUserConfig.resolution = kADC16_Resolution16Bit;
adcUserConfig.enableContinuousConversion = false;
adcUserConfig.clockSource = kADC16_ClockSourceAsynchronousClock;
adcUserConfig.enableLowPower = 1;
ADC16_Init(base, &adcUserConfig);
adcChnConfig.enableInterruptOnConversionCompleted = false;
ADC16_SetChannelConfig(base, ADC_CHANNEL_GROUP, &adcChnConfig);
/* Wait for the conversion to be done */
while (!ADC16_GetChannelStatusFlags(base, ADC_CHANNEL_GROUP))
{
}
ADC16_PauseConversion(base);
}


static bool ADC16_InitHardwareTrigger(ADC_Type *base)
{
adc16_config_t adcUserConfig;
adc16_channel_config_t adcChnConfig;

ADC16_GetDefaultConfig(&adcUserConfig);
adcUserConfig.resolution = kADC16_Resolution16Bit;
/* enabled hardware trigger */
ADC16_EnableHardwareTrigger(base, true);
adcUserConfig.enableContinuousConversion = false;
adcUserConfig.clockSource = kADC16_ClockSourceAsynchronousClock;
adcUserConfig.longSampleMode = kADC16_LongSampleCycle24;
adcUserConfig.enableLowPower = 1;
ADC16_Init(base, &adcUserConfig);
adcChnConfig.channelNumber = ADC_USER_CHANNEL;
adcChnConfig.enableDifferentialConversion = false;
adcChnConfig.enableInterruptOnConversionCompleted = true;
/* Configure channel 0 */
ADC16_SetChannelConfig(base, ADC_CHANNEL_GROUP, &adcChnConfig);
return true;
}


void ADC16_IRQ_HANDLER_FUNC(void)
{
/* Get current ADC value */
adcValue = ADC16_GetChannelConversionValue(ADC_BASE_ADDR, ADC_CHANNEL_GROUP);
/* Set conversionCompleted flag. This prevents an wrong conversion in main function */
conversionCompleted = true;
LED_BLUE_TOGGLE();
}


void LEDInit(void)
{
LED_RED_INIT(LOGIC_LED_OFF);
LED_GREEN_INIT(LOGIC_LED_OFF);
LED_BLUE_INIT(LOGIC_LED_OFF);
LED_YELLOW_INIT(LOGIC_LED_OFF);
}

 

int main(void)
{
pit_config_t pitConfig
   {
   .enableRunInDebug = true
   };

BOARD_InitPins();
BOARD_BootClockRUN();
LEDInit();
ADC16_CalibrateParams(ADC0);
if (!ADC16_InitHardwareTrigger(ADC_BASE_ADDR))
{
   LED_RED_ON();
   return -1;
}
PIT_GetDefaultConfig(&pitConfig);
/* Init pit module */
PIT_Init(PIT, &pitConfig);
/* Set timer period for channel 0 */
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, USEC_TO_COUNT(100U, PIT_SOURCE_CLOCK));
PIT_StartTimer(PIT, kPIT_Chnl_0);
/* Enable timer interrupts for channel 0 */
//PIT_EnableInterrupts(PIT, kPIT_Chnl_0, kPIT_TimerInterruptEnable);
BOARD_ConfigTriggerSource();
/* Enable at the NVIC */
EnableIRQ(ADC_IRQ_ID);
/* Start channel 0 */
PIT_StartTimer(PIT, kPIT_Chnl_0);
   for(;;) /* Infinite loop to avoid leaving the main function */
   {
/* Check whether occur interupt and toggle LED */
   if (conversionCompleted)
      {
      LED_GREEN_ON();
      }
   }
}   

Labels (1)
Tags (4)
0 Kudos
4 Replies

1,445 Views
DavidS
NXP Employee
NXP Employee

Hi Gustavo,

The adc16_low_power_frdmkl25z demo by default is using the LPTMR since it can operate in VLPS mode and wake up the system.

When setting up this demo to use the PIT, the following changes were needed:

  • Include a PIT ISR to clear its flag
  • Change the VLPS mode to Normal Wait so that the PIT could be used.
  • Add the fsl_pit.c/h files to your "drivers" folder.

I have attached my "C" code.  Only need to make following change to run in the default LPTMR mode or switch to use PIT.

#define LPTMR false        //DES true=LPTMR (default code too), false=PIT (test code)

Look for "//DES" to see all changes and comments.

Regards,

David

1,445 Views
markwyman
Contributor III

I am also having the same problem(s).

I am using Processor Expert in KDS 3.2.0 starting with a PE project for TWR-KV31F120M, but resulting in the same symptoms.

I am attempting to use an accurate timing source so that I can get a regular sample rate in order to analyze data on two analog inputs simultaneously.

I can get the output of the Analog Compares (CMP0_Output, CMP1_Output) to produce regular conversion triggers (driven by an external source). It is the only trigger source I have been able to make work so far, apart from single trigger events using AD#_StartSingleMeasurement(). This told me the code for my analog conversion was OK. The events for AD2_OnMeasurementComplete() and AD1_OnMeasurementComplete() fire regularly and in step with the external signal, as well as conversions occur at the same interval, but only with the comparator outputs.

When I attempt to move the converters over to the FTM2_match trigger source, updating the SIM component so SIM_SOPT7 becomes 0x8A8A, the converters no longer will trigger, the status remains ERR_BUSY when I query. I have an event interrupt generated for the FTM2_CNT On-match to test if the timer referenced component is working, and this event occurs as expected, and I am able to update a counter. No triggered conversion though.

I also tried using a PIT component with the same results. Interrupt fires at a regular rate, but no triggered conversion occurs. SIM_SOPT7 is correctly set (I dump it just before calling AD#_StartLoopTriggeredMeasurement())

This is becoming a very serious issue for me as I sold the customer on this project and dev environment since it should be faster to get something running than the competitor's. Here I sit unable to perform synchronized conversions. A basic function of a digital signal controller used for motor control. Everything else work great, but this is a critical issue.

Granted I am a bit rusty at C code, but this one is looking to be a potential errata since all the registers seem to be OK, unless I am missing some other SIM register that is somehow involved in all of this.

HELP!!!

I will try to generate a stripped-down PE project to post here today that exhibits this problem.

0 Kudos

1,445 Views
markwyman
Contributor III

Well, in the process of creating the stripped-down project, I got the PIT timers to work (but not the FTM counters). It did lead to a discovery why I couldn't get them to work previously though, so perhaps the OP can be helped by this?

I had the PIT timers set up in the same way before I performed this task, but they were not working. It appears that if I have the options set up for Number of Conversions set to something other than 1 (I had 4) when I change the trigger source, the code is not generated properly (timing set too slow on Conversion Time?) or some other type of error. I did not get to the bottom of it as I did not know what to look for. The conversion interval on the PIT timer is set to 100uS, and the single conversion time - Differential is set to <40uS, so there was ample time to finish a 4xconversion before the next trigger event. However, if I set the Number of conversions to 1, generate PE code, test, (works), then set back to 4, it begins to work again without changing anything between the two 4 conversions settings.

So something is fishy in the PE tool that is misleading.

As for the OP, did you intend to have continuous conversions off? I think this should be True if you want the PIT to provide regular timing to your conversions.

adcUserConfig.enableContinuousConversion = false;

1,445 Views
ivadorazinova
NXP Employee
NXP Employee

Hi Gustavo Leal,

I am very sorry for the late response.

We will let you know as soon as possible.

Many thanks for your patience.

Best Regards,

Iva

0 Kudos