Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Подкажите решение: 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 ? но как это сделать ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Может оформить SUB1 как прерывание более низкого уровня чем INT1 и вместо установки флага, как-то его иничиировать в конце N-ного INT1 ? но как это сделать ? NVIC_EnableIRQ(CMU_IRQn);// ненужное прерывание периферии NVIC_SetPendingIRQ(CMU_IRQn); Если нет Оси, то можно использовать прерывание PendSVC или SVC (если обычные заняты). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flexz 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Если высокочастотное прерывание идет от внешнего источника, то завести его на таймер, который считает до N и дергает второе прерывание. Если же оно внутреннее, то как уже сказали выше - использовать софтовые прерывания, в stm32 это можно сделать через EXTI, например. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба NVIC_EnableIRQ(CMU_IRQn);// ненужное прерывание периферии NVIC_SetPendingIRQ(CMU_IRQn); Если нет Оси, то можно использовать прерывание PendSVC или SVC (если обычные заняты). Я вот помнил что что-то такое есть, где-то читал. а как понадобилось - не могу вспомнить и найти где это было описано. Не подскажете? В любом случае - спасибо за ключевые слова" для поиска :) Если высокочастотное прерывание идет от внешнего источника, то завести его на таймер, который считает до N и дергает второе прерывание. Если же оно внутреннее, то как уже сказали выше - использовать софтовые прерывания, в stm32 это можно сделать через EXTI, например. Прерывание внутрненее, от периферии. EXTI это же прерывание от ножки? Или его можно сьэмулировать программно? Я тоже думал - может какое прерывание от неиспользованной периферии задействовать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flexz 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба EXTI это же прерывание от ножки? Или его можно сьэмулировать программно? Я тоже думал - может какое прерывание от неиспользованной периферии задействовать? Да, можно программно сгенерить, есть специальный регистр для этого - EXTI_SWIER. А вообще, контроллер прерываний вроде бы позволяет программно генерировать любое прерывание, хотя сам я этим не пользовался никогда. Так что выбор большой :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Я вот помнил что что-то такое есть, где-то читал. а как понадобилось - не могу вспомнить и найти где это было описано. Не подскажете? В любом случае - спасибо за ключевые слова" для поиска :) Чтобы вызвать SVC __ASM volatile ("svc 0"); . PendSVC можно вызвать так: *( volatile uint32_t *) 0xE000ED04 )|= 0x10000000; Где-то эти функции должны быть в хидерах от ARM, но чото не нахожу.. Я тоже думал - может какое прерывание от неиспользованной периферии задействовать? NVIC_SetPendingIRQ(UnesedIO_Irq); Можно ещё вызвать через STIR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Т.е как я понял. проще всего через 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 или это автоматически ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Т.е как я понял. проще всего через EXTI: Ничего себе проще всего...еле в экран влезает... :) А еще такой дурацкий вопрос - в SUB1 надо как-то специально разрешать прерывания более высокого уровня чтобы INT1 могло происходить во время выполнения SUB1 или это автоматически ? Надо сконфигурировать количество уровней прерываний ( функция NVIC_SetPriorityGrouping) и задать уровень прерывания (функция NVIC_SetPriority). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Я пока с 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Не очень вьехал чем отличается PreemptionPriority от SubPriority? Первое - приоритет для вложенных прерываний. Если будет запрос на прерывание, у которого preemption будет выше, чем у текущего исполняющегося прерывания, будет вызвано высокоприоритетное. Второе - порядок выполнения прерываний, если вдруг два запроса поступили одновременно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Первое - приоритет для вложенных прерываний. Если будет запрос на прерывание, у которого preemption будет выше, чем у текущего исполняющегося прерывания, будет вызвано высокоприоритетное. Это понятно, непонятно зачем два уровня распределения приоритетов? Второе - порядок выполнения прерываний, если вдруг два запроса поступили одновременно. Если эти два запроса имеют один приоритет? Т.е. это распределение приоритета среди прерываний с одинаковым приоритетом? Т.е. один номер это группа (0-N), второй - номер внутри группы (0-M), интересно - чем это лучше чем один список приоритетов 0-N*M ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Это понятно, непонятно зачем два уровня распределения приоритетов? Появляется возможность задать приоритет внутри группы. Если эти два запроса имеют один приоритет? Т.е. это распределение приоритета среди прерываний с одинаковым приоритетом? Да Т.е. один номер это группа (0-N), второй - номер внутри группы (0-M), интересно - чем это лучше чем один список приоритетов 0-N*M ? в списке нет возможности задать порядок вызова прерываний с одинаковым приоритетом - первым вызовется тот у кого номер меньше, а не тот какой вы хотели бы. Может и не лучше...но так сделано. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Появляется возможность задать приоритет внутри группы. Да в списке нет возможности задать порядок вызова прерываний с одинаковым приоритетом - первым вызовется тот у кого номер меньше, а не тот какой вы хотели бы. Может и не лучше...но так сделано. Я вот о чем - предположим есть 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 ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Т.е. один номер это группа (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). А тут дали возможность двигать границу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Allregia 9 23 октября, 2012 Опубликовано 23 октября, 2012 · Жалоба Тем, что внутри группы кто первым встал, того и тапки. Приоритет внутри группы — он только на случай одновремённо анализирумеых запросов. Когда уже одно из них выполняется — другие возникшие не будут его прерывать. Т.е. если я хочу чтобы прерывание с более высоким приоритетом прерывало прерывание с более низким, они обязательно долдны быть в разных группах? А если они из одной группы, и выполняется прерывание с бОльшим номером подгруппы (т.е. менее приоритетное), то прерывание той-же группы с меньшим номером (по идее более приоритетное) его не прервет? Группа (почти) равноправных прерываний, выполняемых последовательно, не будет дополнительно тратить время и стек на сохранение регистров R0-R3, R12, LR, PC, PSR («stacking») А разве стекирование работает только для прерываний одной группы? Т.е. если в момент выполнения высокоприоритетного прерывания возникает другое, менее приоритетное, то оно подождет и будет выполнено после, но пролог/эпилог не будут выполняться только если оба эти прерывания одной группы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться