Nikitoc 0 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Всем доброго времени суток. Я тут зацепился с прерываниями на stm32l152. Пишу на Си в Keil'е, использую либы производителя. В общем ситуёвина такая: имеем прерывание по USART1 (по приходу символа в приемник) с приоритетом "1" и прерывание от SysTick таймера с приоритетом "3". Приоритеты выставляю вручную. По всем докам на CORTEX-M3 ясно, что прерывание с более высоким приоритетом должно моментально приостанавливать выполнение прерывания с более низким приоритетом (в данном случае USART1 должно прерывать SysTick). На практике же почему-то выходит наоборот - теряется часть посылки по USART1 если SysTick прерывания разрешены (в обработчике SysTick выполняется довольно много работы). Кто-нибудь сталкивался с подобным? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Дык! Так и есть, чем меньше циферка, тем больше приоритет:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikitoc 0 17 мая, 2011 Опубликовано 17 мая, 2011 (изменено) · Жалоба Дык! Так и есть, чем меньше циферка, тем больше приоритет:) Вы наверное меня неправильно поняли. Поступающий в приемник USART1 (приоритет "1") байт НЕ прерывает выполнение обработчика SysTick (приоритет "3"), либо очень долго прерывает, т.к. за это время затираются другие принятые по USART1 байты... После того как назначил приоритеты я их проверяю посредством такой ф-ции: NVIC_GetPriority(SysTick_IRQn); Ну а выставляю соответственно: NVIC_SetPriority(SysTick_IRQn, 3); Может это неправильный способ назначения приоритета системного таймера? Или нужно еще где-то что-то выставить? Просто такое впечатление, что у него остается его приоритет по дефолту "-1". Изменено 17 мая, 2011 пользователем Nikitoc Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 18 мая, 2011 Опубликовано 18 мая, 2011 · Жалоба А, понятно. Дело в том, что есть ещё такое понятие, как группы приоритетов. По умолчанию все прерывания в одной группе, то есть, друг друга не прерывают. Для того, чтобы прерывали, надо включить несколько групп (NVIC_SetPriorityGrouping()), и развести прерывания по группам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ek74 0 18 мая, 2011 Опубликовано 18 мая, 2011 · Жалоба Ну а выставляю соответственно: NVIC_SetPriority(SysTick_IRQn, 3); Используйте NVIC_EncodePriority(...). Например: /* 2 bits for pre-emption priority and 2 bits for subpriority */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Set USART1 interrupt preemption priority to 1 */ NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0)); /* Set SysTick interrupt preemption priority to 3 */ NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 3, 0)); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikitoc 0 18 мая, 2011 Опубликовано 18 мая, 2011 (изменено) · Жалоба Дело в том, что есть ещё такое понятие, как группы приоритетов. По умолчанию все прерывания в одной группе, то есть, друг друга не прерывают. Для того, чтобы прерывали, надо включить несколько групп (NVIC_SetPriorityGrouping()), и развести прерывания по группам. Т.е. preemption priority для всех одинаковый, а subpriority разные? А зачем тогда нужны эти subpriority если на выполнение прерываний они не влияют? /* 2 bits for pre-emption priority and 2 bits for subpriority */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); Я делаю в самом начале инициализации так: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); а потом уже при настройке отдельных периферийных модулей делаю вот так: /* Enable the USARTx Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART1_Receiver_Priority; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); Это корректно? Изменено 18 мая, 2011 пользователем Nikitoc Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ek74 0 18 мая, 2011 Опубликовано 18 мая, 2011 · Жалоба Т.е. preemption priority для всех одинаковый, а subpriority разные? А зачем тогда нужны эти subpriority если на выполнение прерываний они не влияют?[The Definitive Guide to the ARM Cortex-M3, Second Edition, Page 114] The preempt priority level defines whether an interrupt can take place when the processor is already running another interrupt handler. The subpriority level value is used only when two exceptions with the same preempt priority level occurred at the same time. In this case, the exception with higher subpriority (lower value) will be handled first. Это корректно?В принципе, да. И не забыть установить приоритет для SysTick. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikitoc 0 18 мая, 2011 Опубликовано 18 мая, 2011 · Жалоба Спасибо. Предельно ясно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikitoc 0 25 мая, 2011 Опубликовано 25 мая, 2011 (изменено) · Жалоба В продолжение темы о прерываниях. USART2 почему-то упорно не хочет генерировать повторное прерывание. Один раз все случилось, благополучно обработалось, а второй и последующие разы - полный игнор. Ниже привожу процедуры инициализации USART2: /******************************************************************************* * Function Name : UsartInit * Description : Configures the USART2. * Input : None * Output : None * Return : None *******************************************************************************/ void USART_Init() { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; USART_DeInit(USART2); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); /* Enable GPIO clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); /* Enable UART clock */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); /* Connect alternate function pins to USART */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); /* Connect alternate function pins to USART */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_USART2); /* Connect alternate function pins to USART */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_USART2); /* Connect alternate function pins to USART */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_1; /* Configure USART Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_0; /* Configure USART Rx as input floating */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS; USART_InitStructure.USART_BaudRate = 921600; USART_Init(USART2, &USART_InitStructure); /* USART configuration */ NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 4, 0)); NVIC_EnableIRQ(USART2_IRQn); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); USART_Cmd(USART2, ENABLE); /* Enable USART */ } /*******************************************************************************/ и процедуру обработки прерывания: /*------------------------------------------------------------------------------ This function handles USART2 global interrupt request. *-----------------------------------------------------------------------------*/ void USART2_IRQHandler(void) { if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { HostProt_Parser(); // обработка принятого символа } else { ClearUSART_IT_Bits(USART2); } USART_ClearITPendingBit(USART2, USART_IT_RXNE); } /*------------------------------------------------------------------------------ В том что символ приходит на вход RX - уверен на 100%. P.S. Я где-то натыкался на подобную тему, но не смог найти. Буду благодарен за любые подсказки. Изменено 25 мая, 2011 пользователем Nikitoc Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба USART_IT_RXNE чистится автоматом при вычитывании USARTx->DR, поэтому вручную его чистить не надо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikitoc 0 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба USART_IT_RXNE чистится автоматом при вычитывании USARTx->DR, поэтому вручную его чистить не надо. Да. Спасибо. Но повторного прерывания все равно не происходит :-( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SergSit 0 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба А, понятно. Дело в том, что есть ещё такое понятие, как группы приоритетов. По умолчанию все прерывания в одной группе, то есть, друг друга не прерывают. Для того, чтобы прерывали, надо включить несколько групп (NVIC_SetPriorityGrouping()), и развести прерывания по группам. Что то не понимаю. В Cortex™-M3 r2p0 Technical Reference Manual в разделе 5.3.2 сказано , что если поле PRIGROUP равно 0, то мы имеем 0-ой бит для подгруппы, и 1-7 биты для групп( выгружаемых). А в соответствии с PM0056 Programming manual STM32F10xxx Cortex-M3 programming manual раздел 4.3.4 Application interrupt and reset control register (SCB_AIRCR) поле PRIGROUP после сброса равно нулю. Т.е. после сброса мы имеем 16 выгружаемых групп приоритетов. Где ошибка у Вас или у меня? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба Но повторного прерывания все равно не происходит :-( Да вроде нормально всё... Убедитесь, что в HostProt_Parser(); USARTx->DR вычитывается один и только один раз. Попробуйте убрать это: ClearUSART_IT_Bits(USART2); (Я не знаю что это такое, но по названию догадываюсь, что чистит какие-то флаги) Попробуйте также сконфигурировать USART пока без контроля потока. Т.е. после сброса мы имеем 16 выгружаемых групп приоритетов. Где ошибка у Вас или у меня? Похоже, что вы правы. При включении PRIGROUP=0, и все биты приоритета (кроме самого младшего, отсутствующего), являются pre-emption priority. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikitoc 0 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба Убедитесь, что в HostProt_Parser(); USARTx->DR вычитывается один и только один раз. Ээээ... Вообще-то вычитывается точно не один раз, в этой процедуре я принимаю несколько байт. А в чем собственно засада? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба Вообще-то вычитывается точно не один раз, в этой процедуре я принимаю несколько байт. А в чем собственно засада? Это как это? В прерывании по приёму одного байта вычитываете несколько? Ждёте что ли их? Опрашиваете RXNE? Отключаете прерывание при этом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться