|
|
  |
Как сделать программную задержку на STM32, без использования таймеров |
|
|
|
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
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|