Миландр

Ключевым подразделением нашей компании является Центр Проектирования интегральных микросхем
Текущее время: 2018-июн-19 23:02

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ 1 сообщение ] 
Автор Сообщение
 Заголовок сообщения: Ещё раз про связку АЦП - ПДП
СообщениеДобавлено: 2017-дек-29 20:15 
Не в сети
Аватара пользователя

Зарегистрирован: 2013-июн-21 15:27
Сообщения: 88
Откуда: Новосибирск
Пишу проект на CM-ARM для МК 1986ВЕ92У. Проектируемое устройство должно во время строба передатчика измерять температуру и сигнал с детектора. Ширина строба может меняться в разы и заранее известны только пределы изменения.
Начало и конец строба обнаруживаю с помощью канала таймера в режиме захвата.
В обработчике от начала строба запускаю в режим непрерывной работы подряд друг за другом ADC-2 (для измерения сигнала детектора), ADC-1 (для измерения температуры) и DMA (для записи в массив измеряемых значений). Поскольку ширина строба, а значит и число измерений под стробом заранее неизвестны, задаю для DMA значение для максимально возможной ширины строба.
В обработчике от конца строба выключаю ADC и DMA и обрабатываю собранные данные.
При автономной проверке устройства (вне целевого изделия) или на отл.плате температура берётся с внутреннего датчика в МК, а сигнал детектора выдаётся через DAC-2 из заранее рассчитанного массива в обработчике прерывания ADC-2.
DMA и ADC-1 (а в "боевом" режиме и ADC-2) работают без прерываний (закрыты в NVIC).

Код начальной настройки:
Код:
#pragma locate DMA_Controls 0x20000000 noinit
DMA_CtrlDataTypeDef DMA_Controls[DMA_Channels_Number * (1 + DMA_AlternateData)];
#pragma noinit ADC_data
TADCdata ADC_data[Nadc];               // массив данных АЦП-1,2
pADCdata ADC_ptr = &ADC_data[Nadc - 1];// указатель данных в массиве
#pragma noinit DAC_exp, UnitAddr, Po_Data
ushort    Po_Data[Nadc+2];             // вычисленные значения ЦАП
int       Po_Idx  = 0;                 // индекс в массиве данных ЦАП
// ---------------------------------------------------------------------------
  // тактирование АЦП
  CLOCK->ADC_MCO_CLOCK = 2 << RST_CLK_ADC_MCO_CLOCK_ADC_C1_SEL_Pos // ADC_C1 <- CPU_C2 (96 МГц)
                       | 2 << RST_CLK_ADC_MCO_CLOCK_ADC_C2_SEL_Pos // ADC_C2 <- ADC_C1 (96 МГц)
                       | 0 << RST_CLK_ADC_MCO_CLOCK_ADC_C3_SEL_Pos;// ADC_C3 <- ADC_C2 (96 МГц)
                       | RST_CLK_ADC_MCO_CLOCK_ADC_CLK_EN;         // вкл. тактирование АЦП
  // режим работы АЦП-1
  ADC->ADC1_CFG = ADC_CLOCK_SOURCE_ADC              // тактирование от ADC_C3
                | ADC_CLK_div_64                    // ADC_CLK = ADC_C3/64 (1.5 МГц, 18.75 мкс)
                | 0 << ADC1_CFG_DELAY_ADC_Pos       // нет задержки между АЦП-1 и АЦП-2
                | 7 << ADC1_CFG_DELAY_GO_Pos        // 7 доп.тактов задержки на отл.плате
                | ADC_VREF_CONVERSION_Disable       // не измеряем Uоп
                | ADC_TEMP_SENSOR_CONVERSION_Enable // внутр.термодатчик выбран
                | ADC_TEMP_SENSOR_AMPLIFIER_Enable  // вкл. усилитель термодатчика
                | ADC_TEMP_SENSOR_Enable            // вкл. внутр.термодатчик
                | ADC_SyncMode_Independent          // независимый запуск АЦП-1 и АЦП-2
                | ADC_VREF_SOURCE_INTERNAL          // внутр.источник Uоп
                | 0 << ADC1_CFG_TR_Pos              // без подстройки Uоп
                | ADC_LEVEL_CONTROL_Disable         // без контроля границ
                | ADC_SAMPLING_MODE_CICLIC_CONV     // непрерывное измерение
                | 31 << ADC1_CFG_REG_CHS_Pos        // номер канала для Tпрд
                | ADC_CH_SWITCHING_Disable;         // без перебора каналов
  ADC->ADC1_STATUS = 0;                             // запр. прерывания от АЦП-1
  // режим работы АЦП-2
  ADC->ADC2_CFG = ADC_CLOCK_SOURCE_ADC              // тактирование от ADC_C3
                | ADC_CLK_div_64                    // ADC_CLK = ADC_C3/64 (1.5 МГц, 18.75 мкс)
                | 7 << ADC2_CFG_DELAY_GO_Pos        // 7 доп.тактов задержки на отл.плате
                | ADC_VREF_SOURCE_INTERNAL          // внутр.источник Uоп
                | ADC_INT_VREF_SOURCE_EXACT << ADC2_CFG_ADC1_OP_Pos // точное Uоп в АЦП-1
                | ADC_INT_VREF_SOURCE_EXACT << ADC2_CFG_ADC2_OP_Pos // точное Uоп в АЦП-2
                | ADC_LEVEL_CONTROL_Disable         // без контроля границ
                | ADC_SAMPLING_MODE_CICLIC_CONV     // непрерывное измерение
                | 7 << ADC1_CFG_REG_CHS_Pos         // номер канала для Pвых
                | ADC_CH_SWITCHING_Disable;         // без перебора каналов
  ADC->ADC2_STATUS = 0;                             // запр. прерывания от АЦП-2
// ---------------------------------------------------------------------------
  // Настройка и запуск ЦАП
  DAC->DAC2_DATA = 0;                           // нуль на выходе ЦАП-2
  DAC->CFG       = DAC_SYNC_MODE_Independent    // независимый запуск ЦАП-1 и ЦАП-2
                 | DAC2_AVCC                    // опора ЦАП-2 от AVcc
                 | DAC_CFG_ON_DAC1;             // запуск ЦАП-2
// ---------------------------------------------------------------------------
  // Настройка ПДП
  DMA->CFG               = DMA_AHB_Privileged;     // привилегированный доступ
  DMA->CTRL_BASE_PTR     = (uint)(&DMA_Controls);  // адрес таблицы упр.структур
  DMA->CHNL_SW_REQUEST   = 0;                      // запретить все программные запросы
  DMA->CHNL_USEBURST_CLR = 0xFFFFFFFF;             // запретить пакетный обмен
  DMA->CHNL_REQ_MASK_SET = 0xFFFFFFFF;             // замаскировать все запросы
  DMA->CHNL_ENABLE_SET   = 0xFFFFFFFF;             // разрешить все каналы
  DMA->CHNL_REQ_MASK_CLR = (1 << DMA_Channel_ADC1) // разрешить запросы АЦП-1
                         | (1 << DMA_Channel_ADC2);// разрешить запросы АЦП-2
  DMA->CHNL_PRI_ALT_CLR  = 0xFFFFFFFF;             // первичные упр.структуры
  DMA->CHNL_PRIORITY_CLR = 0xFFFFFFFF;             // приоритет по умолчанию
  DMA->ERR_CLR           = 1;                      // сброс ошибок ПДП
  // Упр.структура канала АЦП-1
  DMA_Controls[DMA_Channel_ADC1].DMA_SourceEndAddr = (uint)&(ADC->ADC1_RESULT);  // источник: ADC1_RESULT
  DMA_Controls[DMA_Channel_ADC1].DMA_DestEndAddr   = (uint)&(ADC_data[Nadc-1].T);// последний адрес приемника
  DMA_Controls[DMA_Channel_ADC1].DMA_Control       = DMA_SourceIncNo             // источник не меняется
                                                   | DMA_DestIncWord             // шаг приемника - слово
                                                   | DMA_MemoryDataSize_HalfWord // размер данных - полуслово
                                                   | DMA_SourcePrivileged        // источник - привилегированный доступ
                                                   | DMA_DestPrivileged          // приемник - привилегированный доступ
                                                   | DMA_Transfers_1             // арбитраж после каждой передачи
                                                   | ((Nadc - 1)     << 4)       // макс.число передач - 1
                                                   | (DMA_BurstClear << 3)       // запрет пакетного обмена
                                                   | DMA_Mode_Basic;             // основной режим
  // Упр.структура канала АЦП-2
  DMA_Controls[DMA_Channel_ADC2].DMA_SourceEndAddr = (uint)&(ADC->ADC2_RESULT);   // источник: ADC2_RESULT
  DMA_Controls[DMA_Channel_ADC2].DMA_DestEndAddr   = (uint)&(ADC_data[Nadc-1].Po);// последний адрес приемника
  DMA_Controls[DMA_Channel_ADC2].DMA_Control       = DMA_SourceIncNo              // источник не меняется
                                                   | DMA_DestIncWord              // шаг приемника - слово
                                                   | DMA_MemoryDataSize_HalfWord  // размер данных - полуслово
                                                   | DMA_SourcePrivileged         // источник - привилегированный доступ
                                                   | DMA_DestPrivileged           // приемник - привилегированный доступ
                                                   | DMA_Transfers_1              // арбитраж после каждой передачи
                                                   | ((Nadc - 1)     << 4)        // число передач - 1
                                                   | (DMA_BurstClear << 3)        // запрет пакетного обмена
                                                   | DMA_Mode_Basic;              // основной режим

здесь Nadc = 32 - максимальное число отсчётов под стробом

Запуск АЦП и ПДП в начале строба:
Код:
  ADC_Cnt = 0;                                     // сброс счетчика
  ADC_T   = 0;                                     // сброс Tпрд
  ADC_P = 0;                                       // - сброс Pвых
  for (i = 0; i < Nadc; i++) ADC_data[i] = 0;      // очистка массива данных АЦП
  DMA_Controls[DMA_Channel_ADC2].DMA_Control = DMA_SourceIncNo              // источник не меняется
                                             | DMA_DestIncWord              // шаг приемника - слово
                                             | DMA_MemoryDataSize_HalfWord  // размер данных - полуслово
                                             | DMA_SourcePrivileged         // источник - привилегированный доступ
                                             | DMA_DestPrivileged           // приемник - привилегированный доступ
                                             | DMA_Transfers_1              // арбитраж после каждой передачи
                                             | ((Nadc - 1)     << 4)        // число передач - 1
                                             | (DMA_BurstClear << 3)        // запрет пакетного обмена
                                             | DMA_Mode_Basic;              // основной режим
  DMA_Controls[DMA_Channel_ADC1].DMA_Control = DMA_SourceIncNo              // источник не меняется
                                             | DMA_DestIncWord              // шаг приемника - слово
                                             | DMA_MemoryDataSize_HalfWord  // размер данных - полуслово
                                             | DMA_SourcePrivileged         // источник - привилегированный доступ
                                             | DMA_DestPrivileged           // приемник - привилегированный доступ
                                             | DMA_Transfers_1              // арбитраж после каждой передачи
                                             | ((Nadc - 1)     << 4)        // число передач - 1
                                             | (DMA_BurstClear << 3)        // запрет пакетного обмена
                                             | DMA_Mode_Basic;              // основной режим
  DMA->CHNL_REQ_MASK_CLR = (1 << DMA_Channel_ADC1) // разрешить запросы АЦП-1
                         | (1 << DMA_Channel_ADC2);// разрешить запросы АЦП-2
  Po_Idx  = 2;                                     // сброс индекса массива данных ЦАП
  DAC->DAC2_DATA = Po_Data[Po_Idx++];              // запуск ЦАП для проверки
  ADC->ADC2_STATUS = 0;                            // сброс флагов АЦП-2
  ADC->ADC2_CFG   |= ADC2_CFG_REG_ADON             // вкл. АЦП-2
                   | ADC2_CFG_REG_GO;              // запуск АЦП-2
  ADC->ADC1_STATUS = 0;                            // сброс флагов АЦП-1
  ADC->ADC1_CFG   |= ADC1_CFG_REG_ADON             // вкл. АЦП-1
                   | ADC1_CFG_REG_GO;              // запуск АЦП-1
  ADC->ADC2_STATUS = ADC_STATUS_ECOIF_IE;          // разр.прерывания по готовности АЦП-2
  NVIC_ClearPendingIRQ(DMA_IRQn);                  // сброс флага ожидания прерывания
//  NVIC_EnableIRQ(DMA_IRQn);                        // разрешить прерывание от ПДП
  DMA->CFG         = DMA_AHB_Privileged            // привилегированный доступ
                   | DMA_FLAG_DMA_ENA;             // включить ПДП


Выключение АЦП и ПДП в конце строба:
Код:
  // Остановка и выключение АЦП-1,2
  ADC->ADC2_CFG   &= ~(ADC2_CFG_REG_ADON |
                       ADC2_CFG_REG_GO); // выкл. АЦП-2
  ADC->ADC1_CFG   &= ~(ADC1_CFG_REG_ADON |
                       ADC1_CFG_REG_GO); // выкл. АЦП-1
  // Остановка и выключение ПДП
  DMA->CHNL_REQ_MASK_SET = 0xFFFFFFFF;   // замаскировать все запросы
  DMA_Controls[DMA_Channel_ADC2].DMA_Control = DMA_SourceIncNo              // источник не меняется
                                             | DMA_DestIncWord              // шаг приемника - слово
                                             | DMA_MemoryDataSize_HalfWord  // размер данных - полуслово
                                             | DMA_SourcePrivileged         // источник - привилегированный доступ
                                             | DMA_DestPrivileged           // приемник - привилегированный доступ
                                             | DMA_Transfers_1              // арбитраж после каждой передачи
                                             | (0              << 4)        // последняя передача
                                             | (DMA_BurstClear << 3)        // запрет пакетного обмена
                                             | DMA_Mode_Stop;               // режим Стоп
  DMA_Controls[DMA_Channel_ADC1].DMA_Control = DMA_SourceIncNo              // источник не меняется
                                             | DMA_DestIncWord              // шаг приемника - слово
                                             | DMA_MemoryDataSize_HalfWord  // размер данных - полуслово
                                             | DMA_SourcePrivileged         // источник - привилегированный доступ
                                             | DMA_DestPrivileged           // приемник - привилегированный доступ
                                             | DMA_Transfers_1              // арбитраж после каждой передачи
                                             | (0              << 4)        // последняя передача
                                             | (DMA_BurstClear << 3)        // запрет пакетного обмена
                                             | DMA_Mode_Stop;               // режим Стоп
  DMA->CFG               = 0;            // выкл. ПДП
  DMA->ERR_CLR           = 1;            // сброс ошибок ПДП
  NVIC_DisableIRQ(DMA_IRQn);             // запретить прерывание от ПДП
  NVIC_ClearPendingIRQ(DMA_IRQn);        // сброс флага ожидания прерывания
  ADC->ADC2_STATUS = 0;                  // сброс флагов АЦП-2
  ADC->ADC1_STATUS = 0;                  // сброс флагов АЦП-1
  NVIC_ClearPendingIRQ(ADC_IRQn);        // сброс флага ожидания прерывания
  DAC->DAC2_DATA   = 0;                  // сброс вых.сигнала ЦАП


Обработчик прерывания АЦП-2:
Код:
  i = (sGet(inStrobe))? Po_Idx++ : 0; // под стробом очередные данные, вне строба нулевые
  DAC->DAC2_DATA = Po_Data[i];        // запуск ЦАП


Есть некоторые сомнения... Для остановки уже запущенного запроса ПДП раньше исчерпания счетчика передач я делаю следующее:
- выключаю АЦП-1 и АЦП-2
- маскирую все запросы ПДП
- в упр.структурах обнуляю счетчик оставшихся передач (впрочем это означает 1 оставшуюся передачу, а не 0)
- там же меняю Основной режим на режим Стоп
- выключаю контроллер ПДП (CFG = 0)
- сбрасываю ошибки ПДП
- сбрасываю флаги состояния АЦП-1 и АЦП-2
- сбрасываю флаги ожидания прерываний АЦП и ПДП в NVIC
возможно, что-то из этого лишнее? Спрашиваю потому что исключение чего-то из перечисленного могло бы позволить исключить обратные действия при запуске АЦП и ПДП в начале строба, а там хотелось бы всё ускорить насколько возможно.

И ещё осталось несколько непоняток:

1. Чем отличается выключенное АЦП от включенного, но не запущенного? То есть достаточно ли для остановки запущенного в режим непрерывного преобразования АЦП сбросить CFG_REG_GO или нужно сбрасывать и CFG_REG_ADON тоже?

2. Почему в указанном коде 1-е прерывание от АЦП происходит сразу после запуска, а не после завершения преобразования? В данном случае это не мешает, но я не могу понять, почему так происходит? Я пробовал ставить точку останова в отладчике сразу после сброса регистра STATUS и установки CFG_REG_GO, при этом в регистре STATUS установлены флаг окончания преобразования и флаг перезаписи. После этого прерывания происходят с периодом, равным времени преобразования.

3. В данном коде я закомментировал разрешение прерываний ПДП (поскольку мне они ни к чему), но если их разрешить, то при запуске программы из среды CM_ARM всё работает нормально, а если запускать кнопкой Сброс на отл.плате, то прерывание ПДП происходит не после 32 передач, а после 3 или 4. Почему?

4. Если не задействовать ЦАП и не разрешать прерывания от АЦП, то попытка запустить АЦП с коэффициентом деления частоты ADC_C3 не 64, а например 4 или 8 (при HCLK = 96 МГц и ADC_C3 = 48 МГц получается ADC_CLK 12 или 6 МГц, что меньше указанных в спецификации 14), то массив данных заполняется не полностью (извините, я пробовал давно и теперь не помню, то ли были "дырки" в середине, то ли просто мало значений), такое впечатление, что или АЦП начинает сбиваться и пропускать отсчёты, или ПДП не успевает забирать данные. Кто-то ещё с этим сталкивался?

_________________
Странник


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ 1 сообщение ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB