|
|
  |
DMA и таймер в режиме захвата |
|
|
|
Jan 18 2012, 13:36
|
Участник

Группа: Участник
Сообщений: 18
Регистрация: 14-03-10
Из: BELARUS
Пользователь №: 55 953

|
Необходимо измерить смещение фазы между двумя сигналами. Использую 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);
} }
|
|
|
|
|
Jan 18 2012, 16:58
|
Участник

Группа: Участник
Сообщений: 57
Регистрация: 9-07-08
Из: Волгоградская обл
Пользователь №: 38 838

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

Группа: Участник
Сообщений: 18
Регистрация: 14-03-10
Из: BELARUS
Пользователь №: 55 953

|
Цитата(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); }
Сообщение отредактировал LEVENVORF - Jan 18 2012, 17:29
|
|
|
|
|
Jan 18 2012, 19:08
|
Участник

Группа: Участник
Сообщений: 57
Регистрация: 9-07-08
Из: Волгоградская обл
Пользователь №: 38 838

|
вобще то имел виду полную выклодку в той программе которой пишите.
а то бывает ошибки в инициализации, так хоть проверить можно
Сообщение отредактировал vvkka - Jan 18 2012, 19:10
|
|
|
|
|
Jan 19 2012, 14:52
|
Участник

Группа: Участник
Сообщений: 18
Регистрация: 14-03-10
Из: BELARUS
Пользователь №: 55 953

|
Цитата(Flexz @ Jan 18 2012, 22:51)  Tim_Capture_Init() запускает DMA и ждет его окончания ДО настройки прерывания от внешней линии в EXTI_init() Просто поменяйте местами их вызовы . Все равно не работает. EXTI прерывание просто перезапускает таймер, так что захват по СС1 все равно произойдет. Т.е. ложным может быть только первое срабатывание, а у меня неверное значение не только первое ))))
|
|
|
|
|
Jan 20 2012, 06:26
|
Местный
  
Группа: Свой
Сообщений: 252
Регистрация: 9-10-08
Из: Московская обл.
Пользователь №: 40 797

|
Цитата(LEVENVORF @ Jan 19 2012, 17:52)  Все равно не работает. EXTI прерывание просто перезапускает таймер, так что захват по СС1 все равно произойдет. Т.е. ложным может быть только первое срабатывание, а у меня неверное значение не только первое )))) В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен. Впрочем если вы предпочитаете ржать над советами - копайтесь сами. Успехов.
|
|
|
|
|
Jan 20 2012, 07:13
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 26-11-05
Пользователь №: 11 420

|
Цитата(Flexz @ Jan 20 2012, 08:26)  В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен. Человек именно и измеряет разность фаз. И как по вашему прерывание от внешней линии зависит от DMA capture?
|
|
|
|
|
Jan 20 2012, 08:48
|
■ ■ ■ ■
    
Группа: Свой
Сообщений: 1 100
Регистрация: 9-08-06
Пользователь №: 19 443

|
Цитата Алгоритм работы следующий: по переднему, восходящему фронту на PC8 срабатывает прерывание, в котором перезапускается таймер 4. По переднему восходящему фронту на PB6 происходит захват значение счетчика, по этому событию происходит передача по DMA значения из регистра ССR1 в буфер. Частота сигнала? Думаю запускать таймер в прерывании не правильно, от фронта до запуска таймера непонятно сколько времени пройдёт. Я бы объединил два сигнала какой-то мелкой логикой и на один вход захвата, ловить два фронта.
--------------------
Делай что должен и будь что будет.
|
|
|
|
|
Jan 20 2012, 10:32
|
Участник

Группа: Участник
Сообщений: 18
Регистрация: 14-03-10
Из: BELARUS
Пользователь №: 55 953

|
Цитата(Flexz @ Jan 20 2012, 09:26)  В исходном виду у вас прерывание вообще не происходит до полного окончания DMA трансфера. Вы измеряете интервал между импульсами на PB6, а не разность фаз, естественно результат неверен. Впрочем если вы предпочитаете ржать над советами - копайтесь сами. Успехов. В моем виде, когда инициализация таймера стоит перед инициализацией EXTI, глюки по DMA ТОЧНО ТАКИЕ ЖЕ, как и в том варианте, который предложили Вы. Первое измерение в моем варианте действительно может быть неверным. Но как только на PB6 придет импульс, произойдет захват, передача по DMA и инициализация EXTI. Так что все остальные циклы измерения должны быть верными.
|
|
|
|
|
Jan 20 2012, 12:58
|
Участник

Группа: Участник
Сообщений: 18
Регистрация: 14-03-10
Из: BELARUS
Пользователь №: 55 953

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