Skocz do zawartości

Stack Aligment w STM32 - o co z tym chodzi?


vp32

Pomocna odpowiedź

Cześć

Próbuję zrozumieć co to jest stack aligment w tych uC i związany z tym bit STKALIGN  w rejestrze SCB->CCR

O co ogólnie chodzi z tym wyrównaniem  podczas wchodzenia do przerwania

Druga sprawa to (w związku z tym wyrównaniem) dodawanie atrybutu interrupt do nazwy przerwania np

__attribute__((interrupt)) void TIM3_IRQHandler(void) {}

 

Podobno dla gcc i STM32F103 jest to konieczne ale pliki generowane prze CubeMX lub CubeIDE tego nie dopisują?

PS. do rewizji jeszcze dojdę z pytaniem za chwile, ale najpierw po kolei zakładając ze mam przy sobie jakiś procek ze starą rewizją. 🙂  Tak coś doczytałem 🙂 ale widać nie do końca.

 

Link do komentarza
Share on other sites

Wytłumacz mi jak możesz jakoś prosto po co to wyrównywanie stosu i co to w ogóle znaczy? Standard to jedno ale to ma czemuś służyć, czemu?

Sprawdziłem, ten atrybut nie jest ignorowany przez GCC. dodaje parę linii kodu na początku i na końcu przerwania.

Link do komentarza
Share on other sites

Wyrównywanie oznacza, że wszystkie dane mają adresy podzielne przez pewną liczbę np. przez 4, albo przez 8. Dlaczego w AAPCS wybrano 8 tego nie wiem, bo dla 32-bitowego układu teoretycznie powinno wystarczyć 4. Możliwe że chodzi o to że niektóre instrukcje działają szybciej jeśli adres jest podzielny przez 8, a może o zgodność z 64-bitowymi układami? Nie znam dokładnego wyjaśnienia, ale ze standardami jest tak, że trzeba przestrzegać, nawet jeśli nie wszystko się o nich wie.

Co do tego kodu generowanego przez kompilator to prawdopodobnie jest niepotrzebny, bo już sam sprzęt zapewni odpowiednie wyrównywanie - ale wyrównanie już wyrównanego stosu nic nie popsuje, chociaż zmarnuje trochę czasu i pamięci. W sumie nawet ciekawe co ten kod robi, możesz go przeanalizować i opisać, zawsze się czegoś nowego dowiemy.

  • Lubię! 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)

Sprzętowe wyrównanie jest od którejś tam rewizji r1p0 chyba ale w r0p0 w ogóle jej już nie ma więc sprzęp nie wyrówna. Co wtedy się dzieje i w ogóle co będzie jak nie będzie tego wyrwnania?

funkcja oryginalna

void SysTick_Handler(void)
{
HAL_IncTick();
 }

 

i po wygenerowaniu asm

         

 SysTick_Handler:
08000be8:   push    {r7, lr}
08000bea:   add     r7, sp, #0
187         HAL_IncTick();
08000bec:   bl      0x8000d34 <HAL_IncTick>
191       }
08000bf0:   nop     
08000bf2:   pop     {r7, pc}

A teraz po dopisaniu atrybutu interrpt

 __attribute__((interrupt))  void SysTick_Handler(void)
{
  HAL_IncTick();
}

 

 

po wygenerowaniu asm
    

 SysTick_Handler:
08000be8:   mov     r0, sp
08000bea:   bic.w   r1, r0, #7
08000bee:   mov     sp, r1
08000bf0:   push    {r0, r3, r7, lr}
08000bf2:   add     r7, sp, #0
187         HAL_IncTick();
08000bf4:   bl      0x8000d44 <HAL_IncTick>
191       }

08000bf8:   nop     
08000bfa:   mov     sp, r7
08000bfc:   ldmia.w sp!, {r0, r3, r7, lr}
08000c00:   mov     sp, r0
08000c02:   bx      lr

 

To samo jest dla każdego przerwania. mam tu SysTick bo w CubeIDE od razu po wygenerowaniu kodu działa przewanie

Edytowano przez vp32
Link do komentarza
Share on other sites

Jak nie wyrówna to mogą być błędy, bo kompilator zakłada zgodnie ze standardem że stos przy wywołaniu funkcji jest wyrównany do 8. Więc jeśli nie jest to może (ale nie musi) się coś popsuć. Nie wiem na której rewizji bazuje f103, trzeba sprawdzić, ale wątpię żeby to wyrównywanie było potrzebne - nawet na stronach ARM-a piszą że nie jest i atrybut nie ma znaczenia.

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

Z tego co doczytałem z datasheet STM32F103C8 bazuje na 3 rewizjach, piszą że można to odczytać z obudowy (ale nie mogę dojść o czym mówią tak zamieszali to kodowanie) oraz można odczytać rejestr SCB->CPUID, więc mogą się zdarzyć pierwsze wersje

Gdzie znalazłeś opis tego atrybutu na stronach ARM. Może o to Ci chodzi, bo ja znalazłem coś takiego

Support of a 4-byte aligned stack (CCR.STKALIGN == ’0’) in ARMv7-M is deprecated

PS. nie do końca również rozumiem ich skrót myślowy (patrząc po debugerze ten bit zawsze jest zero)

Link do komentarza
Share on other sites

Może mi się pomyliło, w każdym razie na stronie gcc jest:

"On ARMv7-M the interrupt type is ignored, and the attribute means the function may be called with a word-aligned stack pointer."

https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html

A na ARM muszę poszukać, bo tam było chyba więcej sprzeczności (raz że potrzebny, innym razem że nie)

Na stronie ARM: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0774g/vvi1465810473505.html

"In ARMv6-M, ARMv7-M, and ARMv8-M, the architectural exception handling mechanism preserves all processor registers, and a standard function return can cause an exception return. Therefore, specifying the interrupt attribute does not affect the behavior of the compiled output. However, ARM recommends using the interrupt attribute on exception handlers for clarity and easier software porting."

Chociaż z tym gcc to chyba zły fragment - nie da się na szybko odpowiadać 🙂 W każdym razie wpisanie w google attribute interrupt zwraca dość rozbieżne wyniki. Natomiast zgodnie z opisem np. w programming manual, na cortex-m3 sprzęt powinien obsługiwać wyrównywanie do 8.

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

Tak ogólnie to trochę zacząłem szukać bo wydaje mi się że temat dość istotny (chyba) a raczej przemilczany. Nie udało mi się znaleźć informacji co się stanie jak nie będzie tego wyrównania, kiedy mogę to sprawdzić  i się "przejechać" na tym.

Druga sprawa ten atrybut interrupt wyrównujący stos przy przerwaniu. Przecież na stos jest odkładane kilka rejestrów sprzętowo zanim zostanie wykonany kod przerwania, więc jaki jest sens wyrównywać stos po odłożeniu na nim czegoś co powinno zostać wyrównane przed początkiem odkładania. To nie AVRy gdzie trzeba było to robić ręcznie.

Wg opisu w technical reference jeśli bit STKALIGN jest ustawiony to uC przy wchodzeniu do przerwania sam wyrównuje stos ale jednocześnie w rejestrze xPSR ustawia bit 9 informując że wyrównał stos. natomiast  wg dokumentacji STM32f103 ten it w xPSR jest zarezerwowany, nie ma takiego bitu.

 

PS. taka prośba od innej strony. próbuje pozbierać dokumantacje od ARM na temat rdzenia i natknąłem sie na mur pewny, może mi pomożesz. Jakie są nazwy doakumentyów opisujących całość łacznie z podziałem na referencje, bo są

Technical Reference Manual Cortex-M3 z podziałem na rewizje

Generic User Guide Cortex-M3 Devices tu chyba bez rewizji

 

Architecture Reference Manual Armv7-M tu też chyba bez rewizji (popraw jeśli się mylę)

Ale wydaje mi się że powinno byc jeszcze Technical Reference Manual ARMv7-M i Architecture Reference Manual Cortex-M3? tych nie moge znaleźć.

 

 

Link do komentarza
Share on other sites

Nie wnikałem tak bardzo w wyrównywanie stosu na stm32, bo jak chodzi o tak niskopoziomowe programowanie zajmuję się cortex-a, a nie cortex-m. W każdym razie bardzo wątpię, żeby to co próbujesz zrobić było problemem. Przeczytaj sobie chociażby programming manual od stm32f10x: https://www.st.com/resource/en/programming_manual/cd00228163-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf

"Unless stack alignment is disabled, the stack frame is aligned to a double-word address. If the STKALIGN bit of the Configuration Control Register (CCR) is set to 1, stack align adjustment is performed during stacking."

Czyli jeśli nie wyłączyłeś wyrównywania to działa - a jak nie to zgłoś do ST że mają błąd.

Wyrównywanie stosu oczywiście ma sens. Sprzętowo odkładane są rejestry, stos jest wyrównywany do 4, rejestry mają po 4 bajty, więc wszystko jest ok. Problemem jest dopiero kompilator. W przypadku cortex-a procedura obsługi przerwania jest pisana w asemblerze i wtedy wyrównanie do 4 jest wystarczające. Natomiast w przypadku cortex-m, procedury obsługiwania najczęściej pisze się w C, a kompilator zakłada że stos podczas wywołania jest wyrównany do 8. Jeśli nie jest to wygenerowany kod może działać niepoprawnie. 

Nie znajdziesz raczej opisów kiedy taki kod powstaje bo to zależy od wszystkiego - wersji kompilatora, bibliotek, ustawień itd. Najmniejsza zmiana i możesz dostać odrobinę inny kod wynikowy, który już będzie działał.

Ale żeby wyjaśnić na czym polega problem, wyobraźmy sobie następujący zupełnie sztuczny przykład. Mamy dwie zmienne lokalne, czyli jak wiemy zapisane na stosie, powiedzmy:

uint32_t x,y;

Teraz kompilator generuje kod odczytu powiedzmy x

ldr r0, =<adr_x>

Teraz można sobie do tego x pisać, czytać itd. wykorzystując adres zmiennej zapisany w rejestrze r0. Ale jak kod będzie chciał odwołać się do y, to musi obliczyć adres. Pewnie zrobiłby to inaczej, ale załóżmy że na danym systemie najszybciej działają proste operacje bitowe. Skoro kompilator zakłada, że stos jest wyrównywany do 8, więc adres zmiennej x ma najniższe bity równe 0. Mógłby więc wygenerować taki kod:

orr r1, r0, #4

Czyli do r1 wpisać (r0 or 4) - to zadziałą poprawnie jeśli x będzie miał adres wyrównany do 8, a po nim będzie y. Ale jeśli stos będzie wyrównany do 4, ten sam kod już zadziała źle.

To oczywiście absolutnie sztuczny przykład, ale chodziło mi o pokazanie na czym polega problem - kompilator, albo raczej optymalizator zakłada że stos jest wyrównany do 8. Może więc wygenerować dziwny, ale optymalny kod, który działa tylko wtedy. A jeśli nie będzie wyrównywania to wszystko się posypie.

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

Z lektury PM0056 po części narodziły się pytania i wątpliwości.

Aby nie było problemów z działaniem przerwań wyrównanie powinno być włączone poprzez ustawienie na 1  bitu STKALIGN. Tylko w debugerze widać że ten bit jest cały czas wyzerowany. Nawet STMCubeMX go nie ustawia przy inicjacji. Co prawda ARM pisze że wartość początkowa (po resecie) tego bitu powinna być 1 (tak zaleca) to nawet w uC które mają najnowszą rewizję ten bit jest zero.

Ciekawe czy jakbym sam na starcie ustawił ten bit (pomimo że sami programiści STM pisząc kod do wygenerowania tego nie robią) to byłby jakiś błąd a może to nie ma zupełnie znaczenia.

Szkoda że nic na ten temat STM nie pisze.

 

Jeszcze jedna taka sprawa. A może dwie. 1. Chcę się upewnić czy dobrze rozumiem. to wyrównanie do 8 bitów czy 4 bajtów oznacza że adres w SP wskazujący na wierzchołek stosu jest odpowiednio wielokrotnością bajta, np wyrównanie oznacza adres w SP = 0x23FFFFE0.  i 2. czy to nie jest tak że adres SP zawsze jest zwiększany o 4 bo dostęp do stosu jest zawsze 4 bajtowy?

 

Link do komentarza
Share on other sites

Może po prostu przetestuj, wtedy będziesz wiedział czy poprawnie wyrównuje, czy nie. Z tego co piszą o cortex-m powinno działać, ale może faktycznie ktoś, czegoś nie dopilnował i jest błąd - w sumie nie pierwszy i nie ostatni w bibliotekach.

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

A czy to prawda że adresy w SP nie mogą być dowolnymi adresami. Mówię tak ogólnie o wpisywaniu adresu do SP.

Bo zauważyłem że nie da się wpisać do SP dowolnej wartości, zawsze LSB jest zero na dwóch pozycjach tj. .........00

Szukałem czy jest gdzieś o tym napisane w dokumentacji ale nie znalazłem.

Link do komentarza
Share on other sites

Sorry za dwuletni offtop, ale właśnie przeglądam poradnik Szczywronka i sam zacząłem się zastanawiać i guglować dlaczego w swoich przykładach do STM32F103 w przerwaniach używa atrybutu __attribute__((interrupt)) skoro niby sam ARM się stakuje (stack allignment). Trafiłem tutaj, w końcu też do dodatku nr 5 poradnika Szczywronka. Raczej nie wniosę nic nowego, ale wywiedziałem się z tutejszej dyskusji i Poradnika Szczywronka że to jest zależne od wersji rdzenia, ponieważ jest ona dość długa i zawiła to zamieszczam sedno:

Cytat

Ale czy warto wydłużać niepotrzebnie kod ISR, skoro procesor może zrobić to samo sprzętowo?


           Rdzenie oznaczone są przez numer „rewizji” i „pod rewizji” np. r1p2. To jaki mamy rdzeń można odczytać z obudowy scalaczka (jak dekodować info poczytaj np. w erracie STMa) lub debuggerem z procesora: rejestr pod adresem 0xe000 ed00. Przypominam (ale proszę sobie doszukać, bo nie jestem pewien na mur beton):

  •  od rewizji r1 wyrównywanie sprzętowe jest dostępne, ale domyślnie wyłączone
  •  od rewizji r2 wyrównywanie sprzętowe jest domyślnie włączone

Decyzję o tym czy stosować atrybut, czy też nie, pozostawiam Czytelnikowi. W ramach dmuchania na zimne, szczególnie na początku edukacji STMowej, proponuję go zostawić.

 

Edytowano przez virtualny
  • 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.