2

現在、STM32F303RE チップを搭載した Nucleo-64 ボードを使用しています。プログラミングには、Arduino IDE と STM32 パッケージを使用します。レジスタとライブラリ関数を同時に学習しなければならない場合、かなり混乱すると思うので、当面は HAL を避けたいと思います。

4 つの入力信号を 5.1 Msps (F303 の最大値) で並列にサンプリングできるようにしたいと考えています。私の計画は、ADC を実行し続けることでした。次に、サンプルを取得する場合は、DMA フラグをリセットし、カウンター (CNDTR-Register) をキャプチャするサンプルの量に設定します。

次の部分は、これを達成するための私の試みを示しています。基本的にはほとんど機能していますが、限られた回数しか機能していません。どのくらいの頻度で機能するかは、プログラムの特定の部分で入力するランダムな睡眠値に依存するようです。例: takeSamples() 関数の後に 10 ミリ秒の遅延を入力すると、プログラムはメイン ループの 41 サイクルの間動作しますが、スタックします。

スタックすると、次のようになります。 DMA-CNDTR レジスタは 1 つの値だけ減少し、そこにとどまります。そのため、プログラムはレジスタ値がゼロになるのを待っていますが、これは決して起こりません。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フライトコントローラーボードでもそのような問題はありませんでした.

4

1 に答える 1