Has anyone had fun with the DMA function on PortentaH7. I am using a code where my ADC is converting based on a timer TRGO and the data is supposed to be sent to the buffer I defined in memory yet I do not read the data at the specified address even though the interrupt for the DMA transfer complete is triggered. Here is my code :
/*************Function prototype************/
void ADC_Init();
void ADC_Start();
void DMA_Config();
void VREFBUF_Init();
void AC_TIMER1_Init();
/*************Variables********************/
int updateEV = 0;
int DMABuffered = 0;
int Eosmp = 0;
int Eocie = 0;
int Eos = 0;
int DMAError=0;
int valADC=0;
bool TCpair=true;
/*************BUFFER***********************/
volatile uint16_t BufferADC1[10];
volatile uint16_t BufferADC2[10];
void setup() {
// put your setup code here, to run once:
//#ifdef CORE_CM7
//bootM4();
VREFBUF_Init();
DMA_Config();
AC_TIMER1_Init();
ADC_Init();
ADC_Start();
//#endif
}
void loop() {
//#ifdef CORE_CM7
// put your main code here, to run repeatedly:
Serial.print("TCpair: ");
Serial.print(TCpair);
Serial.print(" Eosmp : ");
Serial.print(Eosmp);
Serial.print(" valADC : ");
Serial.print(valADC);
// Serial.print(" updateEV : ");
// Serial.print(updateEV);
Serial.print(" DMA_Buffered : ");
Serial.print(DMABuffered);
Serial.print(" DMA_Error : ");
Serial.println(DMAError);
//#endif
//#ifdef CORE_CM4
if(TCpair){
valADC=BufferADC1[1];
digitalWrite(LEDG,LOW);
}else{
valADC=BufferADC2[1];
digitalWrite(LEDG,HIGH);
}
// //#endif
}
void VREFBUF_Init(void) {
SET_BIT(RCC->APB4ENR, RCC_APB4ENR_VREFEN_Msk);
delay(1000);
SET_BIT(VREFBUF->CSR, VREFBUF_CSR_ENVR_Msk);
CLEAR_BIT(VREFBUF->CSR, VREFBUF_CSR_HIZ_Msk);
while (VREFBUF_CSR_VRR & VREFBUF_CSR_VRR_Msk != 1) {
// dataFromRegister=READ_REG(VREFBUF->CSR);
// Serial.println(dataFromRegister,BIN);
}
}
void DMA_Config(void) {
/************DMA CLock Enable******************/
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_DMA1EN_Msk);
delay(1000);
/***************P2M****************************/
CLEAR_BIT(DMA1_Stream1->CR, DMA_SxCR_DIR_0 | DMA_SxCR_DIR_1);
/******************Disable FIFO*************************/
//LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_1);
//LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE);
/******************Memory size**************************/
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_MSIZE_0);
CLEAR_BIT(DMA1_Stream1->CR, DMA_SxCR_MSIZE_1);
/******************MEM Increment**********************/
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_MINC_Msk);
/******************MEM Address to buffer**************/
DMA1_Stream1->M0AR =(uint32_t)&BufferADC1;//0x30000000;
DMA1_Stream1->M1AR =(uint32_t)&BufferADC2;//0x30000000;
/*******************Number of data transfer***********/
SET_BIT(DMA1_Stream1->NDTR,DMA_SxNDT_3 | DMA_SxNDT_1);
/***********************DMA Mode**********************/
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_CIRC_Msk);//circular
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_DBM_Msk);//Double Buffer Mode
/*******************Flow controller*******************/
//SET_BIT(DMA1_Stream1->CR, DMA_SxCR_PFCTRL_Msk);//ADC in control
/******************Periph size************************/
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_PSIZE_0);
CLEAR_BIT(DMA1_Stream1->CR, DMA_SxCR_PSIZE_1);
/******************Peripheral no Increment*************/
CLEAR_BIT(DMA1_Stream1->CR, DMA_SxCR_PINCOS_Msk);
/******************Periph request**********************/
SET_BIT(DMAMUX1_Channel1->CCR, DMAMUX_CxCR_DMAREQ_ID_1 | DMAMUX_CxCR_DMAREQ_ID_3);//adc2_dma
// SET_BIT(DMAMUX1_Channel1->CCR, DMAMUX_CxCR_SYNC_ID_0 | DMAMUX_CxCR_SYNC_ID_1 | DMAMUX_CxCR_SYNC_ID_2);//TIM12_TRGO
// SET_BIT(DMAMUX1_Channel1->CCR, DMAMUX_CxCR_SPOL_0);//rising edge
// DMAMUX1_Channel1->CCR = 0; //Number of requests after synchro (add 1 to the reg value)
// SET_BIT(DMAMUX1_Channel1->CCR, DMAMUX_CxCR_EGE_Msk);//Event Generation end of synchro req
// SET_BIT(DMAMUX1_Channel1->CCR, DMAMUX_CxCR_SE_Msk);//Synchro Enable
/******************Periph address***********************/
DMA1_Stream1->PAR = (uint32_t)&ADC2->DR;
/******************TC IT********************************/
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_TCIE_Msk | DMA_SxCR_TEIE_Msk); //TC IT
DMA1->LIFCR = DMA_LIFCR_CTCIF1;//Clear IT in LISR Register
NVIC_SetVector(DMA1_Stream1_IRQn, (uint32_t)&DMA1_Stream1_IRQHandler);
NVIC_EnableIRQ(DMA1_Stream1_IRQn);
/*******************Enable DMA****************************/
SET_BIT(DMA1_Stream1->CR, DMA_SxCR_EN_Msk);
}
void DMA1_Stream1_IRQHandler(void) {
if (DMA1->LISR & DMA_LISR_TCIF1 ) {
DMABuffered = DMABuffered + 1;
TCpair=!TCpair;
//valADC=BufferADC[0];
DMA1->LIFCR = DMA_LIFCR_CTCIF1;
}
if(DMA1->LISR & DMA_LISR_TEIF1 ){
DMAError = DMAError +1;
DMA1->LIFCR = DMA_LIFCR_CTEIF1;
}
}
void ADC_Init(void) {
/*******************Horloges**************************/
SET_BIT(RCC->APB4ENR, RCC_APB4ENR_SYSCFGEN_Msk); //SYSCFG clock
delay(1000);
SET_BIT(RCC->APB4ENR, RCC_APB4ENR_RTCAPBEN_Msk); //RTCAPB clock
delay(1000);
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_ADC12EN_Msk); //ADC12 clocks
delay(1000);
SET_BIT(RCC->AHB4ENR, RCC_AHB4ENR_GPIOAEN_Msk); //GPIOA clock
delay(1000);
/********************Port config************************/
SET_BIT(GPIOA->MODER, GPIO_MODER_MODE1_0);
SET_BIT(GPIOA->MODER, GPIO_MODER_MODE1_1);
CLEAR_BIT(GPIOA->PUPDR, GPIO_PUPDR_PUPD1_0);
CLEAR_BIT(GPIOA->PUPDR, GPIO_PUPDR_PUPD1_1);
SET_BIT(SYSCFG->PMCR, SYSCFG_PMCR_PA0SO_Msk);
delay(1000);//PA0_C in analog mode
/********************ADC voltage regulator***************/
CLEAR_BIT(ADC2->CR, ADC_CR_DEEPPWD_Msk); //END DEEPPWD
SET_BIT(ADC2->CR, ADC_CR_ADVREGEN_Msk); //ENABLE ADC VOLTAGE REG
delay(1000);//WAIT VOLTAGE REG
/********************ADC calibration*********************/
CLEAR_BIT(ADC2->CR, ADC_CR_ADCALDIF_Msk);
SET_BIT(ADC2->CR, ADC_CR_ADCALLIN_Msk);
SET_BIT(ADC2->CR, ADC_CR_ADCAL_Msk);
while (ADC_CR_ADCAL & ADC_CR_ADCAL_Msk != 0) {}
/******************ADC clock*****************************/
SET_BIT(ADC12_COMMON->CCR, ADC_CCR_CKMODE_0 | ADC_CCR_CKMODE_1);
/*******************ADC Prescaler************************/
SET_BIT(ADC12_COMMON->CCR, ADC_CCR_PRESC_0 | ADC_CCR_PRESC_1 );
/*******************Input Mode***************************/
CLEAR_BIT(ADC2->DIFSEL, ADC_DIFSEL_DIFSEL_0); //Single Ended
/*******************ADC Enable***************************/
SET_BIT(ADC2->ISR, ADC_ISR_ADRDY_Msk);
SET_BIT(ADC2->CR, ADC_CR_ADEN_Msk);
while (ADC_ISR_ADRDY & ADC_ISR_ADRDY_Msk != 1) {}
SET_BIT(ADC2->ISR, ADC_ISR_ADRDY_Msk);
/********************ADC RES*****************************/
SET_BIT(ADC2->CFGR, ADC_CFGR_RES_2 | ADC_CFGR_RES_1);
CLEAR_BIT(ADC2->CFGR, ADC_CFGR_RES_0);
/********************ADC Data Management*****************/
SET_BIT(ADC2->CFGR, ADC_CFGR_DMNGT_0 | ADC_CFGR_DMNGT_1);//DMA Circular mode
/********************OVRMODE*****************************/
SET_BIT(ADC2->CFGR, ADC_CFGR_OVRMOD_Msk); //Erase old data
/********************CONT/Single/Discont*****************/
SET_BIT(ADC2->CFGR, ADC_CFGR_DISCEN_Msk); // discontinuous mode
CLEAR_BIT(ADC2->CFGR, ADC_CFGR_CONT_Msk); // | ADC_CFGR_DISCEN_Msk
/********************Trigger Detection*******************/
SET_BIT(ADC2->CFGR, ADC_CFGR_EXTEN_0 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_3);//Trig rising edge TRGO2
CLEAR_BIT(ADC2->CFGR, ADC_CFGR_EXTEN_1 | ADC_CFGR_EXTSEL_0 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_4);
/********************INput Preselection******************/
SET_BIT(ADC2->PCSEL, ADC_PCSEL_PCSEL_0);//Chan 0
/********************Sample Time reg*********************/
SET_BIT(ADC2->SMPR1, ADC_SMPR1_SMP0_0); //2.5 CLCK Cycles
/********************ADC IT******************************/
SET_BIT(ADC2->IER, ADC_IER_EOCIE_Msk | ADC_IER_EOSMPIE_Msk );//| ADC_IER_EOSIE_Msk | ADC_IER_OVRIE_Msk
NVIC_EnableIRQ(ADC_IRQn);
NVIC_SetVector(ADC_IRQn, (uint32_t)&ADC_IRQHandler);
}
void ADC_IRQHandler(void) {
if (ADC2->ISR & 0x02) {
Eosmp += 1;
SET_BIT(ADC2->ISR, ADC_IER_EOSMPIE_Msk);
}
if (ADC2->ISR & 0x04) {
Eocie += 1;
SET_BIT(ADC2->ISR, ADC_IER_EOCIE_Msk);
}
// if (ADC2->ISR & 0x08) {
// Eos += 1;
// SET_BIT(ADC2->ISR, ADC_IER_EOSIE_Msk);
// }
}
void ADC_Start(void) {
SET_BIT(ADC2->CR, ADC_CR_ADSTART_Msk); //Start
}
void AC_TIMER1_Init(void) {
//------------------------------Horloge Timer1----------------------------------------//
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM1EN_Msk);
//------------------------------Select TRGO source-----------------------------------//
TIM1->PSC = 8399; //PSC=1
//----------------------------------------------------------TIM2 autoreload register--------------------------------------------//
TIM1->ARR = 10000;
//---------selectupdatevent-----------------//
SET_BIT(TIM1->CR2, TIM_CR2_MMS2_1);
//-----------IT-----------------------//
// SET_BIT(TIM1->DIER,TIM_DIER_UIE_Msk);
// NVIC_SetPriority(TIM1_UP_IRQn,0);
// NVIC_SetVector(TIM1_UP_IRQn, (uint32_t)&TIM1_UP_IRQHandler);
// NVIC_EnableIRQ(TIM1_UP_IRQn);
SET_BIT(TIM1->CR1, TIM_CR1_CEN_Msk);//CEN=1
}
//void TIM1_UP_IRQHandler(){
// if (TIM1->DIER & 0x01) {//a check les cd
// if (TIM1->SR & 0x01) {
// numit=numit+1;//all cd checked
// //GPIOH_Port15_Toggle();
// TIM1->SR &= ~(1U << 0);//reset IT
// }
// }
/******************************TIM12 SetUp*******************************/
//void TIM12_Init(void) {
// /**********************Horloge TIM12***********************/
// SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM12EN_Msk);
// delay(1000);
// /**********************Select TRGO source******************/
// SET_BIT(TIM12->CR2, TIM_CR2_MMS_1); //010 UPDATE EVENT
// CLEAR_BIT(TIM12->CR2, TIM_CR2_MMS_0 | TIM_CR2_MMS_2);
// /**********************TIM Update**************************/
// //SET_BIT(TIM12->EGR,TIM_EGR_UG_Msk);//Update generation
// /**********************TIM12 ARR**************************/
// TIM12->ARR = 10000; //CNT TO ARR
// /**********************TIM12 PSC**************************/
// TIM12->PSC = 8399; //Random PSC
// /**********************INTERRUPT**************************/
// SET_BIT(TIM12->DIER, TIM_DIER_UIE_Msk); //IT UEV enabled
// NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 0);
// NVIC_SetVector(TIM8_BRK_TIM12_IRQn, (uint32_t)&TIM8_BRK_TIM12_IRQHandler);
// NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
// /**********************Enable*****************************/
// SET_BIT(TIM12->CR1, TIM_CR1_CEN_Msk);//Timer ON
//}
//void TIM8_BRK_TIM12_IRQHandler(void) {
// if (TIM12->SR & TIM_SR_UIF) {
// updateEV = UpdateEV + 1;
// TIM12->SR &= ~(1U << 0);
// }
//}
Note : The ADC setup allows for conversion at a maximum rate of 900kHz all you need to change is the ARR and PSC register of TIM1 (and switch data management to the ADC Data Register) to check that the problem does not come from the ADC . To go any further than 900 kHz change the system clock and the ADC DELAY, SMP, RES (for it to end conversions before another TRGO2 is generated by the TIM1).