Skocz do zawartości

STM32 C, problem z przerwaniem we własnej bibliotece


Majk32

Pomocna odpowiedź

Cześć

piszę własną bibliotekę, trochę na bazie HAL ale uproszczoną i zoptymalizowaną, język: C++. W pliku serial.cpp zdefiniowałem klasę SerialInterface z podstawową obsługą portu, to jest OK - ślady kodu są widoczne w wynikowym kodzie (plik .list)

 /* USER CODE BEGIN WHILE */
  SerialInterface tty0(USART2, 9600);
 800022a:	463b      	mov	r3, r7
 800022c:	f44f 5216 	mov.w	r2, #9600	; 0x2580
 8000230:	4904      	ldr	r1, [pc, #16]	; (8000244 <main+0x2c>)
 8000232:	4618      	mov	r0, r3
 8000234:	f001 fa06 	bl	8001644 <_ZN15SerialInterfaceC1EP13USART_TypeDefm>
  while (1){
//	  	  if (tty0.getReceived()>5)
//	  		  tty0.sendByte('X');
//	  	  else if (tty0.getReceived()>0)
//	  		  tty0.sendByte('L');
	  	  tty0.sendByte('-');
 8000238:	463b      	mov	r3, r7
 800023a:	212d      	movs	r1, #45	; 0x2d
 800023c:	4618      	mov	r0, r3
 800023e:	f001 fa3f 	bl	80016c0 <_ZN15SerialInterface8sendByteEh>
 8000242:	e7f9      	b.n	8000238 <main+0x20>

Oprócz klasy, w pliku serial.cpp zdefiniowałem obsługę przerwania, funkcję USART2_IRQHandler jako:

void USART2_IRQHandler(void){....}

no i ta funkcja nie pojawia się już w listingu nie pojawia. Program testowy w pętli wysyła znaki, zgodnie z oczekiwaniem:

(...)
SerialInterface tty0(USART2, 9600);

  while (1){
	  	  tty0.sendByte('-');
  }
  /* USER CODE END 3 */
}
(...)

jednak po odebraniu znaku "z zewnątrz" wysypuje się -> na debuggerze widzę, że następuje skok do obsługi nieznanego przerwania (👉Default_Handler), czyli faktycznie jakby linker połączył tylko część mojej biblioteki?? (plik startup_stm32g431kbtx.s w którym "ląduje" procesor, zawartość jest defaultowa, nie grzebane) :

/**
 * @brief  This is the code that gets called when the processor receives an
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
*/
    .section	.text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
	b	Infinite_Loop <--- SKOK TUTAJ
	.size	Default_Handler, .-Default_Handler


Jak spowodować, aby linker dołączył moją obsługę IRQ? W CubeMX nie wyklikałem konfiguracji, żeby nie tworzył mi swoich "śmieci" z HAL, które są dalekie od optymalnych. Obsługa przerwania w oryginalnym HAL trwa wieki, a piszę aplikację wymagającą bardzo krótkich i sprawnych przerwań.

Ktoś poradzi?

Edytowano przez Majk32
bo tak
Link do komentarza
Share on other sites

Może dodam, że manewr z "własną" funkcją obsługi przerwania działa, pod warunkiem, że jest to w ramach jednego projektu - tzn. jak dorzucę USART2_IRQHandler do pliku main.c, problemy są po wyniesieniu obsługi USART do biblioteki....

Link do komentarza
Share on other sites

37 minut temu, Elvis napisał:

Zgaduję, że to nie przenoszenie do jednego pliku jest kluczowe, ale z pliku .cpp do .c

@Majk32 Czy Twoja procedura obsługi przerwań zlokalizowana w *cpp, którą chcesz wołać w *c, posiada deklarację extern "C"...
https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c
 

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)
5 godzin temu, Elvis napisał:

Zgaduję, że to nie przenoszenie do jednego pliku jest kluczowe, ale z pliku .cpp do .c

Z rozpędu napisałem - już uściślam. Oba projekty, zarówno libka jak i aplikacja testowa są w projekcie C++ (main.cpp). Przynajmniej tak zaznaczyłem tworząc projekt, bo po plikach generowanych przez Cube tego nie widać, i z domyślnego pliku main.c musiałem zrobić main.cpp, bo pomimo wspomnianych ustawień projektu kompilator traktował to jak C. (Tak mi się wydaje, bo się wywalał przy definicji klasy itp)
 

4 godziny temu, ReniferRudolf napisał:

@Majk32 Czy Twoja procedura obsługi przerwań zlokalizowana w *cpp, którą chcesz wołać w *c, posiada deklarację extern "C"...
https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c
 

O, chyba to trzeba sprawdzić!

 

EDIT:: Działa! Dzięki @ReniferRudolf

08001630 <USART2_IRQHandler>:
extern "C" void USART2_IRQHandler(){
 8001630:	b508      	push	{r3, lr}
	if ((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE){
 8001632:	4b1c      	ldr	r3, [pc, #112]	; (80016a4 <USART2_IRQHandler+0x74>)
 8001634:	69db      	ldr	r3, [r3, #28]
 8001636:	f013 0f20 	tst.w	r3, #32
 800163a:	d10e      	bne.n	800165a <USART2_IRQHandler+0x2a>
	if (((USART2->CR1 & (FLAGS_TXE)) == (FLAGS_TXE)) &&
 800163c:	4b19      	ldr	r3, [pc, #100]	; (80016a4 <USART2_IRQHandler+0x74>)
 800163e:	681b      	ldr	r3, [r3, #0]
 8001640:	f003 0389 	and.w	r3, r3, #137	; 0x89
 8001644:	2b89      	cmp	r3, #137	; 0x89
 8001646:	d014      	beq.n	8001672 <USART2_IRQHandler+0x42>
	if ((USART2->ISR & USART_ISR_ORE)==USART_ISR_ORE)
 8001648:	4b16      	ldr	r3, [pc, #88]	; (80016a4 <USART2_IRQHandler+0x74>)
 800164a:	69db      	ldr	r3, [r3, #28]
 800164c:	f013 0f08 	tst.w	r3, #8
 8001650:	d002      	beq.n	8001658 <USART2_IRQHandler+0x28>
		USART2->ICR = USART_ICR_ORECF;
 8001652:	4b14      	ldr	r3, [pc, #80]	; (80016a4 <USART2_IRQHandler+0x74>)
 8001654:	2208      	movs	r2, #8
 8001656:	621a      	str	r2, [r3, #32]
}
 8001658:	bd08      	pop	{r3, pc}
		if (rxbuff.getQty())
 800165a:	4813      	ldr	r0, [pc, #76]	; (80016a8 <USART2_IRQHandler+0x78>)
 800165c:	f000 f887 	bl	800176e <_ZN14CircularBuffer6getQtyEv>
 8001660:	2800      	cmp	r0, #0
 8001662:	d0eb      	beq.n	800163c <USART2_IRQHandler+0xc>
			rxbuff.write(USART2->RDR);
 8001664:	4b0f      	ldr	r3, [pc, #60]	; (80016a4 <USART2_IRQHandler+0x74>)
 8001666:	6a59      	ldr	r1, [r3, #36]	; 0x24
 8001668:	b2c9      	uxtb	r1, r1
 800166a:	480f      	ldr	r0, [pc, #60]	; (80016a8 <USART2_IRQHandler+0x78>)
 800166c:	f000 f897 	bl	800179e <_ZN14CircularBuffer5writeEh>
 8001670:	e7e4      	b.n	800163c <USART2_IRQHandler+0xc>
		((USART2->ISR & USART_ISR_TXE) == USART_ISR_TXE)){
 8001672:	4b0c      	ldr	r3, [pc, #48]	; (80016a4 <USART2_IRQHandler+0x74>)
 8001674:	69db      	ldr	r3, [r3, #28]
	if (((USART2->CR1 & (FLAGS_TXE)) == (FLAGS_TXE)) &&
 8001676:	f013 0f80 	tst.w	r3, #128	; 0x80
 800167a:	d0e5      	beq.n	8001648 <USART2_IRQHandler+0x18>
		if (txbuff.getQty())										// if still buffer not sent
 800167c:	480b      	ldr	r0, [pc, #44]	; (80016ac <USART2_IRQHandler+0x7c>)
 800167e:	f000 f876 	bl	800176e <_ZN14CircularBuffer6getQtyEv>
 8001682:	b948      	cbnz	r0, 8001698 <USART2_IRQHandler+0x68>
		else if (USART2->ISR && USART_ISR_TC)						// if buffer sent, disable transmitter and IRQ
 8001684:	4b07      	ldr	r3, [pc, #28]	; (80016a4 <USART2_IRQHandler+0x74>)
 8001686:	69db      	ldr	r3, [r3, #28]
 8001688:	2b00      	cmp	r3, #0
 800168a:	d0dd      	beq.n	8001648 <USART2_IRQHandler+0x18>
			USART2->CR1 &= ~(USART_CR1_TE | USART_CR1_TXEIE);
 800168c:	4a05      	ldr	r2, [pc, #20]	; (80016a4 <USART2_IRQHandler+0x74>)
 800168e:	6813      	ldr	r3, [r2, #0]
 8001690:	f023 0388 	bic.w	r3, r3, #136	; 0x88
 8001694:	6013      	str	r3, [r2, #0]
 8001696:	e7d7      	b.n	8001648 <USART2_IRQHandler+0x18>
			USART2->TDR = txbuff.read();
 8001698:	4804      	ldr	r0, [pc, #16]	; (80016ac <USART2_IRQHandler+0x7c>)
 800169a:	f000 f86a 	bl	8001772 <_ZN14CircularBuffer4readEv>
 800169e:	4b01      	ldr	r3, [pc, #4]	; (80016a4 <USART2_IRQHandler+0x74>)
 80016a0:	6298      	str	r0, [r3, #40]	; 0x28
 80016a2:	e7d1      	b.n	8001648 <USART2_IRQHandler+0x18>
 80016a4:	40004400 	.word	0x40004400
 80016a8:	2000002c 	.word	0x2000002c
 80016ac:	2000013c 	.word	0x2000013c

 

Edytowano przez Majk32
Link do komentarza
Share on other sites

Nie jestem biegły w mixowaniu C z C++, takie połowiczne rozwiązanie to można zrobić tak, że cały działający projekt skompilujesz do biblioteki. O ile wiem funkcje w bibliotece są WEAK, więc potem będziesz używał tylko funkcji z biblioteki, a każda inna, którą zadeklarujesz w kodzie unieważni funkcje skompilowane w bibliotece. Trudno robić coś extremalnie optymalnego w bibliotece - przekonał się mój przyjaciel (i poległ), który moją bibliotekę vectordotów usiłował przerabiać na bibliotekę zgodną ze sztuką... kiedy czas stawiania vectordota jest krytyczny nie ma miejsca na konwenanse czy Application Procedure Call Standard.

 

  • Lubię! 1
Link do komentarza
Share on other sites

9 minut temu, virtualny napisał:

(...) takie połowiczne rozwiązanie to można zrobić tak, że cały działający projekt skompilujesz do biblioteki. O ile wiem funkcje w bibliotece są WEAK, więc potem będziesz używał tylko funkcji z biblioteki, a każda inna, którą zadeklarujesz w kodzie unieważni funkcje skompilowane w bibliotece. (...)

No tak, ale... sensem tworzenia biblioteki jest przede wszystkim jej uniwersalność, żeby dało się ją wykorzystać w wielu projektach - oszczędzając czas.

Na szczęście extern "C" zadziałał. Człowiek się uczy całe życie...

  • Lubię! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.