03.01.2021, 17:44
|
|
Вид на жительство
Регистрация: 27.11.2007
Сообщений: 429
Сказал спасибо: 19
Сказали Спасибо 39 раз(а) в 30 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
Код:
|
TIM1-›DIER = TIM_DIER_CC1DE; |
|
|
|
|
03.01.2021, 17:46
|
|
Вид на жительство
Регистрация: 27.11.2007
Сообщений: 429
Сказал спасибо: 19
Сказали Спасибо 39 раз(а) в 30 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
eddy, Ты не обратил внимание, что второй канал, а не пятый?
|
|
|
|
03.01.2021, 18:05
|
|
Почётный гражданин KAZUS.RU
Регистрация: 27.01.2005
Адрес: Россия, КЧР, Нижний Архыз
Сообщений: 3,629
Сказал спасибо: 115
Сказали Спасибо 814 раз(а) в 591 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
Сообщение от sat_art
|
Код:
|
TIM1-›DIER = TIM_DIER_CC1DE; |
|
Нельзя так: последний импульс в нуль как устанавливать?
Кривое решение.
__________________
Союз Советских Социалистических Округов Северной Америки
|
|
|
|
03.01.2021, 19:11
|
|
Вид на жительство
Регистрация: 27.11.2007
Сообщений: 429
Сказал спасибо: 19
Сказали Спасибо 39 раз(а) в 30 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
Сообщение от eddy
|
Кривое решение
|
у тебя получилось.
eddy, я, почему то вникаю в твой код, что бы помочь найти решение.
Код:
|
uint8_t dmabuff[] = {3,6,3,3,6,6,3,6,0}; |
Это первый импульс.
Код:
|
TIM1-›CCR1=dmabuff[0];
TIM1-›CR1|= TIM_CR1_CEN; |
ДМА начинает со второго и 8 шт - считать умеешь?
Код:
|
DMA1_Channel2-›CNDTR = 8;
DMA1_Channel2-›CMAR = (uint32_t)dmabuff+1; |
|
|
|
|
03.01.2021, 23:02
|
|
Почётный гражданин KAZUS.RU
Регистрация: 27.01.2005
Адрес: Россия, КЧР, Нижний Архыз
Сообщений: 3,629
Сказал спасибо: 115
Сказали Спасибо 814 раз(а) в 591 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
sat_art, ну нельзя изменять содержимое регистра CCR по событию CC!!!
Представь, что у тебя было первое значение 3, а новое — 6. В этом случае "внезапно" еще до прерывания UE сигнал опять сменит полярность на 1, дотянет до 6, и лишь тогда сменится на 0! И в этот момент опять сгенерируется событие CC, которое пнет DMA и изменит CCR1. В итоге будет потерян один бит и один искажен. И так далее…
Разве что делать прелоад CCR1…
Все равно пихать ноль в конце мне не нравится. Оно и так работает, как я сделал.
__________________
Союз Советских Социалистических Округов Северной Америки
|
|
|
|
03.01.2021, 23:09
|
|
Вид на жительство
Регистрация: 27.11.2007
Сообщений: 429
Сказал спасибо: 19
Сказали Спасибо 39 раз(а) в 30 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
|
|
|
|
08.01.2021, 00:31
|
|
Гражданин KAZUS.RU
Регистрация: 17.06.2008
Адрес: Украина
Сообщений: 710
Сказал спасибо: 363
Сказали Спасибо 797 раз(а) в 371 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
Мелкий эксперимент с STM32 F030C8 и STM32 F103C8 с выводом на WS2812B на разных частотах МК с помощью таймера+DMA.
Использовалось burst feature таймера и DMA (запрос DMA по update event таймера, CCR1 - с предзагрузкой).
Поведение выхода канала таймера одинаковое, что в режиме PWM2 c инверсией выхлопа, что в режиме PWM1 без таковой.
Таймер молотил без остановки, т.к. ввиду включенной предзагрузки CCR1 посылка всегда начинается в момент update event таймера.
Все посылки инициировались только 'отмашкой' для DMA. Прерывания не использовались.
Еще один канал таймера (CH2) использовался в режиме статичного PWM просто для визуальной оценки происходящего.
Под спойлер не прячу, т.к. спойлер работает не везде и не всегда.
Инициализация таймера и DMA:
PHP код:
|
//---------------------------------- // TIMER TIMER-›CR1 = 0; TIMER-›PSC = TIM_PSC - 1; TIMER-›ARR = TIM_ARR; TIMER-›CCR1 = 0; TIMER-›CCR2 = TIM_ARR ›› 1; // test output (constant duty cycle = 0.5)
/**/ // PWM2 with inverted output TIMER-›CCMR1 = 0 | (1*TIM_CCMR1_OC1PE) | (1* TIM_CCMR1_OC1M_2) | (1* TIM_CCMR1_OC1M_1) | (1* TIM_CCMR1_OC1M_0) // PWM2 CH1 output (led strip) | (1*TIM_CCMR1_OC2PE) | (1* TIM_CCMR1_OC2M_2) | (1* TIM_CCMR1_OC2M_1) | (1* TIM_CCMR1_OC2M_0) // PWM2 CH2 test output ; TIMER-›CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | (1* TIM_CCER_CC1P) | (1* TIM_CCER_CC2P); /**/ /** // PWM1 with direct output TIMER-›CCMR1 = 0 | (1*TIM_CCMR1_OC1PE) | (1* TIM_CCMR1_OC1M_2) | (1* TIM_CCMR1_OC1M_1) | (0* TIM_CCMR1_OC1M_0) // PWM1 CH1 output (led strip) | (1*TIM_CCMR1_OC2PE) | (1* TIM_CCMR1_OC2M_2) | (1* TIM_CCMR1_OC2M_1) | (0* TIM_CCMR1_OC2M_0) // PWM1 CH2 test output ; TIMER-›CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | (0* TIM_CCER_CC1P) | (0* TIM_CCER_CC2P); /**/
TIMER-›DCR = 0 | (0x00 ‹‹ 8) // DBL, 1 transfer | (0x0D ‹‹ 0) // DBA, starts from TIM-›CCR1 ; TIMER-›EGR = TIM_EGR_UG; TIMER-›DIER = TIM_DIER_UDE; // send DMA request on TIMER update event
//---------------------------------- // DMA for TIMER update event DMA_CH-›CCR = 0; DMA_CH-›CPAR = (uint32_t)&TIMER-›DMAR; DMA_CH-›CCR = 0 | (1* DMA_CCR_DIR) // 1 = read from memory | (0* DMA_CCR_MSIZE_1) | (0* DMA_CCR_MSIZE_0) // source memory 8-bit | (0* DMA_CCR_PSIZE_1) | (1* DMA_CCR_PSIZE_0) // destination peripheral 16-bit | (1* DMA_CCR_MINC) // memory increment | (1* DMA_CCR_PL_1) | (1* DMA_CCR_PL_0) // priority level = very high ;
|
Инициирование отправки посылки:
Код:
|
void HAL_SendLedStripData(uint8_t * array, uint16_t length){
DMA_CH-›CCR &= ~DMA_CCR_EN;
DMA_CH-›CMAR = (uint32_t)array;
DMA_CH-›CNDTR = length;
DMA_CH-›CCR |= DMA_CCR_EN;
} |
Короткая посылка для лог. анализатора ('полезная нагрузка' предваряется и терминируется нулевыми байтами)
Код:
|
const uint8_t Array0[] = {
0,
T0, T1, T1, T0,
0}; |
Длинная посылка для 3-х пикселов в полосе из 8-ми ('полезная нагрузка' также предваряется и терминируется нулевыми байтами)
Код:
|
const uint8_t Array1[] = {
0,
T0, T1, T0, T0, T0, T0, T0, T1,
T0, T0, T0, T0, T0, T0, T0, T1,
T0, T0, T0, T0, T0, T0, T0, T1,
T0, T0, T0, T0, T0, T0, T0, T1,
T0, T1, T0, T0, T0, T0, T0, T1,
T0, T0, T0, T0, T0, T0, T0, T1,
T0, T0, T0, T0, T0, T0, T0, T1,
T0, T0, T0, T0, T0, T0, T0, T1,
T0, T1, T0, T0, T0, T0, T0, T1,
0}; |
В посылках T0 и Т1 - это, согласно документации к WS281x, длительность T0H и T1H соответственно.
Длительность T0 и Т1 для разных рабочих частот МК ( AHB = APB1 = APB2 ):
Код:
|
// 8 MHz
#define T0 3 // T0H
#define T1 6 // T1H
#define TIM_ARR 8 // Timer autoreload
#define TIM_PSC 1 // Timer prescaler
// 10 MHz
#define T0 3
#define T1 6
#define TIM_ARR 10
#define TIM_PSC 1
// 12 MHz
#define T0 4
#define T1 8
#define TIM_ARR 12
#define TIM_PSC 1
// 16 MHz
#define T0 5
#define T1 10
#define TIM_ARR 16
#define TIM_PSC 1
// 24 MHz
#define T0 8
#define T1 16
#define TIM_ARR 24
#define TIM_PSC 1
// 36 MHz
#define T0 12
#define T1 24
#define TIM_ARR 36
#define TIM_PSC 1
/**/ |
Для STM32F103C8:
На частоте 8MHz в выхлопе таймера появляются 1..2 'лишних' импульса на 8 бит посылки (когда 0, когда 1) против заданного количества.
На светодиодной полосе это проявляется как мусор и засветка лишних пикселов.
На частоте 10MHz проскакивает мусор без засветки лишних пикселов.
На частоте 12MHz вроде как замечаний нет.
Для STM32F030C8:
Все как и требовалось, на частотах 8..36MHz 'лишних' импульсов нет, мусора нет, замечаний нет.
|
|
|
|
08.01.2021, 04:23
|
|
Вид на жительство
Регистрация: 27.11.2007
Сообщений: 429
Сказал спасибо: 19
Сказали Спасибо 39 раз(а) в 30 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
j-Roger, можно то же самое - но с TIMER-›DIER = TIM_DIER_CC1DE; ?
И соответственно другой канал ДМА.
И хотелось бы увидеть тот же эксперимент но без burst feature.
Цитата:
|
TIMx_CCR1 preload value is loaded in the active register at each update event.
|
Все таки все в один момент времени происходит.
Последний раз редактировалось sat_art; 08.01.2021 в 04:54.
|
|
|
|
10.01.2021, 03:52
|
|
Гражданин KAZUS.RU
Регистрация: 17.06.2008
Адрес: Украина
Сообщений: 710
Сказал спасибо: 363
Сказали Спасибо 797 раз(а) в 371 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
sat_art, я уже разобрал свой коллайдер
Насчёт burst feature - в данном случае без разницы, пишем прямо в TIMER-›CCRx или через TIMER-›DMAR - ведь обновляется единственный канал таймера.
А вот насчет источника DMA request (по TIM_DIER_UDE или же по TIM_DIER_CC1DE) там появляется проблема на относительно низких тактовых частотах.
DMA должен успеть сделать трансфер ПАМЯТЬ-›CCRx таймера до начала нового периода (на CCRx разрешена предзагрузка).
В случае обновления по update event для этого есть целый период таймера, это величина постоянная.
В случае обновления по событию compare event это время разное и, конечно же, менее длительности периода - DMA может просто не успеть, отсюда лишние периоды.
Вот картинка; DMA request по TIM_DIER_CC1DE, выводим 0110 по "протоколу" WS28xx. Тайминги сильно растянуты, но соотношения соблюдены.
Красные линии - событие update event.
Жёлто-зеленые линии - отрезок времени от момента compare event до update event - за это время DMA должен успеть обновить CCRx таймера.
TIM_ISR_UI и TIM_ISR_CCIF - это прерывания UIF и CCRIF, ногодрыг для лог. анализатора, поэтому с запозданием.
Вывод - ИМХО использование update event в данном случае является более аккуратным решением. Во всяком случае, более предсказуемым. Это для STM32F103. Почему такого не наблюдалось с STM32F030 на 8MHz - не вникал; видимо, новее и более продуман.
|
|
|
|
10.01.2021, 11:03
|
|
Гражданин KAZUS.RU
Регистрация: 17.06.2008
Адрес: Украина
Сообщений: 710
Сказал спасибо: 363
Сказали Спасибо 797 раз(а) в 371 сообщении(ях)
|
Re: Изучаем STM32 Cortex M3
Сообщение от j-Roger
|
Почему такого не наблюдалось с STM32F030 на 8MHz
|
Потому что использовался DMA request по update event.
При использовании compare event - такой же бардак.
Ну это и понятно; как же DMA успеет сделать одну пересылку за 2 такта.
С уважением,
капитан Очевидность
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 15:23.
|
|