Spørsmål:
Påvirkes `millis ()` av lange ISR-er?
Anonymous Penguin
2014-09-29 07:49:44 UTC
view on stackexchange narkive permalink

Jeg har et prosjekt som bruker tidtakere og avbryter ofte. Mye CPU-tid blir brukt på å håndtere ISR-er over en lengre periode.

Ville dette påvirke koden i hovedsløyfen som er avhengig av millis () -funksjonen siden det brukes mye tid på å behandle ISR-ene ?

Også, alt basert på millis () vil også mislykkes? Jeg tror det (nye programvarebaserte) servobiblioteket og kanskje til og med programvare (?) Kan også få timingproblemer? Selv om jeg ikke er sikker på om de begge er basert på det.
Tre svar:
Anonymous Penguin
2014-09-29 07:49:44 UTC
view on stackexchange narkive permalink

Etter litt graving rundt i kjernen ser det ut til at Arduino oppdaterer millis () med en 8-biters timer: den bruker overflow med en prescaler-verdi på 64. I enklere termer har den satt opp slik at et bestemt stykke kode (ISR) kjøres omtrent en gang per millisekund på et 16MHz system (og proporsjonalt sjeldnere på langsommere klokket system).

Når den ISR kjøres, øker den en variabel som brukes av millis () -funksjonen.

Så selv om noen ikke-avbrytbar kode kjøres i en brøkdel av et millisekund, vil det ikke ha noe å si siden biten for den avbruddsvektoren vil fremdeles forbli satt.

Det er imidlertid et problem når ISR kjøres sjeldnere enn den skulle utløses. Dette kan være et resultat av å bruke noInterrupts () over lengre tid, eller når for mange andre avbrudd kjøres og det ikke er nok CPU for alle oppgavene. Hvis mange av de andre ISR-ene har høyere avbrytingsprioriteter , er det mulig at koden for millis () kanskje ikke kjøres. I dette tilfellet vil du ha mer alvorlige problemer enn dette, men det er noe du må huske på når du skriver kode.

Den generelle tommelfingerregelen for ISR-er gjelder fortsatt: hold den kort !!!

Merk: Hvis du trenger ekstrem nøyaktighet, er den innebygde funksjonen ikke det beste valget. En RTC er en god ide for langsiktig tidsoppbevaring.

Jeg tror du kan ha avbrudd, avbryte andre avbrudd-rutiner (ved å ringe `sei ()` inne i `ISR`). Men det er en glatt skråning. F.eks. minneoverløp kan skje mye raskere.
`micros ()` ser ut til å ha det samme problemet, og ga i min test samme feil tid som `millis ()`.
Problemet er ikke begrenset til ISR-er. [Skriv () -funksjonen] (https://github.com/adafruit/Adafruit_TLC59711/blob/master/Adafruit_TLC59711.cpp#L63) i Adafruit's TLC59711-bibliotek deaktiverer avbrudd i muligens mange millisekunder, og forårsaker mitt første forsøk på å time denne funksjonen ved å bruke `micros ()` for å mislykkes.
@UlrichStern, Tehee, adafruit får deg til å tro at biblioteket deres er super raskt, ved å stoppe din "timing benchmark"; D
@Paul, da timingen av Adafruits bibliotek økte returverdien til `micros ()` fortsatt nok til at kjøretiden ikke var åpenbart feil, og jeg ble lurt en stund. :) (Adafruit deaktiverte ikke avbrudd for å lure meg, tror jeg, se bibliotekets [Wiki] (https://github.com/ulrichstern/Tlc59711/wiki#how-does-the-tlc59711-know-when-a- overføring er ferdig).)
Nick Gammon
2016-01-18 11:40:32 UTC
view on stackexchange narkive permalink

Vil dette påvirke koden inne i hovedsløyfen som er avhengig av millis () -funksjonen siden det brukes betydelig tid på å behandle ISR-ene?

Å sette en figur på det for deg ...


Frekvens for Timer 0 overløp ISR blir kalt

Koden som kalles av (standard) Timer 0 overløpsavbruddsvektor (TIM0_OVF_vect) brukes av millis og micros for å bidra til å returnere resultatene. Hensikten er å telle Timer 0-overløp.

For å få nøyaktige resultater, må denne ISR ikke gå glipp av et overløp. Timeren er konfigurert til å krysse hver 4. µs på et 16 MHz-system (på grunn av prescaler på 64: 64 * 62,5 ns = 4000 ns ) og overflow hver 1.024 ms (1024 µs) - fordi den renner over etter 256 flått ( 4 µs * 256 = 1024 µs ).

Siden det bare er ett overløpsflagg, hvis ISR savner et overløp, så vil både millis og micros være ute med 1.024 ms (eller mer, hvis det går glipp av flere overløp).

For å være sikker på å fange det overløpet, må ISR derfor kalles innen 1.024 ms (sannsynligvis litt mindre på grunn av tiden det tar å gå inn i ISR, så si: 1 ms).


Avbryt prioritet

På Atmega328P (slik som brukt i Arduino Uno) disse er avbruddsvektorprioriteringene:

  1 Reset 2 External Interrupt Request 0 (pin D2) (INT0_vect) 3 External Interrupt Request 1 (pin D3) (INT1_vect) 4 Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect) 5 Pin Change Inte rrupt Request 1 (pins A0 to A5) (PCINT1_vect) 6 Pin Change Interrupt Request 2 (pins D0 to D7) (PCINT2_vect) 7 Watchdog Time-out Interrupt (WDT_vect) 8 Timer / Counter2 Compare Match A (TIMER2_COMPA_vect) 9 Timer / Counter2 Sammenlign kamp B (TIMER2_COMPB_vect) 10 Timer / Counter2 Overflow (TIMER2_OVF_vect)
11 Timer / Counter1 Capture Event (TIMER1_CAPT_vect) 12 Timer / Counter1 Sammenlign Match A (TIMER1_COMPA_vect) 13 Timer / Counter1 Sammenlign Match B (TIMER1_COMPB_vect) 14 Timer / Counter1 Overflow (TIMER1_OVF_vect) 15 Timer / Teller_TIMER / Teller0 Counter0 Sammenlign Match B (TIMER0_COMPB_vect) 17 Timer / Counter0 Overflow (TIMER0_OVF_vect) 18 SPI Serial Transfer Complete (SPI_STC_vect) 19 USART Rx Complete (USART_RX_vect) 20 USART, Data Register Empty (USART_UDRE_vect) 21 USART, Konvertering_USC Komplett (ADC_vect) 23 EEPROM Ready (EE_READY_vect) 24 Analog Comparator (ANALOG_COMP_vect) 25 2-leder serielt grensesnitt (I2C) (TWI_vect) 26 Lagre programminneklar (SPM_READY_vect)  

Du kan se fra den listen at TIMER0_OVF_vect er nummer 17 på den listen, så tidligere prioritetsavbrudd vil ha forrang, for eksempel eksterne avbrudd , pin-endringsavbrudd, de andre tidtakerne (dog ikke SPI / Serial / ADC / I2C).

Hvis et overflyt bare hadde skjedd så ville du ha praktisk talt 2 ms nåde ( fordi du har 1 ms før neste og deretter 1 ms til før du trenger å legge merke til det). Men hvis overløpet er i ferd med å skje så har du bare 1 ms avdragsfri periode.

Jeg nevner dette fordi hvis du har en ekstern interrupt 0-hendelse (INT0_vect) og ISR tar 500 µs, og deretter ekstern avbrudd 1-hendelse (INT1_vect) i løpet av den tiden (slik at en annen ISR vil bli betjent), kan tidsavbruddet bli blokkert en stund.

Det er grunnen til at alle ISR-er bør være korte. Det er ikke bra nok at noen av dem er det.


Gjenaktivering av avbrudd

Jeg anbefaler på det sterkeste mot dette. Bibliotekene er ikke designet for å komme inn igjen, og når du begynner å aktivere avbrudd i en ISR, kan du oppdage at den selv blir ringt igjen når den er halvveis gjennom å bli kalt første gang. Du kan også tenke deg å avbryte en biblioteksfunksjon (f.eks. Memcpy) som ikke var designet for den.

Og selvfølgelig, hvis du aktiverer avbrudd på nytt i en ISR fordi ISR tar lang tid: vel, det er den nøyaktige situasjonen når du kan utløse denne re -entrancy.


Mer informasjon:

mpflaga
2014-09-29 18:39:58 UTC
view on stackexchange narkive permalink

ABSOLUTT

enhver ISR som er lang vil forhindre at millis () øker. Det kan være tvilsomt langsom skjevhet av denne klokken.

ISR-funksjonen starter alltid med blokkeringsavbrudd med cli () -kommandoen ved start og slutt ved å aktivere dem med sei () -kommandoen. Blokkering av andre ISR-er sammen med Timer0s OverFlow-avbrudd som brukes til å øke millitelleren.

Enhver utvidet bruk av noInterrupts () eller cli () eller underforstått bruk med ISR-er bør være nøye kortvarig. Det er ingen generell skade å utføre avbrudd () eller sei () med i ISR, for å tillate avbrudd igjen.

Eksempel:

i VS1053-biblioteket har jeg data Be om en INT-pin. Hvilken ISR kan lese fra SdCard, noe som kan ta veldig lang tid. Så jeg aktiverer avbruddene på nytt () før jeg leser SdCard, men fortsatt i ISR.

I ditt eksempel blir hovedsløyfen aldri gjenopptatt under den lange avbruddsrutinen, ikke sant? Så det er en ulempe. Godt å vite at aktivering av avbrudd i andre avbrudd ikke er like "farlig" som jeg.
Jeg tror bare en ISR (eller en ISR-kjede) som er lengre enn en millisekund, vil forhindre at den blir avbrutt. Du kan blokkere den 0,5 ms, og den oppdateres som den neste tingen å gjøre (avbryte).


Denne spørsmålet ble automatisk oversatt fra engelsk.Det opprinnelige innholdet er tilgjengelig på stackexchange, som vi takker for cc by-sa 3.0-lisensen den distribueres under.
Loading...