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

 
 
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

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

 


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


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