ЛР8 > Робота із перериваннями DSP процесору C55x

Тема: Поняття переривань, зовнішні та внутрішні переривання та їх особливість реалізації у процесорі C55x

Завантажити Матеріали до лабораторної работи по ЦСП С55х №8.

Переривання (англ. interrupt) — сигнал, що повідомляє процесору про здійснення якої-небудь події. При цьому, виконання поточної послідовності команд призупиняється і керування передається обробнику переривання, який реагує на подію та обслуговує її, після чого повертає управління основній програмі.

Залежно від джерела надходження сигналу, переривання поділяються на:

  • зовнішні — події, які були ініційовані зовнішніми джерелами (наприклад, периферійними пристроями) в довільний момент часу: передача інформаційного байту по каналу UART до процесора, натискання кнопки і т.п.;
  • внутрішні — події, які були ініційовані в самому процесорі внутрішніми пристроями, або як результат порушення якихось умов при виконанні програми: поділ на нуль або переповнення і т.п.

 

Вектор переривання — закріплений за пристроєм номер, який співвідноситься з відповідною процедурою обробки переривань. Вектори переривань об’єднуються в таблицю векторів переривань, що містить адреси програм – обробників переривань. Розташування таблиці залежить від типу процесора та його режиму роботи.

 

Для обробки переривань процесором сімейства C5510 необхідно виконати наступні дії:

1. Обрати необхідне джерело переривання.

2. Створити таблицю векторів переривань.

3. Дозволити процесору обробку окремих переривань.

4. Дозволити процесору обробку всіх маскуємих переривань.

5. Отримати сигнал запиту на переривання.

6. Встановити прапор(и) переривання в відповідному регістрі (виконується автоматично).

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

8. Виконати обробку переривання.

9. Повернутися до основної програми.

Процесор сімейства C5510 має наступні джерела переривань:

НАЗВА ПЕРЕРИВАННЯ

Зміщення (Offset(hex/byte))

ОПИС

RESET

0

Сброс

NMI

8 

Немаскуєме зовнішнє переривання 

INT0/1/2  

10/80/18  

Зовнішні переривання
0,1,2

INT3/4/5

58/98/B8

Зовнішні переривання
3,4,5

TINT0

20 

Переривання Таймеру#0

TINT1

B0

Переривання Таймеру#1

R/XINT0 

28/88 

McBSP#0 Rcv/Xmt

R/XINT1 

30/38  

McBSP#1 Rcv/Xmt 

R/XINT2 

60/68 

McBSP#2 Rcv/Xmt 

DMAC0 

90 

DMA Ch0 Int 

DMAC1 

48 

DMA Ch1 Int 

DMAC2 

A0 

DMA Ch2 Int 

DMAC3 

A8 

DMA Ch3 Int 

DMAC4 

70 

DMA Ch4 Int 

DMAC5

78

DMA Ch5 Int

DSPINT

50 

Host Int (HPI) 

 

40,D8-FF 

Software Ints 


Розглянемо деякі команди мови асемблер, які використовуються для роботи з перериваннями:

встановлення дозволу обробки окремих переривань:

OR #k16, mmap(@IER0)

заборона дозволу обробки окремих переривань:

AND #k16, mmap(@IER0)

 

встановлення дозволу обробки всіх маскуємих переривань: BCLR INTM

заборона дозволу обробки всіх маскуємих переривань: BSET INTM

 

Для того, щоб скинути біт в регістрі прапорів переривань (IFR), необхідно записати до нього одиницю: MOV #mask, mmap(@IFR0)

 

Для повернення з програми обробки переривання використовується команда: RETI

 

Завдання А.

Обробка переривання таймеру 0 з використанням мови асемблер.

У першому завданні ми виконаємо обробку переривання від таймеру загального призначення. Для цього нам необхідно створити програму з описом векторів переривання. Розглянемо приклад цієї програми (vectors.asm):

        .title    “vectors”

    .sect    “.vectors”

 

.ref _c_int00

 

.def RSV, nmi, int0, int1, int2, int3, int4, int5, int6

.def int7, int8, int9, int10, int11, int12, int13

.def int14, int15, int16, int17, int18, int19, int20

.def int21, int22, int23, int24, int25, int26, int27

.def int28, int29

 

 

 

RSV .ivec _c_int00,NO_RETA

nmi .ivec no_isr

nop_16

int0 .ivec no_isr

nop_16

int1 .ivec no_isr

nop_16

int2 .ivec timer

 

int3 .ivec no_isr

nop_16

int4 .ivec no_isr

        nop_16

int5 .ivec no_isr

nop_16

int6 .ivec no_isr

nop_16

int7 .ivec no_isr

nop_16

int8 .ivec no_isr

nop_16

int9 .ivec no_isr

nop_16

int10 .ivec no_isr

nop_16

int11 .ivec no_isr

nop_16

int12 .ivec no_isr

nop_16

int13 .ivec no_isr

nop_16

int14 .ivec no_isr

nop_16

int15 .ivec no_isr

nop_16

int16 .ivec no_isr

nop_16

int17 .ivec no_isr

nop_16

int18 .ivec no_isr

nop_16

int19 .ivec no_isr

nop_16

int20 .ivec no_isr

nop_16

int21 .ivec no_isr

nop_16

int22 .ivec no_isr

nop_16

int23 .ivec no_isr

nop_16

int24 .ivec no_isr

nop_16

int25 .ivec no_isr

nop_16

int26 .ivec no_isr

nop_16

int27 .ivec no_isr

nop_16

int28 .ivec no_isr

nop_16

int29 .ivec no_isr

nop_16

 

*————————————————————-* This is a dummy interrupt service routine used to initialize the IST.

*————————————————————-

.text

.def no_isr, timer

no_isr:

b #no_isr

 

timer:    ADD    #1, AC0

        MOV    #0x0010, mmap(@IFR0)

        RETI

*————————————————————-

 

Ця програма містить опис таблиці для 32 векторів переривання, та дві підпрограми обробки переривання – одна для таймера, інша – для всіх не використовуваних переривань.

 

Приклад основної програми проекту наведено нижче:

    .title    “main_timer”

    .def _main, _loop

;Точка входу, яка позначає початок виконуваної програми

_main:

    MOV    #0x2222, AC0

    MOV    #0x1111, AC1

;Ініціалізація регістру дозволу окремих переривань, та регістрів – указників розташування таблиці векторів переривання

    MOV #0x0010, mmap(@IER0)

    MOV #0x0001, mmap(@IVPD)

    MOV #0x0001, mmap(@IVPH)

;Ініціалізація таймера

        MOV #0410h, port(#1002h)     ; TLB = 1 TSS = 1

    MOV    #0002h, port(#1003h)    ; TDDR = 2 in PRSC0

    MOV    #00FFh, port(#1001h)    ; PRD0 = FFFFh = 65535

    MOV #0960h, port(#1002h)     ; Load TCR0:

                    ; TLB = 0 (Stop loading TIM and PSC)

                    ; TSS = 0 (Start timer)

                    ; Other bits are unchanged

;Дозвіл обробки всіх маскуємих перериваннь

    BCLR    INTM

;Нескінченний цикл, очікуємо переривання та збільшуємо значення акумулятору:

_loop:

    ADD    #1, AC1

    B    _loop

 

 

Виконайте наступні дії для завдання А:

 

  1. Створіть новий проект у середовищі CCS; назвіть його expА та збережіть його у відповідній директорії. Напишіть програму expА.asm і vectors.asm на основі наведеного вище коду (або додайте до проекту за допомогою команди Project→Add Files to Project… файли expА.asm і vectors.asm з робочої директорії проекту). Додайте командний файл лінкера timer1.cmd до проекту. Підключить бібліотеку засобів динамічної підтримки rts55.lib (розташована у директорії C:\ti\c5500\cgtools\lib). Запустіть програму на компіляцію.
  2. Завантажте програму до процесора. Відкрийте вікно перегляду змісту регістрів процесора. Встановіть точку зупинки програми в строці з кодом     MOV    #0x2222, AC0 (файл expА.asm ), та в строці з кодом
    timer:    ADD    #1, AC0 (файл vectors.asm ). Запустіть програму на виконання за допомогою команди Debug→Run. Cпостерігайте за зміною значень в регістрах АС0, АС1. Поясніть хід виконання програми і перевірте працездатність проекту.
  3. Закоментуйте наступну строку коду у файлі vectors.asm :
    MOV    #0x0010, mmap(@IFR0). Скомпілюйте проект та завантажте його на виконання. Як змінилася поведінка акумулятора АС1? Поясніть результат.

Завдання Б.

Обробка переривання таймеру 0 з використанням мови С та бібліотеки CSL.

 

Бібліотека підтримки кристала (CSL) забезпечує інтерфейс прикладного програмування (API), який використовується для налаштування і керування периферійних пристроїв DSP-процесору (детальний опис цієї бібліотеки наведено у документі SPRU433).

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

Основна програма, що написана мовою С, має наступний вигляд:

 

 

#include <stdio.h>

//–підключення бібліотеки CSL

#include <csl.h>

#include <csl_irq.h>

#include <csl_timer.h>

 

//——–налаштування таймеру———

#define TIMER_CTRL TIMER_TCR_RMK(\

TIMER_TCR_IDLEEN_DEFAULT,/* IDLEEN == 0 */ \

TIMER_TCR_FUNC_OF(0), /* FUNC == 0 */ \

TIMER_TCR_TLB_RESET, /* TLB == 1 */ \

TIMER_TCR_SOFT_BRKPTNOW, /* SOFT == 0 */ \

TIMER_TCR_FREE_WITHSOFT, /* FREE == 0 */ \

TIMER_TCR_PWID_OF(0), /* PWID == 0 */ \

TIMER_TCR_ARB_RESET, /* ARB == 1 */ \

TIMER_TCR_TSS_START, /* TSS == 0 */ \

TIMER_TCR_CP_PULSE, /* CP == 0 */ \

TIMER_TCR_POLAR_LOW, /* POLAR == 0 */ \

TIMER_TCR_DATOUT_0 /* DATOUT == 0 */ \

)

 

 

/* Створення структури, яка буде завантажена до керуючих регістрів таймеру за допомогою конфігураційної функції бібліотеки
CSL */

TIMER_Config timCfg0 = {

TIMER_CTRL, /* TCR0 */

0x0400u, /* PRD0 */

0x0000 /* PRSC */

};

 

/* Створення об’єкту TIMER_Handle для відкриття таймеру */

TIMER_Handle mhTimer0;

 

volatile Uint16 timer0_cnt = 0;

Uint16 eventId0;

int old_intm;

Uint16 tim_val;

 

//——–підключення функцій———

 

/* Підключення таблиці векторів переривання */

/* ця змінна проголошена у файлі
vectors_timer1.s55 */

extern void VECSTART(void);

 

/* Оголошення функції обробки переривання від таймеру */

interrupt void timer0Isr(void);

void taskFxn(void);

 

//———основна програма———

void main(void)

{

    /* ініціалізація бібліотеки CSL */

    CSL_init();


    /* запис до регістрів IVPH/IVPD адреси таблиці векторів переривання*/

    IRQ_setVecs((Uint32)(&VECSTART));


    /* налаштування таймеру */

    taskFxn();

}

 

void taskFxn(void)

{

/* заборона обробки всіх маскуємих перериваннь */

old_intm = IRQ_globalDisable();

 

/* підключення Timer 0, установка всіх регістрів за замовчуванням*/

mhTimer0 = TIMER_open(TIMER_DEV0, TIMER_OPEN_RESET);

 

/* співставлення функції дозволу переривань бібліотеки
CSL з перериванням від таймеру*/

eventId0 = TIMER_getEventId(mhTimer0);

 

/* зкидання флагу переривання від таймера */

IRQ_clear(eventId0);

 

/* Розміщення адреси програми обробки переривання від таймеру у відповідному векторі переривання */

IRQ_plug(eventId0,&timer0Isr);

 

/* конфігурація керуючих регістрів таймера */

TIMER_config(mhTimer0, &timCfg0);

 

/* дозвіл обробки переривань від таймера */

IRQ_enable(eventId0);

 

/* дозвіл обробки всіх маскуємих переривань */

IRQ_globalEnable();

 

/* запуск таймера*/

TIMER_start(mhTimer0);

 

/* очікування 10 переривань від таймера */

while(timer0_cnt != 10) {

;

}


/* передача повідомлення TEST PASSED до консольного вікна */

printf(“\nTEST PASSED\n”);

 

/* повернення попереднього значення INTM */

IRQ_globalRestore(old_intm);

 

/* закінчення роботи з таймером */

TIMER_close(mhTimer0);

}

/* підпрограма обробки переривання від таймеру */

interrupt void timer0Isr(void)

{

++timer0_cnt;

}

 Виконайте наступні дії завдання Б:

 

Створіть новий проект у середовищі CCS; назвіть його expВ та збережіть його у відповідній директорії. Напишіть програму main_timer1.c і vectors_timer1.s55 на основі наведеного вище коду (або додайте до проекту за допомогою команди Project→Add Files to Project… файли main_timer1.c і vectors_timer1.s55 з робочої директорії проекту). Додайте командний файл лінкера timer1.cmd до проекту. Підключить бібліотеку засобів динамічної підтримки rts55.lib та бібліотеку підтримки кристалу csl5510PG2_2.lib. У вікні Build Options перейдіть до закладки Compiler. Виберіть категорію Basic , та вкажіть значення 5510:2 в графі Custom Target (-v). Виберіть категорію Preprocessor , та вкажіть значення CHIP_5510PG2_0 в графі Pre-Define Symbol (-d). Це необхідно для коректного підключення бібліотеки CSL. Запустіть програму на компіляцію.
Завантажте програму до процесора. Відкрийте вікно перегляду змісту регістрів процесора. Встановіть точку зупинки програми в строці з кодом      ++timer0_cnt; (файл main_timer1.c). Запустіть програму на виконання за допомогою команди Debug→Run. Cпостерігайте за зміною значень змінної timer0_cnt (для перегляду поточного значення, підведіть курсор до змінної в тексті програми). Поясніть хід виконання програми і перевірте працездатність проекту.