K64F ADC0 multichannel with PDB and DMA

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

K64F ADC0 multichannel with PDB and DMA

1,020 Views
jernejturnsek
Contributor I

Hi,

I am sampling two analog channels with ADC0 SC1A and SC1B configuration registers with the help of backtoback mode PDB continuous triggering. Now I would like to transfer results from RA and RB register with the help of eDMA. Reference manual states that DMA trigger signal is asserted during ADC conversion complete event when any of the SC1n COCO flag is asserted, but looking into Example-S32K144-PDB-ADC-back2back-v1_0-S32DS12 source code only one DMA channel is utilized to move both registers at the same time. I feel this could not be the case here, because when SC1A COCO is set DMA is triggered and then also when SC1B COCO is set another DMA trigger is asserted. Thus I would think registers are transferred twice instead of once. Did I have missed something? How should I set DMA?

The code in the example is for another type of processor with 4 channels per ADC, but I think peripherials should be very similar to K64F processor. Maybe I am wrong here.

void PDB_Init(void)

PCC->PCCn[PCC_PDB0_INDEX] |= PCC_PCCn_CGC_MASK; /* Enable bus clock in PDB0 */

PDB0->SC |= PDB_SC_TRGSEL(0xF) | /* b1111: Software trigger is selected */
PDB_SC_PRESCALER(1) | /* Prescaler: 010 = sysclck/(2*MULT) = 80 / (2*1) = 40MHz */
PDB_SC_MULT(0) | /* 00: Multiplication factor is 1. */
PDB_SC_PDBEN_MASK; /* 1: PDB enabled */
PDB0->CH[0].C1 |= PDB_C1_BB(0xe) | /* DLY[0] : pre-trigger from PDB DLY */
/* DLY[3:1] : back-to-back enabled */
PDB_C1_TOS(0x00) | /* Pretrigger Output Select: 0=bypassed , 1=enabled */
PDB_C1_EN(0xf); /* PDB channel's [3:0] pre-trigger enabled */
// PDB0->MOD = 2200;
// PDB0->IDLY = 2200;
// PDB0->CH[0].DLY[0] = 100; /* Pretrigger 0 : 100 * 25e-9 = 2.5e-6 */
PDB0->SC |= PDB_SC_LDOK_MASK;
}

void ADC_Init(void)
{

PCC->PCCn[PCC_ADC0_INDEX] &= ~PCC_PCCn_CGC_MASK; /* Disable clock to change PCS */
PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_PCS(6); /* PCS=3: Select SPLL */
PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_CGC_MASK; /* Enable bus clock in ADC */

ADC0->CFG1 |= ADC_CFG1_ADICLK(0) | /* Only ALTCLK1 is available */
ADC_CFG1_ADIV(2) | /* the clock rate is (input clock)/4 */
ADC_CFG1_MODE(1); /* 0b00: 8-bit, 0b01: 12-bit, 0b10: 10-bit */
ADC0->SC2 |= ADC_SC2_ADTRG(1) | /* Conversion Trigger: 0b0= SW , 0b1 = HW */
ADC_SC2_DMAEN(1); /* enable DMA trigger */

ADC0->SC1[0] = ADC_SC1_ADCH(12); /* Select AD12 (ADC0_SE12) @PTC14 */
ADC0->SC1[1] = ADC_SC1_ADCH(12); /* Select AD12 (ADC0_SE12) @PTC14 */
ADC0->SC1[2] = ADC_SC1_ADCH(12); /* Select AD12 (ADC0_SE12) @PTC14 */
ADC0->SC1[3] = ADC_SC1_ADCH(12); /* Select AD12 (ADC0_SE12) @PTC14 */

}

void DMA_init(void)
{

PCC->PCCn[PCC_DMA0_INDEX] |= PCC_PCCn_CGC_MASK; // CGC=1: Clock enabled for DMA0

DMA->TCD[0].CSR &= 0xFFFFFFFF ^ DMA_TCD_CSR_DONE_MASK; // Clear Channel Done flag
DMA->TCD[0].SADDR = DMA_TCD_SADDR_SADDR(&(ADC0->R[0])); // Source Address
DMA->TCD[0].SOFF = DMA_TCD_SOFF_SOFF(4); // Source Offset
DMA->TCD[0].ATTR = DMA_TCD_ATTR_SMOD(0) | // Source address modulo feature is disabled
DMA_TCD_ATTR_SSIZE(2) | // Source data transfer size: 1: 16-bit, 2=32-bit
DMA_TCD_ATTR_DMOD(0) | // Destination address modulo feature: 0=disabled, x= x power of 2 buffer[DMOD=4->buffer of 16bytes]
DMA_TCD_ATTR_DSIZE(2); // Destination data transfer size: 1: 16-bit, 2=32-bit
DMA->TCD[0].NBYTES.MLOFFNO = DMA_TCD_NBYTES_MLNO_NBYTES(4); // Minor Byte Transfer Count is 4-bytes
DMA->TCD[0].SLAST = DMA_TCD_SLAST_SLAST(-16); // Last Source Address Adjustment is -16
DMA->TCD[0].DADDR = DMA_TCD_DADDR_DADDR(&(result[0])); // Destination Address of Buffer
DMA->TCD[0].DOFF = DMA_TCD_DOFF_DOFF(4); // Destination Address Signed Offset is 4
DMA->TCD[0].CITER.ELINKNO = DMA_TCD_CITER_ELINKNO_CITER(4) // Current Major Iteration Count is 4
| DMA_TCD_CITER_ELINKNO_ELINK(0); // The channel-to-channel linking is disabled
DMA->TCD[0].DLASTSGA = DMA_TCD_DLASTSGA_DLASTSGA(-16); // Destination last address adjustment is -16
DMA->TCD[0].BITER.ELINKNO = DMA_TCD_BITER_ELINKNO_BITER(4) | // Starting major iteration count is 4
DMA_TCD_BITER_ELINKNO_ELINK(0); // The minor channel-to-channel linking is disabled
DMA->TCD[0].CSR = DMA_TCD_CSR_BWC(0) | // BWC=0: No eDMA engine stalls - full bandwidth
DMA_TCD_CSR_MAJORELINK(0) | // The channel-to-channel linking is disabled
DMA_TCD_CSR_MAJORLINKCH(0) | // channel 1 will be called from ch0
DMA_TCD_CSR_ESG(0) | // The current channel�fs TCD is normal format - No scatter/gather
DMA_TCD_CSR_DREQ(0) | // The channel's ERQ bit is not affected
DMA_TCD_CSR_INTHALF(0) | // The half-point interrupt is disabled
DMA_TCD_CSR_INTMAJOR(1) | // The end-of-major loop interrupt is enabled
DMA_TCD_CSR_START(0); // The channel is not explicitly started

DMA->SERQ = 0; // enable DMA channel 0 HW trigger
}


void DMAMUX_Init (void)
{
PCC->PCCn[PCC_DMAMUX0_INDEX] |= PCC_PCCn_CGC_MASK; // CGC=1: Clock enabled for DMAMUX0

DMAMUX->CHCFG[0] &= ~ DMAMUX_CHCFG_ENBL(1); // Disabling the DMA channel
DMAMUX->CHCFG[0] |= DMAMUX_CHCFG_SOURCE(40); // ADC0 COCO is the source of the DMA0 channel
DMAMUX->CHCFG[0] |= DMAMUX_CHCFG_ENBL(1); // Enabling the DMA channel
}

Regards,

Jernej

0 Kudos
2 Replies

574 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Jernej,

I see your concern that both ADC_SC1A and ADC_S1B can trigger DMA if you use DMA transfer, but the DMA itself can not identify the source, which leads to the fact that you can not determine the correct the DMA source address, it is an issue.

https://community.nxp.com/message/927352?commentID=927352#comment-927352

Pls refer to the above ticket.

If you would like to use interrupt mechanism, in backto back mode, you can set only the AIEN bit in ADC_S1B, when an interrupt is triggered, in the ISR, you can read both the ADC_RA and ADC_RB.

If you do use DMA, as above ticket, you can use PDBx_IDLY to trigger DMA, you can use DMA minor loop or minor channel link to transfer ADC_RA and ADC_RB to memory. But you have to arrange the timing correctly for the backtoback ADC triggering and DMA triggering so that the DMA is triggered after the ADC two channels have been finished.

Hope it can help you

BR

Xiangjun Rong

0 Kudos

574 Views
jernejturnsek
Contributor I

Hi,

thank you for the reply. I came to that conclusion also about using PDB DMA triggering and carefully choosing delays. Currently I have managed to use DMA to transfer RA and RB and then trigger DMA interrupt which in turn copy values to some buffer. This is working. But for faster sampling I would need to use PDB DMA. I just regret that I have not chosen one analog channel on ADC0 and one on ADC1. Life would be much simpler then:)

BR,

Jernej

0 Kudos