Časovače MSP430

Spíše sporadicky než pravidelně pracuji na finální podobě časomíry, jejíž srdcem bude TI MSP430G2553. V posledních dnech jsem pracoval na přerušeních od vstupů (startovací tlačítko, koncové spínače) a od časovače.

První dílčí úspěch je napájení. Nevěděl jsem, zda stabilizátor LE33 bude dodávat dostatečný proud. Problém byl jediný, v dokumentaci byly přehozené piny Vin a Vout.

Další problém se objevil na vstupech, které způsobovaly přerušení zcela náhodně. Toto více méně vyřešilo připojení kondenzátorů 100 nF mezi pin a zem.

Větší úskalí nastalo při programování. Přístup s přerušeními se diametrálně liší od toho, na co jsem byl  zvyklý a vyžaduje si naprosto jiné smýšlení o problému. Nakonec jsem vypotil kód, který při sepnutí startovacího tlačítka spustí oba časovače a koncový spínač zase jeden z časovačů vypne. Mělo by tak dojít k docela přesnému měření času.

Problém první: jak se ovládá druhý časovač. Původně jsem měl za to, že je v MCU časovač A i časovač B. To byl omyl, v zařízení jsou dva časovače, ale jsou to A0 a A1. Časovač A0 jsem ovládal příkazy, které se běžně dají najít, ale jak na časovač A1?

  TA0CCTL0 = CCIE;					// CCR0 interrupt enabled
  TA0CCR0 = 2048-1;					// 2048 -> 1 sec for ACLK/8
  TA0CTL = TASSEL_1 + ID_3 + MC_0;			// ACLK, /8, stopped
  TA1CCTL0 = CCIE;					// CCR0 interrupt enabled
  TA1CCR0 = 2048-1;                                     // A1 CCR0 level
  TA1CTL = TASSEL_1 + ID_3 + MC_0;			// ACLK, /8, stopped
  TA0R = 0;                                             // clear counter
  TA1R = 0;                                             // clear counter

Za těmito řádkami stojí spousta hledání, pokusů a omylů 🙂 Máme tedy nastavené časovače, tak je spustíme

  TA1CTL |= (MC_1 + TACLR);    //timer A1 starts counting
  TA0CTL |= (MC_1 + TACLR);    //timer A0 starts counting

a zase vypneme

  TA0CTL &= ~MC_1;                         //stop timer A0
  TA1CTL &= ~MC_1;                              //stop timer A1

Pokud časovač dosáhne hladiny CCR0 spustí přerušení. Pro tyto časovače mají vektory přerušení poněkud matoucí názvy

  #pragma vector=TIMER0_A0_VECTOR
  #pragma vector=TIMER1_A0_VECTOR

Zbytek ISR se nijak neliší od běžně dostupných návodů.

Další problém bylo zmenšení ISR pro stisknutá tlačítka na minimum. Pokud pošlete procesor spát a budete naslouchat přerušením. Po provedení ISR jde zase spát. My však potřebujeme aby vykonal ještě nějaké instrukce. Základní myšlenka je taková: pokud se nám spustí několik přerušení najednou, vykonávají se podle předem dané priority, pokud se vykonává ISR k jednomu přerušení, nemůže se spustit ISR jiného a proto potřebujeme v kritických chvílích, jako je měření času, udržet ISR na co nejmenší délce, třeba jen nastavit vlajku a podle ní vykonat zbytek instrukcí jinde, tam, kde se může program přerušit a procesor obsloužit nově příchozí přerušení. Jak na to? Na konci

main()

většinou máme něco jako

_BIS_SR(LPM3_bits + GIE);       // Enter LowPowerMode 3 w/ interrupt

. To jsem obalil nejdříve cyklem

while(1)

, ve kterém je strom

if

, který vykonává zbývající práci po přerušeních, na základě nastavené vlajky.

_BIS_SR(LPM3_bits + GIE);       // Enter LowPowerMode 3 w/ interrupt

přesunu do jeho

else

, takže se provede tolik cyklů while(), kolik máme nastavených vlajek, jsou-li všechny vlajky vyčištěny, jde procesor spát a čeká se na další přerušení.

To ale nestačí, protože normálně po vykonání ISR jde procesor zase spát. V tom mu dočasně zabráníme tím, že na konec ISR, které potřebují ještě vykonat něco mimo, a tedy nastaví příslušnou vlajku, umístíme ještě řádek

__bic_SR_register_on_exit(LPM3_bits + GIE); // Don't Enter LowPowerMode 3 immidiately

Tak se vrátíme do cyklu while() v main(). V té době už můžeme obsluhovat další přerušení.

A to je vše podstatné, ideu ze které jsem čerpal najdete na obrázku v souboru www.ti.com/lit/an/slaa294a/slaa294a.pdf

5 komentářů u „Časovače MSP430

  1. Palo

    Dobry den,
    cisto z hobby zaujmu (aspon zatial) zacinam robit s MSP430. Rozmyslam nad tym problemom s nahodnym geneovanim prerusenia na pinoch. Nemoze byt ten problem sposobeny „plavajucim“ potencialom pinu. Skusali ste nastavit na danom pine vnutorny pull-up/down interny rezistor, alebo pripojit ho cez externy rezistor na zem ci Vcc (samozrejme s ohladom na dalsie zapojenie)?
    PS

  2. Honza Autor příspěvku

    Dobrý den a děkuji za komentář, v tomhle jsem ani problém nehledal, ale když se dívám na schéma desky, ke které mám připojené vstupy, tak tam vážně pull-up/down rezistory nemám, jen rezistor na omezení proudu. Ve skutečnosti to nebylo úplně náhodně, když jsem sepnul start tak se spustila i ostatní přerušení, je-li vůbec možné, aby se tam indukoval nějaký proud z vedlejších drátků. Zkusím ty interní rezistory a děkuji za tip.

    1. Palo

      To indukovanie po vodicoch v zapojeni by ani tak asi problem nerobilo (asi tam nebudu nejake extra dlhe privodne vodice -aj ked mozne je vsetko). Spominam si ale, ked som ciatal odporucania pre pouzitie 10ADC prevodnika, tak tam boli odporucania ohladom vonkajsieho zapojenia, kodu, aj uz existujucej vnutornej logiky, len aby sa minimalizovalo rusenie/sum z jedneho vstupu na druhy. Kopu I/O pinov ma dost zlozitu strukturu vnutornych zapojeni (na jednom vyvode je GPIO, ADC, CLK, …) a preto skor predpokladam, ze tie rusenia sa vytvaraju priamo v obvode – ak ich teda nema co stiahnut na nejaky jasny referencny bod.

  3. Palo

    A este jedna poznamka aj ked to asi riesene mate. Treba brat do uvahy aj zakmitanie mechanickych spojov v mechanickom spinaci pri ich dosadnuti (pri kazdom stalceni tlacitka). To moze generovat postupnost viacerych preruseni (s velmi nahodnym spravanim a opakovanim). Ak je oblsuha prerusnia rychla a procesor to stiha, tak kludne jeden fyzicky „klik“ vyvola aj niekolko desiatok prerusovacich impulzov. Riesi sa to bud hardverovo dvoma hradlami, kotre v podstate prepustia to prve hlavne spojenie kontaktov}pru hranu) a zakmyt odfiltruju, alebo sa to urobi v SW, kde po zachyteni prveho prerusenia sa na cca 50ms vypne sledovanie daneho pinu (tym sa da cas kontaktom „usadit“). Prirozpojeni sa to moze stat samozrejme tiez, ale daleko vyraznejsie je to prave pri zopnuti. Inac tych 50 ms(alebo iny cas) sa da odsedovat aj tak ze, date cakanie po zachyteni prerusenia a jeho znizovanim testujete kedy to zacne chytat aj falosne zakmity a potom date napriklad 2x ci 3x vacsiu hodnotu.

    1. Honza Autor příspěvku

      Debouncing právě řeším v rovině HW těmi kondenzátory, které propustí signál až když je nějakou dobu (v závislosti na jeho kapacitě) stabilně na vysoké hladině. Včera jsem ale zkoušel obvod bez nich a dokonce jsem vypnul i pull-down rezistory na vstupech (ale tím si nejsem úplně jistý) a činnost vykonává tak na 90% správně. Nejspíš na to má vliv i mnohem robustnější program na zpracování přerušení, takže s pull-down rezistory a malými kondenzátory na vstupech se nebojím, že by obsluha přerušení teď fungovala špatně.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *