Альтернативний спосіб відліку часу
Кам'яна сокира. (c) Wiki
Відмірювати
час за допомогою таймерів --
найбільш зручний і коректний спосіб. Однак, іноді він може не підходити, з
тих чи інших мотивів. Одна з альтернатив -- чисто програмна затримка.
Іншими словами, контролер змушують якийсь час виконувати задані
інструкції. Якщо потік виконання один і переривань не виникає, такий
спосіб доволі точний (а з перерахунку вимог, щоб він був точним, видно
основні його недоліки). Важливо, що на відміну від x86, час
виконання інструкцій мікроконтролера значно більш передбачуваний.
Наведений нижче приклад реалізації базується на коді з Leaflab Maple IDE, аналогу оболонки Ардуїно для STM32. Увага: Приклад може бути неточним -- особливо ретельно я не тестував.
Update: Див. також розвиток теми в "Мікросекундні затримки та відлік мікросекунд для STM32".
Update: Див. також розвиток теми в "Мікросекундні затримки та відлік мікросекунд для STM32".
//! Затримка в мікросекундах inline static void delay_some_us1 (uint32_t dlyTicks) { // Взято з leaflabs Maple dlyTicks *= 6; /* Невелика і не дуже точна поправка на час виклику функції */ dlyTicks--; asm volatile(" mov r0, %[dlyTicks] \n\t" "1: subs r0, #1 \n\t" " bhi 1b \n\t" : : [dlyTicks] "r" (dlyTicks) : "r0"); }
- inline переконує компілятор вбудовувати цю функцію, щоб її виклик не займав зайвих тактів, збільшуючи похибку. static каже, що більше ніде, за межами цієї одиниці трансляції, вона не викликатиметься, вважається -- це збільшує шанс, що компілятор врахує прохання про inline (як відомо, даний специфікатор лише дорадчий -- може бути проігнорованим).
- Підрахунок тактів кожної інструкції базується на "Cortex™-M3 Technical Reference Manual: 18.2. Processor instruction timings".
- mov - 2 такти (увага, вона не крутиться в циклі)
- subs - 1
- bhi - 1+2 якщо відбувається перехід (а в циклі всі ітерації, крім останньої, він відбудеться), 1 якщо ні
- Всього тривалість циклу -- 4 такти
- 1 такт = 1/24 мкс = 41.6 нс; 1 мкс - 24 такти
- 4 такти -- 0.167 мкс
- Одна мікросекунда -- 1/0.167 = 6 ітерацій циклу. Тому, власне, на початку кількість мікросекунд множиться на 6.
- Перед початком ітерацій віднімаємо від лічильника 1, щоб частково скомпенсувати час виконання тіла функції. На жаль, більш точної корекції досягнути складно -- кількість інструкцій в функції залежить від компілятора та його опцій, а час виконання може залежати і від контексту виклику.
- Деякі ARM Cortex M мають апаратний лічильник тактів (схожий на Time Stamp Counter в x86) -- DWT. Детальніше про нього пише в офіційній документації: "8.3. DWT Programmers Model", та в обговореннях використання: 1, 2. Однак STM32F100RB його не містить :-(
Немає коментарів:
Дописати коментар