Миландр

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

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




Начать новую тему Ответить на тему  [ Сообщений: 8 ] 
Автор Сообщение
 Заголовок сообщения: АЦП + DMA
СообщениеДобавлено: 2016-ноя-08 18:02 
Не в сети

Зарегистрирован: 2016-апр-27 12:14
Сообщения: 26
Добрый день.
Пытаюсь разобраться с DMA контроллером в связке с АЦП. Взял рабочий код АЦП + DMA для ВЕ92 и добавил к примеру ВЕ8 для АЦП и немного переделал. Задача тривиальная: значения каналов 0-6 и 23 (датчик температуры) складывать в массив ADCConvertedValue. Ниже привожу код:
Открыть
Код:
DMA_ChannelInitTypeDef  DMA_InitStr;
DMA_CtrlDataInitTypeDef DMA_PriCtrlStr;
DMA_CtrlDataInitTypeDef DMA_AltCtrlStr;

uint32_t            ADCConvertedValue[10];

static PORT_InitTypeDef PORT_InitStructure;
void init_DMA(void){
      CLKCTRL_PER0_CLKcmd(CLKCTRL_PER0_CLK_MDR_DMA0_EN, ENABLE);

   // DMA Configuration
   // Reset all settings
      DMA_DeInit();
      DMA_StructInit(&DMA_InitStr);
   // Set Primary Control Data
      DMA_PriCtrlStr.DMA_SourceBaseAddr =    (uint32_t)(&(ADC1->RESULT));
      DMA_PriCtrlStr.DMA_DestBaseAddr =       (uint32_t)ADCConvertedValue;
      DMA_PriCtrlStr.DMA_SourceIncSize =       DMA_SourceIncNo;
      DMA_PriCtrlStr.DMA_DestIncSize =          DMA_DestIncWord;
      DMA_PriCtrlStr.DMA_MemoryDataSize =    DMA_MemoryDataSize_Word;
      DMA_PriCtrlStr.DMA_Mode =                   DMA_Mode_AutoRequest;//DMA_Mode_Basic;//DMA_Mode_PingPong;
      DMA_PriCtrlStr.DMA_CycleSize = 4;
   //DMA_PriCtrlStr.DMA_CycleSize = 3;
      DMA_PriCtrlStr.DMA_NumContinuous =       DMA_Transfers_4;//DMA_Transfers_1;
      DMA_PriCtrlStr.DMA_SourceProtCtrl =    DMA_SourcePrivileged;
      DMA_PriCtrlStr.DMA_DestProtCtrl =       DMA_DestPrivileged;
   // Set Alternate Control Data
   /*
      DMA_AltCtrlStr.DMA_SourceBaseAddr = (uint32_t)(&(ADC1->RESULT));
      DMA_AltCtrlStr.DMA_DestBaseAddr   = (uint32_t)&ADCConvertedValue[3];
      DMA_AltCtrlStr.DMA_SourceIncSize =    DMA_SourceIncNo;
      DMA_AltCtrlStr.DMA_DestIncSize =       DMA_DestIncWord;
      DMA_AltCtrlStr.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
      DMA_AltCtrlStr.DMA_Mode =                DMA_Mode_Basic;//DMA_Mode_PingPong;
      DMA_AltCtrlStr.DMA_CycleSize =          5;
      DMA_AltCtrlStr.DMA_NumContinuous =   DMA_Transfers_1;
      DMA_AltCtrlStr.DMA_SourceProtCtrl = DMA_SourcePrivileged;
      DMA_AltCtrlStr.DMA_DestProtCtrl =    DMA_DestPrivileged;
      */
   // Set Channel Structure
      DMA_InitStr.DMA_PriCtrlData = &DMA_PriCtrlStr;
      DMA_InitStr.DMA_AltCtrlData = &DMA_AltCtrlStr;
      DMA_InitStr.DMA_Priority = DMA_Priority_Default;
      DMA_InitStr.DMA_UseBurst = DMA_BurstClear;
      DMA_InitStr.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;
      DMA_Init(DMA_Channel_ADC1, &DMA_InitStr); // Init DMA channel ADC1
      NVIC_EnableIRQ(DMA_IRQn);
   return;
}
//-----------------------------------------------------------------------------------------
void init_ADC(void){
   CLKCTRL_PER0_CLKcmd(CLKCTRL_PER0_CLK_MDR_PORTC_EN, ENABLE);
  /* Configure PortC[6:13] for analog input */
   PORT_InitStructure.PORT_Pin   = (PORT_Pin_6|PORT_Pin_7|PORT_Pin_8|PORT_Pin_9|
                                                    PORT_Pin_10|PORT_Pin_11|PORT_Pin_12|PORT_Pin_13);
   
  PORT_InitStructure.PORT_CANALOG  = PORT_CANALOG_DIGITAL;//Clear dig, set analog
  PORT_Init(PORTC, &PORT_InitStructure);
   
   CLKCTRL_PER1_CLKcmd(CLKCTRL_PER1_CLK_MDR_ADC1_EN, ENABLE);      
   ADC_CLK_en(ADCx_CLKSRC_MAX_CLK, ADCx_CLKdiv1);         
   ADC1->KEY = 0x8555AAA1;
   ADCx_IS.ADC_RH_MODE    = ADCx_CONFIG0_RH_MODE_ADC_POW; //   Выбор режима задания опрного тока
   //ADCx_IS.ADC_WORKMODE    = ADCx_CONFIG0_WORKMODE_CONT;      //    Непрерывное преобразование
   ADCx_IS.ADC_SETUP       = 15;                                          //  Время "зардки" АЦП
   ADCx_IS.ADC_PAUSE       = 5;
   //ADCx_IS.ADC_FIFOEN_0_31 = FIEN0|FIEN1|FIEN2|FIEN3|FIEN4|FIEN5|FIEN6|FIEN23;
   ADCx_IS.ADC_FIFOEN_0_31 = (uint32_t) 0xFFFFFFFF;  // разрешить запись во все FIFO
   ADC_Init(ADC1, &ADCx_IS);
   
   
   ADC1->CONFIG0 |=2<<1; // 10 – Непрерывное преобразование
   ADC1->CONFIG0 |=1<<5; /* по завершению преобразования производится автоматическое переключение на следующий канал,
                                       заданный в CHSEL (по записи значения SELMODE=1 предустанавливается счетчик перебора каналов)*/
                                 
                                 /*   каналы для переключения   */
   ADC1->CHSEL0|= 1<<0;                                       
   ADC1->CHSEL0|= 1<<1;
   ADC1->CHSEL0|= 1<<2;
   ADC1->CHSEL0|= 1<<3;
   ADC1->CHSEL0|= 1<<4;
   ADC1->CHSEL0|= 1<<5;
   ADC1->CHSEL0|= 1<<6;
   ADC1->CHSEL0|= 1<<23;
                                 /*   разрешить запросы DMA*/
   
   ADC1->DMAREQ |=((1<<0)<<24);
   ADC1->DMAREQ |=((1<<1)<<24);
   ADC1->DMAREQ |=((1<<2)<<24);
   ADC1->DMAREQ |=((1<<3)<<24);
   ADC1->DMAREQ |=((1<<4)<<24);
   ADC1->DMAREQ |=((1<<5)<<24);
   
   init_DMA();
   ADCx_Cmd(ADC1, ENABLE);
   /*
   ADC1->CONFIG2 |= 1 <<4;    // Error IE
   //ADC1->CONFIG2 |= 1 <<3; //FIFO AlmostFull IE
   //ADC1->CONFIG2 |= 1 <<2; // FIFO NotAlmostEmpty IE
   ADC1->CONFIG2 |= 1 <<0; // FIFO Not Empty IE
   NVIC_EnableIRQ(ADC1_IRQn);
*/
   return;
}
//-----------------------------------------------------------------------------------------
void DMA_DONE0_Handler(void){
   
   NVIC_ClearPendingIRQ(DMA_IRQn);
   __NOP();
   return;
}
//-----------------------------------------------------------------------------------------
Закрыть

В результате происходит непрерывное преобразование выбранных каналов АЦП, соответствующие ADC1->RESULTCH_xx постоянно меняются, но DMA ничего не делает. Это происходит хотя бы потому регистр CFG контроллера DMA имеет значение 0x00000000 т.е. 0-й бит (master_enable) имеет значение 0 и контроллер выключен. При попытке включения MDR_DMA->CONFIG|=1<<0; регистр не меняет своего значения.
Еще вопрос связан с датчиком температуры: температуру чего он измеряет и какая при этом зависимость?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2016-ноя-22 17:09 
Не в сети

Зарегистрирован: 2016-апр-27 12:14
Сообщения: 26
Неужели никто не заводил DMA на контроллере? Любой пример был бы очень кстати.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2016-ноя-22 17:49 
Не в сети

Зарегистрирован: 2015-июн-26 10:23
Сообщения: 54
В составе библиотеки viewtopic.php?f=47&t=3504 имеется пример работы dma+dac


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2018-фев-12 10:07 
Не в сети

Зарегистрирован: 2014-дек-12 11:22
Сообщения: 12
Разбираюсь с примером DMA-TIMER1-DAC0. Удается запустить только 0 канал DMA. Удивительно, что в примере в хедере 10 канал выделенный под TMER1 закомментен и назначен на 0 канал. Пытался изменить на любой другой, в том числе и на 10 - нет эффекта. Прерывания от каналов DMA не возникают. Кроме того в стартапе прописаны вектора только для DMA0 и DMA1, остальные занулены, хотя память под них выделяется. Почему? Из описания непонятно каждый ли канал DMA имеет свой вектор или он един для всех? Как разбираться какой канал вызвал прерывание?
(Кстати, пример содержит ошибки, в частности настройке DAC выполняется в неправильной последовательности.)
Need Help!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2018-фев-12 13:05 
Не в сети

Зарегистрирован: 2015-июн-26 10:23
Сообщения: 54
Здесь любое устройство из таблицы (Таблица 103 – Виртуальные номера запросов DMA спецификации) можно завести на канал с 0 по 31 DMA контроллера.

В текущем примере TMR1_REQ в таблице под номером 9.
Согласно таблице (Таблица 68 – Перечень регистров контроллера спецификации) пишем 9<<0 в CHMUX0 получаем 0 канал DMA контроллера. Разрешаем прерывания от DMA 0 канала и работаем.

Хотим, например, завести TMR1_REQ на 5 канал DMA.
Согласно таблице (Таблица 68 – Перечень регистров контроллера спецификации) пишем 9<<8 в CHMUX1 получаем 5 канал DMA контроллера. Разрешаем прерывания от DMA 5 канала (в пример необходимо добавить DMA_IRQn5 и DMA_DONE5_Handler) и работаем.

Выложим позже библиотеку на github, прямо там будем править добавлять множить для всех вариаций устройств (сейчас примеры и библиотеки показывают работу для хотя бы одного устройства каждого из блоков микроконтроллера).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2018-фев-13 10:20 
Не в сети

Зарегистрирован: 2014-дек-12 11:22
Сообщения: 12
Спасибо. Все заработало. Пришлось подправлять многое:
1. startup_1986ve8t.s - вносить недостающие номера обработчиков :

Открыть
DCD DMA_DONE0_Handler ; DMA_DONE0_Handler
...
DCD DMA_DONE31_Handler ; DMA_DONE31_Handler
Закрыть

и заглушки обработчиков :

Открыть
DMA_DONE0_Handler PROC
EXPORT DMA_DONE0_Handler [WEAK]
B .
ENDP

...
DMA_DONE31_Handler PROC
EXPORT DMA_DONE31_Handler [WEAK]
B .
ENDP
Закрыть


2. mdr32f8_dma.h - Виртуальные номера запросов DMA из Таблица 103 раздела 7.13.6.18 Спецификация на микросхему 1986ВЕ8Т( Версия 2.9.0 от 15.08.2017 )

Открыть
#if defined (USE_MDR1986VE9x)
/* 7.13.6.18 Таблица 103 – Виртуальные номера запросов DMA */

#define ETH0_EVENT_0 0 // - Request from ETH0
#define ETH0_EVENT_1 1 // - Request from ETH0
#define ETH1_EVENT_0 2 // - Request from ETH1
#define ETH1_EVENT_1 3 // - Request from ETH1
#define SPW0_RX_SREQ 4 // - SPW0_RX_BREQ Request receiver SPW0
#define SPW1_RX_SREQ 5 // - SPW1_RX_BREQ Request receiver SPW1
#define SPW0_TX_SREQ 6 // - SPW0_TX_BREQ Request transmiter SPW0
#define SPW1_TX_SREQ 7 // - SPW1_TX_BREQ Request transmiter SPW1
#define TMR0_REQ 8 // - Request REQ from Timer 0
#define TMR1_REQ 9 // - Request REQ from Timer 1
#define TMR2_REQ 10 // - Request REQ from Timer 2
#define TMR3_REQ 11 // - Request REQ from Timer 3
#define TMR4_REQ 12 // - Request REQ from Timer 4
#define TMR5_REQ 13 // - Request REQ from Timer 5
#define TMR0_REQ1 14 // - Request REQ1 from Timer 0
#define TMR1_REQ1 15 // - Request REQ1 from Timer 1
#define TMR2_REQ1 16 // - Request REQ1 from Timer 2
#define TMR3_REQ1 17 // - Request REQ1 from Timer 3
#define TMR4_REQ1 18 // - Request REQ1 from Timer 4
#define TMR5_REQ1 19 // - Request REQ1 from Timer 5
#define TMR0_REQ2 20 // - Request REQ2 from Timer 0
#define TMR1_REQ2 21 // - Request REQ2 from Timer 1
#define TMR2_REQ2 22 // - Request REQ2 from Timer 2
#define TMR3_REQ2 23 // - Request REQ2 from Timer 3
#define TMR4_REQ2 24 // - Request REQ2 from Timer 4
#define TMR5_REQ2 25 // - Request REQ2 from Timer 5
#define TMR0_REQ3 26 // - Request REQ3 from Timer 0
#define TMR1_REQ3 27 // - Request REQ3 from Timer 1
#define TMR2_REQ3 28 // - Request REQ3 from Timer 2
#define TMR3_REQ3 29 // - Request REQ3 from Timer 3
#define TMR4_REQ3 30 // - Request REQ3 from Timer 4
#define TMR5_REQ3 31 // - Request REQ3 from Timer 5
#define TMR0_REQ4 32 // - Request REQ4 from Timer 0
#define TMR1_REQ4 33 // - Request REQ4 from Timer 1
#define TMR2_REQ4 34 // - Request REQ4 from Timer 2
#define TMR3_REQ4 35 // - Request REQ4 from Timer 3
#define TMR4_REQ4 36 // - Request REQ4 from Timer 4
#define TMR5_REQ4 37 // - Request REQ4 from Timer 5
#define SSP0_TX_SREQ 38 // SSP0_TX_BREQ Request transmiter SSP0
//#define SSP1_TX_SREQ 39 // SSP1_TX_BREQ Request transmiter SSP1
//#define SSP2_TX_SREQ 40 // SSP2_TX_BREQ Request transmiter SSP2
//#define SSP3_TX_SREQ 41 // SSP3_TX_BREQ Request transmiter SSP3
#define SSP0_RX_SREQ 42 // SSP0_RX_BREQ Request receiver SSP0
//#define SSP1_RX_SREQ 43 // SSP1_RX_BREQ Request receiver SSP1
//#define SSP2_RX_SREQ 44 // SSP2_RX_BREQ Request receiver SSP2
//#define SSP3_RX_SREQ 45 // SSP3_RX_BREQ Request receiver SSP3
#define UART0_TX_SREQ 46 // UART0_TX_BREQ Request transmiter UART0
#define UART1_TX_SREQ 47 // UART 1_TX_BREQ Request transmiter UART 1
#define UART2_TX_SREQ 48 // UART 2_TX_BREQ Request transmiter UART 2
#define UART3_TX_SREQ 49 // UART 3_TX_BREQ Request transmiter UART 3
#define UART0_RX_SREQ 50 // UART 0_RX_BREQ Request receiver UART 0
#define UART1_RX_SREQ 51 // UART 1_RX_BREQ Request receiver UART 1
#define UART2_RX_SREQ 52 // UART 2_RX_BREQ Request receiver UART 2
#define UART3_RX_SREQ 53 // UART 3_RX_BREQ Request receiver UART 3
#define ADC0_SREQ0 54 // - Request REQ0 from ADC0
#define ADC0_SREQ1 55 // - Request REQ1from ADC0
#define ADC0_SREQ2 56 // - Request REQ2from ADC0
#define ADC0_SREQ3 57 // - Request REQ3from ADC0
#define ADC0_SREQ4 58 // - Request REQ4from ADC0
#define ADC0_SREQ5 59 // ADC0_BREQ5 Request REQ5from ADC0
#define ADC1_SREQ0 60 // - Request REQ0 from ADC1
#define ADC1_SREQ1 61 // - Request REQ1from ADC1
#define ADC1_SREQ2 62 // - Request REQ2from ADC1
#define ADC1_SREQ3 63 // - Request REQ3from ADC1
#define ADC1_SREQ4 64 // - Request REQ4from ADC1
#define ADC1_SREQ5 65 // ADC1_BREQ5 Request REQ5from ADC1
#define DAC0_SREQ 66 // DAC0_BREQ Request REQ from DAC0
#define DAC1_SREQ 67 // DAC1_BREQ Request REQ from DAC1
#define CRC_SREQ 68 // - Request REQ from CRC
/******************************************************************************/
#endif
Закрыть

3. Соответственно, сами обработчики.
4. Функция настройки запроса на выбранный канал:
Открыть
/* Setup DMA Chanel for Request */
#include "cm4ikmcu.h"
void Req_N_DMA_Chan(uint32_t Req_N, uint32_t DMA_Channel)
{
#define CHMUX_DATA_SHIFT ((DMA_Channel%4)*8)
volatile uint32_t *ptr;
ptr=&(MDR_DMA->CHMUX0)+(DMA_Channel>>2);
*ptr&=~(0xff<<CHMUX_DATA_SHIFT);
*ptr|=Req_N<<CHMUX_DATA_SHIFT;
}
Закрыть


5. Доступ к регистрам настройки портов KEY_reg_accs(); перенесен после подключения тактирования периферии:

Открыть
#include "mdr32f8_clkctrl.h"
CLKCTRL_PER0_CLKcmd(CLKCTRL_PER0_CLK_MDR_PORTC_EN, ENABLE);
CLKCTRL_PER1_CLKcmd(CLKCTRL_PER1_CLK_MDR_DAC0_EN, ENABLE);
CLKCTRL_PER0_CLKcmd(CLKCTRL_PER0_CLK_MDR_DMA0_EN, ENABLE);
CLKCTRL_PER0_CLKcmd(CLKCTRL_PER0_CLK_MDR_TMR1_EN, ENABLE);
KEY_reg_accs(); // Befor setup friq to perif KEY_req_accs is invalid
Закрыть


6. Функция
Открыть
TIMER_BRGInit(MDR_TMR1,TIMER_HCLKdiv1);
Закрыть

заменена на:
Открыть
TIM_CLK_en(TIM1, TIM_CLKdiv1);
Закрыть


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2018-апр-20 11:06 
Не в сети

Зарегистрирован: 2013-ноя-05 10:44
Сообщения: 3
Осваиваю 1986ВЕ81Т и при попытке наладить совместную работу АЦП и DMA столкнулся с проблемой:
в ответ на одиночный запрос от 0 канала АЦП0 вместо одной передачи выполняется целый цикл DMA

Выполняю такую последовательность действий:

- резервирую в настройках проекта область (0х20000000...0х200003FF) под управляющие данные DMA
- указываю в качестве источника данных основной и альтернативной структуры нулевого канала ADC0->RESULT;
- указываю в качестве приемника данных основной и альтернативной структуры нулевого канала адреса на последние элементы двух интовских массивов;
- настраиваю в обоих структурах режим пингпонг, 1024 передачи, источник: слово, без инкремента, приемник:слово, инкремент-слово;

- включаю тактирование АЦП0 (ADCCLK=MAXCLK/4=10 МГц, MAXCLK=PLL0);
- настраиваю запуск преобразования по установке бита GO;
- настраиваю АЦП0 на 0 канал (ADC2);
- настраиваю на 0 канал и разрешаю ADC_DMA_SREQ0;

- настраиваю 0 канал DMA на 54 реальный канал (ADC0_SREQ0);
- настраиваю базовый адрес первичной структуры (0х20000000);
- разрешаю работу контроллера;
- разрешаю работу 0 канала DMA;

Наконец, устанавливаю для АЦП0 бит GO, после установки которого программа уходит в бесконечный цикл.

За работой программы наблюдаю через Ulink2 в режиме Debug.
Перед установкой бита GO ставлю точку останова и вижу, что управляющие данные нулевого канала прописаны верно (пингпонг, 1024 передачи, размерности, инкременты). Затем продолжаю исполнение программы после чего, остановив программу через пару секунд, вижу, что счетчики передач и биты режимов управляющих данных нулевого канала DMA обнулены, в первый элемент массива-приемника, относящегося к первичной структуре, записано значение АЦ-преобразования, а все оставшиеся элементы обоих массивов обнулены.

Т.е. похоже, что вместо одной передачи выполняется целый цикл DMA...

Не могу понять, в чем дело. Помогите, пожалуйста, разобраться.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: АЦП + DMA
СообщениеДобавлено: 2018-май-14 16:29 
Не в сети

Зарегистрирован: 2017-апр-26 14:51
Сообщения: 121
Откуда: ПКК "Миландр"
При работе DMA с ADC необходимо вычитывать значение из регистра результата определенного канала.

Код:
DMA_DataCtrl_Pri.DMA_SourceBaseAddr = (uint32_t)&ADC1->RESULTCH_xx[ADC_CHANNEL];  // вместо  RESULT;


Поскольку RESULT это на самом деле FIFO, про которое на стр. 563 указано:

7.23.6 Обработка результатов с помощью DMA При необходимости результаты работы АЦП могут быть обработаны с помощью DMA.
При использовании DMA не допускается программное считывание данных из FIFO. ...


То, если вычитывать из RESULT - не сбрасывается флаг того, что результат был считан. Запрос к DMA остается активным и DMA выполняет весь цикл. Если DMA читает из RESULTCH_xx, то флаг считывания данных сбрасывается и на каждое измерение АЦП происходит одна передача DMA.

_________________
Отдел технической поддержки support@milandr.ru


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

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


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

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


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

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