|
Как сделать программную задержку на STM32, без использования таймеров |
|
|
|
 |
Ответов
(1 - 66)
|
Feb 10 2012, 13:13
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 2-09-05
Пользователь №: 8 169

|
Попробуйте вставить __no_operation() в тело цикла.
|
|
|
|
|
Feb 10 2012, 13:15
|

Участник

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

|
Цитата("Firer") Может функцию на ассемблере кто подскажет? Код XTAL_CLK equ 24000 ; частота тактирования в килогерцах ....
Delay_us PROC push {lr,r4} del_us mov r4,#((XTAL_CLK/1000)/3) del1u subs r4,r4,#1 bne del1u subs r0,r0,#1 bne del_us pop {lr,r4} bx lr ENDP
|
|
|
|
|
Feb 10 2012, 17:19
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Firer @ Feb 10 2012, 17:46)  Вопрос - на сколько тактов процессора эта функция делает задержку? Сам цикл. Железобетонный способ - измерить с секундомером. Для этого делается задержка не на 10 циклов, а на 10^9 циклов или около того. Не слишком маленькая, чтобы погрешность отсчёта времени была мала, и не слишком большая, чтобы не уснуть с секундомером в руке. Кстати, задержки для LCD, как правило, не должны быть точными. Обычно достаточно, чтобы было "гарантированно не меньше N циклов".
|
|
|
|
|
Feb 10 2012, 17:59
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 4-05-08
Пользователь №: 37 272

|
Цитата(Firer @ Feb 10 2012, 16:46)  Вопрос - на сколько тактов процессора эта функция делает задержку? Сам цикл. Вносит ли переход сброс конвейера и глотает ли он доп.циклы? Или 10*2 циклов получается ровно? ПМСМ, переход (кроме последнего раза) будет заново заполнять конвеер. (не заполняет тогда, когда не выполняется условие - нет перехода) Лучше 1 раз посчитать, используя системный таймер, с предделением 1. (Вызов функции тоже переход с заполнением конвеера.) Более того, время выполнения, возможно, будеть зависеть от модели контроллера (разрядность памяти) и настроек регистра доступа к памяти. Мне тоже интересна эта тема. Если посчитаете системным таймером - поделистесь, пожалуйста. По крайней мере на IAR вариант с volatile у меня работает. Код void delay_y() { volatile u32_t i, ty; for(i=0; i<10000; i++) ty=GPIOA_ODR; } И ещё замечание.. практически гарантировано не будет заоптимизировано обращение к портам. Но ваш вариант лучше - точнее.
Сообщение отредактировал Юрий_СВ - Feb 10 2012, 18:40
|
|
|
|
|
Feb 11 2012, 11:38
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Firer @ Feb 10 2012, 13:51)  Пожалуйста подскажите. Пишу в FreeRTOS. Нужно написать библиотеку работы с LCD. Там нужна задержка около 1мкс. Как ее сделать? Посмотрите DWT счетчик (DWT_CYCCN, описано тут и здесь): присутствует во всех Cortex по стандарту ARM. Это 32-битное слово, которое "тикает" с частотой ядра. Счетчик надо проинициализировать (включить): Код #define DWT_CYCCNT *(volatile uint32_t *)0xE0001004 #define DWT_CONTROL *(volatile uint32_t *)0xE0001000 #define SCB_DEMCR *(volatile uint32_t *)0xE000EDFC
if (!(DWT_CONTROL & 1)) { SCB_DEMCR |= 0x01000000; DWT_CYCCNT = 0; DWT_CONTROL|= 1; // enable the counter } Задержки можно организовывать так: Код uint32_t DWT_Get(void) { return DWT_CYCCNT; } __inline uint8_t DWT_Compare(int32_t tp) { return (((int32_t)DWT_Get() - tp) < 0); }
void DWT_Delay(uint32_t us) // microseconds { int32_t tp = DWT_Get() + us * (SystemCoreClock/1000000)); while (DWT_Compare(tp)); } Безусловно, по причине задержек исполнения самих инструкций абсолютно точно не будет. Однако же, скажем при 72MHz ядра, даже для 1мкс аддитивная составляющая будет небольшой и постоянной.
Сообщение отредактировал KnightIgor - Feb 11 2012, 11:49
|
|
|
|
|
Feb 16 2012, 05:55
|
Местный
  
Группа: Свой
Сообщений: 249
Регистрация: 2-05-06
Из: Россия, Поволжье
Пользователь №: 16 686

|
Цитата(ReAl @ Feb 15 2012, 21:02)  Очень жаль, что остальные счётчики все 8-битные. На оффтопике (LPC17xx) для счётчика циклов достаточно RIT, который остался в наследство от предыдущих LPC... Вот только в LPC177x его не оказалось  Хотя в LPC176x есть, для этих целей и пользую. Прошу прощения тоже за оффтоп.
|
|
|
|
|
Jun 28 2012, 07:42
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Счетчик надо проинициализировать (включить): - должен подкорректировать, т.к. признаком уже включенного таймера должен служить бит в SCB_DEMCR, а не в DWT_CONTROL - связано с работой под отладчиком. Код #define DWT_CYCCNT *(volatile uint32_t *)0xE0001004 #define DWT_CONTROL *(volatile uint32_t *)0xE0001000 #define SCB_DEMCR *(volatile uint32_t *)0xE000EDFC
if (!(SCB_DEMCR & 0x01000000)) { SCB_DEMCR |= 0x01000000; DWT_CYCCNT = 0; DWT_CONTROL|= 1; // enable the counter }
|
|
|
|
|
Jun 28 2012, 11:54
|
Частый гость
 
Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511

|
Цитата(ukpyr @ Jun 28 2012, 12:01)  не понятно зачем пляски с бубном, выше приводились задержки на инлайн-асме - работают отлично Это прискорбно, но не все знают ASM. Ваши функции "из коробки" у меня не заработали. Возможно их надо подкорректировать самую малость, но как именно я не знаю((( Кроме того не очень приятно использовать функцию, если не понимаешь как она работает. Естественно это не ваша вина, что я не в состоянии переделать их под себя. Но отсюда и пляски с бубном.
Сообщение отредактировал Влад Р. - Jun 28 2012, 11:54
|
|
|
|
|
Jan 6 2013, 16:53
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(_Артём_ @ Jan 6 2013, 20:20)  А отладчик использует? С чего вы взяли? Понятия не имею, использует или нет. Логика подсказывает, что вполне может использовать для профилирования чего-либо. Да и кроме логики, есть основания думать, что использует.
|
|
|
|
|
Jan 6 2013, 20:50
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(_Артём_ @ Jan 7 2013, 00:26)  Но вы используете это самое профилирование? Напрямую - нет. Но не хотелось бы получить граблями по лбу на ровном месте. Когда какой-нить плагин в IAR станет криво работать, уйдет время на то, что бы вспомнить, что сам заложил эту мину. Цитата(_Артём_ @ Jan 7 2013, 00:26)  В работающим устройстве тем более откуда конфликтам взяться? Так в работающем устройстве и отладчик отсутствует. Соотв. и проблемы нет. Цитата(_Артём_ @ Jan 7 2013, 00:26)  P.S. А что таймеров stm32 вам мало что ли? Таймеров хватает, повёлся на это: Цитата(KnightIgor @ Feb 11 2012, 15:38)  присутствует во всех Cortex по стандарту ARM
|
|
|
|
|
Jan 7 2013, 02:02
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Цитата(Porty @ Feb 10 2012, 08:11)  используй специально для этого предназначенное ключевое слово "volatile", оно говорит компилятору чтоб не оптимизировал значение и работу с этой переменной или кодом. Цитата WikipediaIn computer programming, particularly in the C, C++, C#, and Java programming languages, a variable or object declared with the volatile keyword usually has special properties related to optimization and/or threading. Generally speaking, the volatile keyword is intended to prevent the compiler from applying any optimizations on the code that assume values of variables cannot change "on their own." Никакого отношения к оптимизации. Ключевое слово "volatile" запрещает компилятору надеятся, что значение переменной ему известно и требует его обновления при каждом обращении.
--------------------
|
|
|
|
|
Jan 7 2013, 10:31
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(_Артём_ @ Jan 7 2013, 11:20)  Не только для чтения. Писать его тоже можно. Можно. Я написал "по сути для чтения". То есть, программа профилирования может, конечно, каждый раз сбрасывать его перед измерением. Однако кто профилирование пишет, тоже не дурак, чтобы делать это instrusive, то есть с вмешательством в процесс. С большой вероятностью для измерения времен используется разница между считаными значениями свободно бегущего счетчика, то есть, без его пересброса. Во всяком случае в моих программах пока никаких непоняток не было.
|
|
|
|
|
Jan 7 2013, 11:59
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(pitt @ Jan 7 2013, 06:02)  Никакого отношения к оптимизации. Ключевое слово "volatile" запрещает компилятору надеятся, что значение переменной ему известно и требует его обновления при каждом обращении. Угу... щазз... А ещё есть code reordering... Или будете доказывать, что и code reordering "Никакого отношения к оптимизации"??? Цитата(KnightIgor @ Feb 11 2012, 15:38)  Посмотрите DWT счетчик (DWT_CYCCN, описано тут и здесь): присутствует во всех Cortex по стандарту ARM. И в Cortex M0 есть???
|
|
|
|
|
Jan 7 2013, 12:38
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(KnightIgor @ Jan 7 2013, 12:20)  Какие грабли, если его читать? Если только читать - никаких. Однако и здесь, и здесь, при инициализации предлагается запись в DWT_CYCCNT. Как будет вызываться инициализация, единожды или при каждой задержке, оставим за скобками, ибо это отдельный вопрос. Итого. Я бы рекомендовал исключить строку: Код DWT_CYCCNT = 0; Цитата(HHIMERA @ Jan 7 2013, 15:59)  И в Cortex M0 есть??? Ну самостоятельно посмотреть?
|
|
|
|
|
Jan 7 2013, 12:46
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(Tahoe @ Jan 7 2013, 15:38)  самостоятельно посмотреть? Смотрел... Дошёл до Цитата This document is only available in a PDF version to registered ARM customers. и усё... )))
|
|
|
|
|
Jan 8 2013, 07:16
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Цитата(HHIMERA @ Jan 7 2013, 19:46)  Смотрел... Дошёл до
и усё... ))) Так зарегистрируйтесь, это не сложно. Впрочем, не поможет, в М0 и М0+ такого регистра нет.
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
Jan 8 2013, 08:52
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(SSerge @ Jan 8 2013, 11:16)  в М0 и М0+ такого регистра нет. Вот и я о том же... И если последние редакции CMSIS в файлах core_cm3.h и core_cm4.h содержат информацию о DWT, то в core_cm0.h она отсутствует напрочь... Да и в самом железе STM32F0XX DWT не работает...
|
|
|
|
|
Jan 27 2013, 00:00
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Цитата(HHIMERA @ Jan 7 2013, 06:59)  Угу... щазз... А ещё есть code reordering... Или будете доказывать, что и code reordering "Никакого отношения к оптимизации"??? Не стоит путать божий дар с яичничей, а key word "volatile" с оптимизирующим компилятором FYI
--------------------
|
|
|
|
|
Jan 27 2013, 10:23
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Tahoe @ Jan 7 2013, 13:38)  Итого. Я бы рекомендовал исключить строку: Код DWT_CYCCNT = 0; Логично. Но один разочек при старте не мешает: Цитата "The debugger must initialize this to 0 when first enabling" (на стр. 11-19 документа ). Кстати, снова о "подводных" камнях: там же по тексту DWT счетчик явно предлагается для отсчета коротких времен в приложении: Цитата Applications and debuggers can use the counter to measure elapsed execution time. By subtracting a start and an end time, an application can measure time between in-core clocks (other than when Halted in debug). This is valid to 2^32 core clock cycles (for example,almost 86 seconds at 50MHz). DWT действительно нет в -M0. Тогда можно использовать SYSTICK: находить разницу между двумя значениями SYST_CVR с учетом значения перезагрузки SYST_RVR. Чаще всего SYSTICK запускают на генерацию перрывания каждые 1ms. То есть, вполне можно запускать программные задержки на меньшие времена (десятки - сотни мкс).
Сообщение отредактировал KnightIgor - Jan 27 2013, 10:36
|
|
|
|
|
Jan 27 2013, 15:05
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(KnightIgor @ Jan 27 2013, 14:23)  Но один разочек при старте не мешает: Цитата "The debugger must initialize this to 0 when first enabling" Дело за малым - как-либо узнать, что текущий "enabling" будет действительно "first", а не "second", "third" или "hundredfivehundred".  Хотя решение, конечно, очевидно: просто инициализировать счетчик при старте. По крайней мере, для периодических задач профилирования, это не станет серьезной проблемой. Разве что экхотика какая, например, время стартапа подсчитывается, но и в этом случае, по идее, к моменту перехода на main() подсчет должен быть уже выполнен. Другой экзотики в голову не приходит. Цитата(KnightIgor @ Jan 27 2013, 14:23)  DWT счетчик явно предлагается для отсчета коротких времен в приложении А вот этого не видел. Мерси. Насчет моих предположений про DWT, вот чуть конкретнее, в контексте отладчика: Цитата(IAR: What is your application doing inside your microcontroller? Debugging software applications on ARM Cortex-M3 and Cortex-M4 devices[/url) Data Watchpoint and Trace The Data Watchpoint and Trace (DWT) provides a set of functions that collect information from the system buses and generates events to the ITM for packetizing and time stamping and further distribution on the SWO channel. ... и далее по тексту, правда инфы не густо.
|
|
|
|
|
Jan 31 2013, 12:35
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 22-01-13
Пользователь №: 75 284

|
Ну а вот я попробывал сделать так: Код #define F_CPU 8000000UL void delay_us(uint32_t us) { for(volatie unsigned int i=0;i<((F_CPU/1000000-3)*us);i++) {} } где цифра "3" в условии цикла - это поправка, связанная с тем что на создание и сравнение условия также уходят такты. Я поставил аргумент функции 5 млн (т.е 5 секунд), засекал на внешнем таймере: получается довольно точно 5,3 с. Без поправочного коэффициента получается 8,4 с. И, кстате, скажите кто знает: что значит "UL" после частоты? И когда обьявляем переменную "uint16_t" - что значит _t ? И всегда ли эта переменная занимает одну ячейку памяти или под неё выделяется целые 32 бита? И что просходит с переменной обьявленной таким способом, если мы записываем в неё например 1млн? Что плохого/хорошего скажите про всё это?
|
|
|
|
|
Jan 31 2013, 13:13
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(allsettingsdone @ Jan 31 2013, 16:35)  И, кстате, скажите кто знает: что значит "UL" после частоты? Это значит, что константа имеет тип unsigned long. Этот суффикс имеет смысл приписывать, если код может использоваться на системах с 16-битным типом int (когда 8000000 не помещается в int), что для приведённого примера не актуально. Цитата(allsettingsdone @ Jan 31 2013, 16:35)  И когда обьявляем переменную "uint16_t" - что значит _t ? Ничего это не значит. Тип uint16_t, как и многие другие подобные типы, объявлен в файле stdint.h в соответствии со стандартом C99. Просто кто-то так назвал эти типы. Цитата(allsettingsdone @ Jan 31 2013, 16:35)  И всегда ли эта переменная занимает одну ячейку памяти или под неё выделяется целые 32 бита? Что есть ячейка памяти? Бит? Байт? 2 байта? 4 байта? 16 байт? И т.д. Так или иначе, ответ зависит от контекста: если переменная размещается в регистре или стеке, то скорее всего она занимает 32 бита. Статические переменные могут занимать меньше памяти. Цитата(allsettingsdone @ Jan 31 2013, 16:35)  И что просходит с переменной обьявленной таким способом, если мы записываем в неё например 1млн? Если в uint16_t записать 1000000, то скорее всего там окажется 16960 (то есть срежутся старшие биты). Цитата(allsettingsdone @ Jan 31 2013, 16:35)  Что плохого/хорошего скажите про всё это? Код хорош тем, что прост, но плох тем, что время исполнения зависит от версии компилятора, уровня оптимизации, скорости процессора и т.д. Кстати, вам совсем не помешает почитать учебник по языку Си.
|
|
|
|
|
Jan 31 2013, 13:25
|
Частый гость
 
Группа: Свой
Сообщений: 112
Регистрация: 1-05-09
Из: Ростов-на-Дону
Пользователь №: 48 518

|
Цитата(allsettingsdone @ Jan 31 2013, 16:35)  Ну а вот я попробывал сделать так: Код #define F_CPU 8000000UL void delay_us(uint32_t us) { for(volatie unsigned int i=0;i<((F_CPU/1000000-3)*us);i++) {} } где цифра "3" в условии цикла - это поправка, связанная с тем что на создание и сравнение условия также уходят такты. Я поставил аргумент функции 5 млн (т.е 5 секунд), засекал на внешнем таймере: получается довольно точно 5,3 с. Без поправочного коэффициента получается 8,4 с. Лучше уберите этот поправочный коэффициент, а то придет время и понадобится вам задержка меньше чем 3 мкс. Если нужно точно засечь время, лучше использовать таймеры, например, системный.
--------------------
«У современных мобильных телефонов такая же вычислительная мощь, что и у компьютеров NASA в 60-е годы. И в то время этого хватало, чтобы запустить человека в космос, а сегодня — только чтобы запускать птиц в свиней.»
|
|
|
|
|
Jan 31 2013, 14:05
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(allsettingsdone @ Jan 31 2013, 16:35)  когда обьявляем переменную "uint16_t" - что значит _t ? И всегда ли эта переменная занимает одну ячейку памяти или под неё выделяется целые 32 бита? Аккуратнее с такими вопросами. Грамотного Си-программера, _абсолютно_ не должно волновать, сколько там ячеек занимает uint16_t. Единственное, что он должен твердо помнить, что: 1. Это беззнаковый тип. 2. Что размер этого типа 16 бит. Когда программер станет опытным, он узнает ответ и на вопрос о "ячейках", но пока, упаси Б-г об этом задумываться. Потому что итог будет печальным - программа на ассемблере, писаная Си-синтаксисом. Цитата(allsettingsdone @ Jan 31 2013, 16:35)  И что просходит с переменной обьявленной таким способом, если мы записываем в неё например 1млн? См. выше. Единственное, что должен знать грамотный Си-программер, это что при записи в uint16_t числа > 0xFFFF, произойдет переполнение переменной этого типа. И, повторюсь, не дай Б-г начать задумываться о чем-то бОльшем. Во всяком случае, на данном этапе.
|
|
|
|
|
Jan 31 2013, 16:21
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 22-01-13
Пользователь №: 75 284

|
Так а на чем же остановиться в поиске функции для програмной задержки?
|
|
|
|
|
Jan 31 2013, 16:43
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(allsettingsdone @ Jan 31 2013, 20:21)  Так а на чем же остановиться в поиске функции для програмной задержки? Да на чем угодно, лишь бы написано было понятно и пользоваться удобно: Код //////////////////////////////////////////////////////////////////////////////// // DELAY /////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #pragma inline void BspDelayTicks( uint32_t Ticks ) { if (!(SCB_DEMCR & 0x01000000)) { CoreDebug->DEMCR |= 0x01000000; DWT->CYCCNT = 0; DWT->CTRL |= 1 << DWT_CTRL_CYCCNTENA_Pos; // enable the counter }
while( DWT->CYCCNT < Ticks ); }
//////////////////////////////////////////////////////////////////////////////// #pragma inline void BspDelay_uSec( volatile uint32_t uSec ) { while( uSec-- ) { BspDelayTicks( BSP_MCLK_HZ/1000000 ); } }
//////////////////////////////////////////////////////////////////////////////// #pragma inline void BspDelay_mSec( volatile uint32_t mSec ) { while( mSec-- ) { BspDelayTicks( BSP_MCLK_HZ/1000 ); } }
|
|
|
|
|
Jan 31 2013, 19:36
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(Tahoe @ Jan 31 2013, 19:43)  лишь бы написано было понятно Код if (!(SCB_DEMCR & 0x01000000)) { CoreDebug->DEMCR |= 0x01000000; Да вроде как и понятно... но вот глаз режет... Вроде как ... Код CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
|
|
|
|
Jan 31 2013, 20:26
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(HHIMERA @ Jan 31 2013, 23:36)  но вот глаз режет... Да ладно, буквоедствовать... Особенно после этой помойки: Цитата(allsettingsdone @ Jan 31 2013, 16:35)  Код #define F_CPU 8000000UL void delay_us(uint32_t us) { for(volatie unsigned int i=0;i<((F_CPU/1000000-3)*us);i++) {} } В показанном коде еще и счетчик сбрасывается, а не разница между текущим и ожидаемым значением вычисляется.  И потом, основная "ценность" приведенного кода совсем в другом, а именно, в сервисе: BspDelay_uSec( xxx ); BspDelay_mSec( xxx );
|
|
|
|
|
Feb 1 2013, 10:08
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 22-01-13
Пользователь №: 75 284

|
Цитата(Tahoe @ Jan 31 2013, 18:43)  Да на чем угодно, лишь бы написано было понятно и пользоваться удобно: Код //////////////////////////////////////////////////////////////////////////////// // DELAY /////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #pragma inline void BspDelayTicks( uint32_t Ticks ) { if (!(SCB_DEMCR & 0x01000000)) { CoreDebug->DEMCR |= 0x01000000; DWT->CYCCNT = 0; DWT->CTRL |= 1 << DWT_CTRL_CYCCNTENA_Pos; // enable the counter }
while( DWT->CYCCNT < Ticks ); }
//////////////////////////////////////////////////////////////////////////////// #pragma inline void BspDelay_uSec( volatile uint32_t uSec ) { while( uSec-- ) { BspDelayTicks( BSP_MCLK_HZ/1000000 ); } }
//////////////////////////////////////////////////////////////////////////////// #pragma inline void BspDelay_mSec( volatile uint32_t mSec ) { while( mSec-- ) { BspDelayTicks( BSP_MCLK_HZ/1000 ); } } Это не компитируется, куча ошибок. Например: identifier "SCB_DEMCR" is undefined identifier "DWT" is undefined identifier "DWT_CTRL_CYCCNTENA_Pos" is undefined identifier "BSP_MCLK_HZ" is undefined Какие вы библиотеки используете для этого, что пользователь должен задейфайнить сам? Ничего не понимаю
Сообщение отредактировал allsettingsdone - Feb 1 2013, 10:12
|
|
|
|
|
Feb 1 2013, 10:27
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(allsettingsdone @ Feb 1 2013, 14:08)  что пользователь должен задейфайнить сам? Ничего не понимаю А что там понимать... Дефайн SCB_DEMCR описан в начале темы... А CoreDebug->DEMCR, DWT->CYCCNT и DWT->CTRL есть в налиии в последних CMSIS... в старых отсутствуют... Просто как-то... "Смешались в кучу кони, люди" (С)... ))
|
|
|
|
|
Feb 1 2013, 12:04
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(allsettingsdone @ Feb 1 2013, 14:08)  Это не компитируется, куча ошибок. Например: identifier "SCB_DEMCR" is undefined identifier "DWT" is undefined identifier "DWT_CTRL_CYCCNTENA_Pos" is undefined identifier "BSP_MCLK_HZ" is undefined Какие вы библиотеки используете для этого, что пользователь должен задейфайнить сам? Ничего не понимаю В принципе, HHIMERA уже ответил. Названия регистров и битов - стандартные, из CMSIS. Обычно, CMSIS подключается в любом проекте на Cortex-M ядре. А что касается BSP_MCLK_HZ, то, как видно из его префикса и префиксов функций, они указывают на расположение в файле bsp.х Про BSP можно почитать здесь, а лучше здесь. Как явствует из MCLK, это некий clock, в данном случае main clock. HZ указывает на то, что частота задана Герцах. Итого: константа в файле bsp.h, означающая частоту ядра процессора в Герцах.
|
|
|
|
|
Feb 1 2013, 12:11
|
Частый гость
 
Группа: Участник
Сообщений: 147
Регистрация: 18-05-12
Пользователь №: 71 915

|
Цитата Что плохого/хорошего скажите про всё это? рабочий код был дан давно: http://electronix.ru/forum/index.php?s=&am...t&p=1025991работает четко, без всяких попроавочных коэффициентов (на чистом С компилятор может сгенерить что угодно в зависимости от настроек оптимизации). И вычисления количества циклов происходит во время компиляции, а не как у многих тут, которые суют деления/умножения, и даже плавучку в функцию задержки.
Сообщение отредактировал polyname - Feb 1 2013, 12:12
|
|
|
|
|
Feb 1 2013, 12:24
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(polyname @ Feb 1 2013, 16:11)  а не как у многих тут, которые суют деления/умножения, и даже плавучку в функцию задержки. Если речь про мой код, то могу посоветовать только голову включить. Хотел бы я посмотреть на компилер, препроцессор которого, увидев констатное 8000000/1000, пропустит мимо и отправит вычисляться в рантайм. Вот что действительно имеет смысл поправить, так это вместо Код if (!(SCB_DEMCR & 0x01000000)) для единообразия: Код if (!(CoreDebug->DEMCR & 0x01000000))
|
|
|
|
|
Aug 6 2013, 12:54
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(KnightIgor @ Jun 28 2012, 11:42)  Счетчик надо проинициализировать (включить): - должен подкорректировать, т.к. признаком уже включенного таймера должен служить бит в SCB_DEMCR, а не в DWT_CONTROL - связано с работой под отладчиком. Код if (!(SCB_DEMCR & 0x01000000)) { ... } извиняюсь что поднял старый пост. Но у меня так не тикало на LPC1778 - то есть бит DEMCR_TRCENA был установлен, а DWT->CTRL сброшен. Может всё-таки так ? Код if( !( CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk ) || !( DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk ) ) { DWT->CYCCNT = 0; CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // enable the counter } кстати, кому интересно, расширил разрядность DWT до 64 бит Код //---------------------------------------------------------------------------- u64 core_get_cycles_counter( void ) { TN_INTSAVE_DATA
u64 ret = 0; static u32 cch = 0, ccl_prev = 0; u32 ccl = DWT->CYCCNT; tn_disable_interrupt(); if( ccl_prev > ccl ) cch++; ret = ((u64)cch << 32) + ccl; ccl_prev = ccl; tn_enable_interrupt(); return ret; }
//---------------------------------------------------------------------------- u64 get_sys_mks( void ) { u64 ret = core_get_cycles_counter() / ( F_CPU / 1000000UL ); return ret; }
P.S. в векторе SysTick_Handler системного тика каждую секунду считывает core_get_cycles_counter чтобы DWT->CYCCNT не переполнился более одного раза
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Aug 7 2013, 06:52
|
Знающий
   
Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231

|
на новых мк приходится штриховать условие (//) Код if (!(SCB_DEMCR & 0x01000000)) потом расштриховываешь и всё нормально работает при отладке. Правда это на STM32F4/ С чем связано ещё не разбирался
|
|
|
|
|
Aug 7 2013, 07:40
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(toweroff @ Aug 7 2013, 11:13)  Тут тоже набрел на решение, которое, как мне кажется, зависит только от тактовой частоты - это время доступа с внутреннему ОЗУ И тогда довольно точно можно подгонять задержки кто юзал IAR и переходил с AVR на CM3 всегда недоумевали - "куда делись привычные __delay_cycles( N ) ?" а ответ простой - в CM3 есть DMA, который перехватывает системную шину и собственно приостанавливает доступ. Так что на ваших for(i<const) ничего толкового не получишь. P.S. И как мне говорили, есть еще какие-то факторы. Так что если кто подскажет буду признателен
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Aug 12 2013, 02:14
|

Группа: Участник
Сообщений: 14
Регистрация: 10-06-12
Пользователь №: 72 261

|
Цитата(ukpyr @ Jun 28 2012, 18:01)  не понятно зачем пляски с бубном, выше приводились задержки на инлайн-асме - работают отлично +100 Вот код под IAR Код #define __delay_us( US ) __delay_loops( (uint32_t)((double)US * F_CPU / 3000000.0)) #define __delay_ms( MS ) __delay_loops( (uint32_t)((double)MS * F_CPU / 3000.0)) #define __delay_s( S ) __delay_loops( (uint32_t)((double)S * F_CPU / 3.0))
#pragma inline=forced void __delay_loops(uint32_t loops){ asm( "Metka: SUBS %[R1], %[R1], %[imm] \n" " BNE.N Metka \n" : [R1]"+r" (loops) : [imm]"i"(1)); };
|
|
|
|
|
Aug 12 2013, 09:30
|
Профессионал
    
Группа: Участник
Сообщений: 1 264
Регистрация: 17-06-08
Из: бандустан
Пользователь №: 38 347

|
DMA далеко не всегда используется. можно добавить запрет прерываний: Код #define cli() asm volatile ( "CPSID i \n" ) #define sei() asm volatile ( "CPSIE i \n" )
#define __delay_us_cli( US ) cli(); __delay_us( US ); sei(); другой вариант - выделить для задержек таймер.
Сообщение отредактировал ukpyr - Aug 12 2013, 09:36
|
|
|
|
|
Aug 12 2013, 14:19
|

Группа: Участник
Сообщений: 14
Регистрация: 10-06-12
Пользователь №: 72 261

|
Цитата(VAI @ Aug 12 2013, 18:03)  Постом выше megajohn написал, почему Ваши задержки будут кривыми... + к этому, ещё и срабатывание прерываний во время исполнения циклов. Да, проверил, есть такой косяк. Сделал по другому, может уже и не в тему топика, поскольку заюзал таймер: Код #define F_CPU 24000000UL
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM6->CR1 |= TIM_CR1_CEN;
// Процедура формирования линейной задержки #pragma inline=forced void __delay_loops(uint16_t loops) { TIM6->CNT = 0x0000; while(loops > TIM6->CNT); }
#define __delay_us( US ) __delay_loops( (uint16_t)(US * (uint16_t)(F_CPU / 1000000UL)) )
#pragma inline=forced void __delay_ms(uint16_t ms){ do{ __delay_us(1000); } while(ms--); };
|
|
|
|
|
Sep 28 2014, 10:45
|
Группа: Новичок
Сообщений: 6
Регистрация: 4-07-14
Пользователь №: 82 154

|
Цитата(Rash @ Aug 7 2013, 09:52)  на новых мк приходится штриховать условие (//) Код if (!(SCB_DEMCR & 0x01000000)) потом расштриховываешь и всё нормально работает при отладке. Правда это на STM32F4/ С чем связано ещё не разбирался О, а можно с этого места по подробнее. Подключен stm32f103, из IAR прошиваю через ST-LINK, функция расшифровки ногодрыга реализована через DWT - все работает как ожидалось. Сбрасываю питание - функция перестает работать. Никакие электролиты и пр на питании не помогают. Остальные функции работают как нужно. CODE void DWT_Init(void) { DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } uint32_t DWT_Get(void) { return DWT->CYCCNT; } inline uint8_t DWT_Compare(int32_t tp) { return (((int32_t)DWT_Get() - tp) < 0); } void DWT_Delay(uint32_t us) // microseconds { int32_t tp = DWT_Get() + us * (F_CPU/1000000); while (DWT_Compare(tp)); } что я делаю не так? Цитата(Kot_dnz @ Sep 28 2014, 13:15)  [code]void DWT_Init(void) { DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } Сорри, нашел - не хватало строки CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; интересное проявление баго-фичи...
Сообщение отредактировал IgorKossak - Sep 28 2014, 18:59
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Oct 3 2014, 07:00
|

фанат Linux'а
    
Группа: Свой
Сообщений: 1 353
Регистрация: 23-10-05
Из: SPB.RU
Пользователь №: 10 008

|
Цитата(Firer @ Feb 10 2012, 16:51)  Нужно написать библиотеку работы с LCD. Там нужна задержка около 1мкс. Я решаю это так (и на STM32 и на MDR32 и на других): Код unsigned int delay_ms(unsigned int ms) { volatile unsigned int i, t = 0; //for(i = 0; i < (ms*400); i++) t++; // @ 8 MHz for(i = 0; i < (ms*5714); i++) t++; return t; }
unsigned int delay_10us(unsigned int us) { volatile unsigned int i, t = 0; //for(i = 0; i < (us*4); i++) t++; // @ 8 MHz for(i = 0; i < (us*57); i++) t++; return t; } Сначала мигаю светодиодом на delay_ms(1000) - периоды были несколько секунд - так вычисляю во сколько раз мне нужно меньше чтобы была как можно ближе к одной секунде. Получил число допустим 5714. Ну а 10 мкс - это в 100 раз меньше - 57. Знаю какие недостатки этого метода, но лично мне нравится и всё работает стабильно
--------------------
|
|
|
|
|
Oct 3 2014, 07:27
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(AVR @ Oct 3 2014, 11:00)  Код //for(i = 0; i < (ms*[b]400[/b]); i++) t++; // @ 8 MHz for(i = 0; i < (ms*[b]5714[/b]); i++) t++;
//for(i = 0; i < (us*[b]4[/b]); i++) t++; // @ 8 MHz for(i = 0; i < (us*[b]57[/b]); i++) t++; ...мне нравится и всё работает стабильно  почему бы и нет? только маленьчкое замечание: цифры я бы вычислял бы в зависимости от дефайна тактовой. Тем более в STM вроде как они объявлены. Тогда писать новые строчки под разную частоту не понадобиться. И по закону мерфи - меньше кода, меньше багов... ЗЫ И ещё бы добавил ифдеф для делителей меньше 1 или 2... Типа вонинг! не допустимо маленький делитель(умножитель - кому как  ) для данных функций.
|
|
|
|
|
Oct 3 2014, 12:49
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
kolobok0, AVR
Для большей точности и повторяемости можно реализовать на ассемблере, получится совсем немного инструкций, можно будет точнее вычислить кол-во тактов на один цикл, не будет плавать из-за смены опций компиляции. Чтобы не мешали прерывания можно их запрещать на время задержки.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|