현재 STM32F303RE 칩이있는 Nucleo-64 보드를 사용하고 있습니다. 프로그래밍을 위해서 나는 Arduino IDE를 STM32 패키지와 함께 사용한다. 레지스터와 라이브러리 함수를 동시에 배워야 할 때 혼란 스럽기 때문에 HAL을 피하고 싶습니다.STM32F303 : DMA가있는 ADC는 몇 번만 작동합니다.
5.1 Msps (최대 F303)에서 4 개의 입력 신호를 병렬로 샘플링 할 수 있기를 원합니다. 내 계획은 ADC를 계속 실행하는 것이 었습니다. 그런 다음 샘플을 가져 오려면 DMA 플래그를 재설정하고 카운터 (CNDTR-Register)를 캡처 할 샘플 수로 설정하십시오.
다음 부분은이를 달성하기위한 나의 시도입니다. 근본적으로 거의 작동하지만 제한된 시간입니다. 얼마나 자주 작동하는지는 프로그램의 특정 부분에 입력하는 임의의 수면 값에 달려있는 것처럼 보입니다. 예 : takeSamples() - 함수 다음에 10ms 지연을 입력하면 programm는 41주기의 주 루프에서 작동합니다. 그러면 멈추게됩니다.
멈추었을 때 다음을 수행합니다 : DMA-CNDTR 레지스터가 하나의 값으로 만 줄어들면 그곳에 그냥 남아 있습니다. 그래서 프로그래머는 레지스터 값이 0이 될 때까지 기다리고 있지만 결코 발생하지 않습니다. ADC는 전체 시간을 샘플링 중이므로 ADC 데이터 레지스터를 정상적으로 읽을 수 있습니다.
DMA가 특정 시간 후에 데이터 전송을 중단시킬 수있는 원인을 알고있는 사람이 있습니까?
다음은 프로그램의 관련 부분은 다음과 같습니다
void setup() {
Serial.begin(57600);
// Enable clocks
RCC->AHBENR |= (1 << 17); // GPIOA
RCC->AHBENR |= (1 << 18); // GPIOB
// Set ADC pins to analog input
GPIOA->MODER |= (0b11 << 0); // PA0 for ADC1
GPIOA->MODER |= (0b11 << 8); // PA4 for ADC2
GPIOB->MODER |= (0b11 << 2); // PB1 for ADC3
GPIOB->MODER |= (0b11 << 24); // PB1 for ADC4
initClock();
DMA_init();
ADC_init();
// Start conversion
ADC1->CR |= (1 << 2);
ADC3->CR |= (1 << 2);
}
void initClock()
{
FLASH->ACR |= (0b10 << 0); // add two wait states
RCC->CR |= (1 << 18); // Bypass HSE, use external clock signal from STLink instead
RCC->CR &= ~(1 << 24); // turn off PLL
delay(100);
RCC->CFGR |= (0b0000 << 4); // Do not divide system clock
RCC->CFGR |= (0b0111 << 18); // PLL multiply = 9
RCC->CFGR |= (0b10 << 15); // use HSE as PLL source
RCC->CFGR |= (1 << 10); // not divided
delay(100);
RCC->CR |= (1 << 24); // turn on PLL
delay(100);
}
void ADC_init(void) {
RCC->CFGR2 |= (0b10000 << 4); // Prescaler
RCC->CFGR2 |= (0b10000 << 9); // Prescaler
RCC->AHBENR |= (1 << 28); // turn on ADC12 clock
RCC->AHBENR |= (1 << 29); // turn on ADC34 clock
// Set ADC clock
ADC12_COMMON->CCR |= (0b01 << 16); // 0b01
ADC34_COMMON->CCR |= (0b01 << 16); // 0b01
// disable the ADC
ADC1->CR &= ~(1 << 0);
ADC2->CR &= ~(1 << 0);
ADC3->CR &= ~(1 << 0);
ADC4->CR &= ~(1 << 0);
// enable the ADC voltage regulator
ADC1->CR &= ~(1 << 29);
ADC2->CR &= ~(1 << 29);
ADC3->CR &= ~(1 << 29);
ADC4->CR &= ~(1 << 29);
ADC1->CR |= (1 << 28);
ADC2->CR |= (1 << 28);
ADC3->CR |= (1 << 28);
ADC4->CR |= (1 << 28);
// start ADC calibration cycle
ADC1->CR |= (1 << 31);
// wait for calibration to complete
while (ADC1->CR & (1 << 31));
// start ADC calibration cycle
ADC2->CR |= (1 << 31);
// wait for calibration to complete
while (ADC2->CR & (1 << 31));
// start ADC calibration cycle
ADC3->CR |= (1 << 31);
// wait for calibration to complete
while (ADC3->CR & (1 << 31));
// start ADC calibration cycle
ADC4->CR |= (1 << 31);
// wait for calibration to complete
while (ADC4->CR & (1 << 31));
// enable the ADC
ADC1->CR |= (1 << 0);
ADC2->CR |= (1 << 0);
ADC3->CR |= (1 << 0);
ADC4->CR |= (1 << 0);
while (!(ADC1->ISR & (1 << 0)));
while (!(ADC2->ISR & (1 << 0)));
while (!(ADC3->ISR & (1 << 0)));
while (!(ADC4->ISR & (1 << 0)));
// Select ADC Channels
ADC1->SQR1 = (1 << 6);
ADC2->SQR1 = (1 << 6);
ADC3->SQR1 = (1 << 6);
ADC4->SQR1 = (3 << 6);
// Set sampling time for regular group 1
ADC1->SMPR1 |= (0b000 << 3); // 0b000 -> 1.5 clock cycles, shortest available sampling time
ADC2->SMPR1 |= (0b000 << 3);
ADC3->SMPR1 |= (0b000 << 3);
ADC4->SMPR1 |= (0b000 << 3);
// Regular sequence settings
ADC1->SQR1 |= (0b0000 << 0); // One conversion in the regular sequence
ADC2->SQR1 |= (0b0000 << 0);
ADC3->SQR1 |= (0b0000 << 0);
ADC4->SQR1 |= (0b0000 << 0);
// Enable continuous conversion mode
ADC1->CFGR |= (1 << 13); // Master ADC1 + ADC2
ADC3->CFGR |= (1 << 13); // Master ADC3 + ADC4
ADC12_COMMON->CCR |= (0b00110 << 0);
ADC34_COMMON->CCR |= (0b00110 << 0);
// DMA mode
ADC12_COMMON->CCR |= (0 << 13); // 0 -> One Shot; 1 -> Circular
ADC34_COMMON->CCR |= (0 << 13);
// DMA mode for 12-bit resolution
ADC12_COMMON->CCR |= (0b10 << 14);
ADC34_COMMON->CCR |= (0b10 << 14);
}
void DMA_init(void) {
// Enable clocks
RCC->AHBENR |= (1 << 0); // DMA1
RCC->AHBENR |= (1 << 1); // DMA2
// Transfer complete interrupt enable
DMA1_Channel1->CCR |= (1 << 1);
DMA2_Channel5->CCR |= (1 << 1);
// Memory increment mode
DMA1_Channel1->CCR |= (1 << 7);
DMA2_Channel5->CCR |= (1 << 7);
// Peripheral size
DMA1_Channel1->CCR |= (0b11 << 8);
DMA2_Channel5->CCR |= (0b11 << 8);
// Memory size
DMA1_Channel1->CCR |= (0b11 << 10);
DMA2_Channel5->CCR |= (0b11 << 10);
// Number of data to transfer
DMA1_Channel1->CNDTR = uint32_t(maxSamples);
DMA2_Channel5->CNDTR = uint32_t(maxSamples);
// Peripheral address register
DMA1_Channel1->CPAR |= (uint32_t)&ADC12_COMMON->CDR;
DMA2_Channel5->CPAR |= (uint32_t)&ADC34_COMMON->CDR;
// Memory address register
DMA1_Channel1->CMAR |= uint32_t(&dataPoints1232);
DMA2_Channel5->CMAR |= uint32_t(&dataPoints3432);
// Reset flags
DMA1->IFCR |= 0xFF;
DMA2->IFCR |= 0xFF;
}
void takeSamples(void) {
// Reset flags
DMA1->IFCR |= (0b1111111111111111111111111111111 << 0);
DMA2->IFCR |= (0b1111111111111111111111111111111 << 0);
// Number of data to transfer
DMA1_Channel1->CNDTR = uint32_t(maxSamples);
DMA2_Channel5->CNDTR = uint32_t(maxSamples);
delay(10); // does not work without this random delay
elapsedTime = micros();
// Enable DMA
DMA1_Channel1->CCR |= (1 << 0);
DMA2_Channel5->CCR |= (1 << 0);
while ((DMA1_Channel1->CNDTR > 0) || (DMA2_Channel5->CNDTR > 0))
}
elapsedTime = micros() - elapsedTime;
// Reset flags
DMA1->IFCR |= (0b1111111111111111111111111111111 << 0);
DMA2->IFCR |= (0b1111111111111111111111111111111 << 0);;
DMA1_Channel1->CCR &= ~(1 << 0);
DMA2_Channel5->CCR &= ~(1 << 0);
// ADC stop conversion
ADC1->CR |= (1 << 4);
ADC3->CR |= (1 << 4);
while ((ADC1->CR & (1 << 2)) || (ADC3->CR & (1 << 2)));
ADC12_COMMON->CCR &= ~(0b10 << 14);
ADC34_COMMON->CCR &= ~(0b10 << 14);
ADC12_COMMON->CCR |= (0b10 << 14);
ADC34_COMMON->CCR |= (0b10 << 14);
// ADC start conversion
ADC1->CR |= (1 << 2);
ADC3->CR |= (1 << 2);
}
void loop() {
takeSamples();
Serial.print("Elapsed time: ");
Serial.println(elapsedTime);
}
나는이 문제에 관한 조언, 힌트를 정말 thankfull이 될 것입니다!
인사말 베니
편집 : 나는 또한 nucleo-64 STM32F401 칩과 같은 문제가 있었다. STM32F4 발견은 다른 한편으로는 잘 작동했습니다. 내 F103 비행 제어 보드에서도 그와 같은 문제는 없었습니다.
1. 먼저 인간이 읽을 수있는 값을 사용하기 시작합니다. –
2. arduino IDE를 포기하고 예를 들어 openSTM32가 설치된 eclipse를 사용하기 시작합니다. –
3. CMSIS 정의를 사용하십시오 –