Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: DMA и таймер в режиме захвата
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
LEVENVORF
Необходимо измерить смещение фазы между двумя сигналами. Использую 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);

       }
}
vvkka
Цитата(LEVENVORF @ Jan 18 2012, 16:36) *
Необходимо измерить смещение фазы между двумя сигналами. Использую STM32F103RC6T. Первый сигнал заведен на PC8, и настроено внешнее прерывание по этому входу, второй сигнал заведен на PB6 (TIM4_CH1).
Алгоритм работы следующий: по переднему, восходящему фронту на PC8 срабатывает прерывание, в котором перезапускается таймер 4. По переднему восходящему фронту на PB6 происходит захват значение счетчика, по этому событию происходит передача по DMA значения из регистра ССR1 в буфер.
Проблема в следующем: часть буфера заполняется некорректными значениями. Закономерности не выявил т.е. могут быть ошибки в начале, потом правильные данные, потом опять ошибки, а может быть наоборот. Пробовал по СС1 генерить не DMA запрос, а прерывание, и в нем вычитавать значение CCR1, тогда все работает, и значения корректные. Измеряемые сигналы пока беру с образцового генератора.


}[/code]



пожалуста весь проектик в студию.
LEVENVORF
Цитата(vvkka @ Jan 18 2012, 19:58) *
пожалуста весь проектик в студию.


Код
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);
}
vvkka
вобще то имел виду полную выклодку в той программе которой пишите.

а то бывает ошибки в инициализации, так хоть проверить можно
Flexz
Tim_Capture_Init() запускает DMA и ждет его окончания ДО настройки прерывания от внешней линии в EXTI_init()
Просто поменяйте местами их вызовы .
LEVENVORF
Цитата(Flexz @ Jan 18 2012, 22:51) *
Tim_Capture_Init() запускает DMA и ждет его окончания ДО настройки прерывания от внешней линии в EXTI_init()
Просто поменяйте местами их вызовы .


Все равно не работает. EXTI прерывание просто перезапускает таймер, так что захват по СС1 все равно произойдет. Т.е. ложным может быть только первое срабатывание, а у меня неверное значение не только первое ))))
Flexz
Цитата(LEVENVORF @ Jan 19 2012, 17:52) *
Все равно не работает. EXTI прерывание просто перезапускает таймер, так что захват по СС1 все равно произойдет. Т.е. ложным может быть только первое срабатывание, а у меня неверное значение не только первое ))))

В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен.
Впрочем если вы предпочитаете ржать над советами - копайтесь сами. Успехов.
V_M_Luck
Цитата(Flexz @ Jan 20 2012, 08:26) *
В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен.


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

Частота сигнала? Думаю запускать таймер в прерывании не правильно, от фронта до запуска таймера непонятно сколько времени пройдёт.
Я бы объединил два сигнала какой-то мелкой логикой и на один вход захвата, ловить два фронта.
LEVENVORF
Цитата(Flexz @ Jan 20 2012, 09:26) *
В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен.
Впрочем если вы предпочитаете ржать над советами - копайтесь сами. Успехов.

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

Первое измерение в моем варианте действительно может быть неверным. Но как только на PB6 придет импульс, произойдет захват, передача по DMA и инициализация EXTI. Так что все остальные циклы измерения должны быть верными.
LEVENVORF
Проблема решилась! Вся проблема в том, что значения буфера смотрел в Debug'e. И судя по всему входя в режим отладки переферия останавливается неодновременно. Т.е. NVIC, скорее всего, останавливался первым, тем самым переставал сбрасываться счетчик, а DMA c таймером продолжали работать. Частично заполняя буффер некорректными данными. Большое всем спасибо за помощь!!!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.