DMA interrupt with Arduino IDE?
Posted: Fri Jun 19, 2020 9:31 am
Hello everyone,
I would like to ask, if there is by chance a way to create an interrupt service routine which triggers on the DMA in the Arduino IDE. If yes, how do i do this?
The background: I am using a bluepill board (stm32f103c8t6). The plan is to implement an ADC read for a bunch of conversions in circular mode. This converted values are transfered into RAM (incremented memory address) by the DMA. As soon as the DMA sets the transfer complete flag I would like to disable timer 4 which is triggering the ADC and finish the whole conversion and DMA transfer automatically. This is supposed to be done through an interrupt service routine.
Until now I use in the code bit manipulation and native Arduino functions only and don't have any libraries included.
As far as I know there is the possibility to use Timerx.attachInterrupt() as intterupt handler for timers. Is there by chance something similar for DMA? Personaly, I doubt it because there isn't any DMA support by the Arduino IDE (I had to access the DMA registers via hardware addresses). But better ask than guess...
Or can I implement an interrupt service routine similar to the procedure on Arduino UNO with ISR(Interrupt_vect)? How would be the the name of the interrupt vector if this is possible?
In the register datasheet I found in the chapter about interrupts the table with the interrupt vectors and their memory address but I can't get an ISR to function with interrupt "DMA_1Channel1".
Or maybe you have a better idea how an automated not periodical occouring ADC conversion with DMA can be realized?
I would be very glad and thankful if you can fill me in how I can reslize an interrupt on internal vectors in Arduino IDE.
Regards,
Sven
Attached: latest code
I would like to ask, if there is by chance a way to create an interrupt service routine which triggers on the DMA in the Arduino IDE. If yes, how do i do this?
The background: I am using a bluepill board (stm32f103c8t6). The plan is to implement an ADC read for a bunch of conversions in circular mode. This converted values are transfered into RAM (incremented memory address) by the DMA. As soon as the DMA sets the transfer complete flag I would like to disable timer 4 which is triggering the ADC and finish the whole conversion and DMA transfer automatically. This is supposed to be done through an interrupt service routine.
Until now I use in the code bit manipulation and native Arduino functions only and don't have any libraries included.
As far as I know there is the possibility to use Timerx.attachInterrupt() as intterupt handler for timers. Is there by chance something similar for DMA? Personaly, I doubt it because there isn't any DMA support by the Arduino IDE (I had to access the DMA registers via hardware addresses). But better ask than guess...
Or can I implement an interrupt service routine similar to the procedure on Arduino UNO with ISR(Interrupt_vect)? How would be the the name of the interrupt vector if this is possible?
In the register datasheet I found in the chapter about interrupts the table with the interrupt vectors and their memory address but I can't get an ISR to function with interrupt "DMA_1Channel1".
Or maybe you have a better idea how an automated not periodical occouring ADC conversion with DMA can be realized?
I would be very glad and thankful if you can fill me in how I can reslize an interrupt on internal vectors in Arduino IDE.
Regards,
Sven
Attached: latest code
Code: Select all
int x = 0;
int y = 0;
int z = 0;
boolean a = LOW;
boolean b = LOW;
boolean c = LOW;
uint16_t adcoutput[3696] = {0};
// DMA1 pointers on register memory (register not recognized by arduino IDE)
uint32_t *DMA1_ISR = (uint32_t *) 0x40020000;
uint32_t *DMA1_IFCR = (uint32_t *) 0x40020004;
uint32_t *DMA1_CCR1 = (uint32_t *) 0x40020008;
uint32_t *DMA1_CNDTR1 = (uint32_t *) 0x4002000C;
uint32_t *DMA1_CPAR1 = (uint32_t *) 0x40020010;
uint32_t *DMA1_CMAR1 = (uint32_t *) 0x40020014;
uint8_t *NVIC_DMAch1 = (uint8_t *) 0x6C; //memory of NVIC DMA1_Channel1 global interrupt
}
void setup() {
pinMode(PC13, OUTPUT);
digitalWrite(PC13, LOW);
RCC_BASE->APB2ENR |= (1 << 2); //enable IO clock output port a - IOPAEN=1
RCC_BASE->APB2ENR |= (1 << 3); //enable IO clock output port b - IOPBEN=1
RCC_BASE->APB2ENR |= (1 << 9); //enable ADC1 clock - ADC1EN=1
RCC_BASE->APB1ENR |= (1 << 2); //enable timer 4 clock - TIM4EN=1
RCC_BASE->AHBENR |= (1 << 0); //enable DMA1 clock - DMA1EN=1
// TIMER 4 CH4 ---------------------------------------------------------
GPIOB_BASE->CRH |= (1 << 4) | (1 << 5); //for PB9 select output mode, 50MHz - MODEy=11
GPIOB_BASE->CRH |= (1 << 7); //select alternate push-pull mode CNFy=10
GPIOB_BASE->CRH &= ~(1 << 6); //select alternate push-pull mode CNFy=10
TIMER4_BASE->ARR = 71; //frequency selection -> 36MHz/(ARR+1)=0,5MHz
TIMER4_BASE->CCR4 = 1; //duty cycle selection -> 0%
TIMER4_BASE->CNT = 0;
TIMER4_BASE->CCMR2 |= (1 << 14) | (1 << 13); //select PWM mode 1 - OCxM=110
TIMER4_BASE->CCMR2 |= (1 << 11); //enable preload - OCxPE=1
TIMER4_BASE->CR1 |= (1 << 7); //enable auto-reload preload - ARPE=1
TIMER4_BASE->CCER |= (1 << 12); //enable output at OCx - CCxE=1
TIMER4_BASE->DIER |= (1 << 4); //enable CC4 interrupt - CC4IE=1
// ADC1 ---------------------------------------------------------------
ADC1_BASE->SQR3 |= (1 << 0) | (1 << 1) | (1 << 2); //select PA7 as input
ADC1_BASE->CR2 |= (1 << 8); //enable DMA request - DMA=1
ADC1_BASE->CR2 |= (1 << 1); //continous conversion mode - CONT=1
ADC1_BASE->CR2 |= (1 << 20); //enable external trigger - EXTTRIG=1
ADC1_BASE->CR2 |= (1 << 19) | (1 << 17); //select timer 4 CC4 event as trigger - EXTSEL=101
// DMA CH1 - ADC1 -------------------------------------------------
*DMA1_CPAR1 = (int)1073816652; //0x40012400 + 0x0000004C; //ADC1_BASE->DR; //peripheral address
*DMA1_CMAR1 = (int)adcoutput; //memory address
*DMA1_CNDTR1 = (int)3696; //data number to be transferred
*DMA1_CCR1 |= (1 << 12) | (1 << 13); //select very high priority - PL=11
*DMA1_CCR1 |= (1 << 10); //select memory size 16 bit - MSIZE=01
*DMA1_CCR1 |= (1 << 8); //select peripheral size 16 bit - PSIZE=01
*DMA1_CCR1 |= (1 << 7); //enable memory increment mode - MINC=1
*DMA1_CCR1 |= (1 << 1); //enable transfer complete interrupt TCIE=1
*DMA1_CCR1 |= (1 << 5); //enable circular mode - CIRC=1
// ----------------------------------------------
TIMER4_BASE->CR1 |= (1 << 0); //enable counter 4 - CEN=1
ADC1_BASE->CR2 |= (1 << 0); //wake up ADC - ADON=1
*DMA1_IFCR |= 0x00000002; //clears transfer complete flag
*DMA1_CCR1 |= (1 << 0); //DMA1 enable - EN=1
Serial.begin(115200);
}
void loop() {
// test ADC conversion ----------------------------------------
// if(ADC1_BASE->SR & 0x0002){ //triggered on EOC flag
// Serial.println("ADC");
// ADC1_BASE->SR &= ~(1 << 1); //clear EOC flag
// }
// Serial.print("ADC1_BASE->DR: ");
// Serial.println(ADC1_BASE->DR);
// test DMA ---------------------------------------------------
// if (*DMA1_ISR & 0x00000002) { //triggered on TCIFx flag
// Serial.println("DMA");
// Serial.print("DMA1_ISR: ");
// Serial.println(*DMA1_ISR);
// *DMA1_CCR1 &= ~(1 << 0); //DMA1 disable - EN=0
// *DMA1_IFCR |= 0x00000002; //clears transfer complete flag
// delay(500);
// for (x = 0; x < 3696; x++) {
// Serial.print(adcoutput[x]);
// Serial.println(";");
// }
// Serial.print("DMA1_ISR: ");
// Serial.println(*DMA1_ISR);
// delay(500);
// *DMA1_CCR1 |= (1 << 0); //DMA1 enable - EN=0
// }
Serial.println(*NVIC_DMAch1, HEX);
}