Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: прерывания STM32F4
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Метценгерштейн
Вроде все настроил, платка F4Discovery, а работать по нажатию на кнопку не хочет.
Может кто подскажет что не так ему?
Код
void EXTI0_IRQHandler(void)
{
  on (LED_Blue);
  EXTI->PR |= EXTI_PR_PR0;//сбросили бит прерывания
}

Код
void main()
{
  InitPeriph(); // тут лампочка описана и дефайн кнопки
  
// настройка ноги на прерывание PA0
    GPIOA->MODER &= ~GPIO_MODER_MODER0;  //input
    GPIOA->OTYPER &= ~GPIO_OTYPER_OT_0;  //Output push-pull
    GPIOA->OSPEEDR |=GPIO_OSPEEDER_OSPEEDR0;  //40 MHz
    GPIOA->PUPDR &=~GPIO_PUPDR_PUPDR0;  //No pull-up, pull-down
    
    // настройка внешнего прерывания на PA0
      RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
      SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;
      EXTI->IMR |= EXTI_IMR_MR0;
      EXTI->RTSR |= EXTI_FTSR_TR0;
      NVIC_EnableIRQ(EXTI0_IRQn);  
      NVIC_SetPriority(EXTI0_IRQn, 1);
  
  
  while(1)
  {
    
  }      
  
}
Genadi Zawidowski
Почему не работает не скажу, но при таком способе сброса запросов на прерывание сброшены будут все имеющиеся, а не только EXTI_PR_PR0. Надо так:
Код
EXTI->PR = EXTI_PR_PR0;


Проверьте, что с инициализацией - вот образец точно работающего:
http://188.134.5.254/browser/hfreceiver/trunk/pio.c#L362
Программирование вывода на ввод не здесь. У Вас - вне не только дефайн кнопки, но и инициализация регистров? Порт "А" включаете?

Вы везде предполагаете что в регистрах до Вас только нули были.

Вы задаёте proprity - а как сконфигурирована система прерываний? Реакция на вашу "1" от этого зависит.
Метценгерштейн
Цитата(Genadi Zawidowski @ Aug 23 2014, 21:17) *
Почему не работает не скажу, но при таком способе сброса запросов на прерывание сброшены будут все имеющиеся, а не только EXTI_PR_PR0. Надо так:
Код
EXTI->PR = EXTI_PR_PR0;

разве у меня по-другому?
он не заходит в прерывание, раз LED не поджигает. До сброса не доходит дело.
Genadi Zawidowski
Я напимсал, что увиденная ошибка не влияет. Но потом помешает.
Цитата
разве у меня по-другому?
У Вас:
Код
EXTI->PR |= EXTI_PR_PR0;
У меня:
Код
EXTI->PR = EXTI_PR_PR0;
В чём отличия понятно?


Инициализацию кнопки покажите. Или убедитесь, что её видно из программы.

hint: На discovery кнопка зажимает в "0" вход.
Метценгерштейн
да, увидел отличия- глаз замылился.

кнопка- она же видна в 1-м посте.
настройка ноги на прерывание PA0

если имеете ввиду
on (LED_Blue);
то это работает, если просто в код вставить.
Genadi Zawidowski
Если в первом посте, я не вижу
Код
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;    /* I/O port A clock enable */

Метценгерштейн
вот InitPeriph(); здесь
Код
#ifndef HARDWARE_H__
#define HARDWARE_H__

#define  LED_Green      GPIOD, GPIO_Pin_12, H
#define  LED_Orange     GPIOD, GPIO_Pin_13, H
#define  LED_Red        GPIOD, GPIO_Pin_14, H
#define  LED_Blue       GPIOD, GPIO_Pin_15, H

#define RS232_BAUDRATE  38400
#define SYS_CLK             (32000000LL) // частота шины
#define TIM6_PRESCALER      (0x3E8LL) // предделитель системной частоты (делим на 1000)
#define TIM6_COMPARE(ARR)        MS // до скольки считает счетчик и прерывается

#define   MS                SYS_CLK / TIM6_PRESCALER / 1000  // сколько итераций цикла надо на одну миллисекунду
#define   MKS               MS / 1000                 // на микросекунду в 1000 раз меньше
    
void InitPeriph(void)  {
  SysTick_Config(SystemCoreClock/8/1000); // системный таймер -из файла exel видно, что он делится на 8 от тактовой частоты
  
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOAEN;   // Включаем тактирование порта D
  
  GPIOD->MODER |= GPIO_MODER_MODER12_0;  //output
  GPIOD->OTYPER &= ~GPIO_OTYPER_OT_12;  //Output push-pull
  GPIOD->OSPEEDR |=GPIO_OSPEEDER_OSPEEDR12;  //40 MHz
  GPIOD->PUPDR &=~GPIO_PUPDR_PUPDR12;  //No pull-up, pull-down
  
  GPIOD->MODER |= GPIO_MODER_MODER13_0;  //output
  GPIOD->OTYPER &= ~GPIO_OTYPER_OT_13;  //Output push-pull
  GPIOD->OSPEEDR |=GPIO_OSPEEDER_OSPEEDR13;  //40 MHz
  GPIOD->PUPDR &=~GPIO_PUPDR_PUPDR13;  //No pull-up, pull-down
  
  GPIOD->MODER |= GPIO_MODER_MODER14_0;  //output
  GPIOD->OTYPER &= ~GPIO_OTYPER_OT_14;  //Output push-pull
  GPIOD->OSPEEDR |=GPIO_OSPEEDER_OSPEEDR14;  //40 MHz
  GPIOD->PUPDR &=~GPIO_PUPDR_PUPDR14;  //No pull-up, pull-down

  GPIOD->MODER |= GPIO_MODER_MODER15_0;  //output
  GPIOD->OTYPER &= ~GPIO_OTYPER_OT_15;  //Output push-pull
  GPIOD->OSPEEDR |=GPIO_OSPEEDER_OSPEEDR15;  //40 MHz
  GPIOD->PUPDR &=~GPIO_PUPDR_PUPDR15;  //No pull-up, pull-downown
  }

#endif  //  HADRWARE_H__
Genadi Zawidowski
Проверьте видимость кнопки чтением регистра GPIOA->IDR. Вне прерываний. Так же, как проверяли on(LED_BLUE)
Вы включаете pull-down, на плате стоит pull-up... Предположу, что напряжение на входе кнопки меняется от 0 до 0.8 вольта.

Код
for (;;)
{
if ((GPIOA->IDR & 0x0001) != 0)
  on(LED_BLUE);
else
  off(LED_BLUE);
}

А потом поменяйте условие на обратное.
Метценгерштейн
так нет реакции
Код
{
if ((GPIOA->IDR & 0x0001) != 0)
  on(LED_Blue);
else
  off(LED_Blue);
}

так
Код
{
if ((GPIOA->IDR & 0x0001) != 0)
  off(LED_Blue);
else
  on(LED_Blue);
}

загорелась сразу и горит. ничего не нажимал
Genadi Zawidowski
На нажатия должна реагировать. Пока видно, что всегда читается "0".
Цитата
Предположу, что напряжение на входе кнопки меняется от 0 до 0.8 вольта.

Тестер есть?
Метценгерштейн
инициализация прерывания верная же?
просто кнопка работает- опрашивал ее по кругу в цикле
есть и осцилл и тестер

при нажатии на кнопку, напряжение на РА0 2,97В
Genadi Zawidowski
Цитата
просто кнопка работает- опрашивал ее по кругу в цикле

Как Вы заметили, мой тест тоже опрашивает по кругу в цикле... Но нет реакции.
Инициализация прерывания на мой взгляд правильная, разбирайтесь с инициализацией кнопки.
Метценгерштейн
Код
if ( is_bit_active(KEY) )
{
  on (LED_Blue);
}

все работает- зажигается

вот дефайн
Код
#define _setL(port,bit)         do { port -> BSRRH = bit; } while(0)
    #define _setH(port,bit)         do { port -> BSRRL = bit; } while(0)
    #define _clrL(port,bit)         do { port -> BSRRL = bit; } while(0)
    #define _clrH(port,bit)         do { port -> BSRRH = bit; } while(0)
    #define _cpl(port,bit,val)         { if ((port -> ODR) & bit) _clr##val(port, bit); else _set##val(port, bit); }
    #define _bitL(port,bit)         (!((port -> IDR) & bit))
    #define _bitH(port,bit)         ((port -> IDR) & bit)
Genadi Zawidowski
Сорри, посмотрел схему... На PA0 кнопка подает "1".
Тогда смотрите? вообще работают ли прерывания. Таймерное. Закомментируйте NVIC_SetPriority
Цитата
все работает- зажигается

Я про свой код спросил. Он реагирует на кнопку?
Цитата
все работает- зажигается

Интересует, гаснет ли при отпускании кнопки.
Метценгерштейн
провел эксперимент:
в цикле зеленый LED мигает, прерывания разрешены.
как только нажимаю на кнопку, зеленый LED прекращает мигать и останавливается в одном из положений.
???

Цитата(Genadi Zawidowski @ Aug 23 2014, 22:21) *
Сорри, посмотрел схему... На PA0 кнопка подает "1".
Тогда смотрите? вообще работают ли прерывания. Таймерное. Закомментируйте NVIC_SetPriority

Я про свой код спросил. Он реагирует на кнопку?

нет, не реагирует никак. в одном случае горит, во втором случае не горит.
Genadi Zawidowski
Я бы попросил проект целиком, а не только избранные места. Откуда я знаю, кто у Вас гасит светодиод...
Метценгерштейн
https://cloud.mail.ru/public/19d1f1936da5/STM32%20F4_Pl.zip
под ИАР

ну так как? идей нет?
Genadi Zawidowski
Пока всё как у вас... Уточню:
ввод состояния PA0 работает. Прерывание срабатывают - но процессор "улетает" куда-то - скорее всего, в default функцию обработчика прерывания. Выясните, как в данной версии компилятора должна она называться.
Как посмотреть код стартапа, я не нашёл в этом компиляторе.
Ваше EXTI0_IRQHandler оно похоже не то что надо.

Даже уточню - в исходниках билиотеки нашёл только НАЧАЛО этой таблицы - не зависящие от произволителя векторы.

Поправлюсь. В Вашем каталоге есть - EXTI0_IRQHandler в Templates. Но что-то я не понял, как это подключено к Вашему проекту.
Метценгерштейн
я правильно понимаю, что у вас такая же плата?

EXTI0_IRQHandler
все так пишут- в инете смотрел другой код тоже. для F4

лампочки получается макросом включать?
Genadi Zawidowski
Плата идентичная. Лампочки работают.
Посмотрел дамп скомпилированного кода - таблица векторов имеет всего 16 элементов - значит дейчтвительно подключилась та, что о умолчанию для всех кортексов идёт. Прерывание от таймера в неё входит.
Ищите ошибку в настройках, с IAR я никогда не работал - помочь не смогу.
зы: посмотрел другие чужие проекты - там startup_stm32f4xx.s явно включён в проект. Вот например http://www.m0nka.co.uk/wp-content/uploads/...firmware181.zip
Метценгерштейн
да, спасибо, что-то с этим стартапом- с ним в прерывание входит, но зато основной цикл сразу не работает.
Genadi Zawidowski
Ловите работающий вариант. Изменённые файлы.
Метценгерштейн
уже лучше на сон )
в чем причина была?

можете весь проект прислать? ругань сплошная на файлы
Genadi Zawidowski
Ловите подкаталог пользовательской программы - в ней менялся только main.c и проект. Работающий скомпилированный файл в Debug.
Дребезг кнопки никто не давил - потому можете наблюдать странности (светодиод переключает совоё состояние в обработчике).
Метценгерштейн
вы все пути препроцессора удалили. А зачем?
http://c2n.me/iMQnYv

а можно все-таки еще раз попросить проект, который компилится без проблем?
Genadi Zawidowski
Я ничего не удалял. Поместите в Ваш проект main.c и включите указанный мной startap (версия для IAR).
Вот как эта страничка выглядит у меня.
Одномегабайтный архив firmware.zip это оно и есть. Зачем паковать то что не менялось? "облаком" не пользуюсь.
Метценгерштейн
ИАР какая версия?
да, заработало в ИАР 7.20 !
у меня чуть старее версия была- выкидывал настройки.

еще раз- что изменили, чтобы заработало?
Genadi Zawidowski
Смотрите... А что мешает самому добавить один файл в проект?
Метценгерштейн
похоже, что на 7.2 работает, а на моей нет...
разбираюсь
Genadi Zawidowski
Цитата
еще раз- что изменили, чтобы заработало?

1 - включил в проект файл стартапа (это додумался в последнюю очередь)
2 - закомментировал всё в настройке GPIOA кроме MODER (думаю, не повлияло)
3 - сделал сброс запросов прерывания правильным
4 - аккуратнее с RAISE/FALL - там что-то было с именами. Сравните.
5 - убрал содержимое цикла из main. До того у меня там мигалка была.
6 - убрал установку приоритета прерывания.
Цитата
на 7.2 работает

У меня вообще 6.7
Метценгерштейн
да, я видел, что 6.7

ваш код обработчика работает
Код
void EXTI0_IRQHandler(void)
{
  uint32_t pr = EXTI->PR & EXTI_PR_PR0;
  EXTI->PR = pr;         //сбросили бит прерывания
  cpl (LED_Blue);
}


а мой почти такой же нет.

самое интересное, а почему, когда мигалку вставляю, он не мигает?
попробуйте с мигалкой

мигалка работает, если задержка
for (i=0;i<2000000;i++){}

а если как у меня на системном таймере- то не хочет.
как-то они конфликтуют по прерываниям
Genadi Zawidowski
Что-то намудрили с использованием системных тиков. Не происходят прерывания от системного таймера.
Я вот такое использовал:

Код
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"

#include "gpio_ascold.h"
#include "hardware.h"
#include "delay.h"

void EXTI0_IRQHandler(void)
{
  uint32_t pr = EXTI->PR & EXTI_PR_PR0;
  EXTI->PR = pr;         //сбросили бит прерывания
  cpl (LED_Green);
}

#define  KEY    GPIOA, GPIO_Pin_0, H

void stall(int an)
{
  volatile int n = an;
  while (an --)
   ;
}

void main()
{
  InitPeriph();

  // настройка ноги на прерывание PA0
  GPIOA->MODER &= ~GPIO_MODER_MODER0;  //input
  //GPIOA->OTYPER &= ~GPIO_OTYPER_OT_0;  //Output push-pull
  //GPIOA->OSPEEDR |=GPIO_OSPEEDER_OSPEEDR0;  //40 MHz
  //GPIOA->PUPDR &=~GPIO_PUPDR_PUPDR0;  //No pull-up, pull-down

  ////    // настройка внешнего прерывания на PA0
  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
  SYSCFG->EXTICR [0] |= SYSCFG_EXTICR1_EXTI0_PA; // Connect EXTI line 4 to PB
  EXTI->IMR |= EXTI_IMR_MR0; // какую линию выбираем из 23-х (у нас 4-я) = EXTI4
  EXTI->FTSR |= EXTI_FTSR_TR0; // настройка реакции на спад
  //EXTI->RTSR |= EXTI_RTSR_TR0; // настройка реакции на нарастание
  NVIC_EnableIRQ(EXTI0_IRQn);  // NVIC_DisableIRQ(EXTI0_IRQn);
  //NVIC_SetPriority(EXTI0_IRQn, 1); //приоритет
  //  
  
  for (;;)
  {
     cpl (LED_Red);
     stall(10000000);
  }
}


После пары незначительных правок delay.c заработало... Откатил назад - работает. Возможно Rebuild поможет. Деление на 8 в Вашем случае лишнее. Вы же предделитель таймера не программируете на 8?

__IO - это личная собственность библиотеки. В своих программах лучше использовать volatile
Метценгерштейн
а если мне точно надо время мерять?
на другом проце, да и на этом с этим таймером все норм. работает, пока др. прерывания не происходят

да, убрал деление на 8, заработало!
давайте спать пойдем уже)
И спасибо большое за помощь! wink.gif
Genadi Zawidowski
Спокойной ночи.
Метценгерштейн
Вот что странно:
обработчик
Код
void EXTI0_IRQHandler(void)
{
  cpl (LED_Blue);
  EXTI->PR |= EXTI_PR_PR0;//сбросили бит прерывания
}

не работает лампа

а так
Код
void EXTI0_IRQHandler(void)
{
  EXTI->PR |= EXTI_PR_PR0;//сбросили бит прерывания
    cpl (LED_Blue);
}

работает.

Очень странно. Я на STM32L152 именно так и писал, и все работало. А почему тут не хочет? Почему сначала бит надо сбрасывать?
adnega
Цитата(Метценгерштейн @ Aug 24 2014, 18:01) *
Очень странно. Я на STM32L152 именно так и писал, и все работало. А почему тут не хочет? Почему сначала бит надо сбрасывать?

Тыщу раз обсуждали: прерывание вызывается два раза, т.к. сброс в самом конце обработчика.
Бит можете сбрасывать где угодно, но перед миганием нужно ПРОВЕРИТЬ установлен ли бит.
Genadi Zawidowski
Цитата
Вот что странно:
обработчик

Код
EXTI->PR |= EXTI_PR_PR0;

Вы понимаете, что приеденный Вами код сбросит ВСЕ имеющиеся запросы на прерывание, а не только 0-й?

adnega
По второму кругу обсуждаем.
Найдите десять отличий http://electronix.ru/forum/index.php?showtopic=120361,
http://electronix.ru/forum/index.php?showt...t&p=1238176, http://electronix.ru/forum/index.php?showtopic=115489
Метценгерштейн
Цитата(Genadi Zawidowski @ Aug 24 2014, 19:11) *
Код
EXTI->PR |= EXTI_PR_PR0;

Вы понимаете, что приеденный Вами код сбросит ВСЕ имеющиеся запросы на прерывание, а не только 0-й?

почему все?
я маскирую только тот бит, что EXTI_PR_PR0
т.е. я делаю
EXTI->PR = EXTI->PR | EXTI_PR_PR0;
т.е. я в регистре PR не меняя его, делаю ИЛИ по биту одному, т.е. если
PR= 0100
EXTI_PR_PR0= 0001
результат будет 0101

или что не так?

читаю отличия)

получается, что дважды прерывание вызывается? Т.к. если просто зажигать LED, то он зажигается.
Genadi Zawidowski
Цитата
почему все?

Потому, что ЗАПИСЬ единицы в соответствующий бит сбрасывает запрос.
Ну дали Вам работающий код, ну зачем игнорируете? И входил по одному разу... Если дребезг на кнопке - будет входить десятки раз за нажатие. Сброс запросов на этом не скажется.
Метценгерштейн
я просто понять хочу и разобраться. Я не игнорирую )
давайте еще раз-
вот регистр
PR
есть там какое-то число записанное до нас.
я хочу сбросить прерывание
EXTI_PR_PR0, т.е. должен записать в PR 0x00000001
а число, что там уже было до нас? Его разве не надо сохранять?
Видел просто пишут
EXTI->PR = EXTI_PR_PR0;
Genadi Zawidowski
Цитата
я хочу сбросить прерывание
EXTI_PR_PR0, т.е. должен записать в PR 0x00000001

Да, именно так (написано в даташите). Сбросится только этот бит. Примечания и условные обозначения в reference manual RM0090 смотрите.
DocID018909 Rev 7, страница 383 - про его состояние при чтении:
Цитата
0: No trigger request occurred
1: selected trigger request occurred
This bit is set when the selected edge event arrives on the external interrupt line.
This bit is cleared by programming it to ‘1’.

Метценгерштейн
другими словами, можно просто писать
EXTI->PR = EXTI_PR_PR0;
так?
нигде же не сказано, чтобы беречь другие биты.

и Ваш код корректен
EXTI->PR = EXTI->PR & EXTI_PR_PR0;
равносилен верхнему. Т.к. EXTI_PR_PR0 = 0x00000001

вывел через USART содержание EXTI->PR в момент прерывания

как только вошел, значение 0х01
очистили бит, стал 0х00

а если будет несколько прерываний, будет несколько единичек стоять в соотв. местах.
т.е. правильно писать
EXTI->PR |= EXTI_PR_PR0;
так мы накладываем маску 0x00000001 и стираем т.о. только нулевой бит.
ну разве не так?
Genadi Zawidowski
Цитата
так мы накладываем маску 0x00000001 и стираем т.о. только нулевой бит

EXTI->PR |= EXTI_PR_PR0;
стирает всё.
EXTI->PR = EXTI_PR_PR0;
Стирает только нулевой бит.

Я такой немного "извращённый" способ использую (с маскированием интересующих и записью обратно) как шаблон для случая нескольких разных обработчиков на одной функции прерывания.
Цитата
нигде же не сказано, чтобы беречь другие биты.

Если не хотите обрабатывать в других функциях - можно не беречь. Предположим у Вас ещё 4_9 биты установлены - для другого случая. Если вы их здесь сбросите, обработчик 4_9 уже не вызовется.
Метценгерштейн
давайте по шагам.
у меня сработали прерывания EXTI0 и EXTI3
регистр EXTI_PR = 0x00000009
пока верно?

дальше, зашел в обработчик EXTI0
делаю
PR= 0x00000001 (утверждаете, что сотрется только нулевой бит)
и все, потеряли мы прерывание от EXTI3!
Genadi Zawidowski
Цитата
PR= 0x00000001

Так не потеряете. А как Вы писали -
Цитата
PR |= 0x00000001

Потеряете.

По операциям:
t = PR; // 9
t = t | 1; // 9
PR = t; // 9


Метценгерштейн
увидел свою ошибку-
при |
я в регистр запишу полностью значение 0x00000009
что и приведет к очистке всех бит
да, еще раз спасибо за разъяснения wink.gif
Genadi Zawidowski
Ну да! А ведь уже говорили, что разницу увидели... пару страниц назад.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.