Телефонуйте » (+38) 096 227 41 41

Метою лабораторної роботи є вивчення переривань процесора, використання таймерів процесора та інтерфейсу введення/виведення загального призначення (GPIO).

Переривання

Апаратним перериванням (далі по тексту - переривання) називається механізм реакції на подію, що виникає у внутрішніх або зовнішніх, по відношенню до процесора, периферійних пристроях. Сигнал, який інформує про настання такої події, називається «запитом на переривання». Під час отримання запиту на переривання, процесор припиняє виконання основної програми і переходить до виконання підпрограми обробки переривання. Після завершення обробки переривання, процесор повертається до виконання основної програми. Чим швидше процесор обслуговує запити на переривання, тим краще він підходить для вирішення завдань в реальному масштабі часу.

C66x DSP забезпечує два типи асинхронних служб сигналізації про виникнення події: переривання та винятки (Exceptions). Винятки є подібними до переривання, але зазвичай вони пов'язані з помилками в системі. DSP C66x може приймати 12 маскувальних/налаштовуваних переривань, 1 маскувальний виняток та 1 немаскуюче переривання/виняток.

Переривання з найвищим пріоритетом – це RESET,  яке підключається до контакту апаратного скидання (reset) і не може бути замаскованим.  (Маскування - це заборона на переривання. Якщо переривання замасковано, і надійшов запит на нього, то воно або чекає, поки зможе бути прийняте, або втрачається. Замаскованими можуть бути переривання від пристроїв введення-виведення, зовнішні переривання, частина програмних переривань і переривання від схем контролю). Зазвичай сигнал RESET генерується в момент подачі живлення на процесор. Іншим джерелом сигналу RESET може служити внутрішній сторожовий таймер процесора (Watchdog Timer). При переповненні рахункового регістра даного таймера відбувається генерація сигналу апаратного скидання, який надходить в центральне процесорне ядро. Наступне за пріоритетом переривання - це немасковане переривання (NMI), яке зазвичай використовується для попередження процесора про серйозні апаратні проблеми, наприклад, збій живлення (Обробка немаскованих переривань не може бути заборонена користувачем. Поява запиту на переривання по лініях обов'язково викличе зупинку виконання основної програми і перехід на підпрограму обробки даного переривання). 12 маскованих переривань мають нижчі пріоритети INT4-INT15 (INT4  має найвищий, а INT15 - найнижчий пріоритет).

Процесор C6678 містить векторний контролер переривань (C66x CorePac Interrupt Controller), який дозволяє переводити до 124 системних подій на входи переривань DSP. Ці 124 події можуть бути безпосередньо пов'язані з маскованими перериваннями [2]. На рис 1 показано контролер CorePac INTC  [2]. 124 ідентифікаторів подій представлені як EVT [127: 4], а 12 маскованих  переривань представлені як INT[15: 4].

Рис.1.: Контролер переривань

124 системні події зберігаються в чотирьох 32-розрядних регістрах ( Event Flag Registers), і кожна подія відображається у певному біті. Коли системна подія приходить в контролер встановлюється відповідний біт. Зверніть увагу, що регістри Event Flag Registers доступні лише для читання; Registry Set Register та Event Clear Register можуть бути використані для ручного встановлення або очищення будь-яких бітів у Event Flag Registers [2].

Комбінатор подій (Event Combiner) дозволяє об'єднати декілька системних подій у єдину подію. 124 системні події поділяються на 4 групи, як показано на рис. 2. Логіка Event Combiner має можливість групувати декілька входів подій до 4 можливих виходів подій EVT [3: 0]. Ці виходи потім подаються на вхід пристрою вибору переривань (interrupt selector) і трактуються як додаткові системні події. Це проілюстровано на рис 1.

Рис. 2. Комбінатор подій

Архітектура KeyStone має багато периферійних пристроїв та велику кількість джерел подій. Для TMS320C6678 джерелами можуть бути зовнішні контакти на блоці GPIO і внутрішні периферійні пристрої, такі як таймери, McBSP послідовні порти, McASP послідовні порти, канали EDMA.

Обидва пристрої контролер каналів EDMA3 (EDMA3CC) і CorePacs контролер переривань здатні отримувати події безпосередньо. Однак кількість прийнятих подій для кожного контролера EDMA3CC (їх є три) та C66x CorePac обмежена. [1]

Оскільки ЦСП може мати сотні подій, то деякі з цих подій необхідно збирати на рівні чіпа (chip level) за допомогою контролера переривань на рівні чіпа (Chip-level Interrupt Controller - CIC or CpIntc), перш ніж вони будуть направлені до EDMA3CC та контролера CorePacs. Тут важливо зазначити, що CIC/CpIntc відрізняється від контролера переривань всередині C66xCorePac, який позначається абревіатурою INTC. Щоб приймати додаткові події на рівні SoC додають кілька CIC. CIC приймає події на рівні чіпа (системні події) і генерує переривання хоста, які виступають в якості подій для  EDMA3CC і C66x CorePac [1].

На рис. 3 показано топологію переривань 6678 разом з CIC та маршрутизацією переривань [3]. Для отримання додаткової інформації про те, як CIC працює всередині, перегляньте CIC user guide [2].

Рис. 3. Топологія переривань ЦСП 6678

CIC0 та CIC1 забезпечують 17 додаткових подій, а також 8 broadcast подій на кожне ядро Core C66x, CIC2 надає 26 і 24 додаткових подій для EDMA3CC1 і EDMA3CC2 відповідно, а CIC3 забезпечує 8 та 32 додаткові події відповідно до EDMA3CC0 та HyperLink. Кілька подій можуть бути об'єднані в одну подію через рівень чіпа CIC. Проте подія може бути відображена лише на один вихід CIC. Broadcast Події для C66x CorePacs можуть використовуватися для синхронізації між різними ядрами або між процесорами.

Модуль CIC контролює системні переривання (system interrupt, переривання від периферії) відображаючи/перенаправляючи їх на переривання хоста (CorePac). CIC може отримувати системні переривання та відображати їх на внутрішні канали. Канали використовуються для групування переривань. Ці канали потім перетворюються на інтерфейс, який має меншу кількість переривань хоста. Конфігурація CIC у пристроях KeyStone Architecture має фіксоване взаємне відображення між каналами та перериваннями хоста.

Деяку термінологію потрібно з'ясувати з усіма типами переривань, що використовуються в системі. По-перше, переривання, що створюються периферією, називаються периферійними перериваннями. По-друге, периферійні переривання потрібно обробити, щоб вони були готові до використання системою, і вони називаються системними перериваннями. Системні переривання - це ті, які можна використовувати для контролерів переривань. Системні переривання можуть бути індивідуальними для одного ядра або можуть бути розподілені між кількома ядрами. На рис. 4 показана блок-схема роботи модуля CIC (детальніше в CIC User Guide ).

Рис. 4. Блок-схема роботи модуля CIC

На рис. 5  показана блок-схема високого рівня та визначена деяка ключова термінологія, яку слід пам'ятати, коли ми перейдемо до написання програмного забезпечення та використання API.

Рис. 5.  Блок-схема високого рівня та ключова термінологія

Програмне забезпечення

Використання CSL API

В PDK є конкретний модуль (бібліотека Chip Support - CSL), який містить відповідні API інтерфейси для програмування переривання. CSL API-інтерфейси для контролера переривань CorePac Interrupt Controller (INTC) мають вигляд CSL_intcxxx і для контролера переривань Chip-level Interrupt Controller (CIC) мають вигляд CSL_CPINTCxxx.

Загальний підхід CSL для роботи з перериваннями для INTC показано в фрагменті коду нижче. У цьому прикладі події з ID  63 обробляється вектором переривання 4. Якщо ви хочете змінити подію, яка викликає переривання, спочатку виконайте пошук ідентифікатора події, який зазначено в посібнику даних для конкретного пристрою (для 6678 це Таблиця 7-38 в [C6678 Data Manual http://www.ti.com/lit/ds/symlink/tms320c6678.pdf]). Після того, як ви визначили ідентифікатор події (наприклад, хх), змініть фрагмент коду нижче  CSL_INTC_EVENTID_63 на CSL_INTC_EVENTID_xx в другому аргументі у функції CSL_intcOpen. Аналогічно, якщо ви хочете змінити вектор переривання 4 на інший номер вектора (від 4 до 15), назначте новий вектор переривання CSL_INTC_VECTID_xx змінній vectId в коді нижче

{
   CSL_IntcObj intcObj63p;
   CSL_IntcGlobalEnableState state;

   CSL_IntcContext context;

   CSL_Status intStat;
   CSL_IntcParam vectId;

   context.numEvtEntries = 0;
   context.eventhandlerRecord = NULL;

   CSL_intcInit(&context);

   CSL_intcGlobalNmiEnable();
   intStat = CSL_intcGlobalEnable(&state);

   vectId = CSL_INTC_VECTID_4;
   hIntc63 = CSL_intcOpen (&intcObj63, CSL_INTC_EVENTID_63, &vectId, NULL);

   EventRecord.handler = &event63Handler;
   EventRecord.arg = hIntc63;

   CSL_intcPlugEventHandler(hIntc63,&EventRecord);
   CSL_intcHwControl(hIntc63,CSL_INTC_CMD_EVTENABLE,NULL);
 
   CSL_IntcClose(hIntc63);
}

void event63Handler(CSL_IntcHandle hIntc){
  . . .
}


CSL_IntcContext це структура, яка використовується для збереження поточного INTC контексту (ситуації), і включає в себе чотири елементи: поле обробника події, маску виділення подій, кількість входжень подій і зміщення. Поле обробника подій складається з обробника подій, тобто функції ISR, яка буде викликатися при настанні певної події, і відповідний аргумент, який буде переданий в цю функцію ISR.

Число входжень подій відповідає числу подій, які програміст планує відображати/перенаправляти. Маска виділення подій складається з 4-х масивів 32-бітних значень, де кожен біт являє собою один з 128 подій. Карта відображення/перенаправлення являє собою масив з 128 елементів, в якому зберігається кожне з 128 подій, які були нанесені на карту для переривання процесора, і чи є дійсним зв’язаний обробник події.

На наступному етапі в прикладі вмикаються глобальні і NMI переривання за допомогою CSL_intcGlobalEnable() і CSL_intcGlobalNmiEnable() API.

Перенаправлення/відображення подій переривань досягається за допомогою CSL_intcOpen (...) API. API резервує переривання-подію для використання і повертає дійсний дескриптор події якщо подія ще не виділена. У цьому прикладі ми відображаємо ідентифікатор події 63 для вектора переривань процесора 4.

Для визначення функції ISR, яка повинна бути запущена коли ця подія відбувається, ми спочатку оновлюємо запис обробника подій контексту INTC. У цьому прикладі ми вказуємо обробник події "test_isr_handler", яка є функцією, що виконується коли відбувається подія 63. CSL_intcPlugEventHandler(...) API потім використовується для зв'язування обробника події з подією, так що, коли відбувається подія відповідна подія-обробник викликається. Потім використовується CSL_intcHwControl (...) API для включення події, в даному випадку події 63.

CSL_intcClose (...) API визивається для звільнення події. Після того, як вона викличеться дескриптор INTC більше не може використовуватися для доступу до події; подальший доступ до ресурсів подій можливий тільки після "відкриття" об'єкту події знову.

Налаштування CIC

API CSL для налаштування CIC мають форму CSL_CPINTC_xxx. Наступний фрагмент коду показує деякі типові CSL-інтерфейси та загальний спосіб конфігурації CIC.

/* Disable all host interrupts. */
CSL_CPINTC_disableAllHostInterrupt(hnd);

/* Configure no nesting support in the CPINTC Module. */
CSL_CPINTC_setNestingMode (hnd, CPINTC_NO_NESTING);

/* We now map System Interrupt 0 - 3 to channel 3 */
CSL_CPINTC_mapSystemIntrToChannel (hnd, 0 , 2);
CSL_CPINTC_mapSystemIntrToChannel (hnd, 1 , 4);
CSL_CPINTC_mapSystemIntrToChannel (hnd, 2 , 5);
CSL_CPINTC_mapSystemIntrToChannel (hnd, 3 , 3);

/* Enable system interrupts 0 - 3 */
CSL_CPINTC_enableSysInterrupt (hnd, 0);
CSL_CPINTC_enableSysInterrupt (hnd, 1);
CSL_CPINTC_enableSysInterrupt (hnd, 2);
CSL_CPINTC_enableSysInterrupt (hnd, 3);

/* Enable Host interrupt 3 */
CSL_CPINTC_enableHostInterrupt (hnd, 3);

/* Enable all host interrupts also. */
CSL_CPINTC_enableAllHostInterrupt(hnd);

Коментар у фрагменті коду дає пояснення того, що він виконує. Зверніть увагу, що виклик функції CSL_CPINTC_setNestingMode, з другим аргументом CPINTC_NO_NESTING, деактивує " NESTING ". Термін "NESTING" стосується методу, який дає змогу розробникам налаштовувати CIC таким чином, що при обслуговуванні поточного переривання певні переривання вимикаються. Типовим використанням є NESTING на поточному перериванні та вимкнення всіх переривань того ж або нижчого пріоритету. Режим NESTING не підтримується на пристроях KeyStone.

Для більш детального розуміння CSL для конфігурації CIC рекомендується вивчити проект в папці 'pdk_C6678_x_x_x_xx \ packages \ ti \ csl \ example \ cpintc ' та документацію API за адресою 'pdk_C6678_x_x_x_xx \ packages \ ti \ csl \ docs \ csldocs.chm'.

Приклад

За допомогою цього прикладу ми встановимо переривання для Hyperlink.

/*** --- INTC Initializations --- ***/

/* Відзначимо, що будемо використовувати вектор переривання чотири
hyplnk_EXAMPLE_COREPAC_VEC = 4,
та Id події контролера переривань COREPAC 21 (Table 7-32 data manual 6678)
hyplnk_EXAMPLE_COREPAC_INT_INPUT = 21 */

CSL_IntcParam vectId = hyplnk_EXAMPLE_COREPAC_VEC;
Int16 eventId = hyplnk_EXAMPLE_COREPAC_INT_INPUT;
CSL_IntcGlobalEnableState   state;

/* INTC module initialization */
hyplnkExampleIntcContext.eventhandlerRecord = hyplnkExampleEvtHdlrRecord;
hyplnkExampleIntcContext.numEvtEntries      = 2;
CSL_intcInit(&hyplnkExampleIntcContext);  

/* Enable NMIs */
CSL_intcGlobalNmiEnable();

/* Enable global interrupts */
CSL_intcGlobalEnable(&state);

hyplnkExampleIntcHnd = CSL_intcOpen (&hyplnkExampleIntcObj, eventId, &vectId, NULL);
// функція обробки переривання та аргумент, що передається
hyplnkExampleEvtHdlrRecord[0].handler = hyplnkExampleIsr; hyplnkExampleEvtHdlrRecord[0].arg = (void *)eventId;
CSL_intcPlugEventHandler(hyplnkExampleIntcHnd, hyplnkExampleEvtHdlrRecord);

/* Clear the event in case it is pending */
CSL_intcHwControl(hyplnkExampleIntcHnd, CSL_INTC_CMD_EVTCLEAR, NULL);

/* Enable event */
CSL_intcHwControl(hyplnkExampleIntcHnd, CSL_INTC_CMD_EVTENABLE, NULL);

/*** --- CIC Initializations --- ***/

CSL_CPINTC_Handle hnd;
// CSL_CPINTC_open(0) відкриває CIC екземпляр 0, який є CIC0.
// Для CIC1 потрібно CSL_CPINTC_open(1)
hnd = CSL_CPINTC_open (0);
 
/* Disable all host interrupts. */
CSL_CPINTC_disableAllHostInterrupt(hnd);
    
/* Configure no nesting support in the CPINTC Module */
CSL_CPINTC_setNestingMode (hnd, CPINTC_NO_NESTING);

/* Очищаємо системне переривання Hyperlink system interrupt номер 111 */
/* Номер взятий з Table 7-38 data manual 6678 */
CSL_CPINTC_clearSysInterrupt (hnd, CSL_INTC0_VUSR_INT_O);

/* Включаємо системне переривання Hyperlink номер 111 на CIC0 */
CSL_CPINTC_enableSysInterrupt (hnd, CSL_INTC0_VUSR_INT_O);

/* Напрравляємо/відображаємо System Interrupt на Channel. */
/* Відмітимо, що hyplnk_EXAMPLE_INTC_OUTPUT = 32 + (11 * CoreNumber) = 43 канал для Core0*/
CSL_CPINTC_mapSystemIntrToChannel (hnd, CSL_INTC0_VUSR_INT_O, hyplnk_EXAMPLE_INTC_OUTPUT);  

/* Enable the Host Interrupt */
CSL_CPINTC_enableHostInterrupt (hnd, hyplnk_EXAMPLE_INTC_OUTPUT);

CSL_CPINTC_enableAllHostInterrupt(hnd);

Відзначимо, що в 6678 існує прямий взаємозв'язок між інтерфейсом перериванням хоста та каналом, тому не потрібно використовувати CSL_CPINTC_mapChannelToHostInterrupt API. CSL_CPINTC_mapChannelToHostInterrupt функція, необхідна лише для вторинного перенаправлення/відображення переривань (secondary interrupt).

Для виконання роботи нам знадобиться ще один пристрій - таймер.

Таймери

Таймери можуть бути використані для подій, які відбуваються через деякий проміжок часу, підрахунку подій, генерації імпульсів, переривання процесора і посилання подій синхронізації в EDMA.

TMS320C6678 має шістнадцять 64-розрядних таймерів. Таймери Timer0 - Timer7 належать кожному з восьми CorePacs як сторожові таймери, а також можуть бути використані в якості таймерів загального призначення. Кожен з восьми таймерів також може бути налаштований лише як таймер загального призначення, запрограмованим як 64-розрядний таймер або як два окремих 32-розрядних таймера.

При роботі в 64-бітному режимі таймер рахує або VBUS такти або вхідні (TINPLx) імпульси (по наростаючому фронті) і генерує вихідний імпульс/сигнал (TOUTLx) плюс внутрішню подію (TINTLx) на запрограмований період.

При роботі в режимі 32-біт таймер розділяється на два незалежних 32-розрядних таймера. Кожен таймер складається з двох 32-бітових лічильників: лічильник вверх і лічильник вниз. Піни таймера, TINPLx і TOUTLx з’єднані з лічильником вниз. Піни таймера TINPHx і TOUTHx підключені до лічильника вверх.

Коли зовнішній вхідний контакт TINP, обраний в якості джерела синхронізації таймера, таймер може рахувати вхідні імпульси і переривати процесор, коли досягається задана величина.

При роботі в режимі сторожовий таймер, рахунок відбувається до 0 і генерується подія. Скидання ініціюється шляхом програмування сторожового таймера через регістр ''Reset Type Status Register (RSTYPE) '' с. 147, а тип скидання можна встановити шляхом програмування регістра ''Reset Configuration Register (RSTCFG) '' на с. 148. Більш детальна інформація наведена в Timer64P для KeyStone пристроїв  на с. 72.

Внутрішня тактова частота для C6678 таймерів тактується частотою SYSCLK7 - це тактова частота процесора, що ділиться на 6 (CPU clock / 6). Таким чином, тактова частота таймера становить SYSCLK7=1GHz/6 = 166,67 МГц. Якщо тактова частота CorePac (SYSCLK1)  дорівнює 1GHz після PLL.

Кожен таймер має три регістри, показані в таблиці 4.1.

Бібліотека CSL [ ] має Cі-функції і макроси для конфігурації і взаємодії з таймерами.

Таблиця 4.1: Регістри таймера (Timer Registers)

Для того, щоб отримувати періодичні переривання, налаштуйте таймер для роботи в безперервному режимі (ENAMODE = 10b або 11b). Кожен раз, коли таймер закінчує підрахунок, він генерує переривання таймера для CPU і подію таймера для контролера EDMA. Швидкість, з якою це відбувається (швидкість переривання таймера) залежить від того, чи має таймер подільник.

Якщо таймер не має подільника (є тільки один лічильник). Коли лічильник таймера досягає періоду таймера, таймер генерує переривання і подію EDMA. Оскільки таймер знаходиться в безперервному режимі, потрібен один такт після того, як лічильник таймера досягає періоду таймера. Потім лічильник таймера скидається на 0, і відлік починається знову. Швидкість переривання таймера:

Якщо таймер має дільник ( є два лічильника). Один такт виконується після того, як лічильник подільника досягає запрограмованого періоду, і лічильник таймера збільшується на 1, а подільник скидається, щоб почати відлік знову.

Після того як лічильник таймера досягає запрограмованого періоду, таймер генерує переривання і подію EDMA. Через один такт (за умови, безперервного режиму) лічильник таймера скидається на 0 і починає відлік знову. Частота переривань таймера в даному випадку:


 

Виконання лабораторної роботи

Після знайомства з перериваннями та таймерами виконаємо наступне завдання - змінимо програму, яка працює зі світлодіодами таким чином, щоб затухання/загорання світлодіодів відбувалося по перериванню таймера. Період виникнення переривання таймером встановлюється  за проведеними розрахунками. Для створення програми ми скористаємося готовою бібліотекою CSL[].

1.    Зробіть копію проекту з минулої роботи.

2.    Встановіть необхідні шляхи до бібліотеки CSL  по роботі з перериваннями та таймерами.

1.    Додайте перед main наступні бібліотеки, прототипи та глобальні змінні:

#include "ti\platform\platform.h"
#include "ti\platform\resource_mgr.h"

#include <ti/csl/csl_tmr.h>
#include <ti/csl/csl_tmrAux.h>
#include <ti/csl/src/intc/csl_intc.h>
#include <ti/csl/src/intc/csl_intcAux.h>


/************************** Global Variables *************************/

/* INTC Objects */
CSL_IntcObj                  tmrIntcObj;
CSL_IntcContext              context;
CSL_IntcEventHandlerRecord   EventHandler[30];

platform_info p_info;

/* Counter for Timer ISR */
volatile Int32 timerISRCounter = 0;

void TimerInterruptHandler (void *arg);
Int32 intc_init (void);
Int32 test_high_continuous_timer (Uint8 IntcInstance);


4.    Змініть main на наступний

void main(void) {
    platform_init_flags init_flags;
    platform_init_config init_config;

    char message[] = "\r\nHello World.....\r\n";
    uint32_t length = strlen((char *)message);
    uint32_t i;

    /* Initialize platform with default values */

    memset(&init_flags, 0x01, sizeof(platform_init_flags));
    memset(&init_config, 0, sizeof(platform_init_config));
    if (platform_init(&init_flags, &init_config) != Platform_EOK) {
        return;
    }

    platform_uart_init();
    platform_uart_set_baudrate(115200);

    platform_get_info(&p_info);

   //  Write to the UART
    for (i = 0; i < length; i++) {
        if (platform_uart_write(message[i]) != Platform_EOK) {
            return;
        }
    }

    printf ("****************** Timer Testing  ****************\n");

      /* Initialize the INTC Module. */
      if (intc_init() < 0){
          printf ("Error: Initialization of the INTC module failed\n");
          return;
      }

      /* Initialize timer CSL module */
      CSL_tmrInit(NULL);

      /* Start the testing for the  Timer. */
     if (test_high_continuous_timer(CSL_TMR_0) < 0)
     {
         printf("Error: Testing hi Timer (Unchained)  FAILED\n");
         return;
     }
     printf("Debug: Testing hi Timer (Unchained) Passed\n");

    /* Play forever */
    while(1) {}
}

5.    Додайте після main функцію ініціалізації переривання

Int32 intc_init (void)

{
    // Global Interrupt enable state
    CSL_IntcGlobalEnableState   state;

    /* INTC module initialization */
    context.eventhandlerRecord = EventHandler;
    context.numEvtEntries      = 10;
    if (CSL_intcInit(&context) != CSL_SOK)
        return -1;

    /* Enable NMIs */
    if (CSL_intcGlobalNmiEnable() != CSL_SOK)
        return -1;

    /* Enable global interrupts */
    if (CSL_intcGlobalEnable(&state) != CSL_SOK)
        return -1;

    /* INTC has been initialized successfully. */
    return 0;
}

6.    Додайте функцію обробки переривання

void TimerInterruptHandler (void *arg)
{

    static uint32_t led_no = 0;
    /* Increment the number of interrupts detected. */
    timerISRCounter++;
    if (timerISRCounter%2 == 0){
        platform_led(led_no, PLATFORM_LED_ON, PLATFORM_USER_LED_CLASS);
    }
    else
    {
        platform_led(led_no, PLATFORM_LED_OFF, PLATFORM_USER_LED_CLASS);
        led_no = (++led_no) % p_info.led[PLATFORM_USER_LED_CLASS].count;
    }

    /* Clear the event ID. */
    CSL_intcEventClear((CSL_IntcEventId)arg);
}

7.    Додайте  функцію налаштування таймера та переривання за таймером

Int32 test_high_continuous_timer (Uint8 IntcInstance)
{
    CSL_TmrHandle               hTmr; // дескриптор таймера
    CSL_TmrObj                  TmrObj; // об'єкт таймера
    CSL_Status                  status; // статус
    CSL_TmrHwSetup              hwSetup = CSL_TMR_HWSETUP_DEFAULTS; // налаштування таймера (період...)
    CSL_IntcEventHandlerRecord  EventRecord;// запис дескриптора події
    CSL_IntcParam               vectId; // айді вектора переривання
    CSL_IntcHandle              tmrIntcHandle; // дескриптор переривання для таймера
    Uint32                      LoadValue = 83333500; // значення періоду
    CSL_TmrEnamode              TimeCountMode = CSL_TMR_ENAMODE_CONT; // неперервний режим таймера
    Uint32                      count; // лічильник

    /* Clear local data structures */
    memset(&TmrObj, 0, sizeof(CSL_TmrObj)); // обнулення обєкту таймера
    printf("Debug: Testing High Timer (Unchained) in Continuous Mode....\n");

    /**************************************************************
     ********************** INTC related code *********************
     **************************************************************/

    /* Open INTC */
    vectId = CSL_INTC_VECTID_13; // встановлюємо 13 вектор переривання

    // відкриваємо переривання для події CSL_GEM_TINTHN
    tmrIntcHandle = CSL_intcOpen(&tmrIntcObj, CSL_GEM_TINTHN, &vectId, NULL);
    if (tmrIntcHandle == NULL)
        return -1;

    /* Bind ISR to Interrupt */
    // записуємо функцію, яка буде оброблювати переривання по таймеру
    EventRecord.handler = (CSL_IntcEventHandler)&TimerInterruptHandler;
    // передаєм додатковий аргумент
    EventRecord.arg     = (void *)CSL_GEM_TINTLN;
    // зв*язуємо функцію оброблення з перериванням
    CSL_intcPlugEventHandler(tmrIntcHandle, &EventRecord);

    // Event Enable  дозволяємо подію
    CSL_intcHwControl(tmrIntcHandle, CSL_INTC_CMD_EVTENABLE, NULL);

    //********************** Timer related code ********************

    // Open the timer.  Відкриваємо таймер IntcInstance= CSL_TMR_0 для 0 ядра
    hTmr =  CSL_tmrOpen(&TmrObj, IntcInstance, NULL, &status);
    if (hTmr == NULL)
        return -1;

    // Open the timer with the defaults. встановлюємо налаштування по замовчуванню- все по нулях
    CSL_tmrHwSetup(hTmr, &hwSetup);

    // Stop the Timer - зупиняєм таймер
    CSL_tmrHwControl(hTmr, CSL_TMR_CMD_RESET_TIMHI, NULL);

    // Set the timer mode to unchained dual mode -
    // встановлюєм режим таймера unchained dual mode
    hwSetup.tmrTimerMode = CSL_TMR_TIMMODE_DUAL_UNCHAINED;
    CSL_tmrHwSetup(hTmr, &hwSetup);

    /* Reset the timer ISR Counter. */
    timerISRCounter = 0;

    // Load the period register - записуємо період таймера
    status = CSL_tmrHwControl(hTmr, CSL_TMR_CMD_LOAD_PRDHI, (void *)&LoadValue);

    // Start the timer in CONTINUOUS Mode. Запускаєм таймер в непереввному режимі
    CSL_tmrHwControl(hTmr, CSL_TMR_CMD_START_TIMHI, (void *)&TimeCountMode);

    /* Wait for the timer interrupts to fire...*/
    while (timerISRCounter <= 500);

    /* Since the HIGH Counter is operating in Continuous Mode; the value here should
     * be non-zero. Though there is a small probability that the value here could be 0. */
    CSL_tmrGetTimHiCount(hTmr, &count);
    if (count == 0)
    {
        /* Taking into account the small probability; lets confirm out again.
         * This time for sure the value should be non-zero. */
        CSL_tmrGetTimHiCount(hTmr, &count);
        if (count == 0)
            return -1;
    }

    /**************************************************************/

    /* Disable the events. */
    CSL_intcHwControl(tmrIntcHandle, CSL_INTC_CMD_EVTDISABLE, NULL);

    /* Stop the Timer */
    CSL_tmrHwControl(hTmr, CSL_TMR_CMD_RESET_TIMHI, NULL);

    /* Close the Tmr and Interrupt handles. */
    CSL_tmrClose(hTmr);
    CSL_intcClose(tmrIntcHandle);

    /* Test has completed successfully. */
    return 0;
}

8.    Побудуйте програму, загрузіть її в процесор. Виконання на 0 ядрі.

Завдання

1.    Проаналізуйте код програми.  
2.    Змініть період таймера на 100 мс,  500мс,  1с.
3.    Змініть ID вектору переривання на інший.
4.    Реалізуйте перемикання світлодіодів за випадковим законом.
5.    Підключіть Бібліотеку для роботи з портами GPIO,   згенеруйте меандр та спостерігайте його на осцилографі. Перевірте чи співпадають осцилограми з розрахунками.

Домашнє завдання

1.    Заповнення масиву розміром 200 елементів по таймеру.  Налаштуйте таймер на роботу по 5 вектору переривання. Заповнення повинно відбуватися з частотою 100 Гц. Масив заповнювати відліками сигналу, що представляє собою суміш синусоїд з різними частотами, наприклад, 500 Гц, 2500 Гц, 5000 Гц. Після заповнення вивести зображення сигналу, інструментами Code Composer Studio.

Додаткові матеріали

http://processors.wiki.ti.com/index.php/Configuring_Interrupts_on_Keystone_Devices

[1] CorePac User Guide http://www.ti.com/litv/pdf/sprugw0b

[2] CIC User Guide http://www.ti.com/litv/pdf/sprugw4a

[3] C6678 Data Manual http://www.ti.com/lit/ds/symlink/tms320c6678.pdf

Новини

  • Плати розширення з 8-реле підтримують до 64 реле на Raspberry Pi
    Плати розширення з 8-реле підтримують до 64 реле на Raspberry Pi

    "Raspberry Pi 8-Relay Card" від Sequent Microsystems забезпечує керування 8 реле і може бути розширена для включення 64 реле на Raspberry Pi для додатків домашньої автоматизації. Плата може використовувати Raspberry Pi 2, 3, або Zero. У випадку Zero чи Zero W потрібно придбати та приєднати 40-контактний роз’єм, або придбати Raspberry Pi Zero WH з вже припаяним роз’ємом. Вам також знадобиться картка microSD на 8 ГБ, джерело живлення 5 В та трансформатор на 24 В. Вартість плати стартує з 17$.

    in Новини

Записатися на курс