KL27 - Read multiple ADCs + DMA

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

KL27 - Read multiple ADCs + DMA

611 Views
johnbozza
Contributor I

Hi,

I am reading an ADC connected to a DMA at 20Khz at input A, triggered by PIT. However I need to read other 03 ADCs at 100Hz.

Is not possible to squeeze these 03 adc readings in between DMA interrupts because the 20KHz ADC start to miss some bytes. Input B is only hardware triggered and I am not able to get readings from those other 03 ADCs from a simple timer.

Does anyone have a sample code with a similar solution?

Thank you so much,

John

0 Kudos
2 Replies

356 Views
vicentegomez
NXP TechSupport
NXP TechSupport

Hi

I check in all the samples code that we have but we do not have such example code. I'm really sorry.

Have a good day.

0 Kudos

356 Views
mjbcswitzerland
Specialist V

Hi

This solution is integrated in the uTasker Kinetis project as described at https://community.nxp.com/thread/446206

For example, the following sets TPM1 channels 0 and 1 to perform 20kHz sampling with one fixed input (ADC0-SE8) saving to a RAM buffer (sADC_buffer) by DMA. A PIT interrupt is then used to sample the B input

    PWM_INTERRUPT_SETUP pwm_setup;                                       // pwm configuration parameters
    PIT_SETUP pit_setup;                                                 // PIT interrupt configuration parameters
    ADC_SETUP adc_setup;                                                 // interrupt configuration parameters
    adc_setup.int_type = ADC_INTERRUPT;                                  // identifier when configuring
    adc_setup.dma_int_priority = 3;                                      // priority of DMA interrupt the user wants to set
    adc_setup.dma_int_handler = 0;                                       // no interrupt so that free-running circular buffer is used (when ADC_FULL_BUFFER_DMA_AUTO_REPEAT is not defined)
    adc_setup.ucDmaTriggerSource = DMAMUX0_CHCFG_SOURCE_TPM1_OVERFLOW;   // trigger DMA TPM overflows
    adc_setup.ucDmaChannel = 2;                                          // DMA channel 2 used
    adc_setup.int_adc_mode = (ulCalibrate | ADC_FULL_BUFFER_DMA | ADC_HALF_BUFFER_DMA | ADC_SELECT_INPUTS_A | ADC_CLOCK_BUS_DIV_2 | ADC_CLOCK_DIVIDE_8 | ADC_SAMPLE_ACTIVATE_LONG | ADC_CONFIGURE_ADC | ADC_REFERENCE_VREF | ADC_CONFIGURE_CHANNEL | ADC_SINGLE_ENDED_INPUT | ADC_SINGLE_SHOT_MODE | ADC_12_BIT_MODE | ADC_HW_TRIGGERED); // hardware triggering (DMA to buffer)
    adc_setup.int_adc_mode |= ADC_FULL_BUFFER_DMA_AUTO_REPEAT;           // automated DMA (using interrupt) restart when not using modulo repetitions
    adc_setup.pga_gain = PGA_GAIN_OFF;                                   // PGA gain can be specified for certain inputs
    adc_setup.int_adc_controller = 0;                                    // ADC controller 0
    adc_setup.int_adc_int_type = (ADC_SINGLE_SHOT_TRIGGER_INT);          // interrupt type
    adc_setup.int_adc_offset = 0;                                        // no offset
    adc_setup.int_adc_bit = ADC_SE8_SINGLE;                              // input A to sample
    adc_setup.ptrADC_Buffer = sADC_buffer;                               // ADC sample buffer to be used
    adc_setup.ulADC_buffer_length = sizeof(sADC_buffer);                 // physical length of the buffer
    adc_setup.dma_int_handler = 0;                                       // no user DMA interrupt call-back
    adc_setup.int_adc_sample = (ADC_SAMPLE_LONG_PLUS_12 | ADC_SAMPLE_AVERAGING_8); // additional sampling clocks and hardware averaging
    adc_setup.int_adc_bit_b = ADC_TEMP_SENSOR;                           // input B is only valid when using HW triggered mode
    adc_setup.int_adc_result = 0;                                        // no result is requested
    fnConfigureInterrupt((void *)&adc_setup);                            // configure ADC

    pwm_setup.int_type = PWM_INTERRUPT;
    pwm_setup.pwm_mode = (PWM_SYS_CLK | PWM_PRESCALER_16 | PWM_CENTER_ALIGNED | PWM_DMA_PERIOD_ENABLE | PWM_NO_OUTPUT); // clock PWM timer from the system clock with /16 pre-scaler (don't use an output)
    pwm_setup.int_handler = 0;                                           // no user interrupt call-back on PWM cycle
    pwm_setup.pwm_frequency = PWM_FREQUENCY(20000, 16);                  // generate 20kHz on PWM output (/16 pre-scaler)
    pwm_setup.pwm_value = _PWM_PERCENT(1, pwm_setup.pwm_frequency);      // 1% PWM (high/low)
    pwm_setup.pwm_reference = (_TIMER_1 | 0);                            // timer module 1, channel 0 (triggers ADC0 input A)
    fnConfigureInterrupt((void *)&pwm_setup);
    pwm_setup.pwm_value = _PWM_PERCENT(99, pwm_setup.pwm_frequency);     // 99% PWM (high/low)
    pwm_setup.pwm_reference = (_TIMER_1 | 1);                            // timer module 1, channel 1 (triggers ADC0 input B)
    fnConfigureInterrupt((void *)&pwm_setup);

    pit_setup.int_type = PIT_INTERRUPT;
    pit_setup.mode = PIT_PERIODIC;
    pit_setup.ucPIT = 0;                                                 // use PIT0
    pit_setup.int_handler = slow_sample;
    pit_setup.int_priority = PIT0_INTERRUPT_PRIORITY;
    pit_setup.count_delay = PIT_MS_DELAY(5);                             // 5ms period
    fnConfigureInterrupt((void *)&pit_setup);                            // configure PIT


The PIT interrupt can cycle through 4 x B inputs using (eg. of ADC0-SE4, ADC0-SE12 ADC0-Differential, temperature sensor sequence)

#define MUX_INPUT_COUNT    4
static const unsigned long ulNextMuxInput[MUX_INPUT_COUNT] = {
    ADC_SE4_SINGLE, ADC_SE12_SINGLE, (ADC_D3_DIFF | ADC_SC1A_DIFF), ADC_TEMP_SENSOR
};
static unsigned short usLastSample[MUX_INPUT_COUNT];

static void slow_sample(void)                   // PIT interrupt called periodically to collect result and set next mux input 
{
    static int InputMuxSelect = 0;
    usLastSample[InputMuxSelect] = ADC0_RB;     // read the result of the previous B input sample
    if (++InputMuxSelect >= MUX_INPUT_COUNT) {  // cycle though inputs
        InputMuxSelect = 0;                     // set back to the first input
    }
    ADC0_SC1B = ulNextMuxInput[InputMuxSelect]; // set next B input to be sampled
}


Regards

Mark


Professional support for Kinetis: http://www.utasker.com/index.html
Remote desktop one-on-one coaching: http://www.utasker.com/services.html
Getting started to expert videos: https://www.youtube.com/results?search_query=utasker+shorts

0 Kudos