Jump to content

    
Sign in to follow this  
LEVENVORF

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

Recommended Posts

Необходимо измерить смещение фазы между двумя сигналами. Использую 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);

       }
}

Share this post


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

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

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

 

 

}[/code]

 

 

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

Share this post


Link to post
Share on other sites
пожалуста весь проектик в студию.

 

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);
}

Edited by LEVENVORF

Share this post


Link to post
Share on other sites

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

 

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

Edited by vvkka

Share this post


Link to post
Share on other sites

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

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

Share this post


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

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

 

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

Share this post


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

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

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

Share this post


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

 

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

 

Share this post


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

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

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

Share this post


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

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

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

 

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this