DMA+ADC+TC требуется помощь знающих людей
- Войдите на сайт для отправки комментариев
Здравия желаю. Зарядил ацп на измерения пользовательской последовательности 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);
}
Отдышитесь хоть немного.
Контроллер какой?
А чё там с этой фразой не так, регистры делятся на две группы - текущие (куда прям счас расписывается) и следующие ( как там заполнится, так все данные и адреса перепищутся и станут текущими). Двойная буферизация обзывается. Код по моему кривой, на раз, не видно чтоб следующие регистры записывались.
Реально волшебник....
arduino due) В начале кода в комментариях указано. Настолько проникся процессом что забыл в заголовок кинуть)
Как организуется этот переход? Автоматом или инициализировать нужно? Это мое первое знакомство с микроконтроллерами, по stm пытался аналогию найти как то не густо, с ADC и TC по проще получилось все (http://www.mwmw.ca/ - аналогичный МК). Интересен принцип конфигурации и работы DMA.
У Вас по сути вопроса что - то имеется ?
Как организуется этот переход? Автоматом или инициализировать нужно? Это мое первое знакомство с микроконтроллерами, по 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; } }После долгого отсутствия вернулся к освоению DUE) Нашел довольно позновательную ссылку по обсуждаемой теме: http://forum.arduino.cc/index.php?topic=271381.0 . Пригодится в качестве помощи для начинающих.