Kysymys:
Upotettu C - tyylikkäin tapa lisätä viive
a_bet
2019-07-31 14:21:37 UTC
view on stackexchange narkive permalink

Työskentelen projektissa, johon liittyy cortex-m4 mcu (LPC4370). Ja minun on lisättävä viive kääntäjän optimoinnin ollessa päällä. Toistaiseksi kiertotavani oli siirtyä ylös ja alas digitaalisessa lähdössä for-loop:

  (int i = 0; i < 50000; i ++)
{
     LPC_GPIO_PORT->B [DEBUGPIN_PORT] [DEBUG_PIN1] = TOSI;
     LPC_GPIO_PORT->B [DEBUGPIN_PORT] [DEBUG_PIN1] = EPÄTOSI;
}
 

Mutta ihmettelen, onko olemassa parempi tapa huijata GCC: tä.

Tämä ei ole hyvä tapa tehdä viivästyksiä.
Kuinka kauan haluat viivästyksen olla?Kuinka tarkan sen on oltava?
Voit asettaa ajastimen keskeyttämään alivuoto / ylivuoto haluamallesi viiveelle ja siirtymään vain lepotilaan.Suoritin herää keskeytyksessä, jolla voi olla yksinkertaisesti yksi paluulauseke.
Kiitos kommentista. Teen tämän, koska minulla on ongelmia, kun yritän olla yhteydessä Matlabiin USB: n kautta. Hävitin synkronoinnin tietokoneen ja mcu: n välillä, joten yritän korjata ongelman viivästyttämällä sitä täällä.Tiedän, että tämä ei todennäköisesti ole paras käytäntö, mutta en löytänyt muita tapoja.Joten minun ei tarvitse olla erittäin tarkka, kuten millisekunnissa voisi olla ok.tässä on toinen USB-viestini https://electronics.stackexchange.com/questions/450659/embedded-c-usb-stack-and-arm-none-eabi-gcc-settings
Äänestän tämän kysymyksen sulkemisesta aiheen ulkopuoliseksi, koska se on XY-ongelma: Viivästyksen käyttäminen viestintäkoodissa on periaatteessa * aina * virheellistä.Sinun on ymmärrettävä ja ratkaistava * todellinen * ongelmasi.Ei-viestintätapauksissa, joissa viive * on sopiva *, huomaat, että useimmissa MCU-ohjelmistoasetuksissa on varattu odotusviive.
Minä ymmärrän tämän.Olen pahoillani, teen parhaani työskennelläksesi tämän ohjaimen kanssa, mutta tuki NXP-foorumeilla on lähes 0.
Ei, tuhlaat aikaasi väärään suuntaan.Jos haluat tunnistaa ja ratkaista * todellisen * ongelmasi, noudata nykyiseen kysymykseesi lähetettyjä ohjeita ja tee muokkauksia tarkentamaan ongelmasi lausuntoa ja sisällyttämään näiden virheenkorjaustoimien havainnot.
@ChrisStratton En tiedä, että XY-tyyppiset viestit ovat pätevä läheinen syy kaikkialla verkossa.
@Marc.2377 XY-kysymykset ovat itse asiassa melko yleinen läheinen syy * täällä *, koska näemme paljon tällaisia väärin suunnattuja tehtäviä.
Neljä vastused:
Jeroen3
2019-07-31 16:54:33 UTC
view on stackexchange narkive permalink

Tämän sisäisen riippumattomuusviiveen konteksti puuttuu täältä.Mutta oletan, että tarvitset lyhyen viiveen alustuksen aikana tai muussa koodin osassa, jossa sen sallitaan estää.

Kysymyksesi ei saisi olla fool GCC.Sinun tulisi tell GCC mitä haluat.

  #pragma GCC push_options
#pragma GCC-optimointi ("O0")

(uint i = 0; i<T; i ++) {__ NOP ()}

#pragma GCC: n pop_options
 

Pään päältäni tämä silmukka on noin 5 * T-kelloa.

( lähde)


Colin kertoi oikeudenmukaisesti toisen vastauksen.NOP: n ei voida taata ottavan jaksoja M4: llä.Jos haluat hidastaa asioita, ehkä parempi vaihtoehto on ISB (huuhteluputki).Katso yleinen käyttöopas.

Ok, joten se on ensimmäinen kerta, kun näen #pragman.Jos ymmärsin oikein, tällaiset asetukset koskevat vain tätä pientä koodiosaa. Neuvoisitko tätä sovelluksessa, joka käyttää ajastinta?
@a_bet Se riippuu asiayhteydestä.Mutta yleensä viivästys on viimeinen viive, jota haluat käyttää.
Voit käyttää myös sen sijaan muuta kuin "ei" -käskyä, jota ei poisteta putkistosta.
@Jeroen3: `-O0` tekee [vähän huonompi kuin 5 * T] (https://godbolt.org/z/S_zh6l), jotain 8 ohjetta, joissa on joukko yleiskustannuksia.Olisi parempi luoda lyhyt optimoitu silmukka (tai ainakin yksi, joka kääntyy samalla tavalla ilman käytäntöjä) ja käyttää `__asm__ __volatile __ (" ");` estämään GCC: tä optimoimasta silmukkaa poispäin, ts. [Jotain tällaista](https://godbolt.org/z/NcwHdc).
@Groo En voi uskoa, että keskustelemme viivekoodin tehokkuudesta ihmisen likaisimmalla tavalla.Mutta kyllä, haihtuva linjan kokoonpanolinja toimii yhtä hyvin.Uskon, että pragma ilmaisee tarkoituksen paremmin kaikille uusille lukijoille.
asm volatile on oikea tapa tehdä tämä, jos sinulla ei ole toimittajan toimittamaa viivetoimintoa / makroa.Älä poista optimointia käytöstä, edes yhdelle riville, se sekoittaa for-silmukan.
Testaan tätä ratkaisua ajoituksen tarkkuuden suhteen.Toistaiseksi se näyttää olevan "hyvä" nopea ja likainen työ!
Colin
2019-07-31 14:35:49 UTC
view on stackexchange narkive permalink

Käytä ajastinta, jos sinulla on sellainen käytettävissä.SysTick on erittäin helppo konfiguroida, ja sen ohjeet ovat Cortex M4 -käyttöoppaassa (tai M0, jos olet M0-osassa).Lisää numeroa sen keskeytyksessä ja viivetoiminnossa voit estää, kunnes numero on lisännyt tiettyä määrää vaiheita.

Sinun osassasi on paljon ajastimia, jos systick on jo käytössä, ja periaate pysyy samana.Jos käytät eri ajastinta, voit määrittää sen laskuriksi ja katsoa vain sen lukurekisteriä välttääksesi keskeytyksiä.

Jos todella haluat tehdä sen ohjelmistolla, voit laittaa silmukan sisään asm ("nop"); . nop ei tarvitse viedä aikaa, prosessori voi poistaa ne putkistosta suorittamatta sitä, mutta kääntäjän tulisi silti luoda silmukka.

Systick on erittäin helppo konfiguroida, mutta suosittelen toisen ajastimen käyttämistä niin pian kuin mahdollista, koska Systickillä on rajoituksia laskurin kokoon ja keskeytyksiin, kun sitä käytetään viivästyksiin.
Sinun ei tarvitse edes käyttää keskeytyksiä, vain kysele laskurirekisteriä.Tämä tulisi määritellä haihtuvaksi, joten kääntäjä ei optimoi sitä.IMO, SysTick on hyvä valinta, koska se on usein määritetty antamaan 'O / S-ajastin', esim.mikrosekunnin ajastin.Sitten koodissa on yksinkertaisia `odota_mikrosekuntia (100);` -tyyppisiä asioita.
@EvilDogPie Eikö "_ vain kysele laskurirekisteriä_" ole melkein yhtä huono kuin vain tiukka silmukka?(vaikka luultavasti helpompi lopettaa GCC: n optimointi sen pois).
@TripeHound Kyllä, sillä on tarkalleen tiukka silmukka.Tätä o / p pyytää: tiukka silmukka lyhyelle viiveelle, jota kääntäjän optimointi ei poista.On paikkoja, joissa tiukka silmukka ei ole huono tapa tehdä lyhyt viive, varsinkin sulautetussa järjestelmässä, joka ei ole moniajo.
John Burger
2019-07-31 20:19:02 UTC
view on stackexchange narkive permalink

Älä vähennä muita vastauksia täällä, mutta tarkalleen kuinka pitkää viivettä tarvitset? Joissakin taulukoissa mainitaan nanosekunnit; muut mikrosekunnit; ja vielä muut millisekunnit.

  • Nanosekunnin viivästykset palvelevat yleensä parhaiten lisäämällä "aikaa tuhlaavia" ohjeita. Tosiaankin mikro-ohjaimen nopea nopeus tarkoittaa, että viive on tyydytetty osoittamiesi ohjeiden "aseta tappi korkealle, aseta tappi matalalle" välillä. Muussa tapauksessa yksi tai useampi NOP , JMP -to-next-command tai muu aikaa vievä ohje riittää.
  • Lyhyet mikrosekunnin viiveet voi tehdä for -silmukalla (suorittimen nopeudesta riippuen), mutta pidemmät voivat edellyttää odottamista varsinaisella ajastimella;
  • Millisekunnin viivästykset palvelevat yleensä parhaiten tekemällä jotain muuta täysin odottaen prosessin päättymistä ja palaten sitten takaisin varmistaaksesi, että se on todella suoritettu ennen jatkamista.

Lyhyesti sanottuna kaikki riippuu oheislaitteesta.

Lundin
2019-08-05 14:26:34 UTC
view on stackexchange narkive permalink

Paras tapa on käyttää sirun ajastimia. Systick-, RTC- tai oheislaitteiden ajastimet. Näillä on se etu, että ajoitus on tarkka, deterministinen ja se voidaan helposti mukauttaa, jos prosessorin kellotaajuutta muutetaan. Vaihtoehtoisesti voit jopa antaa CPU: n nukkua ja käyttää herätyskeskeytystä.

Likaiset "varattu-viive" -silmukat ovat toisaalta harvoin tarkkoja ja niissä on erilaisia ​​ongelmia, kuten "tiukka kytkentä" tiettyyn suorittimen käskyjoukkoon ja kelloon.

Joitakin huomioitavia asioita:

  • GPIO-nastan vaihtaminen toistuvasti on huono idea, koska se vetää virtaa tarpeettomasti ja aiheuttaa myös EMC-ongelmia, jos tappi on kytketty jälkiin.
  • NOP-ohjeiden käyttäminen ei välttämättä toimi. Monet arkkitehtuurit (kuten Cortex M, iirc) voivat vapaasti ohittaa NOP: n suorittimen tasolla eivätkä itse suorita niitä.

Jos haluat vaatia likainen kiireisen silmukan luomista, riittää, että vain volatile hyväksytään silmukka-iteraattori. Esimerkiksi:

  void dirty_delay (mitätöity)
{
  for (haihtuva uint32_t i = 0; i<50000u; i ++)
    ;
}
 

Tämän avulla voidaan taata erilaisia ​​roskakoodeja. Esimerkiksi ARM gcc -O3 -vapaasti seisova antaa:

  likainen_viive:
        mov r3, # 0
        sub sp, sp, # 8
        str r3, [sp, # 4]
        ldr r3, [sp, # 4]
        ldr r2,. L7
        cmp r3, r2
        bhi. L1
.L3:
        ldr r3, [sp, # 4]
        lisää r3, r3, # 1
        str r3, [sp, # 4]
        ldr r3, [sp, # 4]
        cmp r3, r2
        bls. L3
.L1:
        lisää sp, sp, # 8
        bx lr
.L7:
        .sana 49999
 

Siitä lähtien voit teoriassa laskea, kuinka monta punkkia kukin käsky vie, ja muuttaa taikuuslukua 50000 vastaavasti. Putkilinja, haaraennuste jne. Tarkoittaa, että koodi saattaa kuitenkin suorittaa nopeammin kuin vain kellojaksojen summa. Koska kääntäjä päätti ottaa pinon mukaan, myös tietojen välimuistilla voi olla merkitystä.

Koko ajatukseni on, että on vaikeaa laskea tarkasti kuinka paljon aikaa tämä koodi todella vie.Kokeiluversioiden vertailuanalyysi &ista on todennäköisesti järkevämpi idea kuin teoreettisten laskelmien yrittäminen.



Tämä Q & A käännettiin automaattisesti englanniksi.Alkuperäinen sisältö on saatavilla stackexchange-palvelussa, jota kiitämme cc by-sa 4.0-lisenssistä, jolla sitä jaetaan.
Loading...