DMA+ADC+TC требуется помощь знающих людей

Student33
Offline
Зарегистрирован: 31.10.2017

Здравия желаю. Зарядил ацп на измерения пользовательской последовательности 15 каналов от таймера с периодом "Т".  Хотелкой вызывать прерывания по готовности данных наткнулся в интернете на код АЦП с DMA, чуток поправил на свой лад.

Из даташита понял что:

1.Для одного периферийного модуля отводится несколько  регистров - указателей (RPR, RNPR) и несколько регистров-счетчиков (RCR, RNCR).

2. Количество пересылок устанавливается внутренним 16-ти битным регистром счетчика пересылок. 

3. Нарастающий фронт на DRDY запускает запрос на передачу данных

4.Счетчики автоматически декрементируются после каждой пересылки данных, а указатель памяти инкрементируется.

5.Программирование вторых регистров счетчиков/указателей позволяет организовать непрерывность буферов.

Т.е. получается готовность данных на одном из измерительных каналов запускает передачу данных, забивает элемент массива,декрементирует счетчик, инкрементирует адрес. Достижение счетчиком 0 (массив забит) выставляет флаг ENDRX и вызывает прерывание ацп с непонятным переходом ко второму регистру указателя приема. Непонятен переход от одного регистра к другому......

окончательно убила вот такая фраза из даташита "Но как только счетчик пересылок достигает нуля, значения 2-рых счетчиков/указателей загружаются в регистры счетчиков/указателей" 

Поправте если я где то наврал и поясните по переходам от одних регистров к другим, код прилагаю.
 

#include <Streaming.h>
int const NUM_CHANNELS=12;
uint16_t global_ADCounts_Array[NUM_CHANNELS];  // holds the raw data from the analog to digital 
void setup_AtoD(){
 // Arduino Due ADC->DMA 
// first modified by contravalent from code on the  internet by "Stimmer"
// fills the array global_ADCounts_Array in the background, with data from the ADC  z
pmc_enable_periph_clk(ID_ADC);   //power management controller told to turn on adc
ADC->ADC_CR |=1; //reset the adc
ADC->ADC_MR= 0x90380f03;  //this setting is used by arduino. 
ADC->ADC_CHER=0x3cff;       //   use channels A0 to A11 //
ADC->ADC_SEQR1=0x01234567;  // use A0 to A7 in order into array 
ADC->ADC_SEQR2=0x00dcba00;      //use A8 to A11 following in order into array
NVIC_EnableIRQ(ADC_IRQn); // interrupt controller set to enable adc.
ADC->ADC_IER=(1<<27);   // interrupt enable register, enables only ENDRX
 // following are the DMA controller registers for this peripheral
 // "receive buffer address" 
 ADC->ADC_RPR=(uint32_t) global_ADCounts_Array;   //  УКАЗАЛИ АДРЕС ДЛЯ ДАННЫХ
 // "receive count" 
 ADC->ADC_RCR=NUM_CHANNELS;  //  УКАЗАЛИ КОЛИЧЕСТВО ПЕРЕСЫЛОК
 // "next-buffer address"
 ADC->ADC_RNPR=(uint32_t)global_ADCounts_Array; // ???
 // and "next count"
 ADC->ADC_RNCR=NUM_CHANNELS;   //  ???
 // "transmit control register"
 ADC->ADC_PTCR=1;  // Регистр управления передачи, разрешает запросы приемных пересылок, если не установлен флаг RXTDIS.
 // now that all things are set up, it is safe to start the ADC.....

// сетапаем таймер
REG_PMC_PCER0|=1<<27;
REG_TC0_CMR0|=0xCC000;
REG_TC0_RC0= 21000;
REG_TC0_CCR0=5; 
}
void ADC_Handler()
{     // for the ATOD: re-initialize DMA pointers and count 
 int f=ADC->ADC_ISR;  //   read the interrupt status register 
 if (f & (1<<27)){ /// check the bit "endrx"  in the status register
  /// set up the "next pointer register" 
  ADC->ADC_RNPR=(uint32_t) global_ADCounts_Array;  // ???
  // set up the "next count"
  ADC->ADC_RNCR=NUM_CHANNELS;  // ???
   REG_PIOB_ODSR^=1<<27; 
 }
}
void setup(){
Serial.begin(115200); 
REG_PIOB_PER |= PIO_PER_P27; //ВКЛ 13 PIN
REG_PIOB_OER |= PIO_PER_P27; //УСТАНОВИТЬ 13 PIN КАК ВЫХОД
setup_AtoD();
}
void loop() {
  unsigned int temp[NUM_CHANNELS];
  for (int i = 0; i < NUM_CHANNELS; i++){
    temp[i] = global_ADCounts_Array[i]&=0xFFF;  //keep only data on buffer
    Serial << "temp " << i  << " = " << temp[i] << endl;
  }
  Serial << endl;
  delay(500);
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

Отдышитесь хоть немного.

Контроллер какой?

Волшебник
Offline
Зарегистрирован: 22.12.2016

А чё там с этой фразой не так, регистры делятся на две группы - текущие (куда прям счас расписывается) и следующие ( как там заполнится, так все данные и адреса перепищутся и станут текущими).  Двойная буферизация обзывается. Код по моему кривой, на раз, не видно чтоб следующие регистры записывались.

0x100 Receive Pointer Register PERIPH _RPR Read-write 0
0x104 Receive Counter Register PERIPH_RCR Read-write 0
0x108 Transmit Pointer Register PERIPH_TPR Read-write 0
0x10C Transmit Counter Register PERIPH_TCR Read-write 0
 
0x110 Receive Next Pointer Register PERIPH_RNPR Read-write 0
0x114 Receive Next Counter Register PERIPH_RNCR Read-write 0
0x118 Transmit Next Pointer Register PERIPH_TNPR Read-write 0
0x11C Transmit Next Counter Register PERIPH_TNCR Read-write 0
 
0x120 Transfer Control Register PERIPH_PTCR Write-only 0
0x124 Transfer Status Register PERIPH_PTSR Read-only 0
brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Реально волшебник.... 

Student33
Offline
Зарегистрирован: 31.10.2017

arduino due)  В начале кода в комментариях указано. Настолько проникся процессом что забыл в заголовок кинуть) 

Student33
Offline
Зарегистрирован: 31.10.2017

Как организуется этот переход? Автоматом или инициализировать нужно? Это мое первое знакомство с микроконтроллерами, по stm пытался аналогию найти как то  не густо, с ADC  и TC по проще получилось все (http://www.mwmw.ca/  -  аналогичный МК). Интересен принцип  конфигурации и работы DMA.

Student33
Offline
Зарегистрирован: 31.10.2017

У Вас по сути вопроса что - то имеется ?

Волшебник
Offline
Зарегистрирован: 22.12.2016

Student33 пишет:

Как организуется этот переход? Автоматом или инициализировать нужно? Это мое первое знакомство с микроконтроллерами, по stm пытался аналогию найти как то  не густо, с ADC  и TC по проще получилось все (http://www.mwmw.ca/  -  аналогичный МК). Интересен принцип  конфигурации и работы DMA.

Автоматически, весь квартет перезаписывается. Вам остаётся в прерывании по заполнению буфера занести новые значения в регистры-нэкст. Чтобы система не писала в один и тот-же массив и не нарушала временную последовательность данных, буфера надо два, и переключать как раз по прерыванию.

void adc_setup ()
{
  pmc_enable_periph_clk(ID_ADC);
  adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
  NVIC_EnableIRQ (ADC_IRQn);               // enable ADC interrupt vector

  adc_disable_all_channel(ADC);
  adc_enable_interrupt(ADC, ADC_IER_RXBUFF);

  ADC->ADC_RPR  =  (uint32_t)  inp[0];      // DMA buffer
  ADC->ADC_RCR  =  INP_BUFF;
  ADC->ADC_RNPR =  (uint32_t)  inp[1];      // next DMA buffer
  ADC->ADC_RNCR =  INP_BUFF;
  ADC->ADC_PTCR =  1;

  adc_set_bias_current(ADC, 0x01); 
  //  adc_enable_tag(ADC);
  adc_enable_channel(ADC, ADC_CHANNEL_7);  // AN0
  adc_configure_trigger(ADC, ADC_TRIG_TIO_CH_0, 0);
  adc_start(ADC); 
}

void ADC_Handler (void)
{
  if((adc_get_status(ADC) & ADC_ISR_RXBUFF) ==	ADC_ISR_RXBUFF) {
    flag = ++sptr; 
    sptr &=  0x01;
    ADC->ADC_RNPR  =  (uint32_t)  inp[sptr];
    ADC->ADC_RNCR  =  INP_BUFF;
    }
}

 

Student33
Offline
Зарегистрирован: 31.10.2017

После долгого отсутствия вернулся к освоению DUE)  Нашел довольно позновательную ссылку по обсуждаемой теме: http://forum.arduino.cc/index.php?topic=271381.0  . Пригодится в качестве помощи для начинающих.