我目前正在使用具有STM32F303RE芯片的Nucleo-64电路板。对于编程,我使用带有STM32软件包的Arduino IDE。我现在想避免使用HAL,因为我认为当你必须同时学习寄存器和库函数时,它会相当混乱。
我希望能够以5.1 Msps(F303的最大值)并行采样4个输入信号。我的计划是保持ADC运行。然后,当我想取样时,我重置DMA标志并将计数器(CNDTR-Register)设置为我想要捕获的样本量。
以下部分显示了我实现此目标的尝试。它基本上几乎可以工作,但只有有限的时间。它的工作频率似乎取决于我在程序中的某些部分输入的随机睡眠值。 例如:如果我在takeSamples() - 函数之后输入10ms的延迟,则程序将在主循环的41个循环中起作用 - 然后它会卡住。
当它卡住时,会执行以下操作:DMA-CNDTR寄存器仅减少一个值,然后它就会停留在那里。所以程序正在等待寄存器值变为零,但这种情况永远不会发生。 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);
}
我真的非常感谢有关此问题的任何提示或提示!
问候 尼
编辑:我对使用STM32F401芯片的nucleo-64也有同样的问题。另一方面,STM32F4 Discovery工作得很好。我的F103飞行控制板也没有这样的问题。答案 0 :(得分:2)
作为示例,使用计时器进行简单的转换。
void ReadChannels(int channel, size_t nsamples, uint8_t *obuff)
{
TIM1 -> CR1 = 0;
TIM1 -> CR2 = 0;
TIM1 -> PSC = PSC;
TIM1 -> ARR = ARR;
TIM1 -> EGR |= TIM_EGR_UG;
DMA1_Channel1 -> CPAR = (uint32_t)&(ADC1 -> DR);
DMA1_Channel1 -> CMAR = (uint32_t)obuff;
DMA1_Channel1 -> CNDTR = nsamples;
DMA1_Channel1 -> CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN;
ADC1 -> CFGR = ADC_CFGR_DMAEN | (0b10 << ADC_CFGR_RES_Pos) | (9 << ADC_CFGR_EXTSEL_Pos) | (0b01 << ADC_CFGR_EXTEN_Pos);
ADC1 -> SMPR1 = 0;
ADC1 -> SMPR2 = 0;
ADC1 -> SQR1 &= ~(ADC_SQR1_L_Msk);
ADC1 -> SQR1 &= ~(ADC_SQR1_SQ1_Msk);
ADC1 -> SQR1 |= channel << ADC_SQR1_SQ1_Pos);
ADC1 -> CR |= ADC_CR_ADSTART;
TIM1 -> CR2 |= TIM_CR2_MMS_1;
TIM1 -> CR1 |= TIM_CR1_CEN;
DMA1_Channel1 -> CCR = 0;
TIM1 -> CR1 = 0;
}