Перейти к содержанию
    

Вложенные прерывания Cortex M3 (LPC1768)

Здравствуйте, уважаемые!

Пишу реализацию ПИД-регулятора. МК LPC1768

Период перерасчета должен быть соблюден крайне точно, поэтому использую прерывания по таймеру и устанавливаю этому прерыванию наивысший приоритет.

void init_tmr1()
{
 T1TCR_bit.CR = 1;		 // Сбрасываем
 T1TCR_bit.CR = 0;
 /*
 Fp = 25 МГц			Частота периферии.
 T = 20 мс			Желаемый период таймера.
 N = Fp/T			Формула рачета кол-ва тактов за период.
 N = 250000			Кол-во тактов за желаемый период таймера.
 */
 T1MR0 = 250000;			// Загружаем регистр сравнения
 T1MCR_bit.MR0I = 1;		// Разрешаем прерывание по совпадению MR0
 T1MCR_bit.MR0R = 1;		// Разрешаем сброс таймера по совпадению MR0
 T1TCR_bit.CE = 1;		// Разрешаем счет

 IP0_bit.PRI_2 = 0;		// Приоритет прерывания: наивысший (0)
 SETENA0_bit.SETENA2 = 1;		// Разрешаем прерывания в NVIC
}

 

Далее в обработчике прерываний от этого таймера есть получение данных с абсолютного датчика положения.

Опрос датчика производится из прерывания таймера 1 раз за прерывания,

поэтому на осциллографе я наблюдаю пакеты опроса датчика строго с частотой таймера.

Ок.

Теперь инициализирую UART для приема управляющего воздействия (DMX512)

  PCONP_bit.PCUART3 = 1;

 FIO3DIR_bit.P3_26 = 1;
 FIO3CLR = 1 << 26;

 PINSEL0_bit.P0_0 = 2;
 PINSEL0_bit.P0_1 = 2;

 // Скорость
 /*
 F = Fp/(16*(DLM*256+DLL)*(1+DIV/MUL))
 F = 250 kBod
 Fp = 100 MHz
 DLM = 0
 DLL = 25
 DIV = 0
 MUL = 1
 */
 U3LCR_bit.DLAB = 1;
 U3DLL = 25;
 U3DLM = 0;
 U3LCR_bit.DLAB = 0;

 // FIFO
 U3FCR_bit.FCRFE = 1;			// Включаем FIFO
 U3FCR_bit.RFR = 1;			// Сбрасываем RxFIFO
 U3FCR_bit.TFR = 1;			// Сбрасываем TxFIFO
 U3FCR_bit.RTLS = 2;			// Порог срабатывания 8 символов

 // Формат
 U3LCR_bit.WLS = 3;			// 8 бит
 U3LCR_bit.SBS = 1;			// 2 стоп-бита

 // Преывания
 U3IER_bit.RDAIE = 1;			// Разрешаем прерывание по входящим данным
 U3IER_bit.RXLSIE = 1;			// Разрешаем прерывание по статусу линии

 IP2_bit.PRI_8 = 2;			// Приоритет прерывания: средний (2)
 SETENA0_bit.SETENA8 = 1;			// Разрешаем в NVIC
}

И в обработчике прерываний уже непосредственно получение данных из FIFO.

Итак: приоритет таймера - 0, приоритет UART - 2. Но когда по UART приходят данные период таймера нарушается и становится вообще не понятно каким.

То есть вложенные прерывания не выполняются? Как это исправить?

 

А если в процессе приема данных по UART отключить источник сигнала, то программа из прерывания UART вообще не выходит и прерывания таймера не выполняются вообще!

Вот обработчик UART

void UART3_IRQHandler()
{
 char uiir, ulsr, urbr;

 do
 {
uiir = U3IIR;
ulsr = U3LSR;

if((uiir & INTID) == RLS)
{
  if(ulsr & (OE | PE))
	bDMX = 0;
  if(ulsr & BI)
  {
	nDMX = 0;
	bDMX = 1;
  }
  U3RBR;
}
if((uiir & INTID) == RDA)
{
	urbr = U3RBR;
	if(nDMX && bDMX && (nDMX < 513))
	  DMX[(nDMX++)-1] = urbr;
	else
	  if(!(nDMX++) && urbr)
		bDMX = 0;
  }
 }
 while(!(uiir & INTPEND));

 CLRPEND0_bit.CLRPEND8 = 1;
}

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!, форматирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А что с регистром AIRCR и полем PRIGROUP в нём?

Там у кортексов настраиваются группы приоритетов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А что с регистром AIRCR и полем PRIGROUP в нём?

Там у кортексов настраиваются группы приоритетов.

Не пойму, о каких регистрах идет речь?

В мануале описаны следующие регистры, относящиеся к NVIC:

ISER0 - ISER3 RW Set-Enabe Разрешение прерывания

ICER0 - ICER3 RW Clear-Enable Запрет прерывания

ISPR0 - ISPR3 RW Set-Pending Установка ожидания (обработки)

ICPR0 - ICPR3 RWClear-Pending Снятие ожидания (обработки)

IABR0 - IABR3 RO Active Bit Состояние текущих прерываний (только чтение)

IPR0 - IPR27 RW Priority Установка приоритетов

STIR WO Software Trigger Программные прерывания

 

У меня в конце каждой функции инициализации периферии стоит установка приоритета и разрешение прерывания. А в конце каждого обработчика снятие ожидания.

Повторюсь: у таймера приоритет - 0, у UART'а - 2. Только почему-то из обработчика UART при возникновении прерывания по таймеру с высшим приоритетом перехода к его обработчику не происходит никогда.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня в конце каждой функции инициализации периферии стоит установка приоритета и разрешение прерывания. А в конце каждого обработчика снятие ожидания.

Повторюсь: у таймера приоритет - 0, у UART'а - 2. Только почему-то из обработчика UART при возникновении прерывания по таймеру с высшим приоритетом перехода к его обработчику не происходит никогда.

По умолчанию контроллер прерываний не настроен на вложенные прерывания. Для большинства случаев (до 16-ти уровней приоритетов и 16 подгрупп) подойдет вызов NVIC_SetPriorityGrouping(0x03) при инициализации приложения. Функция объявлена и реализована в core_cm3.h (но включать этот заголовок явно не надо, т.к. он включается через аппаратно-зависимый заголовок процессора).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ого! Только что нашел: Appendix: Cortex-M3 user guide в мануале на LPC1768!

Там как раз всё расписано!

Всем спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По умолчанию контроллер прерываний не настроен на вложенные прерывания.

 

Что-то я не понимаю...

По умолчанию в AIRCR поле "Interrupt priority grouping field" равно нулю. По моим соображениям, это означает, что приоритеты прерываний - это именно priority, а не subpriority. Т.е. количество вложенных прерываний может быть максимальным.

 

Ссылку на infocenter.arm.com дать не могу - никак не найду, где её там взять :-)

 

На железе, правда, все свои соображения проверить поленился: у меня критичное к времени старта прерывание ровно одно, оно же - самое длительное. Остальные прерывания быстрые, и особо не влияют. Пока, во всяком случае...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По умолчанию в AIRCR поле "Interrupt priority grouping field" равно нулю. По моим соображениям, это означает, что приоритеты прерываний - это именно priority, а не subpriority. Т.е. количество вложенных прерываний может быть максимальным.

Да, именно так. Я, помнится, тоже когда читал этот тред, удивился. Но раз заработало, то и ладно:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может, нам theBMV расскажет, что у него за компилятор? И даже стартапы все покажет? :-)

 

Кейл по умолчанию делает только инициализацию стеков, включает питание на периферию и настраивает PLL.

Тут, кажется, IAR, и там, может, есть настройки NVIC ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По умолчанию в AIRCR поле "Interrupt priority grouping field" равно нулю. По моим соображениям, это означает, что приоритеты прерываний - это именно priority, а не subpriority. Т.е. количество вложенных прерываний может быть максимальным.

Так-то оно так, но если используется не 8, а только 4 бита под приоритеты непонятно как интерпретировать значения 0, 1 и 2 в этом поле.

Нигде определённо этого не сказано.

Могли для экономии вентилей сделать "как получится".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так-то оно так, но если используется не 8, а только 4 бита под приоритеты непонятно как интерпретировать значения 0, 1 и 2 в этом поле.

Они все эквивалентны значению 0. (Потому что различия между этими вариантами приходятся на не-имплементированные биты приоритета).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то я не понимаю...

По умолчанию в AIRCR поле "Interrupt priority grouping field" равно нулю. По моим соображениям, это означает, что приоритеты прерываний - это именно priority, а не subpriority. Т.е. количество вложенных прерываний может быть максимальным.

Я тоже так думал, пока у меня одно прерывание не зациклилось (с наинизшим приоритетом, между прочим) и не давало прерываниям с наивысшими приоритетами отработать.

Поэтому (PRIGROUP == 0) - это отключенная вложенность, и приоритетность прерываний ни коим образом не работает. Проверено.

А "приоритеты прерываний - это именно priority, а не subpriority" достигается, когда (PRIGROUP == 2). Table 660. Priority grouping в мануале на LPC1768.

 

Может, нам theBMV расскажет, что у него за компилятор? И даже стартапы все покажет? :-)

 

Кейл по умолчанию делает только инициализацию стеков, включает питание на периферию и настраивает PLL.

Тут, кажется, IAR, и там, может, есть настройки NVIC ?

Компилятор IAR. В стартапе указатлель на вершину стека, вектор сброса и вектора прерываний периферии с именами функций. Взят из примеров к IAR'у

/**************************************************
*
* Part one of the system initialization code, contains low-level
* initialization, plain thumb variant.
*
* Copyright 2009 IAR Systems. All rights reserved.
*
* $Revision: 33389 $
*
**************************************************/

;
; The modules in this file are included in the libraries, and may be replaced
; by any user-defined modules that define the PUBLIC symbol _program_start or
; a user defined start symbol.
; To override the cstartup defined in the library, simply add your modified
; version to the workbench project.
;
; The vector table is normally located at address 0.
; When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
; The name "__vector_table" has special meaning for C-SPY:
; it is where the SP start value is found, and the NVIC vector
; table register (VTOR) is initialized to this address if != 0.
;
; Cortex-M version
;

	MODULE  ?cstartup

  ;; Forward declaration of sections.
	SECTION CSTACK:DATA:NOROOT(3)

	SECTION .intvec:CODE:NOROOT(2)

	EXTERN  __iar_program_start
	PUBLIC  __vector_table
	PUBLIC  __vector_table_0x1c

	DATA
__vector_table
	DCD	 sfe(CSTACK)			; Top of Stack
	DCD	 __iar_program_start	; Reset Handler
	DCD	 NMI_Handler			; NMI Handler
	DCD	 HardFault_Handler		 ; Hard Fault Handler
	DCD	 MemManage_Handler		 ; MPU Fault Handler
	DCD	 BusFault_Handler		  ; Bus Fault Handler
	DCD	 UsageFault_Handler		; Usage Fault Handler
__vector_table_0x1c
	DCD	 0						 ; Reserved
	DCD	 0						 ; Reserved
	DCD	 0						 ; Reserved
	DCD	 0						 ; Reserved
	DCD	 SVC_Handler			; SVCall Handler
	DCD	 DebugMon_Handler		  ; Debug Monitor Handler
	DCD	 0						 ; Reserved
	DCD	 PendSV_Handler			; PendSV Handler
	DCD	 SysTick_Handler		; SysTick Handler
	DCD	 WDT_IRQHandler			; Watchdog Handler
	DCD	 TMR0_IRQHandler		; TIMER0 Handler
	DCD	 TMR1_IRQHandler		; TIMER1 Handler
	DCD	 TMR2_IRQHandler		; TIMER2 Handler
	DCD	 TMR3_IRQHandler		; TIMER3 Handler
	DCD	 UART0_IRQHandler		  ; UART0 Handler
	DCD	 UART1_IRQHandler		  ; UART1 Handler
	DCD	 UART2_IRQHandler		  ; UART2 Handler
	DCD	 UART3_IRQHandler		  ; UART3 Handler
	DCD	 PWM1_IRQHandler		; PWM1 Handler
	DCD	 I2C0_IRQHandler		; I2C0 Handler
	DCD	 I2C1_IRQHandler		; I2C1 Handler
	DCD	 I2C2_IRQHandler		; I2C2 Handler
	DCD	 SPI_IRQHandler			; SPI Handler
	DCD	 SSP0_IRQHandler		; SSP0 Handler
	DCD	 SSP1_IRQHandler		; SSP1 Handler
	DCD	 PLL0_IRQHandler		; PLL0 Handler
	DCD	 RTC_IRQHandler			; RTC Handler
	DCD	 EINT0_IRQHandler		  ; EXT Interupt 0 Handler
	DCD	 EINT1_IRQHandler		  ; EXT Interupt 1 Handler
	DCD	 EINT2_IRQHandler		  ; EXT Interupt 2 Handler
	DCD	 EINT3_IRQHandler		  ; EXT Interupt 3 Handler
	DCD	 ADC_IRQHandler			; ADC Handler
	DCD	 BOD_IRQHandler			; BOD Handler
	DCD	 USB_IRQHandler			; USB Handler
	DCD	 CAN_IRQHandler			; CAN Handler
	DCD	 GPDMA_IRQHandler		  ; General Purpose DMA Handler
	DCD	 I2S_IRQHandler			; I2S Handler
	DCD	 Ethernet_IRQHandler	; Ethernet Handler
	DCD	 RIT_IRQHandler			; Repetitive Interrupt Timer Handler
	DCD	 MotorControlPWM_IRQHandler; Motor Control PWM Handler
	DCD	 QE_IRQHandler			 ; Quadrature Encoder Handler
	DCD	 PLL1_IRQHandler		; PLL1 Handler

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Default interrupt handlers.
;;

  PUBWEAK NMI_Handler	   
  PUBWEAK HardFault_Handler 
  PUBWEAK MemManage_Handler 
  PUBWEAK BusFault_Handler  
  PUBWEAK UsageFault_Handler
  PUBWEAK SVC_Handler	   
  PUBWEAK DebugMon_Handler  
  PUBWEAK PendSV_Handler	
  PUBWEAK SysTick_Handler   
  PUBWEAK WDT_IRQHandler	
  PUBWEAK TMR0_IRQHandler   
  PUBWEAK TMR1_IRQHandler   
  PUBWEAK TMR2_IRQHandler   
  PUBWEAK TMR3_IRQHandler   
  PUBWEAK UART0_IRQHandler  
  PUBWEAK UART1_IRQHandler  
  PUBWEAK UART2_IRQHandler  
  PUBWEAK UART3_IRQHandler  
  PUBWEAK PWM1_IRQHandler   
  PUBWEAK I2C0_IRQHandler   
  PUBWEAK I2C1_IRQHandler   
  PUBWEAK I2C2_IRQHandler   
  PUBWEAK SPI_IRQHandler	
  PUBWEAK SSP0_IRQHandler   
  PUBWEAK SSP1_IRQHandler   
  PUBWEAK PLL0_IRQHandler   
  PUBWEAK RTC_IRQHandler	
  PUBWEAK EINT0_IRQHandler  
  PUBWEAK EINT1_IRQHandler  
  PUBWEAK EINT2_IRQHandler  
  PUBWEAK EINT3_IRQHandler  
  PUBWEAK ADC_IRQHandler	
  PUBWEAK BOD_IRQHandler	
  PUBWEAK USB_IRQHandler	
  PUBWEAK CAN_IRQHandler	
  PUBWEAK GPDMA_IRQHandler  
  PUBWEAK I2S_IRQHandler	
  PUBWEAK Ethernet_IRQHandler		 
  PUBWEAK RIT_IRQHandler			  
  PUBWEAK MotorControlPWM_IRQHandler  
  PUBWEAK QE_IRQHandler			   
  PUBWEAK PLL1_IRQHandler			 

	SECTION .text:CODE:REORDER(1)
	THUMB
NMI_Handler	   
HardFault_Handler 
MemManage_Handler 
BusFault_Handler  
UsageFault_Handler
SVC_Handler	   
DebugMon_Handler  
PendSV_Handler	
SysTick_Handler   
WDT_IRQHandler	
TMR0_IRQHandler   
TMR1_IRQHandler   
TMR2_IRQHandler   
TMR3_IRQHandler   
UART0_IRQHandler  
UART1_IRQHandler  
UART2_IRQHandler  
UART3_IRQHandler  
PWM1_IRQHandler   
I2C0_IRQHandler   
I2C1_IRQHandler   
I2C2_IRQHandler   
SPI_IRQHandler	
SSP0_IRQHandler   
SSP1_IRQHandler   
PLL0_IRQHandler   
RTC_IRQHandler	
EINT0_IRQHandler  
EINT1_IRQHandler  
EINT2_IRQHandler  
EINT3_IRQHandler  
ADC_IRQHandler	
BOD_IRQHandler	
USB_IRQHandler	
CAN_IRQHandler	
GPDMA_IRQHandler  
I2S_IRQHandler	
Ethernet_IRQHandler		 
RIT_IRQHandler			  
MotorControlPWM_IRQHandler  
QE_IRQHandler			   
PLL1_IRQHandler			 
Default_Handler		  
	B Default_Handler 
	END

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поэтому (PRIGROUP == 0) - это отключенная вложенность, и приоритетность прерываний ни коим образом не работает. Проверено.

А вот ARM утверждает обратное:

PRIGROUP[2:0] : 0

Pre-emption field : [7:1]

Subpriority field : [0].

Note.

  • For a processor configured with less than eight bits of priority, the lower bits of the register are always 0. For example, if four bits of priority are implemented, PRI_N[7:4] sets the priority, and PRI_N[3:0] is 4'b0000

 

Table 660. Priority grouping в мануале на LPC1768.

Думаете, NXP смогли переделать ядро? Сильно сомневаюсь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прошёл всего лишь месяц, и у меня дошли руки проверить.

 

LPC1778 (уж что было под рукой, с припаяным лог.анализатором).

 

Один таймер с NVIC_SetPriority(4), другой таймер с NVIC_SetPriority(0).

В первом - длительная задержка (в половину его периода) и дрыганье ножкой на входе и выходе.

Во втором - также дрыганье ножкой.

Кроме EnableIRQ и SetPriority, в проекте больше нет никаких обращений к NVIC'у. Компилятор - кейл.

 

В итоге - дрыг ножкой второго таймера от первого никак не зависит, находится ли тот в прерывании, или нет.

 

Собственно, что и требовалось доказать - NXP люди вменяемые и делают контроллеры, которые работают согласно документации :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...