Перейти к содержанию
    

DMA и таймер в режиме захвата

Необходимо измерить смещение фазы между двумя сигналами. Использую STM32F103RC6T. Первый сигнал заведен на PC8, и настроено внешнее прерывание по этому входу, второй сигнал заведен на PB6 (TIM4_CH1).

Алгоритм работы следующий: по переднему, восходящему фронту на PC8 срабатывает прерывание, в котором перезапускается таймер 4. По переднему восходящему фронту на PB6 происходит захват значение счетчика, по этому событию происходит передача по DMA значения из регистра ССR1 в буфер.

Проблема в следующем: часть буфера заполняется некорректными значениями. Закономерности не выявил т.е. могут быть ошибки в начале, потом правильные данные, потом опять ошибки, а может быть наоборот. Пробовал по СС1 генерить не DMA запрос, а прерывание, и в нем вычитавать значение CCR1, тогда все работает, и значения корректные. Измеряемые сигналы пока беру с образцового генератора.

 

Код приведен ниже:

 

unsigned short CCR1_val[500];

void Tim_Capture_Init(void)
{
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);

        DMA_InitTypeDef DMA_InitStructure;
        
        DMA_DeInit(DMA1_Channel1);
        
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM4->CCR1;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&CCR1_val;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = 500;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
   
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_ICInitTypeDef  TIM_ICInitStructure;
        
        TIM_TimeBaseStructure.TIM_Prescaler = 13;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
        
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
        
        TIM_PrescalerConfig(TIM4, 13, TIM_PSCReloadMode_Immediate);       
        
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
        TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
        TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
        TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInitStructure.TIM_ICFilter = 0;
      
        TIM_ICInit(TIM4, &TIM_ICInitStructure);
                                
        /* TIM1 Update DMA Request enable */
        TIM_DMACmd(TIM4, TIM_DMA_CC1, ENABLE);
               
        TIM_Cmd(TIM4, ENABLE);
        
        DMA_Cmd(DMA1_Channel1, ENABLE);
        
        while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
}

void EXTI_init(void)
{      
        EXTI_InitTypeDef   EXTI_InitStructure;
        NVIC_InitTypeDef   NVIC_InitStructure;

        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource8);
      
        /* Configure EXTI0 line */
        EXTI_InitStructure.EXTI_Line = EXTI_Line8;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);
      
        /* Enable and set EXTI0 Interrupt to the lowest priority */
        NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = Priority_EXTI;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);   
}

void EXTI9_5_IRQHandler(void)
{  
       if(EXTI_GetITStatus(EXTI_Line8) != RESET)
       {                  

                          TIM_GenerateEvent(TIM4, TIM_EventSource_Update);                          
                          EXTI_ClearITPendingBit(EXTI_Line8);

       }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Необходимо измерить смещение фазы между двумя сигналами. Использую STM32F103RC6T. Первый сигнал заведен на PC8, и настроено внешнее прерывание по этому входу, второй сигнал заведен на PB6 (TIM4_CH1).

Алгоритм работы следующий: по переднему, восходящему фронту на PC8 срабатывает прерывание, в котором перезапускается таймер 4. По переднему восходящему фронту на PB6 происходит захват значение счетчика, по этому событию происходит передача по DMA значения из регистра ССR1 в буфер.

Проблема в следующем: часть буфера заполняется некорректными значениями. Закономерности не выявил т.е. могут быть ошибки в начале, потом правильные данные, потом опять ошибки, а может быть наоборот. Пробовал по СС1 генерить не DMA запрос, а прерывание, и в нем вычитавать значение CCR1, тогда все работает, и значения корректные. Измеряемые сигналы пока беру с образцового генератора.

 

 

}[/code]

 

 

пожалуста весь проектик в студию.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

пожалуста весь проектик в студию.

 

unsigned short CCR1_val[500];

void Tim_Capture_Init(void)
{
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);

        DMA_InitTypeDef DMA_InitStructure;
        
        DMA_DeInit(DMA1_Channel1);
        
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM4->CCR1;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&CCR1_val;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = 500;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
   
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_ICInitTypeDef  TIM_ICInitStructure;
        
        TIM_TimeBaseStructure.TIM_Prescaler = 13;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
        
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
        
        TIM_PrescalerConfig(TIM4, 13, TIM_PSCReloadMode_Immediate);       
        
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
        TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
        TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
        TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInitStructure.TIM_ICFilter = 0;
      
        TIM_ICInit(TIM4, &TIM_ICInitStructure);
                                
        /* TIM1 Update DMA Request enable */
        TIM_DMACmd(TIM4, TIM_DMA_CC1, ENABLE);
               
        TIM_Cmd(TIM4, ENABLE);
        
        DMA_Cmd(DMA1_Channel1, ENABLE);
        
        while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
}

void EXTI_init(void)
{      
        EXTI_InitTypeDef   EXTI_InitStructure;
        NVIC_InitTypeDef   NVIC_InitStructure;

        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource8);
      
        /* Configure EXTI0 line */
        EXTI_InitStructure.EXTI_Line = EXTI_Line8;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);
      
        /* Enable and set EXTI0 Interrupt to the lowest priority */
        NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = Priority_EXTI;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);   
}

void EXTI9_5_IRQHandler(void)
{  
       if(EXTI_GetITStatus(EXTI_Line8) != RESET)
       {                  

                          TIM_GenerateEvent(TIM4, TIM_EventSource_Update);                          
                          EXTI_ClearITPendingBit(EXTI_Line8);

       }
}

void main(void)
{
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
          RCC_APB2PeriphResetCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, DISABLE);

          GPIO_InitTypeDef GPIO_InitStructure;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
          GPIO_Init(GPIOB, &GPIO_InitStructure);

          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
          GPIO_Init(GPIOC, &GPIO_InitStructure);

          Tim_Capture_Init();
          EXTI_init();

          while(1);
}

Изменено пользователем LEVENVORF

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вобще то имел виду полную выклодку в той программе которой пишите.

 

а то бывает ошибки в инициализации, так хоть проверить можно

Изменено пользователем vvkka

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Tim_Capture_Init() запускает DMA и ждет его окончания ДО настройки прерывания от внешней линии в EXTI_init()

Просто поменяйте местами их вызовы .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Tim_Capture_Init() запускает DMA и ждет его окончания ДО настройки прерывания от внешней линии в EXTI_init()

Просто поменяйте местами их вызовы .

 

Все равно не работает. EXTI прерывание просто перезапускает таймер, так что захват по СС1 все равно произойдет. Т.е. ложным может быть только первое срабатывание, а у меня неверное значение не только первое ))))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все равно не работает. EXTI прерывание просто перезапускает таймер, так что захват по СС1 все равно произойдет. Т.е. ложным может быть только первое срабатывание, а у меня неверное значение не только первое ))))

В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен.

Впрочем если вы предпочитаете ржать над советами - копайтесь сами. Успехов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен.

 

Человек именно и измеряет разность фаз. И как по вашему прерывание от внешней линии зависит от DMA capture?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Алгоритм работы следующий: по переднему, восходящему фронту на PC8 срабатывает прерывание, в котором перезапускается таймер 4. По переднему восходящему фронту на PB6 происходит захват значение счетчика, по этому событию происходит передача по DMA значения из регистра ССR1 в буфер.

Частота сигнала? Думаю запускать таймер в прерывании не правильно, от фронта до запуска таймера непонятно сколько времени пройдёт.

Я бы объединил два сигнала какой-то мелкой логикой и на один вход захвата, ловить два фронта.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен.

Впрочем если вы предпочитаете ржать над советами - копайтесь сами. Успехов.

В моем виде, когда инициализация таймера стоит перед инициализацией EXTI, глюки по DMA ТОЧНО ТАКИЕ ЖЕ, как и в том варианте, который предложили Вы.

 

Первое измерение в моем варианте действительно может быть неверным. Но как только на PB6 придет импульс, произойдет захват, передача по DMA и инициализация EXTI. Так что все остальные циклы измерения должны быть верными.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема решилась! Вся проблема в том, что значения буфера смотрел в Debug'e. И судя по всему входя в режим отладки переферия останавливается неодновременно. Т.е. NVIC, скорее всего, останавливался первым, тем самым переставал сбрасываться счетчик, а DMA c таймером продолжали работать. Частично заполняя буффер некорректными данными. Большое всем спасибо за помощь!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...