GPIO ustawiam:
GPIOA->CRL &= ~GPIO_CRL_CNF0_0; // floating input to pull-down
GPIOA->CRL |= GPIO_CRL_CNF0_1;Puszczam zegar do EXTI (w tym procku AFIO):
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;Zdejmuję maskę z interesujących pinów:
EXTI->IMR |= EXTI_IMR_MR0 | EXTI_IMR_MR1 | EXTI_IMR_MR2 | EXTI_IMR_MR3 | EXTI_IMR_MR4;Ustawiam reakcję na zbocze narastające:
EXTI->RTSR |= EXTI_RTSR_TR0 | EXTI_RTSR_TR1 | EXTI_RTSR_TR2 | EXTI_RTSR_TR3 | EXTI_RTSR_TR4;Dodaję priorytety przerwania i uruchamiam przerwania (tu tylko po jednym żeby nie mnożyć):
NVIC_SetPriority(EXTI0_IRQn, 1);
NVIC_EnableIRQ(EXTI0_IRQn);Przykładowe przerwanie:
__attribute__((section(".after_vectors"))) void EXTI0_IRQHandler()
{
printf("++ \r\n");
EXTI->PR |= EXTI_PR_PR0;
}
Co bym nie robił tak działa tylko jedno przerwanie i to z PA2. Wiązać pinów z EXTI niby nie muszę (po resecie akurat się zgrywają), ale robię to dla pewności, nie widzę już gdzie szukać. W komentarzu dla czytelności wrzucam cały kod okrojony do obsługi EXTI.
Co mogę robić źle albo gdzie szukać? Do debugowania mam UART i LEDa ( ͡° ͜ʖ ͡°)
#stm32 #embedded #programowanie #baremetal
static void gpio_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// BUT_CANC (PA0)
GPIOA->CRL &= ~GPIO_CRL_CNF0_0; // floating input to pull-down
GPIOA->CRL |= GPIO_CRL_CNF0_1;
// (PA1)
GPIOA->CRL &= ~GPIO_CRL_CNF1_0; // floating input to pull-down
GPIOA->CRL |= GPIO_CRL_CNF1_1;
// (PA2)
GPIOA->CRL &= ~GPIO_CRL_CNF2_0; // floating input to pull-down
GPIOA->CRL |= GPIO_CRL_CNF2_1;
// (PA3)
GPIOA->CRL &= ~GPIO_CRL_CNF3_0; // floating input to pull-down
GPIOA->CRL |= GPIO_CRL_CNF3_1;
// (PA4)
GPIOA->CRL &= ~GPIO_CRL_CNF4_0; // floating input to pull-down
GPIOA->CRL |= GPIO_CRL_CNF4_1;
}
static void exti_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
EXTI->IMR |= EXTI_IMR_MR0 | EXTI_IMR_MR1 | EXTI_IMR_MR2 | EXTI_IMR_MR3 | EXTI_IMR_MR4;
EXTI->RTSR |= EXTI_RTSR_TR0 | EXTI_RTSR_TR1 | EXTI_RTSR_TR2 | EXTI_RTSR_TR3 | EXTI_RTSR_TR4;
// connect pin to interrupt
AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA;
AFIO->EXTICR[1] |= AFIO_EXTICR1_EXTI1_PA;
AFIO->EXTICR[2] |= AFIO_EXTICR1_EXTI2_PA;
AFIO->EXTICR[3] |= AFIO_EXTICR1_EXTI3_PA;
AFIO->EXTICR[0] |= AFIO_EXTICR2_EXTI4_PA;
NVIC_SetPriority(EXTI0_IRQn, 1);
NVIC_SetPriority(EXTI1_IRQn, 2);
NVIC_SetPriority(EXTI2_IRQn, 2);
NVIC_SetPriority(EXTI3_IRQn, 1);
NVIC_SetPriority(EXTI4_IRQn, 1);
NVIC_EnableIRQ(EXTI0_IRQn);
NVIC_EnableIRQ(EXTI1_IRQn);
NVIC_EnableIRQ(EXTI2_IRQn);
NVIC_EnableIRQ(EXTI3_IRQn);
NVIC_EnableIRQ(EXTI4_IRQn);
}
__attribute__((section(".after_vectors"))) void EXTI0_IRQHandler()
{
EXTI->PR |= EXTI_PR_PR0;
}
__attribute__((section(".after_vectors"))) void EXTI1_IRQHandler()
{
EXTI->PR |= EXTI_PR_PR1;
}
__attribute__((section(".after_vectors"))) void EXTI2_IRQHandler()
{
EXTI->PR |= EXTI_PR_PR2;
}
__attribute__((section(".after_vectors"))) void EXTI3_IRQHandler()
{
EXTI->PR |= EXTI_PR_PR3;
}
__attribute__((section(".after_vectors"))) void EXTI4_IRQHandler()
{
EXTI->PR |= EXTI_PR_PR4;
}
Mam nadzieję, że formatowanie przetrwa.
Nie zeby to cos zmienilo (bo to wszystko sa zera) ale EXTI0...3 sa w AFIO->EXTICR[0] a EXTI4 w AFIO->EXTICR[1].
W ramach debugowania sprobuj wywolac przerwanie programowe ustawiajac bity w rejestrze EXTI->SWIER. To pomoze Ci znalezc czy problem jest po stronie EXTI / NVIC / CPU czy konfiguracji GPIO. Sprawdz tez, prosta petla, czy czytanie pinu GPIO i pokazywanie go na LEDzie dziala dla wszystkich pieciu. Najgorzej jest spedzic wieczor debugujac program jak problem jest sprzetowy.
@Skylark dzięki. Jutrzejsze popołudnie zapowiada się zatem pod znakiem debugu, oby skutecznego.
EXTICR[0] i EXTICR[1] próbowałem wcześniej, ale też nie chodziło. Nie zapuściłem żadnego SVN, to tak zostało : )
Jak na razie spędziłem kilka dobrych posiedzeń nad szukaniem przyczyny całkowitego niedziałania nawet zwykłego blinky, a wyszło że to był jakiś pokopany CMSIS, choć wprost pobrany ze źródła.
@Skylark przerwania programowanie wywołują się. Problem polega na tym, że na dwóch pinach zamiast 3V3 z pullupa rezystorem 10k pojawia mi się jedynie 0,7 V. Poprawiałem na nich diody, a że są w obudowie SOD323, to może jedną - dwie odwrotnie wlutowałem. Napięcie pasuje ładnie do złącza p-n.
No albo coś w kodzie, ale przy ctrl+c/v to raczej nie powinno tak się stać.
To kara za obsługę przycisków na przerwaniach ( ͡° ͜ʖ ͡°)
@cec trzy z pięciu są dość kluczowe do działania tego przyrządu, więc zależy mi na szybkim ich zadziałaniu. Zostają dwa, które w sumie też można wrzucić do jednego wora i mieć spokój
@macgajster miłej zabawy z drgającymi stykami ¯\_( ͡° ͜ʖ ͡°)_/¯
Takie rzeczy się robi na przerwaniu od timera. Co 5 - 10 ms timer odpala przerwanie i w nim sprawdzasz czy przycisk był naciśnięty przez kilka cykli po zmianie stanu. Jeśli tak to wywołujesz funkcje onButton i ustawiasz jakiś "cooldown", żeby nie odpaliła się kilka razy przy jednym naciśnięciu.
Obsługa przycisku na przerwaniu wymaga kasowania flagi przerwania przed wyjściem z niego i pewnie jakiegoś dodatkowego timera albo delaya, żeby obsługa przerwania nie wywołała się kilka razy.
P.S. daj znać czy udało się odpalić pozostałe przerwania.
@cec teraz jak toś napisał to ja nie wiem czy chcę na EXTI : D
(coś tam o drgających stykach pamiętałem, ale nic konkretnego, więc zrobiłem jak zrobiłem)
@cec bardziej dla sportu uruchomiłem 3 z 4 niedziałających przycisków. Jak pisałem wcześniej - diody zabezpieczające coś kiełbasiły, więc problem sprzętowy. Co ciekawe na ostatnim niedziałającym diody już nie ma, a wciąż dostaję 0,7 V jeśli mam podłączoną płytkę-klawiaturę. Jak klawiatura jest luzem to na niej jest 3V3. Z kolei zwieranie bezpośrednio pinów nawet z dołączoną klawiaturą też działa. Zostaje do dalszego prześledzenia.
Debouncing w sumie mogłem zrobić bardziej sprzętowy, no ale już nie da się ładnie, więc nie będę kładł kynaru. Na trzech przyciskach na pewno się przyda opcja kodem pisana (mam funkcje zwiększ, zmniejsz i anuluj, przy czym anuluj kliknięte dwukrotnie mam zamiar wykorzystać do ustawienia z góry założonej wartości). Na pozostałych dwóch zależy mi tylko na tym żeby złapało wciśnięcie, bo to wyłączniki awaryjne, więc brzydko na EXTI mogę zostawić i mieć w przerwaniu z wysokim priorytetem.
Zaloguj się aby komentować