реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Stm32f103 +Tim PWM странный глюк
cebotor
сообщение Aug 17 2017, 23:55
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 6-04-07
Из: Бронницы
Пользователь №: 26 809



Приветствую всех!

Вопрос по работе затертого уже всеми давно до дыр stm32f103 в части связки PWM + DMA
Обратился бывший коллега - задача проста, выдавать в PWM аналоговый сигнал, при чем больше
частота PWM - тем лучше.

Частоты CPU 72000000 PWM 400000 - разрешение получается 180 отсчетов CPU.
Выдаем четыре отсчета в кольцевом режиме
Код
  mas_sin[0]=160; //!!!!!!!!!!! если здесь заменить на 170 то увидим сдвиг
  mas_sin[1]=90;
  mas_sin[2]=30;
  mas_sin[3]=10;

Наблюдаемый эффект: при небольшом заполнении PWM все хорошо, при приближении заполнения к 100%
- импульс дублируется в следующий, следующий сдвигается в третий, а третий "выпадает"...

Не поверил я что может быть неописанная засада в таком не сложном деле.
Он прислал код. Я проверил и упростил код до минимального "сбоящего" варианта без кучи ненужностей.

Далее собственно полный (не длинный ) код
CODE
// задаем частоты - выдернуто из SystemClock_Config();
FLASH->ACR= LL_FLASH_LATENCY_2;
RCC->CR|= RCC_CR_HSEON;
while ((RCC->CR&RCC_CR_HSERDY)!=(RCC_CR_HSERDY));
RCC->CFGR=(LL_RCC_PLLSOURCE_HSE_DIV_1 & (RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE)) | LL_RCC_PLL_MUL_9;
RCC->CR|=RCC_CR_PLLON;
while((RCC->CR&RCC_CR_PLLRDY)!=RCC_CR_PLLRDY);
RCC->CFGR|=LL_RCC_SYSCLK_DIV_1;
RCC->CFGR|=LL_RCC_SYS_CLKSOURCE_PLL;
while (RCC->CFGR& RCC_CFGR_SWS!= LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
RCC->CFGR|=LL_RCC_APB1_DIV_2;
RCC->CFGR|=LL_RCC_APB2_DIV_1;

mas_sin[0]=160; //!!!!!!!!!!! если здесь заменить на 170 то увидим сдвиг
mas_sin[1]=90;
mas_sin[2]=30;
mas_sin[3]=10;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG;
AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP | AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
GPIOB->CRL &= ~GPIO_CRL_CNF4 & ~GPIO_CRL_CNF5 & ~GPIO_CRL_CNF0 & ~GPIO_CRL_CNF1;
GPIOB->CRL |= GPIO_CRL_CNF4_1 | GPIO_CRL_MODE4_0 | GPIO_CRL_CNF5_1 | GPIO_CRL_MODE5_0 | GPIO_CRL_CNF0_1 | GPIO_CRL_MODE0_0 | GPIO_CRL_CNF1_1 | GPIO_CRL_MODE1_0;

RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E;
TIM3->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE;
TIM3->CCMR2 |= TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE | TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE;
TIM3->CCMR2 |= TIM_CCMR2_OC4M_0 | TIM_CCMR2_OC3M_1;
TIM3->DIER |= TIM_DIER_CC1DE | TIM_DIER_CC3DE;
TIM3->CR1 |= TIM_CR1_CEN | TIM_CR1_ARPE;
TIM3->PSC = 0;
TIM3->ARR = PREC-1;

RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel2->CPAR = (uint32_t)&TIM3->CCR3;
DMA1_Channel2->CMAR = (uint32_t)&mas_sin[0];
DMA1_Channel2->CNDTR = POINTS;
DMA1_Channel2->CCR = DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_DIR | DMA_CCR_EN | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0;

while(1);

когда mas_sin[0]==160 видим следующую картинку


но если заполнить еще чуть больше mas_sin[0]==170
то будет вот так:



Долго смотрел в картинку схемы работы узла Capture/Compare -


Может быть запись из DMA по событию совпадения CCR3 == CNT совпадает с событием UEV и пропускается? при этом релоад регистр не переписывается в теневой?
Но с этим должны были столкнуться десятки и сотни?

Не подскажет ли уважаемое сообщество, отчего не едут лыжи.
Заранее спасибо.


--------------------
если еррата пуста - это не хорошо а плохо
Go to the top of the page
 
+Quote Post
amiller
сообщение Aug 18 2017, 03:01
Сообщение #2


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612



Цитата(cebotor @ Aug 18 2017, 03:55) *
Может быть запись из DMA по событию совпадения CCR3 == CNT совпадает с событием UEV и пропускается? при этом релоад регистр не переписывается в теневой?
Но с этим должны были столкнуться десятки и сотни?

В общем и целом не совсем корректно писать в теневой регистр ровно в тот момент, когда он переписывается в основной регистр сравнения. И неважно через ДМА или напрямую.
Время от события до выполнения записи ДМА не всегда одинаковое и может зависеть от многих факторов (частоты шин, их занятость и т.п.)
Я бы синхронизировал ДМА по какому нибудь событию таймера, которое гарантированно не совпадает с апдейтом.
Для этого можно задействовать свободный канал сравнения, если такие есть.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Aug 18 2017, 06:12
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



https://electronix.ru/forum/index.php?s=&am...t&p=1201975


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
Timmy
сообщение Aug 18 2017, 19:08
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 835
Регистрация: 9-08-08
Из: Санкт-Петербург
Пользователь №: 39 515



Тут принципиально неверное управление таймером. Надо записывать теневые регистры только в ответ на UE, никаких CCxDE, только UDE, тогда гарантируется латентность записи в один период таймера(по ARR). Запись регистров непосредственно по событиям от ССR - это очень специальные случаи и они не для чайников.
Go to the top of the page
 
+Quote Post
cebotor
сообщение Aug 19 2017, 00:39
Сообщение #5


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 6-04-07
Из: Бронницы
Пользователь №: 26 809



Большое спасибо откликнувшимся!
Ошибка найдена - именно такая как указал Timmy.
Как и часто бывает корень зла - донор кода, а им являются библиотечные функции.
В актуальных на данный момент библиотеках от ST есть файл stm32f1xx_hal_tim.c (у меня версия от мая сего года).
В этом файле в функции HAL_TIM_PWM_Start_DMA есть строки (есть для всех каналов но данные строки для 3го канала)
Код
    case TIM_CHANNEL_3:
    {
      /* Set the DMA Period elapsed callback */
      htim->hdma[TIM_DMA_ID_CC3]->XferCpltCallback = TIM_DMADelayPulseCplt;
      /* Set the DMA error callback */
      htim->hdma[TIM_DMA_ID_CC3]->XferErrorCallback = TIM_DMAError;
      /* Enable the DMA channel */
      HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC3], (uint32_t)pData, (uint32_t)&htim->Instance->CCR3,Length);
      /* Enable the TIM Output Capture/Compare 3 request */
      __HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC3); //!!!!!!! неверно, нужно TIM_DMA_UPDATE

в которых выставляется TIM_DMA_CC3 как источник ДМА запроса.
что неверно. требуется установить в качестве источника запроса TIM_DMA_UPDATE
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_UPDATE);



Цитата(amiller @ Aug 18 2017, 06:01) *
В общем и целом не совсем корректно писать в теневой регистр ровно в тот момент, когда он переписывается в основной регистр сравнения. И неважно через ДМА или напрямую.
Время от события до выполнения записи ДМА не всегда одинаковое и может зависеть от многих факторов (частоты шин, их занятость и т.п.)
Я бы синхронизировал ДМА по какому нибудь событию таймера, которое гарантированно не совпадает с апдейтом.
Для этого можно задействовать свободный канал сравнения, если такие есть.

Точно, не корректно одновременно с UE, надо это делать в ответ на этот самый UE( ставить источник UDE как написал Timmy), то есть позже самой записи

Цитата(SSerge @ Aug 18 2017, 09:12) *

Спасибо за ссылку, сам механизм работает без бёрста, то есть запускается трансфер по запросу дма в обычный регистр релоада. Проблема в выпадениях (была)


Цитата(Timmy @ Aug 18 2017, 22:08) *
Тут принципиально неверное управление таймером. Надо записывать теневые регистры только в ответ на UE, никаких CCxDE, только UDE, тогда гарантируется латентность записи в один период таймера(по ARR). Запись регистров непосредственно по событиям от ССR - это очень специальные случаи и они не для чайников.

Вы абсолютно правы, пропустил маразмус мимо глаз! кроме того можно за один период при работе по событию CCR схватить больше чем одно обновление, что было бы еще веселее. Отдельное спасибо за чайника wink.gif


--------------------
если еррата пуста - это не хорошо а плохо
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 19:17
Рейтинг@Mail.ru


Страница сгенерированна за 0.01398 секунд с 7
ELECTRONIX ©2004-2016