реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> ADC c PDC и программным запуском, sam7x
xelax
сообщение May 12 2008, 06:49
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035



Про работу АЦП c PDC в мануале честно говоря мало информации. Я посчитал, что настроив PDC и ADC на работу с ним и программно запустив первое преобразование, далее PDC самостоятельно запустит N преобразований, а затем дернет прерывание, о том что приёмный буфер полный.

На практике оказалось иначе. Стартую преобразование, оно происходит один раз, причём вижу, что результат сохранился в регистре, а в PDC значение N(количество преобразований), стало равно N-1.
Далее отпускаю программу поработать какое-то время, затем останавливаю и вижу что в регистрах картина не изменилась. Тот же самый результат преобразования, теже значения в регистрах PDC.
Проверял в связке sam7x-ek + arm-elf-gdb + sam-ice + eclipse.

Собственно вопросы:
1. Может ли вообще АЦП работать таким образом? И если может, то почему у меня не работает?
2. А если не может, то на кой ляд они прикрутили к АЦП контроллер доступа к памяти, в чём его глубокий смысл?

вот код работы с АЦП
Код
void adcHandler(void)
{  
  if (AT91C_BASE_ADC->ADC_SR & AT91C_ADC_RXBUFF)
  {       
     // Disable data ready Interrupt
     AT91C_BASE_ADC->ADC_IDR = AT91C_ADC_RXBUFF;
     // disables all channels  
     AT91C_BASE_ADC->ADC_CHDR = ALL_CHANNEL_DISABLE;          
     AdcInterrupt();
  }
}

/******************************************************************************
Inits the ADC.
******************************************************************************/
void  OpenAdc(AdcParams_t *param)
{    
  //enable the clock of ADC
  AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_ADC;
                
  // initialization adc
  // reset adc
  AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
  
  /* disable receiver PDC transfer requests */
  AT91C_BASE_ADC->ADC_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
  
  // Starting a conversion is only possible by software. 8-bit resolution mode.
  AT91C_BASE_ADC->ADC_MR = (uint32_t)sampleRate | AT91C_ADC_LOWRES;
  
  /* set pdc pointer and counter */
  AT91C_BASE_ADC->ADC_RCR = selectionsAmount;
  AT91C_BASE_ADC->ADC_RPR = bufferPointer;
      
  // disables all channels  
  AT91C_BASE_ADC->ADC_CHDR = ALL_CHANNEL_DISABLE;                                                                                                                                                                                                      
  // disable all adc interrupt                  
  AT91C_BASE_ADC->ADC_IDR = ALL_PERIPHERIAL_INTERRUPT_DISABLE;
              
  if (AT91C_BASE_AIC->AIC_SVR[AT91C_ID_ADC] != (uint32_t)adcHandler)
  {    /*first start*/                           
    /* Enable interrupts */
    /* Disable the interrupt on the interrupt controller */
    AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_ADC);
    /* Save the interrupt handler routine pointer and the interrupt priority */
    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_ADC] = (uint32_t)adcHandler;
    /* Store the Source Mode Register */
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_ADC] = AT91C_AIC_SRCTYPE_HIGH_LEVEL |
    AT91C_AIC_PRIOR_LOWEST;
    /* Clear the interrupt on the interrupt controller */
    AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_ADC);  
    /* Enable the interrupt on the interrupt controller */
    AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_ADC);
  }                       
}

/******************************************************************************
Starts convertion on the ADC channel.
Parameters:
  channel - channel number.
******************************************************************************/
void StartAdc(AdcChannelNumber_t channel)
{
  // enable current channel
  AT91C_BASE_ADC->ADC_CHER = channel;  
  // enable receiver PDC transfer requests  
  AT91C_BASE_ADC->ADC_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
  // enable receiver buffer full interrupt                     
  AT91C_BASE_ADC->ADC_IER = AT91C_ADC_RXBUFF;        
  // Starts conversion
  AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
}
Go to the top of the page
 
+Quote Post
_dem
сообщение May 12 2008, 09:22
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Можно "клокить" ADC от таймеров.
Примерно так :

Код
    // Setup TC0
    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;   // Enable clock to TC0
    AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV2_CLOCK | AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR;   // Prescaler set to 1024, Compare mode on RC, Change TIOA0 according to RA and RC
    AT91C_BASE_TC0->TC_RC = TIME_PERIOD;   // Compare value of RC, clear TIOA0 and reset timer
    AT91C_BASE_TC0->TC_RA = TIME_PERIOD/2;  // Compare value of RA, set TIOA0
    AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // Enable timer

    // configure ADC
    AT91C_BASE_PMC->PMC_PCER = ( 1 << AT91C_ID_ADC);
    // ad2, ad1 channels, pio PB 29,30
    AT91C_BASE_PIOB->PIO_PDR = ( 1 << 29) | (1<<30);
    
    AT91C_BASE_ADC->ADC_CHER = (1<<5);
    AT91C_BASE_ADC->ADC_MR = AT91C_ADC_LOWRES_8_BIT | AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA0 | AT91C_ADC_SHTIM | (( 0x02 ) << 8);//prescaler


И тогда, как и хочется, прерывание будет по заполнению буфера

Код
    // Setup interrupts
    AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_ADC, INT_LEVEL_ADC, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, adc_isr);
//    AT91C_BASE_ADC->ADC_IER  = AT91C_ADC_EOC4;  //  IRQ enable EOC0
    AT91C_BASE_ADC->ADC_IER  = AT91C_ADC_RXBUFF;  //  IRQ enable EOC0
    AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_ADC;   // Enable interrupt in AIC
    AT91C_BASE_ADC->ADC_PTCR = AT91C_PDC_RXTEN;

    
    // start timer
    AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;    // Start timer


В прерывании настраиваем PDC на новый буфер

Код
// starting PDC
AT91C_BASE_ADC->ADC_RPR = (long)(data);
AT91C_BASE_ADC->ADC_RCR    = BUFF_SIZE;


Извините, если код не очень читабелен - выдрал из тестового проекта.
Go to the top of the page
 
+Quote Post
xelax
сообщение May 12 2008, 11:08
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035



Это понятно.

Только всё таки мне интересно, при программном старте измерения АЦП должен сам доизмерять оставшиеся разы или его нужно пинать каждый раз(таймером, внешним триггером, программой).
Go to the top of the page
 
+Quote Post
_dem
сообщение May 12 2008, 12:22
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Вы либо пинаете его программно (на одно преобразование), либо настраиваете так, чтобы он сам себя пинал от таймера smile.gif

В любом случае один пинок = одно преобразование.
Go to the top of the page
 
+Quote Post
prottoss
сообщение May 12 2008, 12:30
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(xelax @ May 12 2008, 19:08) *
пару недель назад тоже пинал АЦП. Хотелось, чтоб через ДМА АЦП сам загонял несколько измерений в буфер. Так ничего и не получилось. В итоге отказался от этой затеи и от прерываний от АЦП тоже. От ДМА у меня один плюс - не надо считывать каждый раз его регистр данных. В начале цикла измерений задаю адрес и размер буфера. Через нужные периоды времени пинаю АЦП

Запускаю АЦП из задачи.


--------------------
Go to the top of the page
 
+Quote Post
xelax
сообщение May 12 2008, 12:59
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035



Наверное примерно также и прийдётся сделать.
По прерыванию от окончания преобразования рестартовать АЦП заново, а когда ДМА выдаст прерывание о заполнении приёмного буфера, прекращать все преобразования.

По таймеру пинать АЦП не получится smile.gif таймеры уже все заняты.

Что-то как-то не продумал Atmel с PDC, потому что автоматический набор значений в буфер сам собой напрашивается. sad.gif
Go to the top of the page
 
+Quote Post
_dem
сообщение May 12 2008, 13:21
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Да елки-палки smile.gif все работает нормально, автоматически заполняет буфер - вот этот код выдрал из тестового проекта для осфиллографа-на-коленке-за-пять-минут.

Почитайте еще раз ДШ, если что - вечером помогу с исходником более плотно.

Ну не мог же я сделать осцилл на 300 килогерц на побайтных прерываниях, да еще и успевать по UDP слать данные smile.gif
Go to the top of the page
 
+Quote Post
prottoss
сообщение May 12 2008, 13:32
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(_dem @ May 12 2008, 21:21) *
вот этот код выдрал из тестового проекта для осфиллографа-на-коленке-за-пять-минут.
Какой код? smile.gif Ничего вроде не прикреплено. Ну так ткнули бы в даташит носом. Я вроде внимательно читал, но так и не понял про ЭТО


--------------------
Go to the top of the page
 
+Quote Post
_dem
сообщение May 12 2008, 14:22
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Вечером ткну smile.gif Сейчас на работе, занят.

Курим пока
35.4.5 Timer Triggers
35.5.5 Conversion Triggers
Conversions of the active analog channels are started with a software or a hardware trigger. The
software trigger is provided by writing the Control Register (ADC_CR) with the bit START at 1.

The conversion sequencer allows automatic processing with minimum processor intervention
and optimized power consumption. Conversion sequences can be performed periodically using
a Timer/Counter output. The periodic acquisition of several samples can be processed automatically
without any intervention of the processor thanks to the PDC.
Go to the top of the page
 
+Quote Post
prottoss
сообщение May 12 2008, 14:41
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(_dem @ May 12 2008, 22:22) *
Вечером ткну smile.gif Сейчас на работе, занят.
Курим пока
Да это все уже прокуреноsmile.gif Я не хочу использовать таймер и создавать лишние прерывания, которых и так полно в проекте. По этому пинаю АЦП из задачи. Ну а с таймером и так все понятно. То, что буфер заполняется автоматом - это и так очевидно - работает ДМА, если его настроить.

2 xelax

В любом случае АЦП нужен период измерений, который и задается либо таймером аппаратно, либо программным пинком.


--------------------
Go to the top of the page
 
+Quote Post
_dem
сообщение May 12 2008, 14:53
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Понятно.

Из вашего сообщения
"пару недель назад тоже пинал АЦП. Хотелось, чтоб через ДМА АЦП сам загонял несколько измерений в буфер. "

тяжело понять, что "сам загонял" - это без пинаний его вообще smile.gif
Go to the top of the page
 
+Quote Post
prottoss
сообщение May 12 2008, 15:23
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(_dem @ May 12 2008, 22:53) *
Из вашего сообщения
"пару недель назад тоже пинал АЦП. Хотелось, чтоб через ДМА АЦП сам загонял несколько измерений в буфер. " тяжело понять, что "сам загонял" - это без пинаний его вообще smile.gif
Да, пока не изучил работу АЦП - хотел smile.gif В итоге сделал так, как сделал.


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение May 12 2008, 16:21
Сообщение #13


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



В атаче выдранные исходники из рабочего проекта. Присоединил как есть, дабы не вносить багов.

Использовать снаружи так:

Код
while(adcContext.pReadDesc->status)
{
    memcpy_burst( (U32 *)din, (U32 *)adcContext.pReadDesc->storage, sizeof( din ));
    // free up the DMA descriptor
    adcContext.pReadDesc->status = 0;
    adcContext.pReadDesc = adcContext.pReadDesc->pNext;
    .... обработка текщего фрейма в din
              
}

if (adcContext.Overload)
{
    //printf("ALERT: OUT OF MIPS\n");
    printf("~");
    adcContext.Overload = 0;
}


где din - массив такой же длины как и pReadDesc->storage.
Прикрепленные файлы
Прикрепленный файл  adc_example.zip ( 2.27 килобайт ) Кол-во скачиваний: 41
 
Go to the top of the page
 
+Quote Post
xelax
сообщение May 13 2008, 05:27
Сообщение #14


Местный
***

Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035



2 _dem

Где же обещанный пример без таймера, где PDC самостоятельно запускает и читает ADC. wink.gif
Go to the top of the page
 
+Quote Post
_dem
сообщение May 13 2008, 08:34
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



А кто обещал пример без таймера 8( ???
Нет пока возможности, извините.
Дедлайн sad.gif

Обещал и выложу позже свой проект - пинание от таймера, складывание в PDC, отправка буферов по UDP (Ethernet).
Тянет до 500 кбпс примерно, 8 бит, один канал.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th June 2025 - 14:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01515 секунд с 7
ELECTRONIX ©2004-2016