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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Xmega АЦП
Xeon
сообщение Mar 11 2012, 07:26
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Сначала приведу код , а потом расскажу в чём проблема:

Хэдер для АЦП:

Код
#define ADC_BUFFER_SIZE 256

/*
AdcConvertionMode - режим преобразования, знаковый или без знаковый (см. в даташите на странице )
        == 0 - беззнаковый режим
        == 1 - знаковый режим
Resolution - разрядность
        == 00 - 12 бит выравнивание справа
        == 01 - зарезервированно
        == 10 - 8 бит выравневание справа
        == 11 - 12 бит выравнивание слева
Reference - опорное напряжения
        == 00 - внутреннее 1.00V
        == 01 - внешнее VCC/1.6
        == 10 - внешнее на порту A.
        == 11 - внешнее на порту B.
Prescaler - делитель частоты АЦП
        == 000 - 4
        == 001 - 8
        == 010 - 16
        == 011 - 32
        == 100 - 64
        == 101 - 128
        == 110 - 256
        == 111 - 512
AdcPin - Вход АЦП
        == 000 - ADC0 pin
        == 001 - ADC1 pin
        == 010 - ADC2 pin
        == 011 - ADC3 pin
        == 100 - ADC4 pin
        == 101 - ADC5 pin
        == 110 - ADC6 pin
        == 111 - ADC7 pin
Values[ADC_BUFFER_SIZE] - буфер в котором хранятся преобразованные значения
CurVal - текущее количество значений в буфере
ConversionCnt - количество измерений которые надо сделать
Flags - текущее состояние АЦП
*/
struct ADC_cfg
{
    unsigned char    AdcConvertionMode;
    unsigned char    Resolution;
    unsigned char    Reference;
    unsigned char    Prescaler;
    unsigned char    AdcPin;
    
    unsigned short    Values[ADC_BUFFER_SIZE];
    unsigned short    CurVal;
    unsigned short    ConversionCnt;
    
    unsigned char    Flags;
} ADC_config;

#define ADC_STOPED                    0
#define ADC_STARTED                    1
#define ADC_CONVERSION_COMPLETE        2

void ADC_init();
void ADC_deinit();
void ADC_flush();
void ADC_start();
void ADC_wait();


Соурс для АЦП:

Код
void ADC_init()
{
    // нужную ногу настраиваем на вход
    PORTA.DIRCLR = 1 << ADC_config.AdcPin;
    
    // CTRLA - ADC Control Register A (см. в даташите на странице 302)
    // здесь просто включаем АЦП выставляя нуливой бит
    ADCA.CTRLA = 1;
    
    //     CTRLB - ADC Control Register B
    // здесь в зависимосте от настроек выставляем знак, режим, разрядность
    ADCA.CTRLB = ((ADC_config.AdcConvertionMode << ADC_CONMODE_bp) | (ADC_config.Resolution << 1));
    
    // REFCTRL - ADC Reference Control register
    // выставляем опорное напряжение
    ADCA.REFCTRL = (ADC_config.Reference << 4) | 2;
    
    // делитель частоты АЦП, по даташиту максимальная частота 2 МГц
    ADCA.PRESCALER = ADC_config.Prescaler;
    
    // Настраиваем мультиплексор
    ADCA.CH0.CTRL = 1;
    ADCA.CH0.MUXCTRL = ADC_config.AdcPin << 3;
    ADCA.CH0.INTCTRL = 3;
    
    ADC_config.CurVal = 0;
    ADC_config.Flags = ADC_STOPED;
}

void ADC_deinit()
{
    // отключаем АЦП
    ADCA.CTRLA = 0;
    ADC_config.Flags = ADC_STOPED;
}

void ADC_flush()
{
    // очистить АЦП
    ADCA.CTRLA |= 2;
    
    ADC_config.CurVal = 0;
    ADC_config.Flags = ADC_STOPED;
}    

void ADC_start()
{
    // начать преобразование
    //ADCA.CH0.CTRL |= 128;
    ADCA.CTRLA |= 4; // start channel 0
    ADC_config.Flags = ADC_STARTED;
}        

void ADC_wait()
{
    do {} while(ADC_config.Flags != ADC_CONVERSION_COMPLETE);
}

ISR(ADCA_CH0_vect)
{
    ADC_config.Values[ADC_config.CurVal] = ADCA.CH0.RES;
    //ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm;
    
    ADC_config.CurVal++;
    ADC_config.ConversionCnt--;
    
    if(ADC_config.ConversionCnt != 0)
    {
        ADC_start();
    }    
    else
    {
        ADC_config.Flags = ADC_CONVERSION_COMPLETE;
    }            
}


И как пользуюсь:

Код
// заполняем конфигурационную структуру
            ADC_config.AdcConvertionMode    = 0;    // без знаковый
            ADC_config.Resolution            = 0;    // 12 бит, выравневание справа
            ADC_config.Reference            = 0;    // внутрений источник опорного напряжения 1 В
            ADC_config.Prescaler            = 2;    // делитель частоты 64 (частота АЦП получается 2 МГц при тактовой частоте камня 500 КГц)
            ADC_config.AdcPin                = 0;    // выбираем ногу ADC0
            // инициализируем АЦП
            ADC_init();
            
            // устанавляваем количество преобразований
            ADC_config.ConversionCnt = ((unsigned short) ParseBuf[1]) << 8;
            ADC_config.ConversionCnt |= (unsigned short) ParseBuf[0];
            
            // запускаем цикл измерений
            ADC_flush();
            ADC_start();

            // ожидаем завершения цикла измерений
            [color="#FF0000"]_delay_us(50); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![/color]
            ADC_wait();
            // отключаем АЦП
            ADC_deinit();



Проблема в следующем: если есть строка _delay_us(50); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! то всё работает норм, делаются нужное количество преобразований и отсылаются мне на комп... А вот если я убираю данную строку то программа зависает в функции ADC_wait(); (там цикл выполняется пока все преобразования не выполнятся). Флаг выставляется в прерывании АЦП (строчка ADC_config.Flags = ADC_CONVERSION_COMPLETE;)... Без вот этой задержки почему то не каких преобразований не делается, может конечно они делаются но прерывание не срабатывает!!!
Люди, может я что то упускаю из особенностей работы с данным АЦП?

Вот если нужно проект для AVR Studio 5: Прикрепленный файл  ADC.rar ( 290.39 килобайт ) Кол-во скачиваний: 106

Go to the top of the page
 
+Quote Post
Палыч
сообщение Mar 11 2012, 07:40
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Вероятно, не хватает volatile при описании Flags
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 11 2012, 08:34
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Цитата(Палыч @ Mar 11 2012, 10:40) *
Вероятно, не хватает volatile при описании Flags

А зачем? это же просто переменная в которой я храню текущее состояние АЦП и все...
Go to the top of the page
 
+Quote Post
Палыч
сообщение Mar 11 2012, 08:54
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Xeon @ Mar 11 2012, 12:34) *
А зачем?

Поскольку значение этого поля структуры может измениться "вдруг" при наступлении прерывания
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 11 2012, 09:24
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Цитата(Палыч @ Mar 11 2012, 11:54) *
Поскольку значение этого поля структуры может измениться "вдруг" при наступлении прерывания


А можно по подробней... просто я считал что volatile используется для гарантирования, что что-то запишется во флэш (например volatile asm("cli"))!!!!!

Поставил volatile помогло БОЛЬШУЩЕЕ СПАСИБО Палыч!!!!!!!!
Go to the top of the page
 
+Quote Post
Палыч
сообщение Mar 11 2012, 09:42
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Xeon @ Mar 11 2012, 13:24) *
А можно по подробней...

Выполнение цикла в ADC_wait() выполняется следующим образом:
1. Взять значение Flags на регистр Temp
2. Сравнить значение регистра Temp со значением ADC_CONVERSION_COMPLETE
3. Если условие не выполняется то выход из цикла и функции
4. В противном случае - переход:
а) при отсутствии volatile - значение Flags не изменилось в теле цикла и находится в регистре Temp, то переход на п.2 (впадаем в бесконечный цикл)
б) с volatile - значение Flags могло быть изменено где-то (не важно где), то на п.1
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 11 2012, 12:58
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Цитата(Палыч @ Mar 11 2012, 13:42) *
Выполнение цикла в ADC_wait() выполняется следующим образом:
1. Взять значение Flags на регистр Temp
2. Сравнить значение регистра Temp со значением ADC_CONVERSION_COMPLETE
3. Если условие не выполняется то выход из цикла и функции
4. В противном случае - переход:
а) при отсутствии volatile - значение Flags не изменилось в теле цикла и находится в регистре Temp, то переход на п.2 (впадаем в бесконечный цикл)
б) с volatile - значение Flags могло быть изменено где-то (не важно где), то на п.1


Если я правельно понил: получается, что без volatile зайдя в цикл копируется Flags в temp регистр один раз и потом проверяется при этом нового копирования не происходит...а в случае присутствия volatile значение Flags копируется в temp на каждой итерации?????
Go to the top of the page
 
+Quote Post
Палыч
сообщение Mar 11 2012, 15:37
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Xeon @ Mar 11 2012, 16:58) *
Если я правельно понил: получается...

Да, это - "гримаса" оптимизатора. Спецификатор volatile "подсказывает" оптимизатору, что значение Flags может изменяться в любой момент времени, и заставляет генерить код, который "достаёт" значение переменной из памяти всякий раз, когда её значение используется в неком выражении.
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 11 2012, 16:53
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Цитата(Палыч @ Mar 11 2012, 19:37) *
Да, это - "гримаса" оптимизатора. Спецификатор volatile "подсказывает" оптимизатору, что значение Flags может изменяться в любой момент времени, и заставляет генерить код, который "достаёт" значение переменной из памяти всякий раз, когда её значение используется в неком выражении.


Помимо того, что volatile используется для того что бы гарантировать, что какая либо команда будет точно вставленна компилятором и "доставать значение всякий раз когда пытаемся изменить его, для чего ещё может быть использованна volatile?"
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 28 2012, 10:39
Сообщение #10


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



И снова Всем привет! Ситуация следующая нужно использовать АЦП вместе с ДМА... Есть Буфер в который надо положить 256 значений.

Код инициализации:
CODE

void ADC_init()
{
// нужную ногу настраиваем на вход
PORTA.DIRCLR = 1 << /*ADC_config.*/AdcPin;
// CTRLA - ADC Control Register A (см. в даташите на странице 302)
// здесь просто включаем АЦП выставляя нулeвой бит
ADCA.CTRLA = ADC_ENABLE_bm /*| (1 << 7) | (1 << 6)*/;
// CTRLB - ADC Control Register B
// здесь в зависимосте от настроек выставляем знак, режим, разрядность
ADCA.CTRLB = ((/*ADC_config.*/AdcConvertionMode << ADC_CONMODE_bp) | (/*ADC_config.*/Resolution << 1)) | 0x08;
// REFCTRL - ADC Reference Control register
// выставляем опорное напряжение
ADCA.REFCTRL = (/*ADC_config.*/Reference << 4) | 2;
// делитель частоты АЦП, по даташиту максимальная частота 2 МГц
ADCA.PRESCALER = /*ADC_config.*/Prescaler;
// Настраиваем мультиплексор
ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
ADCA.CH0.MUXCTRL = /*ADC_config.*/AdcPin << 3;
//ADCA.CH0.INTCTRL = 3;

/*ADC_config.*/CurVal = 0;
/*ADC_config.*/Flags = ADC_STOPED;

DMA
DMA.CTRL = DMA_ENABLE_bm;
DMA.CH0.CTRLA = /*DMA_CH_SINGLE_bm |*/ DMA_CH_REPEAT_bm;
DMA.CH0.CTRLB = 3;
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_gm | DMA_CH_SRCDIR0_bm | DMA_CH_DESTRELOAD_gm/* | DMA_CH_DESTDIR0_bm*/;
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc;
DMA.CH0.TRFCNT = 10;
DMA.CH0.SRCADDR0 = /*(uint16_t)&inval;*/(uint16_t)&ADCA.CH0.RES;
DMA.CH0.SRCADDR1 = /*(uint16_t)&inval>>8;*/(uint16_t)&ADCA.CH0.RES>>8;
DMA.CH0.SRCADDR2 = 0;
DMA.CH0.DESTADDR0 = /*(uint16_t)&outval;*/(uint16_t)&Values;
DMA.CH0.DESTADDR1 = /*(uint16_t)&outval>>8;*/(uint16_t)&Values>>8;
DMA.CH0.DESTADDR2 = 0;
DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
}


Есть ещё функция которая начинает цикл измерений:
CODE

void ADC_start()
{
// начать преобразование
ADCA.CH0.CTRL |= 128;
ADCA.CTRLA |= 4; // start channel 0
}


И прерывание ДМА:
CODE

ISR(DMA_CH0_vect)
{
_DebugMes(USARTE0, "DMA interrupt\r\n", 19);
ADCA.CTRLA = 0;
Flags = ADC_CONVERSION_COMPLETE;
DMA.CH0.CTRLB |= (1 << 4) | (1 << 5);
}


В итоге получается что измерения не происходит...в прерывание не когда не входим...и...если вывожу значения из буфера, то там нули. В чём моя ошибка?
+Вопрос: ставлю на АЦП частоту в 250кГЦ, знаковый режим, 8 бит... по даташиту получаю задержку распространения в 20мкс что соответствует реально 50000 выборок в секунду, так же в даташите сказано при 8 разрядах минимальная задержка распространения 2,5 мкс что чоответствует 400000 выборок... и там же говорят что максимальная частота преобразований 2 мегавыборки...Врут?...противоречат сами себе? Или используя ДМА эта задержка убирается?

И в добавок: какую максимальную частоту можно подавать на АЦП? Например, когда я подавал 500КГц и мерил синусоиду к 63,5КГц, всё было ок... крачивая такая синусойда на графике))), а вот когда увеличивал частоту до 1МГц, то получал полную белиберду!!!!
Go to the top of the page
 
+Quote Post
ASDFG123
сообщение Apr 5 2013, 06:19
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 165
Регистрация: 2-01-13
Пользователь №: 75 042



Как у Xmega 32 A4 дела с ацп ? померить нужно импульс длительностью в 6 Мкс. сможет ?
Go to the top of the page
 
+Quote Post
Herz
сообщение Apr 5 2013, 06:36
Сообщение #12


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(ASDFG123 @ Apr 5 2013, 09:19) *
Как у Xmega 32 A4 дела с ацп ? померить нужно импульс длительностью в 6 Мкс. сможет ?

Дела у неё хорошо. А что значит "померить импульс"? И почему бы не заглянуть в даташит?
Go to the top of the page
 
+Quote Post
ASDFG123
сообщение Apr 5 2013, 07:11
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 165
Регистрация: 2-01-13
Пользователь №: 75 042



почитал отзывы по ней, и ацп в пред. ревизиях не работал с заявленными хар-ками.

Нужно сделать вольтметр который сможет померить напряжения импульсов длительностью 6 мкс

даташита кстати у нее нет, есть только подобии в виде manual
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Apr 5 2013, 08:10
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(ASDFG123 @ Apr 5 2013, 10:11) *
даташита кстати у нее нет, есть только подобии в виде manual

Даташиты у иксмег есть - плохо искали наверное.
Go to the top of the page
 
+Quote Post
Herz
сообщение Apr 5 2013, 10:46
Сообщение #15


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(ASDFG123 @ Apr 5 2013, 10:11) *
Нужно сделать вольтметр который сможет померить напряжения импульсов длительностью 6 мкс

У импульсов, наверное, и период есть? Минимальный, максимальный. Для такого вольтметра нужен пиковый детектор, а АЦП вторично.
Go to the top of the page
 
+Quote Post
ASDFG123
сообщение Apr 26 2013, 16:24
Сообщение #16


Частый гость
**

Группа: Участник
Сообщений: 165
Регистрация: 2-01-13
Пользователь №: 75 042



да 6 мс, ну вольтметр это я очень упрощенно сказал, т.к. надо знать каждый отсчет, например в 6мкс импульсе 5 отсчетов (sample) потом переключить канал и еще 5 со второго канала. Затем посчитать, записать в еепром, если чтото не работает по и2с отправить данные.
как наиболее беспроблемно перейти с МЕГ на Хмеги ? почитал инфу по ним, и написание программы довольно сильно отличается.

п.с Где можно скачать примеры программ о которых в аппноутах атмела говориться? Опасения у меня потому что в ошибках у атмела то что А3 ревизия работала со скоростью едва 500кСэмп, а про А4 незнаю косяк был исправлен или нет.
Go to the top of the page
 
+Quote Post
vitas56
сообщение Apr 27 2013, 04:13
Сообщение #17





Группа: Новичок
Сообщений: 2
Регистрация: 27-04-13
Пользователь №: 76 649



Цитата(ASDFG123 @ Apr 5 2013, 11:11) *
почитал отзывы по ней, и ацп в пред. ревизиях не работал с заявленными хар-ками.

Нужно сделать вольтметр который сможет померить напряжения импульсов длительностью 6 мкс

даташита кстати у нее нет, есть только подобии в виде manual


Сделал подобный вольтметр на мега8. Принцип очень простой. На микроконтроллере формируется экспонентно спадающая пила с периодом 200 -300 мс. Входные импульсы длит ~ 1мкс. подаются на вход встроенного компаратора. На другой вход пила. В момент совпадения пила останавливается и ее напряжение оцифровывается встроенным АЦП. Затем цикл повторяется. На зтом принципе сделал измеритель импульсной мощности на AD8313.
Точность измерений 0.5дБ. Динамический диапазон 60дБ. Входные радиочастотные импульсы длит от 0.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 - 03:54
Рейтинг@Mail.ru


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