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

 
 
5 страниц V  « < 2 3 4 5 >  
Reply to this topicStart new topic
> Как сделать программную задержку на STM32, без использования таймеров
Tahoe
сообщение Jan 31 2013, 20:26
Сообщение #46


Местный
***

Группа: Свой
Сообщений: 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++) {}
}


В показанном коде еще и счетчик сбрасывается, а не разница между текущим и ожидаемым значением вычисляется. wink.gif И потом, основная "ценность" приведенного кода совсем в другом, а именно, в сервисе:
BspDelay_uSec( xxx );
BspDelay_mSec( xxx );
Go to the top of the page
 
+Quote Post
allsettingsdone
сообщение Feb 1 2013, 10:08
Сообщение #47


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
HHIMERA
сообщение Feb 1 2013, 10:27
Сообщение #48


Местный
***

Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126



Цитата(allsettingsdone @ Feb 1 2013, 14:08) *
что пользователь должен задейфайнить сам? Ничего не понимаю

А что там понимать...
Дефайн SCB_DEMCR описан в начале темы...
А CoreDebug->DEMCR, DWT->CYCCNT и DWT->CTRL есть в налиии в последних CMSIS... в старых отсутствуют...
Просто как-то... "Смешались в кучу кони, люди" (С)... ))
Go to the top of the page
 
+Quote Post
Tahoe
сообщение Feb 1 2013, 12:04
Сообщение #49


Местный
***

Группа: Свой
Сообщений: 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, означающая частоту ядра процессора в Герцах.
Go to the top of the page
 
+Quote Post
polyname
сообщение Feb 1 2013, 12:11
Сообщение #50


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

Группа: Участник
Сообщений: 147
Регистрация: 18-05-12
Пользователь №: 71 915



Цитата
Что плохого/хорошего скажите про всё это?
рабочий код был дан давно:
http://electronix.ru/forum/index.php?s=&am...t&p=1025991
работает четко, без всяких попроавочных коэффициентов (на чистом С компилятор может сгенерить что угодно в зависимости от настроек оптимизации). И вычисления количества циклов происходит во время компиляции, а не как у многих тут, которые суют деления/умножения, и даже плавучку в функцию задержки.

Сообщение отредактировал polyname - Feb 1 2013, 12:12
Go to the top of the page
 
+Quote Post
Tahoe
сообщение Feb 1 2013, 12:24
Сообщение #51


Местный
***

Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600



Цитата(polyname @ Feb 1 2013, 16:11) *
а не как у многих тут, которые суют деления/умножения, и даже плавучку в функцию задержки.

Если речь про мой код, то могу посоветовать только голову включить. Хотел бы я посмотреть на компилер, препроцессор которого, увидев констатное 8000000/1000, пропустит мимо и отправит вычисляться в рантайм.


Вот что действительно имеет смысл поправить, так это вместо
Код
if (!(SCB_DEMCR & 0x01000000))

для единообразия:
Код
if (!(CoreDebug->DEMCR & 0x01000000))
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 22 2013, 16:02
Сообщение #52


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Код
void dwt_init(void)
{
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT       = 0;                            // reset
    DWT->CTRL        |= 1;                            // enable the counter
}

static __inline uint32_t dwt_dt(uint32_t t0, uint32_t t1)
{
    return (t1 - t0); // всегда верно, даже если t1<t0
}

void dwt_delay(uint32_t us) // microseconds (max = 2^32 / (fcpu*1.0E-6) - 1)
{
    uint32_t t0 = DWT->CYCCNT;
    uint32_t dt = us * (F_CPU/1000000UL); // 1us = 72tics @ 72MHz

    while (dwt_dt(t0, DWT->CYCCNT) < dt)  {;}
}
И нет проблем при попадании момента переполнения счётчика внутрь измеряемого диапазона времени...
Естественно максимальный диапазон не должен превышать одного периода dwt таймера, то бишь типа uint32_t.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
megajohn
сообщение Aug 6 2013, 12:54
Сообщение #53


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

Группа: Свой
Сообщений: 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 штук).
Go to the top of the page
 
+Quote Post
Rash
сообщение Aug 7 2013, 06:52
Сообщение #54


Знающий
****

Группа: Свой
Сообщений: 639
Регистрация: 5-09-05
Пользователь №: 8 231



на новых мк приходится штриховать условие (//)
Код
if (!(SCB_DEMCR & 0x01000000))

потом расштриховываешь и всё нормально работает при отладке. Правда это на STM32F4/
С чем связано ещё не разбирался
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 7 2013, 07:13
Сообщение #55


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Тут тоже набрел на решение, которое, как мне кажется, зависит только от тактовой частоты - это время доступа с внутреннему ОЗУ
И тогда довольно точно можно подгонять задержки
Код
volatile uint32_t trash_in, trash_out;

for (uint32_t i=0; i<delay; i++) trash_in = trash_out;
Go to the top of the page
 
+Quote Post
megajohn
сообщение Aug 7 2013, 07:40
Сообщение #56


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

Группа: Свой
Сообщений: 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 штук).
Go to the top of the page
 
+Quote Post
Rimsky
сообщение Aug 12 2013, 02:14
Сообщение #57





Группа: Участник
Сообщений: 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));
        };

Go to the top of the page
 
+Quote Post
VAI
сообщение Aug 12 2013, 09:03
Сообщение #58


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

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



Цитата(Rimsky @ Aug 12 2013, 06:14) *
Вот код под IAR....

Постом выше megajohn написал, почему Ваши задержки будут кривыми... + к этому, ещё и срабатывание прерываний во время исполнения циклов.


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
ukpyr
сообщение Aug 12 2013, 09:30
Сообщение #59


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

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Aug 12 2013, 09:38
Сообщение #60


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(ukpyr @ Aug 12 2013, 12:30) *
можно добавить запрет прерываний:

А можно из буханки ржаного хлеба..
ну вы понимаете, о чем я..


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post

5 страниц V  « < 2 3 4 5 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


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


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