This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi anyone can do help:
Currently I am working on the F28377D (development tools). I tried to use DMA to read the ADC. Now I have two problems:
1, DMA can be triggered by ADC's interrupt, but each time the ADC's interrupt function will be run with the DMA.
That means the CPU will response each ADC interruption, and the DMA becomes no sense at all.
2, DMA can not read the ADC result registers correctly. In other words, the DMA's registers' value are changing with the ADC interruption, and I can see that the values in source/destination address registers are correct; however, there is no output to the destination variable. --- it may not read the ADC result register, or it may not write the result to the destination variable address.
From the datasheet(TMS320F2837xD Delfino Microcontrollers, Technical Reference Manual), at the DMA part(page591), 'DMA Block Diagram' shows that CPU1/2 Bus can access the ADC result registers, but CPU1/2DMA bus looks like can not.
Thanks for your reading; and if you can answer them, I appreciate it.
-----------------------------------
#include "F28x_Project.h" // Device Headerfile and Examples Include File #include "F2837xD_struct.h" #include "F2837xD_Dma_defines.h" // function prototypes void ConfigureADC(void); void ConfigureEPWM(void); void ConfigureDAC(void); void SetupADCEpwm(void); interrupt void adca1_isr(void); // variables #define RESULTS_BUFFER_SIZE 256 #define MAX_SAMPLES 1024 #define ONE_WORD_BURST 0 // 16-bit word per burst #define TWO_WORD_BURST 1 // 32-bit word per burst #define SOURCE_NO_ADDRESS_CHANGE 0 #define DESTINATION_INCREMENT_ONE_ADDRESS 1 #define TRANSFER_SIZE_256 255 #define TRANSFER_STEP_SOURCE_NO_CHANGE 0 #define TRANSFER_STEP_DEST_INCREMENT_ONE_ADDRESS 1 volatile uint16_t *DMA1Source, *DMA1Dest; volatile Uint16 DMABuf1[RESULTS_BUFFER_SIZE]; //DMA buffer store ADC results __interrupt void local_DMACH1_ISR(void); void DMA_configure(void); volatile uint16_t DMA_Done = 0; Uint16 AdcaResults[RESULTS_BUFFER_SIZE]; Uint16 AdcbResults[RESULTS_BUFFER_SIZE]; Uint16 resultsIndex; Uint16 ToggleCount = 0; Uint16 dacOffset; Uint16 dacOutput; Uint16 sineEnable = 0; extern int QuadratureTable[40]; Uint16 i; void main(void) { // Initialize System Control: PLL, WatchDog, enable Peripheral Clocks InitSysCtrl(); EALLOW; ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV = 0; EDIS; // Initialize GPIO: InitGpio(); // configure default GPIO EALLOW; GpioCtrlRegs.GPADIR.bit.GPIO8 = 1; // used as input to ADC GpioCtrlRegs.GPADIR.bit.GPIO31 = 1; // drives LED LD2 on controlCARD EDIS; GpioDataRegs.GPADAT.bit.GPIO8 = 0; // force GPIO8 output LOW GpioDataRegs.GPADAT.bit.GPIO31 = 1;// turn off LED // Clear all interrupts and initialize PIE vector table: DINT; InitPieCtrl(); IER = 0x0000; IFR = 0x0000; InitPieVectTable(); // Map ISR functions EALLOW; PieVectTable.DMA_CH1_INT = &local_DMACH1_ISR; //function for DMA interrupt 1 PieVectTable.ADCA1_INT = &adca1_isr; EDIS; // Enable global Interrupts and higher priority real-time debug events: // IER = M_INT7 ; //Enable INT7 (7.1 DMA Ch1) EnableInterrupts(); // Configure the ADC and power it up ConfigureADC(); // Configure the ePWM ConfigureEPWM(); // Setup the ADC for ePWM triggered conversions on channel 0 SetupADCEpwm(); //--- Enable the ADC interrupt EALLOW; PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable ADCINT in PIE group 1 IER |= 0x0001; // Enable INT1 in IER to enable PIE group EDIS; DMA_configure(); // Initialize results buffer for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++) { AdcaResults[resultsIndex] = 0; AdcbResults[resultsIndex] = 0; DMABuf1[i] = 0; } resultsIndex = 0; EALLOW; // Sync ePWM CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; EDIS; // Start ePWM EPwm2Regs.TBCTL.bit.CTRMODE = 0; // un-freeze and enter up-count mode do { GpioDataRegs.GPADAT.bit.GPIO31 = 0; // Turn on LED DELAY_US(1000 * 500); // ON delay GpioDataRegs.GPADAT.bit.GPIO31 = 1; // Turn off LED DELAY_US(1000 * 500); // OFF delay } while(1); } void DMA_configure(void) { EALLOW; CpuSysRegs.SECMSEL.bit.VBUS32_1 = 1; EDIS; DMAInitialize(); DMA1Source = &AdcaResultRegs.ADCRESULT0; DMA1Dest = &DMABuf1[0]; //DMA destination; DMACH1AddrConfig(DMA1Dest,DMA1Source); // BURST size = 1 | Source step size = 0 | Dest step size += 1 DMACH1BurstConfig(ONE_WORD_BURST,SOURCE_NO_ADDRESS_CHANGE,DESTINATION_INCREMENT_ONE_ADDRESS); // Transfer size = 0x1000 | Source step size = 0 | Dest step size += 1 DMACH1TransferConfig(TRANSFER_SIZE_256,TRANSFER_STEP_SOURCE_NO_CHANGE, TRANSFER_STEP_DEST_INCREMENT_ONE_ADDRESS); DMACH1WrapConfig(0,0,256,256); DMACH1ModeConfig(DMA_ADCAINT1,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC, OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE); StartDMACH1(); } __interrupt void local_DMACH1_ISR(void) { DMA_Done = 0x0001; EALLOW; PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; DmaRegs.CH1.CONTROL.bit.TRANSFERSTS = 1; DmaRegs.CH1.CONTROL.bit.RUN = 1; EDIS; // ESTOP0; } //Write ADC configurations and power up the ADC for both ADC A and ADC B void ConfigureADC(void) { //Device_cal(); EALLOW; AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // set ADCCLK divider to /4 AdcaRegs.ADCCTL2.bit.RESOLUTION = 0; // 12-bit resolution AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0; // single-ended channel conversions (12-bit mode only) AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // Set pulse positions to late AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // power up the ADC DELAY_US(1000); // delay for 1ms to allow ADC time to power up EDIS; } void ConfigureEPWM(void) { EALLOW; // Assumes ePWM clock is already enabled EPwm2Regs.TBCTL.bit.CTRMODE = 3; // freeze counter EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0; // TBCLK pre-scaler = /1 EPwm2Regs.TBPRD = 0x0FA0; // Set period to 4000 counts (50kHz) EPwm2Regs.CMPA.half.CMPA = 0x0800; // Set compare A value to 2048 counts EPwm2Regs.ETSEL.bit.SOCAEN = 0; // Disable SOC on A group EPwm2Regs.ETSEL.bit.SOCASEL = 4; // Select SOC on up-count EPwm2Regs.ETSEL.bit.SOCAEN = 1; // enable SOCA EPwm2Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event EDIS; } void SetupADCEpwm(void) { EALLOW; AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0 will convert pin A0 AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // sample window is 15 SYSCLK cycles AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 7; // trigger on ePWM2 SOCA/C AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // end of SOC0 will set INT1 flag AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // enable INT1 flag AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // make sure INT1 flag is cleared EDIS; } interrupt void adca1_isr(void) { // Read the ADC result and store in circular buffer AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0; if(RESULTS_BUFFER_SIZE <= resultsIndex) { resultsIndex = 0; } // Return from interrupt AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // Clear INT1 flag PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // acknowledge PIE group 1 to enable further interrupts } // end of file
Hi King Kong,
DMA doesn't have access to every memory location. One safe location to use for DMA is the global shared memory (GS). This means in your code, you have to link the DMA buffer into one of the GSM eg: RAMGS0.
I added this line->
#pragma
DATA_SECTION(DMABuf1,"SecureRam0");
Uint16 DMABuf1[RESULTS_BUFFER_SIZE];
I have attached the code with the changes. This should work. You also have to add a line like this to your linker file in the "SECTIONS" section
#include "F28x_Project.h" // Device Headerfile and Examples Include File //#include "F2837xD_struct.h" //#include "F2837xD_Dma_defines.h" // function prototypes void ConfigureADC(void); void ConfigureEPWM(void); void ConfigureDAC(void); void SetupADCEpwm(void); interrupt void adca1_isr(void); // variables #define RESULTS_BUFFER_SIZE 256 #define MAX_SAMPLES 1024 #define ONE_WORD_BURST 0 // 16-bit word per burst #define TWO_WORD_BURST 1 // 32-bit word per burst #define SOURCE_NO_ADDRESS_CHANGE 0 #define DESTINATION_INCREMENT_ONE_ADDRESS 1 #define TRANSFER_SIZE_256 255 #define TRANSFER_STEP_SOURCE_NO_CHANGE 0 #define TRANSFER_STEP_DEST_INCREMENT_ONE_ADDRESS 1 volatile uint16_t *DMA1Source, *DMA1Dest; #pragma DATA_SECTION(DMABuf1,"SecureRam0"); Uint16 DMABuf1[RESULTS_BUFFER_SIZE]; //DMA buffer store ADC results __interrupt void local_DMACH1_ISR(void); void DMA_configure(void); volatile uint16_t DMA_Done = 0; Uint16 AdcaResults[RESULTS_BUFFER_SIZE]; Uint16 AdcbResults[RESULTS_BUFFER_SIZE]; Uint16 resultsIndex; Uint16 ToggleCount = 0; Uint16 dacOffset; Uint16 dacOutput; Uint16 sineEnable = 0; extern int QuadratureTable[40]; Uint16 i; void main(void) { // Initialize System Control: PLL, WatchDog, enable Peripheral Clocks InitSysCtrl(); EALLOW; ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV = 0; EDIS; /* // Initialize GPIO: InitGpio(); // configure default GPIO EALLOW; GpioCtrlRegs.GPADIR.bit.GPIO8 = 1; // used as input to ADC GpioCtrlRegs.GPADIR.bit.GPIO31 = 1; // drives LED LD2 on controlCARD EDIS; GpioDataRegs.GPADAT.bit.GPIO8 = 0; // force GPIO8 output LOW GpioDataRegs.GPADAT.bit.GPIO31 = 1;// turn off LED */ // Configure the ADC and power it up ConfigureADC(); // Configure the ePWM ConfigureEPWM(); // Setup the ADC for ePWM triggered conversions on channel 0 SetupADCEpwm(); //--- Enable the ADC interrupt DMA_configure(); // Clear all interrupts and initialize PIE vector table: DINT; InitPieCtrl(); IER = 0x0000; IFR = 0x0000; InitPieVectTable(); // Map ISR functions EALLOW; PieVectTable.DMA_CH1_INT = &local_DMACH1_ISR; //function for DMA interrupt 1 PieVectTable.ADCA1_INT = &adca1_isr; EDIS; EALLOW; IER |= M_INT1; // Enable CPU Interrupt 1 IER |= M_INT10; // Enable CPU Interrupt 10 EINT; // Enable Global interrupt INTM ERTM; PieCtrlRegs.PIEIER1.all = 0xFFFF; // Enable INT 1 in the PIE // Initialize results buffer for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++) { AdcaResults[resultsIndex] = 0; AdcbResults[resultsIndex] = 0; DMABuf1[i] = 0; } resultsIndex = 0; EALLOW; // Sync ePWM CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; EDIS; // Start ePWM EPwm2Regs.TBCTL.bit.CTRMODE = 0; // un-freeze and enter up-count mode /* do { GpioDataRegs.GPADAT.bit.GPIO31 = 0; // Turn on LED DELAY_US(1000 * 500); // ON delay GpioDataRegs.GPADAT.bit.GPIO31 = 1; // Turn off LED DELAY_US(1000 * 500); // OFF delay }*/ StartDMACH1(); while(1); } void DMA_configure(void) { EALLOW; CpuSysRegs.SECMSEL.bit.VBUS32_1 = 1; EDIS; DMAInitialize(); DMA1Source = &AdcaResultRegs.ADCRESULT0; DMA1Dest = &DMABuf1[0]; //DMA destination; DMACH1AddrConfig(DMA1Dest,DMA1Source); // BURST size = 1 | Source step size = 0 | Dest step size += 1 DMACH1BurstConfig(ONE_WORD_BURST,SOURCE_NO_ADDRESS_CHANGE,DESTINATION_INCREMENT_ONE_ADDRESS); // Transfer size = 0x1000 | Source step size = 0 | Dest step size += 1 DMACH1TransferConfig(TRANSFER_SIZE_256,TRANSFER_STEP_SOURCE_NO_CHANGE, TRANSFER_STEP_DEST_INCREMENT_ONE_ADDRESS); DMACH1WrapConfig(0,0,256,256); DMACH1ModeConfig(DMA_ADCAINT1,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC, OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE); StartDMACH1(); } __interrupt void local_DMACH1_ISR(void) { DMA_Done = 0x0001; EALLOW; PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; DmaRegs.CH1.CONTROL.bit.TRANSFERSTS = 1; DmaRegs.CH1.CONTROL.bit.RUN = 1; EDIS; // ESTOP0; } //Write ADC configurations and power up the ADC for both ADC A and ADC B void ConfigureADC(void) { //Device_cal(); EALLOW; AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // set ADCCLK divider to /4 AdcaRegs.ADCCTL2.bit.RESOLUTION = 0; // 12-bit resolution AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0; // single-ended channel conversions (12-bit mode only) AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // Set pulse positions to late AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // power up the ADC DELAY_US(1000); // delay for 1ms to allow ADC time to power up EDIS; } void ConfigureEPWM(void) { EALLOW; // Assumes ePWM clock is already enabled EPwm2Regs.TBCTL.bit.CTRMODE = 3; // freeze counter EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0; // TBCLK pre-scaler = /1 EPwm2Regs.TBPRD = 0x0FA0; // Set period to 4000 counts (50kHz) EPwm2Regs.CMPA.half.CMPA = 0x0800; // Set compare A value to 2048 counts EPwm2Regs.ETSEL.bit.SOCAEN = 0; // Disable SOC on A group EPwm2Regs.ETSEL.bit.SOCASEL = 4; // Select SOC on up-count EPwm2Regs.ETSEL.bit.SOCAEN = 1; // enable SOCA EPwm2Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event EDIS; } void SetupADCEpwm(void) { EALLOW; AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0 will convert pin A0 AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // sample window is 15 SYSCLK cycles AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 7; // trigger on ePWM2 SOCA/C AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // end of SOC0 will set INT1 flag AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // enable INT1 flag AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // make sure INT1 flag is cleared EDIS; } interrupt void adca1_isr(void) { // Read the ADC result and store in circular buffer AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0; if(RESULTS_BUFFER_SIZE <= resultsIndex) { resultsIndex = 0; } // Return from interrupt AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // Clear INT1 flag PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // acknowledge PIE group 1 to enable further interrupts } // end of file
SecureRam0 : > RAMGS0 PAGE = 1
Regards,
Frank
Hi Frank,
Thanks again, your advice is working very well.
Now I'm moving to seek a way to avoid the calling of ADC's interruption function with every EOC.
Bests,
King
Hi King Kong,
Glad i could help. About the ADC, i'm not exactly sure what you are trying to achieve with it but looking through your code, it looks like you want to oversample one channel. To avoid calling the ADC interrupt after every EOC, you could setup SOC1-SOC15 to sample the same channel (this is effectively oversampling) and setup the ADC interrupt to trigger after EOC15. Keep in mind that if you do it this way, you would have to reconfigure the DMA to transfer 16 words after every trigger instead of just 1.
Regards,
Frank
Dear Frank,
I got the same result by myself, and it is similar you suggested.
Basically I am using EPwm2.SOCA to trigger the ADC, and at the same time, use the same SOCA to trigger the DMA. Since the ADC result will have one trigger delay, the first value read by DMA has no meaning (trigger1->DMA read0 and ADC convert1; trigger2->DMA read1 and ADC convert2, and so on). In this case I disabled the interrupt of ADC(from EOC), so the ADC interrupt function will not be called anymore.
Thanks a lot for your help, I appreciate. Have a good day :)
Sincerely,
King