Example S32K144 PDB ADC DMA S32DS.ARM.2018.R1

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

Example S32K144 PDB ADC DMA S32DS.ARM.2018.R1

Example S32K144 PDB ADC DMA S32DS.ARM.2018.R1

Detailed Description:

Example shows possible implementation of multiple ADC conversions using SDK.
Here 25 channels are sampled periodically. 

2 ADC modules and 2 PDBs are used.
ADC0 is configured to sample 16 channels, ADC1 9 channels.
PDBs are set to back-to-back mode to perform chain conversion.
Within ADC component you need to select ADC input to be measured for each item
in configuration list. For ADC0 channels ADC ch12 is selected, as it is connected
to trimmer on the EVB.
DMA is used to read result into single buffer, and DMA callbacks are issued
to indicate end of transfer for each ADC module.
Within those callbacks PTE14 and PTE15 is toggled.
PDB0 output pulse is generated on the PTE16 to indicate start of ADC measurement.
This is done periodically at LPIT ch0 rate, which is set to 30us.

The ADC0 ch0 result is used to dim LEDs.

* ------------------------------------------------------------------------------
* Test HW:       S32K144EVB-Q100
* MCU:           FS32K144UAVLL 0N57U
* Target:        Debug_FLASH
* EVB connection:
* Compiler:      S32DS.ARM.2018.R1
* SDK release:   S32SDK_S32K1xx_RTM_3.0.0
* Debugger:      Lauterbach Trace32
Revision History:
Ver Date          Author          Description of Changes
0.1 May-04-2019   Petr Stancik    Initial version
Labels (1)

Many thanks, I am debugging multiple adc channels and dma transfer!

This example is just what i need! This speeds up my application development a lot!
I am using 3 channels on ADC0 and 30 channels from ADC1 on S32K148. This example is using ADC R register array, which has size of 16. What would be correct way to set this up?  Using aR registers?


Nevermind, i got it working using aR registers.

I am using PDLY_TIMEOUT with value 50UL on app_init.h and LPIT timer period of 400, so buffer gets update at rate of 20KHz.

Only using ch0 on PDB0, and using channels 0,1,2 and 3 on PDB1, each channel triggered 10µs after another.

app_init.c looks like this:

#include "app_init.h"
void PDB0_init(void);
void PDB1_init(void);

uint16_t delayValue;
extern uint16_t buffer[33];
extern uint16_t value;

/* configuration structures for simple loop transfers */
edma_loop_transfer_config_t loopConfig = {
    .majorLoopIterationCount = 0,
    .srcOffsetEnable = false,
    .dstOffsetEnable = false,
    .minorLoopOffset = 0,
    .minorLoopChnLinkEnable = false,
    .minorLoopChnLinkNumber = 0,
    .majorLoopChnLinkEnable = false,
    .majorLoopChnLinkNumber = 0

edma_transfer_config_t transferConfig = {
    .srcAddr = 0,
    .destAddr = 0,
    .srcTransferSize = EDMA_TRANSFER_SIZE_2B,
    .destTransferSize = EDMA_TRANSFER_SIZE_2B,
    .srcOffset= 4,
    .destOffset = 2,
    .srcLastAddrAdjust = 0,
    .destLastAddrAdjust = 0,
    .srcModulo = EDMA_MODULO_OFF,
    .destModulo = EDMA_MODULO_OFF,
    .minorByteTransferCount = 2,
    .scatterGatherEnable = false,
    .scatterGatherNextDescAddr = 0,
    .interruptEnable = true,
    .loopTransferConfig = &loopConfig

void ADC0_Init(void)

    ADC_DRV_ConfigConverter(INST_ADCONV0, &adConv0_ConvConfig0);

    ADC_DRV_ConfigChan(INST_ADCONV0, 0UL, &adConv0_ChnConfig0);
    ADC_DRV_ConfigChan(INST_ADCONV0, 1UL, &adConv0_ChnConfig1);
    ADC_DRV_ConfigChan(INST_ADCONV0, 2UL, &adConv0_ChnConfig2);

void ADC1_Init(void)

    ADC_DRV_ConfigConverter(INST_ADCONV1, &adConv1_ConvConfig0);

    ADC_DRV_ConfigChan(INST_ADCONV1, 0UL, &adConv1_ChnConfig0);
    ADC_DRV_ConfigChan(INST_ADCONV1, 1UL, &adConv1_ChnConfig1);
    ADC_DRV_ConfigChan(INST_ADCONV1, 2UL, &adConv1_ChnConfig2);
    ADC_DRV_ConfigChan(INST_ADCONV1, 3UL, &adConv1_ChnConfig3);
    ADC_DRV_ConfigChan(INST_ADCONV1, 4UL, &adConv1_ChnConfig4);
    ADC_DRV_ConfigChan(INST_ADCONV1, 5UL, &adConv1_ChnConfig5);
    ADC_DRV_ConfigChan(INST_ADCONV1, 6UL, &adConv1_ChnConfig6);
    ADC_DRV_ConfigChan(INST_ADCONV1, 7UL, &adConv1_ChnConfig7);
    ADC_DRV_ConfigChan(INST_ADCONV1, 8UL, &adConv1_ChnConfig8);
    ADC_DRV_ConfigChan(INST_ADCONV1, 9UL, &adConv1_ChnConfig9);
    ADC_DRV_ConfigChan(INST_ADCONV1, 10UL, &adConv1_ChnConfig10);
    ADC_DRV_ConfigChan(INST_ADCONV1, 11UL, &adConv1_ChnConfig11);
    ADC_DRV_ConfigChan(INST_ADCONV1, 11UL, &adConv1_ChnConfig11);
    ADC_DRV_ConfigChan(INST_ADCONV1, 12UL, &adConv1_ChnConfig12);
    ADC_DRV_ConfigChan(INST_ADCONV1, 13UL, &adConv1_ChnConfig13);
    ADC_DRV_ConfigChan(INST_ADCONV1, 14UL, &adConv1_ChnConfig14);
    ADC_DRV_ConfigChan(INST_ADCONV1, 15UL, &adConv1_ChnConfig15);
    ADC_DRV_ConfigChan(INST_ADCONV1, 16UL, &adConv1_ChnConfig16);
    ADC_DRV_ConfigChan(INST_ADCONV1, 17UL, &adConv1_ChnConfig17);
    ADC_DRV_ConfigChan(INST_ADCONV1, 18UL, &adConv1_ChnConfig18);
    ADC_DRV_ConfigChan(INST_ADCONV1, 19UL, &adConv1_ChnConfig19);
    ADC_DRV_ConfigChan(INST_ADCONV1, 20UL, &adConv1_ChnConfig20);
    ADC_DRV_ConfigChan(INST_ADCONV1, 21UL, &adConv1_ChnConfig21);
    ADC_DRV_ConfigChan(INST_ADCONV1, 22UL, &adConv1_ChnConfig22);
    ADC_DRV_ConfigChan(INST_ADCONV1, 23UL, &adConv1_ChnConfig23);
    ADC_DRV_ConfigChan(INST_ADCONV1, 24UL, &adConv1_ChnConfig24);
    ADC_DRV_ConfigChan(INST_ADCONV1, 25UL, &adConv1_ChnConfig25);
    ADC_DRV_ConfigChan(INST_ADCONV1, 26UL, &adConv1_ChnConfig26);
    ADC_DRV_ConfigChan(INST_ADCONV1, 27UL, &adConv1_ChnConfig27);
    ADC_DRV_ConfigChan(INST_ADCONV1, 28UL, &adConv1_ChnConfig28);
    ADC_DRV_ConfigChan(INST_ADCONV1, 29UL, &adConv1_ChnConfig29);

void PDB0_init()
    PDB_DRV_Init(INST_PDB0, &pdb0_InitConfig0);

    // config 8 pretriggers on ch0 based on component setting
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB0, 0UL, &pdb0_AdcTrigInitConfig0);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB0, 0UL, &pdb0_AdcTrigInitConfig1);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB0, 0UL, &pdb0_AdcTrigInitConfig2);

    // set PDB0 counter period to delayValue
    PDB_DRV_SetTimerModulusValue(INST_PDB0, (uint32_t) delayValue);
    // set ch0 trigger0 delay to happen immediate upon Trigger_In 0 (PIT0 ch0)
    PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB0, 0UL, 0UL,(uint32_t) (1));
    PDB_DRV_SetCmpPulseOutDelayForHigh(INST_PDB0, 0L , 0);
    PDB_DRV_SetCmpPulseOutDelayForLow(INST_PDB0, 0L, delayValue/PDLY_TIMEOUT);
    PDB_DRV_SetCmpPulseOutEnable(INST_PDB0, 1<<0, true);


void PDB1_init()
    PDB_DRV_Init(INST_PDB1, &pdb1_InitConfig0);

    // config 8 pretriggers on ch0 based on component setting
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig0);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig1);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig2);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig3);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig4);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig5);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig6);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 0UL , &pdb1_AdcTrigInitConfig7);
    // config 8 pretrigger on ch1 based on component setting
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig0);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig1);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig2);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig3);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig4);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig5);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig6);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 1UL , &pdb1_AdcTrigInitConfig7);
    // config 8 pretrigger on ch2 based on component setting
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig0);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig1);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig2);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig3);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig4);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig5);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig6);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 2UL , &pdb1_AdcTrigInitConfig7);
    // config 6 pretrigger on ch3 based on component setting
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 3UL , &pdb1_AdcTrigInitConfig0);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 3UL , &pdb1_AdcTrigInitConfig1);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 3UL , &pdb1_AdcTrigInitConfig2);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 3UL , &pdb1_AdcTrigInitConfig3);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 3UL , &pdb1_AdcTrigInitConfig4);
    PDB_DRV_ConfigAdcPreTrigger(INST_PDB1, 3UL , &pdb1_AdcTrigInitConfig5);

    // set PDB1 counter period to delayValue (~30us)
    PDB_DRV_SetTimerModulusValue(INST_PDB1,(uint32_t) delayValue);
    // set ch0 trigger delay to happen immediate upon Trigger_In 0 (PIT0 ch0)
    PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB1, 0UL , 0UL , (uint32_t) (1));
    // set ch1 trigger0 delay to happen 10us upon Trigger_In 0 (PIT0 ch0)
    PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB1, 1UL , 0UL , (uint32_t) (10*delayValue/PDLY_TIMEOUT));
    // set ch2 trigger0 delay to happen 20us upon Trigger_In 0 (PIT0 ch0)
    PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB1, 2UL , 0UL , (uint32_t) (20*delayValue/PDLY_TIMEOUT));
    // set ch3 trigger0 delay to happen 30us upon Trigger_In 0 (PIT0 ch0)
    PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB1, 3UL , 0UL , (uint32_t) (30*delayValue/PDLY_TIMEOUT));



/* This function triggers a loop memory-to-memory transfer. */
void triggerLoopTransfer(uint8_t channel, uint8_t * srcBuff, uint16_t * dstBuff, uint32_t size)
    //transferComplete = false;

    dma_request_source_t DmaReq;

    /* configure transfer source and destination addresses */
    transferConfig.srcAddr                 = (uint32_t)srcBuff;
    transferConfig.destAddr             = (uint32_t)dstBuff;
    transferConfig.srcLastAddrAdjust     = -(4*size);
    transferConfig.destLastAddrAdjust    = -(2*size);
    loopConfig.majorLoopIterationCount    = size;

    if(channel == 0)
        DmaReq = EDMA_REQ_ADC0;
        DmaReq = EDMA_REQ_ADC1;

    /* configure the eDMA channel for a loop transfer (via transfer configuration structure */
    EDMA_DRV_ConfigLoopTransfer(channel, &transferConfig);

    /* select hw request */
    EDMA_DRV_SetChannelRequestAndTrigger(channel, DmaReq, false);

    /* start the channel */

// DMA channel0 callback
void DMA_ADC0_CHANNEL0(void *parameter, edma_chn_status_t status)

    value = buffer[0];



// DMA channel1 callback
void DMA_ADC1_CHANNEL1(void *parameter, edma_chn_status_t status)



void DMA_Init(void)
    EDMA_DRV_Init(&dmaController1_State, &dmaController1_InitConfig0, edmaChnStateArray, edmaChnConfigArray, EDMA_CONFIGURED_CHANNELS_COUNT);

    // set DMA ch0 to read first 3 ADC0 Results registers and move it to buffer array starting from 1st element
    triggerLoopTransfer(DMA_CHANNEL0, (uint8_t *)&(ADC0->aR[0]),buffer, 3);
    // set DMA ch1 to read first 30 ADC1 Results registers and move it to buffer array starting from 4th element
    triggerLoopTransfer(DMA_CHANNEL1, (uint8_t *)&(ADC1->aR[0]),&buffer[3],30);

void app_init(void)


    if(!calculateIntValue(&pdb0_InitConfig0, PDLY_TIMEOUT, &delayValue))
        /* Stop the application flow */



    // Initialize TRGMUX to route LPIT0 ch0 trigger to both PDBs and PDB's OUT pulse to TRGMUX out7
    TRGMUX_DRV_Init(INST_TRGMUX1, &trgmux1_InitConfig0);

    // Initialize LPIT instance 0. Reset and enable peripheral
    LPIT_DRV_Init(INST_LPIT1, &lpit1_InitConfig);
    // Initialize LPIT channel 0 to generate trigger for PDB via TRGMUX
    LPIT_DRV_InitChannel(INST_LPIT1, 0, &lpit1_ChnConfig0);
    // Start LPIT0 channel 0 counter
    LPIT_DRV_StartTimerChannels(INST_LPIT1, 1);



100% helpful (1/1)
Version history
Last update:
‎09-10-2020 01:43 AM
Updated by: