ЛР8 > Робота із перериваннями DSP процесору C55x
Статьи по теме
- ЛР9 > Передача даних через канал DMA DSP-процесора C55x
- ЛР8 > Робота із перериваннями DSP процесору C55x
- ЛР7 > Швидке перетворення Фур’є на базі ЦСП
- ЛР6 > Реалізація БІХ-фільтра з використанням TMS320C55x
- ЛР5(б) > Реалізація КІХ – фільтру: на базі пристрою MAC
- ЛР5(а) > Реалізація КІХ – фільтру: блоковий фільтр
Тема: Поняття переривань, зовнішні та внутрішні переривання та їх особливість реалізації у процесорі 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 |
Зовнішні переривання |
INT3/4/5 |
58/98/B8 |
Зовнішні переривання |
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
Виконайте наступні дії для завдання А:
-
Створіть новий проект у середовищі CCS; назвіть його expА та збережіть його у відповідній директорії. Напишіть програму expА.asm і vectors.asm на основі наведеного вище коду (або додайте до проекту за допомогою команди Project→Add Files to Project… файли expА.asm і vectors.asm з робочої директорії проекту). Додайте командний файл лінкера timer1.cmd до проекту. Підключить бібліотеку засобів динамічної підтримки rts55.lib (розташована у директорії C:\ti\c5500\cgtools\lib). Запустіть програму на компіляцію.
-
Завантажте програму до процесора. Відкрийте вікно перегляду змісту регістрів процесора. Встановіть точку зупинки програми в строці з кодом MOV #0x2222, AC0 (файл expА.asm ), та в строці з кодом
timer: ADD #1, AC0 (файл vectors.asm ). Запустіть програму на виконання за допомогою команди Debug→Run. Cпостерігайте за зміною значень в регістрах АС0, АС1. Поясніть хід виконання програми і перевірте працездатність проекту.
-
Закоментуйте наступну строку коду у файлі 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;
}
Виконайте наступні дії завдання Б: