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

М3/М4 - как сделать трюк с прерываниями?

Подкажите решение:

1) есть проограмма, сейчас на М3 (lpc1768) но вообще будет на М4 (stm32f4), без ОС.

в ней выполняются фоновые задачи, в т.ч и пересылка DMA, и есть циклы типа while()

2) есть довольно высокочастотное прерывание (неважно от чего) INT1 с регулярной частотой (периодом - T1)

3) после каждых N должна выполниться подпрограмма SUB1, время выполнения SUB1 - T2

Естественно, T2< N*T1,

но - T2>T1.

Т.е. во время выплонения SUB1 обязательно произойдет прерывание INT1.

4) пропустить INT нельзя, как нельзя пропустить и SUB1.

 

Первой что пришло в голову - крутить в INT1 счетчик, когда он досчитал до N - выставлять флаг.

В SUB1 его проверять, но при в основной программе во всех циклах вставлять вызов SUB1

#define N 10
u8 IntFlag=0;
//-----
void INT1(void){
static cnt=0;
    .........
   if(++cnt>N){
      cnt=0;
      IntFlag=1;
   }
}
//-----
void SUB1(void){
   if(IntFlag){
      IntFlag=0;
      ...........
   }
}
//
int main(void){
    .......
   while(xxxx){
      .....
      SUB1();
   }

    ........
}

 

Проблемы:

1) не пропустить бы какой-то while/for, это надо из все просматривать во всей программе, е везде вставлять вызов SUB1

2) на многочисленные вызовы SUB1 тратиться довольно много времени, так например скорость записи в SD-флешку (по DMA!) падает процентов на 20-30 (хотя и огстается в пределат требуемогодля моей задачи).

 

Может кто подскажет более элегантное решение ?

Может оформить SUB1 как прерывание более низкого уровня чем INT1 и вместо установки флага, как-то его иничиировать в конце N-ного INT1 ? но как это сделать ?

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


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

Может оформить SUB1 как прерывание более низкого уровня чем INT1 и вместо установки флага, как-то его иничиировать в конце N-ного INT1 ? но как это сделать ?

 

    NVIC_EnableIRQ(CMU_IRQn);// ненужное прерывание периферии
    NVIC_SetPendingIRQ(CMU_IRQn);

Если нет Оси, то можно использовать прерывание PendSVC или SVC (если обычные заняты).

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


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

Если высокочастотное прерывание идет от внешнего источника, то завести его на таймер, который считает до N и дергает второе прерывание.

Если же оно внутреннее, то как уже сказали выше - использовать софтовые прерывания, в stm32 это можно сделать через EXTI, например.

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


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

    NVIC_EnableIRQ(CMU_IRQn);// ненужное прерывание периферии
     NVIC_SetPendingIRQ(CMU_IRQn);

Если нет Оси, то можно использовать прерывание PendSVC или SVC (если обычные заняты).

 

Я вот помнил что что-то такое есть, где-то читал. а как понадобилось - не могу вспомнить и найти где это было описано. Не подскажете?

В любом случае - спасибо за ключевые слова" для поиска :)

 

Если высокочастотное прерывание идет от внешнего источника, то завести его на таймер, который считает до N и дергает второе прерывание.

Если же оно внутреннее, то как уже сказали выше - использовать софтовые прерывания, в stm32 это можно сделать через EXTI, например.

 

Прерывание внутрненее, от периферии. EXTI это же прерывание от ножки? Или его можно сьэмулировать программно?

Я тоже думал - может какое прерывание от неиспользованной периферии задействовать?

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


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

EXTI это же прерывание от ножки? Или его можно сьэмулировать программно?

Я тоже думал - может какое прерывание от неиспользованной периферии задействовать?

Да, можно программно сгенерить, есть специальный регистр для этого - EXTI_SWIER.

А вообще, контроллер прерываний вроде бы позволяет программно генерировать любое прерывание, хотя сам я этим не пользовался никогда. Так что выбор большой :)

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


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

Я вот помнил что что-то такое есть, где-то читал. а как понадобилось - не могу вспомнить и найти где это было описано. Не подскажете?

В любом случае - спасибо за ключевые слова" для поиска :)

 

Чтобы вызвать SVC

__ASM volatile ("svc 0");

.

 

PendSVC можно вызвать так:

*( volatile uint32_t *) 0xE000ED04 )|= 0x10000000;

Где-то эти функции должны быть в хидерах от ARM, но чото не нахожу..

 

Я тоже думал - может какое прерывание от неиспользованной периферии задействовать?

 

NVIC_SetPendingIRQ(UnesedIO_Irq);

 

Можно ещё вызвать через STIR.

 

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


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

Т.е как я понял. проще всего через EXTI:

 

//высокочастотное прерывание:
void INT1(void){
static cnt=0;
    .........
   if(++cnt>N){
      cnt=0;
      EXTI_GenerateSWInterrupt(EXTI_Line15);// "взвоим курок" - после выхода из INT1 произойдет вызов прерывания EXTI15_10  
   }
}

// программное прерывание:
void EXTI15_10_IRQHandler(void){
  if(EXTI_GetITStatus(EXTI_Line15) != RESET)  {
    SUB1();
    EXTI_ClearITPendingBit(EXTI_Line15); // Clear the EXTI line 15 pending bit 
  }
}

// Настройки:
void Init_EXTI_SWI(void){
  EXTI_InitTypeDef   EXTI_InitStructure;
  NVIC_InitTypeDef   NVIC_InitStructure;

  /* Enable SYSCFG clock */
//  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  
  /* Configure EXTI Line15 */
  EXTI_InitStructure.EXTI_Line = EXTI_Line15;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  /* Enable and set EXTI15_10 Interrupt to the lowest priority */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}
// в настройке ВЧ прерывания приоритет повыше:
//  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
//  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;

 

А еще такой дурацкий вопрос - в SUB1 надо как-то специально разрешать прерывания более высокого уровня чтобы INT1 могло происходить во время выполнения SUB1 или это автоматически ?

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


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

Т.е как я понял. проще всего через EXTI:

Ничего себе проще всего...еле в экран влезает... :)

 

А еще такой дурацкий вопрос - в SUB1 надо как-то специально разрешать прерывания более высокого уровня чтобы INT1 могло происходить во время выполнения SUB1 или это автоматически ?

Надо сконфигурировать количество уровней прерываний ( функция NVIC_SetPriorityGrouping) и задать уровень прерывания (функция NVIC_SetPriority).

 

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


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

Я пока с NVIC до конца не разобрался.

Не очень вьехал чем отличается PreemptionPriority от SubPriority?

 

У меня в программе 4 прерывания, в порядке приоритета:

1) SPI

2) мое программное, инициируемое в прерывании SPI

3) UART

4) SysTick

 

и делать надо так:

 

...
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
                        // Setup SysTick Timer for 1 msec interrupts, lowest priority
      if (SysTick_Config(SystemCoreClock / 1000)) { while (1);} // Capture error 
        NVIC_SetPriority(SysTick_IRQn,  4);  //    SysTick priority=4
       ..

      // uart
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
      ...
     // sw interrupt
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
     ...
     // SPI, highest priority
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    ...

 

Или можно просто после всех инициализаций, которые у меня есть сейчас, написать:

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        NVIC_SetPriority(SPI2_IRQn,                1);  //    SPI priority=1
        NVIC_SetPriority(EXTI15_10_IRQn,       2);  //    SW interrupt priority=2
        NVIC_SetPriority(USART3_IRQn_IRQn,  3);  //    UART=3
        NVIC_SetPriority(SysTick_IRQn,            4);  //    SysTick priority=4

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


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

Не очень вьехал чем отличается PreemptionPriority от SubPriority?

Первое - приоритет для вложенных прерываний. Если будет запрос на прерывание, у которого preemption будет выше, чем у текущего исполняющегося прерывания, будет вызвано высокоприоритетное.

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

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


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

Первое - приоритет для вложенных прерываний. Если будет запрос на прерывание, у которого preemption будет выше, чем у текущего исполняющегося прерывания, будет вызвано высокоприоритетное.

 

Это понятно, непонятно зачем два уровня распределения приоритетов?

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

 

Если эти два запроса имеют один приоритет? Т.е. это распределение приоритета среди прерываний с одинаковым приоритетом?

 

Т.е. один номер это группа (0-N), второй - номер внутри группы (0-M), интересно - чем это лучше чем один список приоритетов 0-N*M ?

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


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

Это понятно, непонятно зачем два уровня распределения приоритетов?

Появляется возможность задать приоритет внутри группы.

 

Если эти два запроса имеют один приоритет? Т.е. это распределение приоритета среди прерываний с одинаковым приоритетом?

Да

Т.е. один номер это группа (0-N), второй - номер внутри группы (0-M), интересно - чем это лучше чем один список приоритетов 0-N*M ?

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

Может и не лучше...но так сделано.

 

 

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


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

Появляется возможность задать приоритет внутри группы.

 

 

Да

 

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

Может и не лучше...но так сделано.

 

Я вот о чем - предположим есть 3 группы, A,B,C, внутри каждой два прерывания, 0 и 1:

A 0,0

B 0,1

C 0,1

 

порядок приоритетов ведь все равно будет такой: A0,A1, B0, B1, C0, C1

так какая разница, если это будет порядок: 0,1,2,3,4,5

где:

0=A0

1=A1

2=B0

3=B1

4=C0

5=C1

 

ведь тоже самое?

 

но раз так сделали, значит о чем-то думали, вот и пытаюсь найти скрытый смысл :)

---------------

ну ладно, это все теории, а что с тем что я спросил в #9 ?

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


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

Т.е. один номер это группа (0-N), второй - номер внутри группы (0-M), интересно - чем это лучше чем один список приоритетов 0-N*M ?
Тем, что внутри группы кто первым встал, того и тапки. Приоритет внутри группы — он только на случай одновремённо анализирумеых запросов. Когда уже одно из них выполняется — другие возникшие не будут его прерывать. Группа (почти) равноправных прерываний, выполняемых последовательно, не будет дополнительно тратить время и стек на сохранение регистров R0-R3, R12, LR, PC, PSR («stacking»)

 

Совсем разные приоритеты, групп нет

isr1 enter -- stacking

...

isr2 enter -- stacking

...

...

isr2 exit -- unstacking

...

isr1 exit -- unstacking

 

Внутри группы

isr1 enter -- stacking

...

...

isr1 exit -- isr2 enter

...

...

isr2 exit -- unstacking

 

p.s. Похожее было и в Q-bus (электроника-60), хоть там и «stacking» включал в себя только PC и PSW.

Уровни приоритета это одно, а внутри каждого уровня распространение сигнала по платам/разъёмам обеспечивало «подприоритет» внутри группы, действующий только на момент входа в прерывание, дальше запросы этого уровня просто не воспринимались процессором (до понижения приоритета процессора в драйвере). И у всех остальных процессоров с несколькими уровнями приоритета -- внутри одного приоритета вытеснения уже работающего обработчика нет.

Только там железно было разбито на количество групп (число входов запросов прерывания у процессора) и количество в группе (сколько плат можно в корзину натолкать в случае Q-bus).

А тут дали возможность двигать границу.

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


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

Тем, что внутри группы кто первым встал, того и тапки. Приоритет внутри группы — он только на случай одновремённо анализирумеых запросов. Когда уже одно из них выполняется — другие возникшие не будут его прерывать.

 

Т.е. если я хочу чтобы прерывание с более высоким приоритетом прерывало прерывание с более низким, они обязательно долдны быть в разных группах?

А если они из одной группы, и выполняется прерывание с бОльшим номером подгруппы (т.е. менее приоритетное), то прерывание той-же группы с меньшим номером (по идее более приоритетное) его не прервет?

 

 

Группа (почти) равноправных прерываний, выполняемых последовательно, не будет дополнительно тратить время и стек на сохранение регистров R0-R3, R12, LR, PC, PSR («stacking»)

 

А разве стекирование работает только для прерываний одной группы?

Т.е. если в момент выполнения высокоприоритетного прерывания возникает другое, менее приоритетное, то оно подождет и будет выполнено после, но пролог/эпилог не будут выполняться только если оба эти прерывания одной группы?

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


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

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

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

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

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

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

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

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

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

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