vp32 Napisano Kwiecień 26, 2020 Udostępnij Napisano Kwiecień 26, 2020 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.
Popularny post Elvis Kwiecień 27, 2020 Popularny post Udostępnij Kwiecień 27, 2020 (edytowany) W starszych mikrokontrolerach (oraz nowszych mikroprocesorach) opartych o rdzeń projektowany przez ARM, procedura obsługi przerwań wymagała na początku i końcu specjalnego kodu. Można go było pisać ręcznie w asemblerze, albo pozwolić wygenerować odpowiedni kod kompilatorowi - i do tego służyło dodawanie atrybutu interrupt. Architektura ARMv7-M, na której opartych jest sporo współczesnych mikrokontrolerów w tym STM32F103 wprowadziła znaczne ułatwienie dla programistów, kosztem skomplikowania sprzętu (ale widocznie krzem jest teraz tańszy niż kiedyś). Obecnie sam sprzęt zajmuje się wszystkimi niezbędnymi operacjami na początku i końcu przerwania - czyli zachowaniem stanu rejestrów oraz wyrównaniem stosu. Bit STKALIGN pozwala na wyłączenie wyrównywania stosu, wówczas kod obsługi przerwania musiałby to wykonać albo być tak skompilowany, żeby działał poprawnie bez wyrównywania. Ogólnie stos w przypadku ARM i to nie tylko ARMv7M, jest zawsze wyrównywany do wielokrotności 4 bajtów. Natomiast standard AAPCS wymaga dodatkowo, żeby podczas wywoływania procedury stos był wyrównany do wielokrotności 8 bajtów. Jeśli bit STKALIGN jest wyzerowany, sprzęt sam zajmie się wyrównaniem stosu do wielokrotności 8 i przywracaniem jego stanu po zakończeniu obsługi przerwania. W przypadku ARMv7-M atrybut interrupt jest ignorowany przez kompilator, ale może być potrzebny jeśli użyjemy mikrokontrolera lub mikroprocesora opartego o innej architekturze. Gcc potrafi kompilować kod na bardzo różne układy, stąd pewnie informacja że atrybut jest wymagany (bo czasem jest ) Edytowano Kwiecień 27, 2020 przez Elvis 3 1
vp32 Kwiecień 27, 2020 Autor tematu Udostępnij Kwiecień 27, 2020 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.
Elvis Kwiecień 27, 2020 Udostępnij Kwiecień 27, 2020 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. 1
vp32 Kwiecień 27, 2020 Autor tematu Udostępnij Kwiecień 27, 2020 (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 Kwiecień 27, 2020 przez vp32
Elvis Kwiecień 27, 2020 Udostępnij Kwiecień 27, 2020 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. 1
vp32 Kwiecień 27, 2020 Autor tematu Udostępnij Kwiecień 27, 2020 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)
Elvis Kwiecień 27, 2020 Udostępnij Kwiecień 27, 2020 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. 1 1
vp32 Kwiecień 28, 2020 Autor tematu Udostępnij Kwiecień 28, 2020 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źć.
Elvis Kwiecień 28, 2020 Udostępnij Kwiecień 28, 2020 (edytowany) 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 Kwiecień 28, 2020 przez Elvis 1 1
vp32 Kwiecień 28, 2020 Autor tematu Udostępnij Kwiecień 28, 2020 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?
Elvis Kwiecień 28, 2020 Udostępnij Kwiecień 28, 2020 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. 1
vp32 Kwiecień 30, 2020 Autor tematu Udostępnij Kwiecień 30, 2020 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.
Elvis Kwiecień 30, 2020 Udostępnij Kwiecień 30, 2020 Tak, stos musi być zawsze wyrównany do 4, czyli dwa najniższe bity mają wartość zero. Czasem musi być też wyrównywany do 8. 1
virtualny Maj 29, 2022 Udostępnij Maj 29, 2022 (edytowany) 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 Maj 29, 2022 przez virtualny 1
Pomocna odpowiedź
Bądź aktywny - zaloguj się lub utwórz konto!
Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony
Utwórz konto w ~20 sekund!
Zarejestruj nowe konto, to proste!
Zarejestruj się »Zaloguj się
Posiadasz własne konto? Użyj go!
Zaloguj się »