Mister_DSP 0 17 декабря, 2016 Опубликовано 17 декабря, 2016 (изменено) · Жалоба Доброе время суток! Так уж получилось, что приходится использовать Port C8 для ножки внешнего прерывания с устройства. Я чуть не пророс, когда увидел, что порты с номерами 5,6,7,8,9 объединены в один обработчик прерывания - в Keil это функция EXTI9_5_IRQHandler(). Ранее на макете были линии 0 и 4 (на них линии и обработчики прерываний по-отдельности и о подвохах не догадывался). Пока код использую такой (он рабочий). Инициализация(здесь в тексте много опущено для упрощения): GPIO_InitTypeDef gpio; EXTI_InitTypeDef exti; NVIC_InitTypeDef nvic; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE); GPIO_StructInit(&gpio); //INPUT //C8=>IRQ !!! gpio.GPIO_Pin=GPIO_Pin_8; gpio.GPIO_Mode=GPIO_Mode_IN; gpio.GPIO_Speed=GPIO_Speed_25MHz; //!!! gpio.GPIO_OType=GPIO_OType_PP; gpio.GPIO_PuPd=GPIO_PuPd_NOPULL; GPIO_Init(GPIOC,&gpio); //IRQ C8 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource8); exti.EXTI_Line=EXTI_Line8; exti.EXTI_LineCmd=ENABLE; exti.EXTI_Mode=EXTI_Mode_Interrupt; exti.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_Init(&exti); nvic.NVIC_IRQChannel=EXTI9_5_IRQn; nvic.NVIC_IRQChannelPreemptionPriority=0; nvic.NVIC_IRQChannelSubPriority=0; nvic.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&nvic); Сам обработчик: void EXTI9_5_IRQHandler() { if(EXTI_GetITStatus(EXTI_Line8)!=RESET) //Make sure that interrupt flag is set { //Тут код полезной нагрузки....... EXTI_ClearITPendingBit(EXTI_Line8); //Clear interrupt flag return; //для надёжности - на одном сайте говорили что лучше так принудительно выходить :) } } За CMSIS и SPL не пинайте, так как не являюсь фанатом КУБа и его HAL. Вопрос вот в чём: Я использую одну из ножек порта C - линию 8 для прерывания (настроена на ввод). Этот же порт C я использую для аппаратного SPI + ещё другие линии отдельно как GPIO на вывод. Можно ли в обработчике не делать проверку: if(EXTI_GetITStatus(EXTI_Line8)!=RESET)...... а сразу приступать к полезной нагрузке? При условии что более нет прерываний на C5,6,7,9 ? И линия 8 также не используется по прерываниям. И когда правильнее сбрасывать бит прерывания - ДО или ПОСЛЕ полезной нагрузки? EXTI_ClearITPendingBit(EXTI_Line8); //Clear interrupt flag Изменено 17 декабря, 2016 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
hd44780 0 17 декабря, 2016 Опубликовано 17 декабря, 2016 · Жалоба Можно ли в обработчике не делать проверку: if(EXTI_GetITStatus(EXTI_Line8)!=RESET)...... а сразу приступать к полезной нагрузке? При условии что более нет прерываний на C5,6,7,9 ? И линия 8 также не используется по прерываниям. Насколько я понимаю - да. но если Вы добавите 5,6,7 или 9 - условия понадобятся. И когда правильнее сбрасывать бит прерывания - ДО или ПОСЛЕ полезной нагрузки? EXTI_ClearITPendingBit(EXTI_Line8); //Clear interrupt flag Моё ИМХО - после нагрузки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eugen 0 17 декабря, 2016 Опубликовано 17 декабря, 2016 · Жалоба Насколько я понимаю - да. но если Вы добавите 5,6,7 или 9 - условия понадобятся. Моё ИМХО - после нагрузки. Не знаю как в данной библиотек ( SPL ,HAL ) но если на CMSIS то надо До, Если поставить после, то может не сбросится прерывание и будет повторный заход , чтоб этого не произошло надо еще барьер ставить тогда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mister_DSP 0 17 декабря, 2016 Опубликовано 17 декабря, 2016 (изменено) · Жалоба Спасибо за внимание. Сделал как hd44780 написал - работает, глюки пока не обнаружены. EugenPKH, прерывание по перепаду состояния, а не по уровню. Там же ТАКЖЕ сбрасывается бит ВНЕШНЕГО устройства. Так что при любом желании, оно повторно не выскочет. Вот зато есть такая особенность: при включении питания прерывание срабатывает сразу в первый раз! Приходится программно игнорировать первое вхождение: static char f=0; if(!f)f=1; else { //...делаем полезное... } При этом порты инициализируются раньше, чем разрешаются прерывание. И такое на AVR-ках тоже было. Как можно это устранить? Изменено 17 декабря, 2016 пользователем Mister_DSP Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 17 декабря, 2016 Опубликовано 17 декабря, 2016 · Жалоба Пока вы не разрешите прерывания от ног 5-7, 9 в регистре EXTI->IMR, они не будут выставлять свои флаги и не будут вызывать прерывание. Как это делается в SPL или кубах - понятия не имею. В обычной жизни для этого достаточно одной строки записи в регистр. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mister_DSP 0 17 декабря, 2016 Опубликовано 17 декабря, 2016 · Жалоба Пока вы не разрешите прерывания от ног 5-7, 9 в регистре EXTI->IMR, они не будут выставлять свои флаги и не будут вызывать прерывание. Как это делается в SPL или кубах - понятия не имею. В обычной жизни для этого достаточно одной строки записи в регистр. Так речь идет о том, что как раз я и разрешаю прерывание и оно в первый раз случается без воздействия внешнего устройства (источника прерывания). Подозреваю, что такое поведение возникает из-за запоминания контроллером состояния перепада уровня при настройке портов. А вот со второго раза и далее - прерывания уже идут в тему - от устройства. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 17 декабря, 2016 Опубликовано 17 декабря, 2016 · Жалоба Так вы его очистите, прежде, чем разрешать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eugen 0 17 декабря, 2016 Опубликовано 17 декабря, 2016 · Жалоба EugenPKH, прерывание по перепаду состояния, а не по уровню. Там же ТАКЖЕ сбрасывается бит ВНЕШНЕГО устройства. Так что при любом желании, оно повторно не выскочет. При этом порты инициализируются раньше, чем разрешаются прерывание. И такое на AVR-ках тоже было. Как можно это устранить? Если будете сбрасывать прерывания не через библиотеку, а напрямую(EXTI->PR = EXTI_PR_PR8;) увидите двойной вхождения скорее всего. Второе вхождения происходит из-за того что не успевает флаг сбросится , а не потому что его кто то вызвал. Чтоб убрать первое вхождение в прерывания при запуске - на просто перед разрешением прерывания сбросить флаг EXTI->PR = EXTI_PR_PR8; Как через библиотеку не знаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mister_DSP 0 18 декабря, 2016 Опубликовано 18 декабря, 2016 · Жалоба всем спасибо. помогла очистка флага перед разрешением прерывания: EXTI_ClearITPendingBit(EXTI_Line8); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться