STM32F7: передача ADC DMA работает только один раз - PullRequest
0 голосов
/ 21 марта 2019

Я хочу постоянно читать значения АЦП и записывать их в массив, используя DMA.Я использую плату Nucleo с STM32F767ZI.Для простоты вывода данных я использую Arduino IDE с пакетом плат STM32.Мне удалось заставить АЦП работать в непрерывном режиме, но когда я добавляю DMA, он не будет работать.Кажется, передается только одно значение.Регистр NDTR, содержащий количество передаваемых данных, остается на значении, которое я установил, равным минус 1.

Вот небольшая программа:

volatile static bool dma_active = 1;
#define maxSamples 512
int16_t dataPoints[maxSamples];

void setup() {
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // GPIOA clock enable
  GPIOA->MODER |= (0b11 << 6); // PA3 as analog input
  Serial.begin(115200);
  Serial.println("starting");  
  initADC();
  initDMA();
}

void initADC() {
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;     // ADC1 clock enable
  ADC1->CR2 |= ADC_CR2_ADON;              //  ADC on
  ADC1->CR2 |= ADC_CR2_CONT;              //  continuous conversion mode
  ADC1->CR1 |= ADC_CR1_EOCIE;             // EOC interrupt
  ADC1->CR1 &= ~ADC_CR1_DISCEN;           // discontinuous mode disabled

  ADC1->CR1 &= ~ADC_CR1_SCAN;             // scan mode disabled
  ADC1->CR2 |= ADC_CR2_DMA;               // DMA mode
  ADC1->CR2 |= ADC_CR2_DDS;               // continuous DMA request
  ADC1->SQR3 |= 0b11;                     // ADC1_IN3 = PA3
  ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L);  // 1 conversion
  ADC1->CR2 |= ADC_CR2_SWSTART;           // Start conversion
}

void initDMA() {
  // DMA2 Stream4 : Channel 0 is ADC1
  RCC->AHB1ENR |= (1 << 22);                        // DMA2 clock enable
  DMA2_Stream4->CR &= ~DMA_SxCR_EN; // Disable
  while (DMA2_Stream4->CR & (1 << 0));
  DMA2_Stream4->CR |= (0b0100 << DMA_SxCR_CHSEL);   // Channel 4
  DMA2_Stream4->CR |= (0b11 << DMA_SxCR_PL);        // Very high priority
  DMA2_Stream4->PAR = (uint32_t)&ADC1->DR;          // Data source register
  DMA2_Stream4->M0AR = uint32_t(&dataPoints);      // Buffer 1
//  DMA2_Stream4->M1AR = uint32_t(&dataPoints1);      // Buffer 2
  DMA2_Stream4->NDTR = maxSamples;                  // Number of transferred data
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_PSIZE);     // Source data size (00 = byte, 01 = half word, 10 = word)
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_MSIZE);     // Memory data size (00 = byte, 01 = half word, 10 = word)
  DMA2_Stream4->CR |= DMA_SxCR_TCIE;                // Transfer complete interrupt enable
  DMA2_Stream4->CR |= DMA_SxCR_CIRC;                // circular mode
  DMA2_Stream4->CR &= ~DMA_SxCR_PINC;               // no peripheral increment mode
  DMA2_Stream4->CR |= DMA_SxCR_MINC;                // memory increment mode
//  DMA2_Stream4->CR |= DMA_SxCR_DBM;               // double buffer mode
  DMA2->HIFCR |= 0b111101;                         // clear flags
  NVIC_EnableIRQ(DMA2_Stream4_IRQn);
  delay(20);
  DMA2_Stream4->CR |= DMA_SxCR_EN;                  // Enable
}

void loop() {
  Serial.print(ADC1->DR);
  Serial.print("  ");
  Serial.print(dataPoints[0]);
  Serial.print("  ");
  Serial.print(dma_active);
  Serial.print("  ");
  Serial.println(DMA2_Stream4->NDTR);
  delay(100);
 }



void DMA2_Stream4_IRQHandler(void) {
  dma_active = 0;
}

Я использовал ADC + DMA наSTM32F3 успешно, но я не могу заставить его работать на этом F7.

Часы для GPIOA включены, и PA3 настроен на аналоговый вход.Часы для АЦП включаются.АЦП установлен в непрерывный режим с режимом DMA и непрерывными запросами DMA.Вход PA3.Преобразование АЦП началось.Поток 4 прямого доступа к памяти настроен на правильный канал для ADC1 (канал 0).Устанавливаются адреса входа и выхода, а также количество передаваемых данных и включается режим приращения памяти.Тогда поток становится активным.

Я не уверен, что шаг, который я здесь пропускаю.

Я был бы очень признателен за вашу помощь!

РЕДАКТИРОВАТЬ # 2

Я случайно принял канал за поток, и поэтому для DMA был выбран неправильный канал (канал 4 вместо канала 0 для ADC1 в DMA2 Stream 4).Это было главной проблемой, почему это не сработало.Теперь он работает нормально в режиме двойного буфера, за исключением одного: когда я включаю прерывание завершения передачи, программа больше не работает.Он только пишет одно письмо через Serial.print, "s" от запуска.Значения не передаются.Я сделал прерывание так, чтобы оно сейчас просто отключило DMA, но по какой-то причине прерывание, похоже, вообще не работает.

volatile static bool dma_active = 1;
#define maxSamples 512
int16_t dataPoints[maxSamples];
int16_t dataPoints2[maxSamples];
void setup() {
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN_Msk; // GPIOA clock enable
  GPIOA->MODER |= (0b11 << GPIO_MODER_MODER3_Pos); // PA3 as analog input
  Serial.begin(115200);
  Serial.println("starting");
   initDMA(); 
 initADC();
}

void initADC() {
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN_Msk;     // ADC1 clock enable
  ADC1->CR2 |= ADC_CR2_ADON_Msk;              //  ADC on
  ADC1->CR2 |= ADC_CR2_CONT_Msk;              //  continuous conversion mode
  ADC1->CR1 |= ADC_CR1_EOCIE_Msk;             // EOC interrupt
  ADC1->CR1 &= ~(ADC_CR1_DISCEN_Msk);           // discontinuous mode disabled

  ADC1->CR1 &= ~(ADC_CR1_SCAN_Msk);             // scan mode disabled
  ADC1->CR2 |= ADC_CR2_DMA_Msk;               // DMA mode
  ADC1->CR2 |= ADC_CR2_DDS_Msk;               // continuous DMA request
  ADC1->SQR3 |= 0b11;                     // ADC1_IN3 = PA3
  ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L_Pos);  // 1 conversion
  ADC1->CR2 |= ADC_CR2_SWSTART_Msk;           // Start conversion
}

void initDMA() {
  // DMA2 Stream4 : Channel 0 is ADC1
  RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN_Msk;                            // DMA2 clock enable
  DMA2_Stream4->CR &= ~(DMA_SxCR_EN_Msk);               // Disable
  while (DMA2_Stream4->CR & (1 << 0));
  DMA2->HIFCR |= 0b111101;                              // clear flags
  DMA2_Stream4->CR |= (0b11 << DMA_SxCR_PL_Pos);        // Very high priority
  DMA2_Stream4->PAR = (uint32_t)&(ADC1->DR);              // Data source register
  DMA2_Stream4->M0AR = uint32_t(&dataPoints);           // Buffer 1
  DMA2_Stream4->M1AR = uint32_t(&dataPoints2);           // Buffer 2
  DMA2_Stream4->NDTR = maxSamples;                      // Number of transferred data
  DMA2_Stream4->CR &= ~(0b1111 << DMA_SxCR_CHSEL_Pos);   // Channel 4
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_PSIZE_Pos);     // Source data size (00 = byte, 01 = half word, 10 = word)
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_MSIZE_Pos);     // Memory data size (00 = byte, 01 = half word, 10 = word)
//  DMA2_Stream4->CR |= DMA_SxCR_TCIE_Msk;                // Transfer complete interrupt enable
//  DMA2_Stream4->CR |= DMA_SxCR_CIRC_Msk;                // circular mode
  DMA2_Stream4->CR |= DMA_SxCR_DBM_Msk;                // double buffer mode
  DMA2_Stream4->CR &= ~(DMA_SxCR_PINC_Msk);             // no peripheral increment mode
  DMA2_Stream4->CR |= DMA_SxCR_MINC_Msk;                // memory increment mode

  NVIC_EnableIRQ(DMA2_Stream4_IRQn);
  DMA2_Stream4->CR |= DMA_SxCR_EN_Msk;                  // Enable
}

void loop() {
  for (int i = 0; i < maxSamples; i++)
  {
    Serial.print(dataPoints[i]);
    Serial.print("  ");
 //   Serial.print(dataPoints2[i]);
    Serial.print("  ");
    Serial.print(dma_active);
    Serial.println("");
  }
  delay(2000);
}

void DMA2_Stream4_IRQHandler(void) {
  if ((DMA2->HISR) & DMA_HISR_TCIF4_Msk)
  {
    DMA2_Stream4->CR &= ~DMA_SxCR_EN_Msk;                  // Disable
    dma_active = 0;
    DMA2->HIFCR |= 0b111101;                         // clear flags
  }
}

Ответы [ 2 ]

1 голос
/ 21 марта 2019

Прежде всего, вы не очищаете флаг прерывания, и прерывание вызывается все время.

Те же ошибки:

ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L); не очищает L в регистре SQR1.

Это должно быть ADC1->SQR1 &= ~(ADC_SQR1_L_Msk << ADC_SQR1_L_Pos);

Та же ошибка везде:(например) 0b01 << DMA_SxCR_PSIZE

в моем .h файле DMA_SxCR_PSIZE имеет значение 0x00001800:)

И еще много много другого:)

0 голосов
/ 01 апреля 2019

Это из-за D и я кеширую.Отключи его.

...