Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Në pjesës së parë Përpiqesha t'u tregoja elektronikëve amatorë, që kanë kaluar nga Arduino, si dhe pse duhet të lexojnë fletët e të dhënave dhe dokumentacionin tjetër për mikroproçesorët. Teksti doli i gjatë, prandaj premtova se do të jepja shembuj praktikë në një artikull tjetër. Pra, fillojmë...

Sot do të tregoj se si, duke përdorur fletët e të dhënave, të zgjidhni disa probleme të thjeshta, por të nevojshme për shumë projekte mbi kontrollorët STM32 (Blue Pill) dhe STM8. Të gjitha projekte të demonstrimit janë të dedikuara për LED-të e mi të preferuar, do t'i ndezim ato në numër të madh, për këtë do të angazhojmë pajisje interesante.

Teksti është përsëri shumë i gjatë, prandaj për lehtësinë e leximit do të bëj një përmbledhje:

STM32 Blue Pill: 16 LED me drejtuesin DM634
STM8: Konfigurojmë gjashtë daljet PWM
STM8: 8 RGB-LED në tri pinë, ndërprerje

Kujdes: Nuk jam inxhinier, nuk pretendon të kem njohuri të thella në elektronikë, ky artikull është i destinuar për të tillë si unë amatorë. Në të vërtetë, për publikun e synuar, kam marrë parasysh veten time dy vjet më parë. Po të më kishte thënë dikush atëherë se leximi i fletëve të të dhënave për një çip të panjohur nuk është e frikshme, nuk do të kisha humbur kaq shumë kohë për të kërkuar ndonjë copë kodi në internet dhe për të shpikur zgjidhje me gërshërë dhe plaster.

Qendra e këtij artikulli janë fletët e të dhënave, jo projektet, prandaj kodi mund të mos jetë shumë i rregullt dhe shpeshherë improvizuar. Vetë projektet janë shumë të thjeshta, edhe pse janë të dobishme për një takimin e parë me një çip të ri.

Shpresoj që artikulli im t'i ndihmojë dikujt në një fazë të ngjashme të zhytjes në këtë hobi.

STM32

16 LED me DM634 dhe SPI

Një projekt i vogël duke përdorur Blue Pill (STM32F103C8T6) dhe drejtuesin e LED DM634. Me ndihmën e fletëve të të dhënave do të kuptojmë se si të punojmë me drejtuesin, portet IO të STM dhe do të konfigurojmë SPI.

DM634

NjĂ« çip tajvanez me 16 dalje PWM 16-bitĂ«she, mund tĂ« lidhen nĂ« seri. Modeli mĂ« i vogĂ«l 12-bit i njohur nga projekti vendas Lightpack. NĂ« atĂ« kohĂ«, duke zgjedhur midis DM63x dhe TLC5940 tĂ« njohur, u ndala tek DM pĂ«r disa arsye: 1) TLC nĂ« AliExpress pĂ«r siguri Ă«shtĂ« fals; 2) DM ka PWM tĂ« pavarur me gjeneratorin e tij tĂ« frekuencĂ«s; 3) e kam blerĂ« me çmim tĂ« volitshĂ«m nĂ« MoskĂ«, jo tĂ« pres njĂ« dĂ«rgesĂ« nga Ali. Dhe, natyrisht, mĂ« interesonte tĂ« mĂ«soja tĂ« menaxhoja çipin, jo tĂ« pĂ«rdorja njĂ« bibliotekĂ« tĂ« gatshme. Çipat tani janĂ« kryesisht nĂ« njĂ« paketim SSOP24, nuk Ă«shtĂ« e vĂ«shtirĂ« t'i salosh nĂ« njĂ« adaptues.

Pasi prodhuesi është tajvanez, datasheet të dhënat për çipin janë shkruar në anglishten kineze, prandaj do të jetë zbavitëse. Fillimisht shikojmë lidhjen (Pin Connection), që të kuptojmë se çfarë duhet të lidhim me çdo pin, dhe përshkrimin e pinëve (Përshkrimi i Pinëve). 16 dalje:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Burimet e rrymës së vazhdueshme (shtëpia e hapur)

Sink / Dalja me hapje tĂ« hapur – stoku; burim i rrymĂ«s sĂ« daljes; dalje qĂ«, nĂ« gjendje aktive, lidhet me tokĂ«n, - LED-tĂ« lidhen me drejtuesin nga katodet. NĂ« mĂ«nyrĂ« elektrike, nuk Ă«shtĂ« asnjĂ« "shtĂ«pi e hapur" (kanale tĂ« hapura), por nĂ« fletĂ«t e tĂ« dhĂ«nave ky term pĂ«r daljet nĂ« mĂ«nyrĂ« tĂ« zakonshme pĂ«rdoret pĂ«r daljet nĂ« mĂ«nyrĂ« tĂ« hapur.

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Rezistorët e jashtëm midis REXT dhe GND për të vendosur vlerën e daljes së rrymës

Midis pinit REXT dhe tokës vendoset një rezistor referencë, i cili kontrollon rezistencën e brendshme të daljeve, shih diagramin në faqen 9 të fletës së të dhënave. Në DM634, kjo rezistencë mund të menaxhohet gjithashtu programatikisht, duke vendosur ndriçimin e përgjithshëm (global brightness); në këtë artikull nuk do të hyj në detaje, thjesht do të vë këtu një rezistor prej 2.2 - 3 kΩ.

Për të kuptuar se si të menaxhojmë çipin, le të shikojmë përshkrimin e ndërfaqes së pajisjes:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Ah, ja, anglishtja kineze në gjithë shkëlqimin e saj. Të përkthehet kjo është e vështirë, por mund të kuptohet nëse keni dëshirë, por ka një rrugë tjetër - të shikoni se si përshkruhet lidhja në fletën e të dhënave për TLC5940 që është funksionalisht e ngjashme:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

 PĂ«r tĂ« futur tĂ« dhĂ«na nĂ« pajisje kĂ«rkohen vetĂ«m tri pinĂ«. Fronti i sinjalit SCLK kalon tĂ« dhĂ«nat nga pini SIN nĂ« regjistrin e brendshĂ«m. Pasi tĂ« gjitha tĂ« dhĂ«nat janĂ« ngarkuar, njĂ« sinjal i shkurtĂ«r i lartĂ« XLAT fikson tĂ« dhĂ«nat e transferuara nĂ« regjistrat e brendshĂ«m. Regjistrat e brendshĂ«m – janĂ« regjistrat me nivel sinjali XLAT. TĂ« gjitha tĂ« dhĂ«nat kalohen me bitin mĂ« tĂ« lartĂ« pĂ«rpara.

Latch – ndalĂ«si.
Rising edge – skaji i pĂ«rparme i impulsit.
MSB first – bitin mĂ« tĂ« lartĂ« (nĂ« tĂ« majtĂ«) pĂ«rpara.
to clock data – pĂ«r tĂ« kaluar tĂ« dhĂ«nat nĂ« mĂ«nyrĂ« sekuenciale (bit pĂ«r bit).

Fjala mbajtës përdoret shpesh në dokumentacionin e çipave dhe përkthehet në mënyra të ndryshme, prandaj për të kuptuar do të lejoj vetes një

shpjegim tĂ« vogĂ«lDrejtuesi LED - nĂ« thelb njĂ« regjistĂ«r i zhvendosur. "Zhvillimi" (zhvendosje) nĂ« emĂ«r – zhvendosje bitore e tĂ« dhĂ«nave brenda pajisjes: çdo bit i ri i futur brenda shtyn tĂ« gjithĂ« vargun pĂ«rpara. Duke qenĂ« se gjatĂ« kĂ«tij lĂ«vizjeje askush nuk dĂ«shiron tĂ« shohĂ« ndricimin e rastĂ«sishĂ«m tĂ« LED-ve, procesi ndodh nĂ« regjistrat buferĂ«, tĂ« ndarĂ« nga porti i punĂ«s (mbajtĂ«s) – ky Ă«shtĂ« njĂ« lloj paraqitjeje, ku bitet radhiten nĂ« sekuencĂ«n e duhur. Kur gjithçka Ă«shtĂ« gati, porti hapet dhe bitet dĂ«rgohen pĂ«r tĂ« punuar, duke zĂ«vendĂ«suar grupin e mĂ«parshĂ«m. Fjala mbajtĂ«s nĂ« dokumentacionin e çipave zakonisht nĂ«nkupton njĂ« port tĂ« tillĂ«, pa marrĂ« parasysh kombinimet nĂ« tĂ« cilat pĂ«rdoret ajo.

Pra, transferimi i të dhënave në DM634 realizohet si më poshtë: vendosim hyrjen DAI në vlerën e bitit më të lartë të LED-it të largët, lëvizim DCK lart-për-poshtë; vendosim hyrjen DAI në vlerën e bitit tjetër, lëvizim DCK; dhe kështu me radhë, derisa të gjitha bitet të jenë transferuar (clocked in), pas të cilit lëvizim LAT. Kjo mund të bëhet manualisht (bit-bang), por është më mirë të përdorim një ndërfaqe të dizajnuar posaçërisht për këtë, e cila është e pranishme në STM32 tonë në dy ekzemplarë.

Pilula Blu STM32F103

Hyrje: kontrolluesit STM32 janĂ« ndjeshĂ«m mĂ« tĂ« komplikuar se Atmega328, sesa mund tĂ« duken. NĂ« kĂ«tĂ« mĂ«nyrĂ«, pĂ«r shkak tĂ« kursimit tĂ« energjisĂ«, pothuajse tĂ« gjithĂ« periferikĂ«t janĂ« tĂ« çaktivizuar nĂ« fillim, dhe frekuenca takt Ă«shtĂ« 8 MHz nga burimi i brendshĂ«m. FatmirĂ«sisht, programuesit STM kanĂ« shkruar kod pĂ«r ta çuar çipin nĂ« “nivelet” 72 MHz, dhe autorĂ«t e tĂ« gjitha IDE-ve qĂ« njoh, e kanĂ« pĂ«rfshirĂ« atĂ« nĂ« procedurĂ«n e inicializimit, kĂ«shtu qĂ« nuk kemi nevojĂ« ta taktizojmĂ« (por mund tĂ« bĂ«het, nĂ«se do shumĂ«). Por do tĂ« duhet ta aktivizojmĂ« periferinĂ«.

Dokumentacioni: në Blue Pill është instaluar çipi popullor STM32F103C8T6, për të cilin ka dy dokumente të dobishme:

Në datashit mund të na interesojnë:

  • Pinouts – renditjet e çipave – nĂ« rast se vendosim tĂ« krijojmĂ« bordet tona;
  • Memory Map – mapa e kujtesĂ«s pĂ«r çipin specifik. NĂ« Manualin e ReferencĂ«s ka njĂ« hartĂ« pĂ«r tĂ« gjithĂ« gamĂ«n, nĂ« tĂ« cilĂ«n pĂ«rmenden regjistrat qĂ« nuk kanĂ« nĂ« tonin.
  • Tabela e Definicionit tĂ« PinĂ«ve – pĂ«rshkrimi i funksioneve tĂ« rĂ«ndĂ«sishme dhe alternative tĂ« pinĂ«ve; pĂ«r “pilulĂ«n blu” nĂ« internet mund tĂ« gjeni imazhe mĂ« tĂ« pĂ«rshtatshme me listĂ«n e pinĂ«ve dhe funksioneve tĂ« tyre. Prandaj, menjĂ«herĂ« kĂ«rkojmĂ« renditjen e pinĂ«ve Blue Pill dhe mbajmĂ« njĂ« imazh tĂ« tillĂ« nĂ«n dorĂ«:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
NB: nĂ« imazhin nga interneti kishte njĂ« gabim, i evidencuar nĂ« komentet, pĂ«r tĂ« cilĂ«n faleminderit. Imazhi Ă«shtĂ« zĂ«vendĂ«suar, por kjo Ă«shtĂ« njĂ« mĂ«sim – informacioni jo nga datashit duhet kontrolluar.

E heqim datashitin, hapim Manualin e Referencës, tani përdorim vetëm atë.
Renditja e veprimeve: kuptojmë me hyrjen/daljen standarde, konfiguroni SPI, aktivizoni periferinë e nevojshme.

Hyrje-dalje

Në Atmega328 hyrja-dalja është realizuar ekstremisht thjeshtë, për shkak të së cilës shumica e opsioneve në STM32 mund të ngatërrojnë. Tani, na duhen vetëm daljet, por edhe ato kanë katër variante:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
dalje me stok tĂ« hapur, dalje “tĂ«rheq-dhĂ«mbĂ«â€, dalje alternative “tĂ«rheq-dhĂ«mbĂ«â€, stok alternative i hapur.

“TĂ«rheq-dhĂ«mbĂ«â€ (push-pull) – njĂ« dalje e njohur nga Arduino, pin mund tĂ« marrĂ« vlerĂ«n ose HIGH ose LOW. NdĂ«rsa me “stok tĂ« hapur” ndodhin vĂ«shtirĂ«si, megjithatĂ« nĂ« tĂ« vĂ«rtetĂ« kĂ«tu gjithçka Ă«shtĂ« e thjeshtĂ«:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Konfigurimi i daljes / kur porta Ă«shtĂ« e caktuar pĂ«r dalje: / Ă«shtĂ« aktivizuar tamponi i daljes: / – nĂ« modin e stokut tĂ« hapur: “0” nĂ« regjistrin e daljes aktivizon N-MOS, “1” nĂ« regjistrin e daljes e lĂ« portĂ«n nĂ« modin Hi-Z (P-MOS nuk aktivizohet) / – nĂ« modin “tĂ«rheq-dhĂ«mbĂ«â€: “0” nĂ« regjistrin e daljes aktivizon N-MOS, “1” nĂ« regjistrin e daljes aktivizon P-MOS.

E gjithĂ« dallimi i stokut tĂ« hapur (kanale tĂ« hapura) nga “tĂ«rheq-dhĂ«mbĂ«â€ (push-pull) Ă«shtĂ« se nĂ« tĂ« parin pin nuk mund tĂ« marrĂ« gjendje HIGH: kur shkruhet nish nĂ« regjistrin e daljes, ai kalon nĂ« modin e rezistencĂ«s sĂ« lartĂ« (high impedance, Hi-Z). Kur shkruhet zero, pini nĂ« tĂ« dyja modet sillet njĂ«soj, si logjikisht ashtu edhe elektrikisht.

NĂ« modin normal tĂ« daljes, pini thjesht transmeton pĂ«rmbajtjen e regjistrit tĂ« daljes. NĂ« “alternativin”, ai kontrollohet nga periferia pĂ«rkatĂ«se (shih. 9.1.4):

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Nëse bita i portës është i konfiguruar si dalje funksioni alternativ, regjistri i daljes ndalohet, dhe pini lidhet me sinjalin e daljes së periferisë.

Funksionaliteti alternativ i çdo pini është përshkruar në Definimet e Pinëve të datashit dhe është në imazhin e shkarkuar. Për pyetjen se çfarë të bëni nëse një pini ka disa funksione alternative, përgjigjen e jep një shënim në datashit:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Nëse disa blloqe periferike përdorin të njëjtin pin, për të shmangur konfliktet midis funksioneve alternative duhet të përdoret vetëm një bllok periferik në të njëjtën kohë, duke kaluar me anë të bitit të aktivizimit të taktimit të periferisë (në regjistrin përkatës RCC).

Më në fund, pinat në modin e daljes kanë gjithashtu shpejtësinë e taktimeve. Kjo është një tjetër karakteristikë për kursimin e energjisë, në rastin tonë thjesht e vendosim në maksimum dhe e harrojmë.

Pra: ne po pĂ«rdorim SPI, kĂ«shtu qĂ« dy pinĂ« (me tĂ« dhĂ«nat dhe me sinjalin e taktimeve) duhet tĂ« jenĂ« "funksion alternativ tĂ«rheqĂ«s- shtytĂ«s", dhe njĂ« tjetĂ«r (LAT) – "tĂ«rheqĂ«s- shtytĂ«s normal". Por pĂ«rpara se t'i emĂ«rojmĂ«, le tĂ« merremi me SPI.

SPI

Një edukim i vogël

SPI ose Serial Peripheral Interface (interface periferik seri) është një interface i thjeshtë dhe mjaft efikas për komunikimin e mikroproçesorëve me mikroproçesorë të tjerë dhe në përgjithësi me botën e jashtme. Prinsipi i funksionimit të tij është përshkruar më sipër, atje ku flitet për LED-draiverin kinez (në manualin reference keni seksionin 25). SPI mund të funksionojë në modin master ("pronar") dhe slave ("skllav"). SPI ka katër kanale themelore, nga të cilat mund të aktivizohen jo të gjithë:

  • MOSI, Master Output / Slave Input: ky pin nĂ« modin master dĂ«rgon dhe nĂ« modin slave pranon tĂ« dhĂ«na;
  • MISO, Master Input / Slave Output: pĂ«rkundrazi, nĂ« master pranon, nĂ« slave – dĂ«rgon;
  • SCK, Serial Clock: pĂ«rcakton frekuencĂ«n e transmetimit tĂ« tĂ« dhĂ«nave nĂ« master ose pranon sinjalin e taktimeve nĂ« slave. NĂ« thelb, mat bitĂ«t;
  • SS, Slave Select: me anĂ« tĂ« kĂ«tij kanali, slave e di qĂ« dikush dĂ«shiron diçka nga ai. NĂ« STM32 quhet NSS, ku N = negative, dmth. kontrolluesi bĂ«het slave, nĂ«se nĂ« kĂ«tĂ« kanal Ă«shtĂ« toka. ShkĂ«lqyeshĂ«m kombinon me modin Open Drain Output, por kjo Ă«shtĂ« njĂ« histori tjetĂ«r.

Siç është gjithçka tjetër, SPI në STM32 është i pasur me funksionalitete, e cila e komplikon pak kuptimin e tij. Për shembull, ai mund të funksionojë jo vetëm si SPI, por edhe si interface I2S, dhe, për më tepër, përshkrimet e tyre në dokumentacion janë të ndërthurura, duhet të ndajmë informacionin e tepërt në kohë. Në rastin tonë, detyra është mjaft e thjeshtë: duhet thjesht të dërgojmë të dhëna, duke aktivizuar vetëm MOSI dhe SCK. Shkoni në seksionin 25.3.4 (komunikim poluduplex), ku gjejmë 1 clock and 1 unidirectional data wire (1 sinjal taktimesh dhe 1 rrjedhë të dhënash njëdrejtimëshe):

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Në këtë mod, aplikacioni përdor SPI ose në modin e vetëm dërgimit, ose vetëm pranim. / Modin e vetëm dërgimit ngjason me modin dupleks: të dhënat dërgohen përmes pinës dërguese (MOSI në modin master ose MISO në modin slave), ndërsa pino marrës (MISO ose MOSI përkatësisht) mund të përdoret si një pin normal hyrës. Në këtë rast, aplikacioni mjafton të injorojë bufferin Rx (nëse e lexon, aty nuk do të ketë të dhëna të dërguara).

ShkĂ«lqyeshĂ«m, pino MISO Ă«shtĂ« i lirĂ«, do ta lidhim atĂ« me sinjalin LAT. Le t’i heqim para Slave Select, tĂ« cilin nĂ« STM32 mund ta menaxhojmĂ« programatikisht, gjĂ« qĂ« Ă«shtĂ« jashtĂ«zakonisht e dobishme. LexojmĂ« seksionin me tĂ« njĂ«jtin emĂ«r tĂ« seksionit 25.3.1 pĂ«rshkrimi i pĂ«rgjithshĂ«m i SPI:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Menaxhimi programatik i NSS (SSM = 1) / Informacioni mbi zgjedhjen e slave gjendet në bitin SSI të regjistrit SPI_CR1. Pini i jashtëm NSS mbetet i lirë për qëllime të tjera të aplikacionit.

Ka ardhur koha tĂ« shkruajmĂ« nĂ« regjistra. Kam vendosur tĂ« pĂ«rdor SPI2, po kĂ«rkojmĂ« adresĂ«n e tij themelore nĂ« faktin e dhĂ«nĂ« – nĂ« seksionin 3.3 Memory Map (HartĂ« e memories):

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Pra, fillojmë:

#define _SPI2_(mem_offset) (*(volatile uint32_t *)(0x40003800 + (mem_offset)))

Hapim seksionin 25.3.3 me titullin vetë-shpjegues "Konfigurimi i SPI në modin master":

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

1. Vendosni frekuencën e taktimeve të interfejsit serik me bitë BR[2:0] në regjistrin SPI_CR1.

Regjistrat janë mbledhur në seksionin e njëjtë të manualit referues. Shkalla e adresës (Address offset) në CR1 është 0x00, për defaultin të gjithë bitët janë të zeruar (Reset value 0x0000):

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Bitët BR vendosin ndarësin e frekuencës së kontrolluesit, duke përcaktuar kështu frekuencën me të cilën do të punojë SPI. Frekuenca STM32 do të jetë 72 MHz, LED-draiveri, sipas dokumentacionit të tij, funksionon me frekuencë deri në 25 MHz, kështu që duhet ta ndajmë në katër (BR[2:0] = 001).

#define _SPI_CR1 0x00

#define BR_0        0x0008
#define BR_1        0x0010
#define BR_2        0x0020

_SPI2_ (_SPI_CR1) |= BR_0;// pclk/4

2. Vendosni bitët CPOL dhe CPHA për të përcaktuar marrëdhëniet midis dërgimit të të dhënave dhe taktimeve të interfejsit serik (shihni diagramin në fq. 240)

Duke qenë se ne po lexojmë dokumentacionin e dhënë dhe jo duke shqyrtuar diagramet, le të shqyrtojmë përshkrimin tekstual të bitëve CPOL dhe CPHA në fq. 704 (Përshkrimi i përgjithshëm i SPI):

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Faza dhe polariteti i sinjalit të taktimeve
Me anë të bitëve CPOL dhe CPHA të regjistrit SPI_CR1, mund të zgjidhen katër tipare të marrëdhënieve temporale. Biti CPOL (polariteti i sinjalit të taktimeve) kontrollon gjendjen e sinjalit të taktimeve kur të dhënat nuk dërgohen. Ky bit kontrollon modulet master dhe slave. Nëse CPOL është zeruar, pino SCK në modalitetin e pushimit ndodhet në nivelin e ulët. Nëse biti CPOL është vendosur, pino SCK në modalitetin e pushimit ndodhet në nivelin e lartë.
Nëse është vendosur biti CPHA (faza e sinjalit të taktimeve), stroboskopi që mbajnë bitin më të lartë është fronti i dytë i sinjalit SCK (së poshtme, nëse CPOL është zeruar, ose së lartë, nëse CPOL është vendosur). Të dhënat regjistrohen në ndryshimin e dytë të sinjalit të taktimeve. Nëse biti CPHA është zeruar, stroboskopi që mbajnë bitin më të lartë është fronti i parë i sinjalit SCK (së poshtme, nëse CPOL është vendosur, ose së lartë, nëse CPOL është zeruar). Të dhënat regjistrohen në ndryshimin e parë të sinjalit të taktimeve.

Duke këtyre njohurive, arrijmë në përfundimin se të dy bitët duhet të mbeten zero, pasi na nevojitet që sinjali SCK të mbetet i ulët kur nuk është në përdorim, dhe të dhënat të transmetohen në rastin në rritje të impulsit (shih Rising Edge në datasheetin DM634).

Me rastin e kĂ«saj, kĂ«tu takojmĂ« pĂ«r herĂ« tĂ« parĂ« njĂ« veçori tĂ« leksikut nĂ« datasheetet ST: aty fraza “pĂ«rshtatni bitin nĂ« zero” shkruhet to reset a bit, jo to clear a bit, siç Ă«shtĂ« rasti pĂ«r AtmegĂ«n.

3. Aktivizoni bitin DFF për të përcaktuar formatin e bllokut të dhënave 8-bit ose 16-bit

E kam marrë qëllimisht DM634 16-bit, për të mos u shqetësuar me transmetimin e të dhënave 12-bit PWM, si në DM633. DFF ka kuptim të vendoset në njësi:

#define DFF         0x0800

_SPI2_ (_SPI_CR1) |= DFF; // 16-bit mode

4. Konfiguroni bitin LSBFIRST në regjistrin SPI_CR1 për të përcaktuar formatin e bllokut

LSBFIRST, siç e tregon emri, konfiguron transmetimin me bitin më të vogël përpara. Por DM634 dëshiron të marrë të dhënat duke filluar nga biti më i madh. Prandaj, e lëmë të qëndrojë i fikur.

5. Në modalitetin harduerik, nëse kërkohet hyrje nga pini NSS, sigurohuni që me pini NSS të aplikohet një sinjal i lartë gjatë gjithë sekuencës së transmetimit të byte. Në modalitetin programues, vendosni bitët SSM dhe SSI në regjistrin SPI_CR1. Nëse pini NSS duhet të punojë si dalës, duhet të aktivizoni vetëm bitin SSOE.

Aktivizoni SSM dhe SSI, për ta lënë pas modalitetin harduerik NSS:

#define SSI         0x0100
#define SSM         0x0200

_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high

6. Duhet të jenë aktivizuar bitët MSTR dhe SPE (ata mbeten aktivizuar vetëm nëse në NSS aplikohet një sinjal i lartë)

Këto bita e caktuan SPI-në ton si master dhe e aktivizuan atë:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//ĐșĐŸĐłĐŽĐ° ĐČсД ĐłĐŸŃ‚ĐŸĐČĐŸ, ĐČĐșĐ»ŃŽŃ‡Đ°Đ”ĐŒ SPI
_SPI2_ (_SPI_CR1) |= SPE;

SPI Ă«shtĂ« konfiguruar, le tĂ« shkruajmĂ« menjĂ«herĂ« funksionet qĂ« dĂ«rgojnĂ« byte te drejtuesi. Vazhdoni tĂ« lexoni 25.3.3 “Konfigurimi i SPI nĂ« modalitetin master”:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Rendi i transmetimit të të dhënave
Transmetimi fillon kur një byte shkruhet në tamponin Tx.
Byte-i i të dhënave ngarkohet në regjistrin e ndryshimit në modalitetin paralel (nga autobusi i brendshëm) gjatë transmetimit të bitit të parë, pas së cilës transmetohet në modalitetin në pinin MOSI, bitin e parë ose të fundit përpara sipas konfigurimit të bitit LSBFIRST në regjistrin CPI_CR1. Flaga TXE aktivizohet pas transmetimit të të dhënave sekuenciale nga tamponi Tx në regjistrin e ndryshimit , si dhe krijohet një ndërprerje, nëse bitin TXEIE është aktivizuar në regjistrin CPI_CR1.Kam theksuar disa fjalë në përkthim, për të tërhequr vëmendjen për një veçori të zbatimit të SPI në kontrolluesit STM. Në Atmega, flaga TXE (

Tx Empty, Tx e zbrazĂ«t dhe e gatshme pĂ«r tĂ« pranuar tĂ« dhĂ«na) aktivizohet vetĂ«m pas dĂ«rgimit tĂ« gjithĂ« byte-itjashtĂ«. Dhe kĂ«tu kjo flag aktivizohet pas faktit se byte-i Ă«shtĂ« futur nĂ« regjistrin e brendshĂ«m tĂ« ndryshimit. Duke qenĂ« se futet aty me tĂ« gjithĂ« bitĂ«t njĂ«herĂ«sh (paralelisht), ndĂ«rsa mĂ« pas tĂ« dhĂ«nat transmetohen njĂ« pĂ«r njĂ«, TXE aktivizohet para se byte-i tĂ« dĂ«rgohet plotĂ«sisht. Kjo Ă«shtĂ« e rĂ«ndĂ«sishme, pasi nĂ« rastin e drejtuesit tonĂ« LED na duhet tĂ« tĂ«rheqim pini LAT pas dĂ«rgimittĂ« tĂ« dhĂ«nave, dmth vetĂ«m me flakĂ«n TXE nuk do tĂ« mjaftojĂ«. tĂ« gjitha Kjo do tĂ« thotĂ« se na nevojitet edhe njĂ« flag tjetĂ«r. Le tĂ« shikojmĂ« nĂ« 25.3.7 – “Flagat e-statusit”:

<
>

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Flaga BUSY
Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Flaga BSY aktivizohet dhe fiket harduerikisht (shkrimi në të nuk ka ndonjë efekt). Flaga BSY tregon gjendjen e shtresës komunikuese SPI.
Ajo fiket:
kur transmetimi përfundon (përveç modalitetit master, nëse transmetimi është i vazhdueshëm)
kur SPI ndalet
kur ndodh një gabim në modalitetin master (MODF=1)
Nëse transmetimi nuk është i vazhdueshëm, flaga BSY fiket midis çdo transmetimi të të dhënave.
Ok, do tĂ« na nevojitet. TĂ« kuptojmĂ« se ku ndodhet tamponi Tx. PĂ«r kĂ«tĂ«, le tĂ« lexojmĂ« “Regjistrin e tĂ« dhĂ«nave SPI”:

Bitët 15:0 DR[15:0] Regjistri i të dhënave

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Të dhënat e marra ose të dhënat për transmetim.
Regjistri i tĂ« dhĂ«nave Ă«shtĂ« i ndarĂ« nĂ« dy tampona – njĂ« pĂ«r shkrim (tamponi i transmetimit) dhe tjetri pĂ«r lexim (tamponi i pranuar). Shkrimi nĂ« regjistrin e tĂ« dhĂ«nave shkruan nĂ« tamponin Tx, ndĂ«rsa leximi nga regjistri i tĂ« dhĂ«nave do tĂ« kthejĂ« vlerĂ«n qĂ« ndodhet nĂ« tamponin Rx.
Dhe regjistri i statusit, ku do të gjenden flagat TXE dhe BSY:

Dhe pasi na nevojitet të transmetojmë 16 herë nga dy byte, sipas numrit të daljeve të drejtuesit LED, atëherë ndoshta kështu:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Shkruani:

#define _SPI_DR  0x0C
#define _SPI_SR  0x08

#define BSY         0x0080
#define TXE         0x0002

void dm_shift16(uint16_t value)
{
    _SPI2_(_SPI_DR) = value; //send 2 bytes
    while (!(_SPI2_(_SPI_SR) & TXE)); //wait until they're sent
}

void sendLEDdata() { LAT_low(); uint8_t k = 16; do { k--; dm_shift16(leds[k]); } while (k);while (_SPI2_(_SPI_SR) & BSY); // finish transmissionLAT_pulse(); }

Por ne akoma nuk dimë të lëvizim pini LAT, prandaj le të kthehemi në I/O.

Caktojmë pinët

NĂ« STM32F1, regjistrat qĂ« pĂ«rgjigjen pĂ«r gjendjen e pinĂ«ve janĂ« mjaft tĂ« pazakontĂ«. ËshtĂ« e qartĂ« se ata janĂ« mĂ« tĂ« shumtĂ« sesa nĂ« Atmega, por ata gjithashtu ndryshojnĂ« nga çipat e tjerĂ« STM. Seksioni 9.1 PĂ«rshkrimi i pĂ«rgjithshĂ«m i GPIO:

Çdo port i hyrjes/daljes sĂ« pĂ«rgjithshme

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
(GPIO) ka dy regjistra konfigurimi 32-bit (GPIOx_CRL dhe GPIOx_CRH), dy regjistra të dhënash 32-bit (GPIOx_IDR dhe GPIOx_ODR), një regjistër 32-bit për vendosje/fikje (GPIOx_BSRR), një regjistër 16-bit për fikje (GPIOx_BRR) dhe një regjistër 32-bit të bllokimit (GPIOx_LCKR). përmban dy regjistra 32-bitësh të konfigurimit (GPIOx_CRL dhe GPIOx_CRH), dy regjistra 32-bitësh të të dhënave (GPIOx_IDR dhe GPIOx_ODR), një regjistër 32-bitësh për vendosje/rivendosje (GPIOx_BSRR), një regjistër 16-bitësh për rivendosje (GPIOx_BRR) dhe një regjistër 32-bitësh bllokues (GPIOx_LCKR).

Të pazakontë dhe gjithashtu mjaft të pakëndshme, këtu janë dy regjistrat e parë, sepse 16 pins e portit janë të shpërndara në to në formatin "katër bita për vëlla". Domethënë, pins nga zero deri në shtatë ndodhen në CRL, ndërsa të tjerët në CRH. Megjithatë, regjistrat e tjerë ndihmojnë në përmbushjen e biteve të të gjithë pinsave të portit - shpesh duke mbetur gjysmë "të rezervuar".

Për qëllim thjeshtësie, le të fillojmë nga fundi i listës.

Regjistri bllokues nuk na nevojitet.

Regjistrat e vendosjes dhe zerimit janë mjaft të këndshëm sepse pjesërisht dublikojnë njëri-tjetrin: mund të shkruani gjithçka vetëm në BSRR, ku 16 bitat e lartë do të zerojnë pinin, ndërsa të miturit do ta vendosin në 1, ose gjithashtu mund të përdorni BRR, ku 16 bitat e mitur vetëm do të zerojnë pinin. Më pëlqen opsioni i dytë. Këta regjistra janë të rëndësishëm sepse sigurojnë akses atomik në pins:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Vendosje ose zerim atomik
Nuk Ă«shtĂ« nevoja tĂ« çaktivizoni ndĂ«rprerjet kur programoni GPIOx_ODR nĂ« nivelin e bitit: mund tĂ« ndryshoni njĂ« ose disa bita me njĂ« operacion atomik tĂ« shkrimit nĂ« APB2. Kjo arrihet duke shkruar „1“ nĂ« regjistrin e vendosjes/zerimit (GPIOx_BSRR ose, vetĂ«m pĂ«r zerim, nĂ« GPIOx_BRR) tĂ« bitit qĂ« duhet ndryshuar. Bitet e tjera do tĂ« mbeten tĂ« pandryshuar.

Regjistrat e tĂ« dhĂ«nave kanĂ« emra mjaft pĂ«rshkrues — IDR = Input Regjistri i Drejtimit, regjistri i hyrjes; ODR = Output Regjistri i Drejtimit, regjistri i daljes. NĂ« projektin aktual nuk do na nevojiten.

Dhe, përfundimisht, regjistrat e kontrollit. Duke qenë se na interesojnë pinsat e SPI të dytë, konkretisht PB13, PB14 dhe PB15, shikojmë menjëherë në CRH:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Dhe shohim se do të duhet të shkruajmë diçka në bitët nga 20 në 31.

Ne tashmĂ« e kuptuam mĂ« sipĂ«r se çfarĂ« duam nga pinsat, kĂ«shtu qĂ« kĂ«tu do tĂ« kaloj pa kapjen e ekranit, thjesht do tĂ« them se MODE pĂ«rcakton drejtimin (hyrje, nĂ«se tĂ« dy bitat janĂ« nĂ« 0) dhe shpejtĂ«sinĂ« e pinave (na nevojitet 50MHz, domethĂ«nĂ«, tĂ« dy pinat nĂ« "1"), ndĂ«rsa CNF pĂ«rcakton modin: hyrĂ«s "tĂ«rheqje-pushim" – 00, "alternativ" – 10. Siç e shohim lart, tĂ« gjithĂ« pinsat kanĂ« bitin e tretĂ« poshtĂ« (CNF0) qĂ« i vendos nĂ« modin input floating.

Duke pasur parasysh se planifikoj të bëj diçka tjetër me këtë çip, për thjeshtësi kam definuar gjithashtu të gjitha vlerat e mundshme MODE dhe CNF për regjistrat e kontrollit të poshtëm dhe atyre të sipërm.

Ashtu siç e shohim

#define CNF0_0 0x00000004
#define CNF0_1 0x00000008
#define CNF1_0 0x00000040
#define CNF1_1 0x00000080
#define CNF2_0 0x00000400
#define CNF2_1 0x00000800
#define CNF3_0 0x00004000
#define CNF3_1 0x00008000
#define CNF4_0 0x00040000
#define CNF4_1 0x00080000
#define CNF5_0 0x00400000
#define CNF5_1 0x00800000
#define CNF6_0 0x04000000
#define CNF6_1 0x08000000
#define CNF7_0 0x40000000
#define CNF7_1 0x80000000
#define CNF8_0 0x00000004
#define CNF8_1 0x00000008
#define CNF9_0 0x00000040
#define CNF9_1 0x00000080
#define CNF10_0 0x00000400
#define CNF10_1 0x00000800
#define CNF11_0 0x00004000
#define CNF11_1 0x00008000
#define CNF12_0 0x00040000
#define CNF12_1 0x00080000
#define CNF13_0 0x00400000
#define CNF13_1 0x00800000
#define CNF14_0 0x04000000
#define CNF14_1 0x08000000
#define CNF15_0 0x40000000
#define CNF15_1 0x80000000

#define MODE0_0 0x00000001
#define MODE0_1 0x00000002
#define MODE1_0 0x00000010
#define MODE1_1 0x00000020
#define MODE2_0 0x00000100
#define MODE2_1 0x00000200
#define MODE3_0 0x00001000
#define MODE3_1 0x00002000
#define MODE4_0 0x00010000
#define MODE4_1 0x00020000
#define MODE5_0 0x00100000
#define MODE5_1 0x00200000
#define MODE6_0 0x01000000
#define MODE6_1 0x02000000
#define MODE7_0 0x10000000
#define MODE7_1 0x20000000
#define MODE8_0 0x00000001
#define MODE8_1 0x00000002
#define MODE9_0 0x00000010
#define MODE9_1 0x00000020
#define MODE10_0 0x00000100
#define MODE10_1 0x00000200
#define MODE11_0 0x00001000
#define MODE11_1 0x00002000
#define MODE12_0 0x00010000
#define MODE12_1 0x00020000
#define MODE13_0 0x00100000
#define MODE13_1 0x00200000
#define MODE14_0 0x01000000
#define MODE14_1 0x02000000
#define MODE15_0 0x10000000
#define MODE15_1 0x20000000

Pinsat tanĂ« ndodhen nĂ« portin B (adresa bazĂ« – 0x40010C00), kodi:

#define _PORTB_(mem_offset) (*(volatile uint32_t *)(0x40010C00 + (mem_offset)))

#define _BRR  0x14
#define _BSRR 0x10
#define _CRL  0x00
#define _CRH  0x04

//ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”ĐŒ ŃŃ‚Đ°ĐœĐŽĐ°Ń€Ń‚ĐœŃ‹Đč SPI2: MOSI ĐœĐ° B15, CLK ĐœĐ° B13
//LAT пусть Đ±ŃƒĐŽĐ”Ń‚ ĐœĐ° ĐœĐ”ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”ĐŒĐŸĐŒ MISO – B14

//ĐŸŃ‡ĐžŃ‰Đ°Đ”ĐŒ ĐŽĐ”Ń„ĐŸĐ»Ń‚ĐœŃ‹Đč бОт, ĐŸĐœ ĐœĐ°ĐŒ Ń‚ĐŸŃ‡ĐœĐŸ ĐœĐ” ĐœŃƒĐ¶Đ”Đœ
_PORTB_ (_CRH) &= ~(CNF15_0 | CNF14_0 | CNF13_0 | CNF12_0);

//Đ°Đ»ŃŒŃ‚Đ”Ń€ĐœĐ°Ń‚ĐžĐČĐœŃ‹Đ” Ń„ŃƒĐœĐșцоо ĐŽĐ»Ń MOSI Đž SCK
_PORTB_ (_CRH) |= CNF15_1 | CNF13_1;

//50 МГц, MODE = 11
_PORTB_ (_CRH) |= MODE15_1 | MODE15_0 | MODE14_1 | MODE14_0 | MODE13_1 | MODE13_0;

Dhe, përkatësisht, mund të shkruaj definita për LAT, që do të lëvizë regjistrat BRR dhe BSRR:

/*** LAT pulse – high, then low */
#define LAT_pulse() _PORTB_(_BSRR) = (1<<14); _PORTB_(_BRR) = (1<<14)

#define LAT_low() _PORTB_(_BRR) = (1<<14)

(LAT_low thjesht nga inertia, siç ka qenë gjithmonë, le të mbetet)

Tani gjithçka është mirë, vetëm se nuk punon. Sepse ky është STM32, këtu kursen energji, dhe do të duhet të aktivizojmë taktimin e periferisë që na nevojitet.

Aktivizojmë taktimin

Për taktimin përgjigjen orët, të cilat gjithashtu njihen si Clock. Dhe kemi vënë re shkronjën RCC. E kërkojmë në dokumentacion: kjo është Kontrolli i Rinisë dhe Taktimit.

Siç u tha më sipër, fatmirësisht, më e komplikuara nga tema e taktimit është bërë për ne nga njerëzit e STM, për të cilët ju falënderojmë shumë (po ashtu do të jap një lidhje në faqen e Di Halt'it, në mënyrë që të kuptohet se sa e komplikuar është). Na nevojiten vetëm regjistrat që janë përgjegjës për aktivizimin e taktimit të periferisë (Regjistrat e Aktivizimit të Takti). Fillimisht, gjejmë adresën bazë RCC, e cila ndodhet në fillim të "Hartës së Memories":

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

#define _RCC_(mem_offset) (*(volatile uint32_t *)(0x40021000 + (mem_offset)))

Dhe më pas ose klikoni lidhjen, ku do të përpiqemi të gjejmë diçka në tabelë, ose, shumë më mirë, kaloni nëpër përshkrimet e regjistrave të përfshirë nga seksionet mbi regjistrat e aktivizimit. Ku do të gjejmë RCC_APB1ENR dhe RCC_APB2ENR:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Dhe në to, përkatësisht, bitët që aktivizojnë taktimin për SPI2, IOPB (I/O Port B) dhe funksionet alternative (AFIO).

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

#define IOPBEN 0x0008
#define SPI2EN 0x4000
#define AFIOEN 0x0001

//ĐČĐșĐ»ŃŽŃ‡Đ°Đ”ĐŒ таĐșŃ‚ĐžŃ€ĐŸĐČĐ°ĐœĐžĐ” ĐżĐŸŃ€Ń‚Đ° B Đž Đ°Đ»ŃŒŃ‚. Ń„ŃƒĐœĐșцоĐč
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//ĐČĐșĐ»ŃŽŃ‡Đ°Đ”ĐŒ  таĐșŃ‚ĐžŃ€ĐŸĐČĐ°ĐœĐžĐ” SPI2
_RCC_(_APB1ENR) |= SPI2EN;

Kodi përfundimtar mund të gjendet këtu.

Nëse keni mundësi dhe dëshIroni të testoni, lidhni DM634 në këtë mënyrë: DAI në PB15, DCK në PB13, LAT në PB14. Ushqeni drejtuesin nga 5 volt, mos harroni të bashkoni tokat.

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

STM8 PWM

PWM në STM8

Kur sapo po planifoja këtë artikull, vendosa për shembull të provoja të zotëroja ndonjë funksionalitet të një çipi që nuk e njihja përmes dokumentacionit, për të mos qenë si një këpucë që s'ka këpucë. STM8 ishte perfekt për këtë rol: së pari, kisha disa tabela kineze me STM8S103, dhe së dyti, ai nuk është aq popullor, kështu që tundimi për të lexuar dhe gjetur një zgjidhje në internet përballet me mungesën e këtyre zgjidhjeve.

PĂ«r çipin gjithashtu ka datasheet dhe manualin e referencĂ«s RM0016, nĂ« tĂ« parin pinout dhe adresat e regjistrave, ndĂ«rsa nĂ« tĂ« dytin – gjithçka tjetĂ«r. STM8 programohet nĂ« C nĂ« njĂ« IDE tĂ« çuditshme ST Visual Develop.

Taktimi dhe hyrja-dalja

Si fillim, STM8 punon me një frekuencë prej 2 MHz, kjo duhet korrigjuar menjëherë.

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Sinjali i taktimit HSI (i brendshëm i shpejtë)
Sinjali i taktimit HSI merret nga një gjenerator RC 16-MHz të brendshëm me një ndarës të programueshëm (nga 1 deri në 8). Ai përcaktohet në regjistrin e ndarësit të sinjalit të taktimit (CLK_CKDIVR).
Shënim: në fillim, burimi kryesor i sinjalit të taktimeve zgjidhet HSI RC-gjeneratori me ndarës 8.

Gjejmë adresën e regjistrit në datasheet, përshkrimin në refman dhe shohim se regjistri duhet të pastrohet:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Duke qenë se po përgatitemi të aktivizojmë PWM dhe të lidhim LED-et, le të shohim ndarjen e pinëve:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Çipi Ă«shtĂ« i vogĂ«l, shumĂ« funksione janĂ« varur nĂ« tĂ« njĂ«jtĂ«t pinĂ«. Ajo qĂ« ndodhet nĂ« katrorĂ«t [] – "funksionalitet alternativ", mund tĂ« kalojĂ« "me bajta opsionesh" (option bytes) – diçka si fuse tĂ« Atmega. Vlerat e tyre mund tĂ« ndryshohen nĂ« mĂ«nyrĂ« programore, por nuk Ă«shtĂ« e nevojshme, pasi funksionaliteti i ri aktivizohet vetĂ«m pas ripĂ«rtĂ«ritjes. MĂ« e lehtĂ« Ă«shtĂ« tĂ« pĂ«rdorin ST Visual Programmer (i cili shkarkohet me Visual Develop), duke qenĂ« se di tĂ« ndryshojĂ« kĂ«to bajta. NĂ« ndarjen e pinĂ«ve, Ă«shtĂ« e qartĂ« se daljet CH1 dhe CH2 tĂ« timerit tĂ« parĂ« janĂ« tĂ« fshehura nĂ« katrorĂ«t; duhet tĂ« vendosim bitĂ«t AFR1 dhe AFR0 nĂ« STVP, ndĂ«rsa toni i dytĂ« gjithashtu do tĂ« transferojĂ« daljen CH1 tĂ« timerit tĂ« dytĂ« nga PD4 nĂ« PC5.

Prandaj, ne do të menaxhojmë LED-et me 6 pinë: PC6, PC7 dhe PC3 për timerin e parë, PC5, PD3 dhe PA3 për timerin e dytë.

Konfigurimi i vetë pinëve të hyrjes-daljes në STM8 është më i lehtë dhe më logjik se në STM32:

  • regjistri i njohur i drejtimit tĂ« tĂ« dhĂ«nave DDR (Data Direction Register): 1 = dalje;
  • regjistri i parĂ« kontrollues CR1 pĂ«r daljen pĂ«rcakton modalitetin "tĂ«rheqje-tulĂ«" (1) ose kolektor tĂ« hapur (0); pasi e lidh LED-et me çipin me katoda, lĂ« kĂ«tu zero;
  • regjistri i dytĂ« kontrollues CR2 pĂ«r daljen pĂ«rcakton shpejtĂ«sinĂ« e taktimeve: 1 = 10 MHz

#define PA_DDR     *(volatile uint8_t *)0x005002
#define PA_CR2     *(volatile uint8_t *)0x005004
#define PD_DDR     *(volatile uint8_t *)0x005011
#define PD_CR2     *(volatile uint8_t *)0x005013
#define PC_DDR     *(volatile uint8_t *)0x00500C
#define PC_CR2     *(volatile uint8_t *)0x00500E

PA_DDR = (1<<3); //output
PA_CR2 |= (1<<3); //fast
PD_DDR = (1<<3); //output
PD_CR2 |= (1<<3); //fast
PC_DDR = ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //output
PC_CR2 |= ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //fast

Konfigurimi i PWM

Fillimisht le të përcaktojmë terminologjinë:

  • PWM Frequency – frekuenca me tĂ« cilĂ«n bie timeri;
  • Auto-reload, AR – vlera e vetĂ«-ngarkuar, deri nĂ« tĂ« cilĂ«n do tĂ« numĂ«rojĂ« timeri (periudha e impulsit);
  • Update Event, UEV – ngjarja qĂ« ndodh kur timeri ka arritur AR;
  • PWM Duty Cycle – koeficienti i mbushjes sĂ« PWM, shpesh quhet "pjesĂ«marrje";
  • Capture/Compare Value – vlera pĂ«r kapjen/krahasimin, deri nĂ« tĂ« cilin timeri do tĂ« bĂ«jĂ« diçka (nĂ« rastin e PWM – inverton sinjalin dalĂ«s);
  • Preload Value – vlera e parapaguar. Vlera e krahasimit nuk mund tĂ« ndryshojĂ«, ndĂ«rsa timeri numĂ«ron, pĂ«rndryshe cikli PWM do tĂ« prishĂ«t. Prandaj, vlerat e reja tĂ« dĂ«rguara vendosen nĂ« njĂ« tampon dhe nxirren prej aty, kur timeri arrin fundin e numĂ«rimit dhe restet;
  • Edge-aligned dhe Center-aligned modes – rreshtimi sipas kufirit dhe sipas qendrĂ«s, si dhe ato tĂ« Atmel; Fast PWM dhe Phase-correct PWM.
  • OCiREF, Output Compare Reference Signal – sinjali referues dalĂ«s, nĂ« thelb, ajo qĂ« nĂ« modalitetin PWM ndodhet nĂ« pinin pĂ«rkatĂ«s.

Siç Ă«shtĂ« e qartĂ« nga ndarja e pinĂ«ve, mundĂ«sitĂ« e PWM i pĂ«rkasin dy timerĂ«ve – tĂ« parit dhe tĂ« dytit. TĂ« dy janĂ« 16-bit, tĂ« parit ka shumĂ« veçori shtesĂ« (pĂ«rfshirĂ« aftĂ«sinĂ« pĂ«r tĂ« numĂ«ruar lart dhe poshtĂ«). Na duhet qĂ« tĂ« dy tĂ« funksionojnĂ« njĂ«soj, kĂ«shtu qĂ« vendosa tĂ« filloj me tĂ« dytin, i cili Ă«shtĂ« mĂ« i varfĂ«r, pĂ«r tĂ« mos pĂ«rdorur rastĂ«sisht diçka qĂ« nuk e ka. NjĂ« problem e shkakton shpjegimi i funksionalitetit tĂ« PWM tĂ« tĂ« gjithĂ« timerĂ«ve nĂ« manualin referues qĂ« ndodhet nĂ« kapitullin pĂ«r timerin e parĂ« (17.5.7 PWM Mode), kĂ«shtu qĂ« duhet tĂ« hidhemi gjithmonĂ« atje-kĂ«tu nĂ« dokument.

PWM në STM8 ka një përparësi të rëndësishme mbi PWM të Atmela:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
PWM me rreshtim sipas kufirit
Konfigurimi i numërimit nga poshtë lart
Numërimi nga poshtë lart është aktiv, nëse bita DIR në regjistrin TIM_CR1 është i zbrazët
Shembuj
Shembulli përdor modalitetin e parë të PWM. Sinjali referues PWM OCiREF mbahet në nivel të lartë, derisa TIM1_CNT < TIM1_CCRi. Përndryshe, ai merr nivel të ulët. Nëse vlera për krahasim në regjistrin TIM1_CCRi është më e madhe se vlera e vetë-ngarkuar (regjistri TIM1_ARR), sinjali OCiREF mbahet në 1. Nëse vlera për krahasim është 0, OCiREF mbahet në zero.


Timeri STM8 gjatë ngjarjes së përditësimit fillimisht kontrollon vlerën e krahasimit, dhe pastaj jep sinjalin referues. Në Atmega, timeri fillimisht punon, dhe pastaj krahasohet, si rezultat, kur vlera e krahasimit == 0 këtu rezulton një pikë, me të cilën duhet të luftojmë disi (p.sh., duke inverton logjikën programore).

Pra, çfarë dëshirojmë të bëjmë: PWM 8-bit (AR == 255), numërojmë nga poshtë lart, rreshtim sipas kufirit. Duke qenë se llambat janë të lidhura me çipin me katoda, PWM duhet të japë 0 (LED ndizet) deri vlerën e krahasimit dhe 1 më pas.

Tani kemi lexuar pĂ«r disa modalitete PWM, kĂ«shtu qĂ« po kĂ«rkojmĂ« regjistrin pĂ«rkatĂ«s tĂ« timerit tĂ« dytĂ« duke krijuar njĂ« kĂ«rkim nĂ« manualin referues me kĂ«tĂ« frazĂ« (18.6.8 – TIMx_CCMR1):

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
110: Modaliteti i parĂ« i PWM – gjatĂ« numĂ«rimit nga poshtĂ« lart, kanali i parĂ« Ă«shtĂ« aktiv derisa TIMx_CNT < TIMx_CCR1. PĂ«rndryshe, kanali i parĂ« nuk Ă«shtĂ« aktiv. [mĂ« pas nĂ« dokument ka njĂ« kopje tĂ« gabuar nga timeri 1]
111: Modaliteti i dytĂ« i PWM – gjatĂ« numĂ«rimit nga poshtĂ« lart, kanali i parĂ« nuk Ă«shtĂ« aktiv derisa TIMx_CNT < TIMx_CCR1. PĂ«rndryshe, kanali i parĂ« Ă«shtĂ« aktiv.

Duke qenë se LED-et janë të lidhura me MK me katoda, ne zgjidhim modalitetin e dytë (i pari gjithashtu, por ne ende nuk e dimë këtë).

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Biti 3 OC1PE: Aktivizo para-ngarkimin e daljes 1
0: Regjistri i parazgjedhjes në TIMx_CCR1 është i fikur. Mund të shkruhet në TIMx_CCR1 në çdo kohë. Vlera e re funksionon menjëherë.
1: Regjistri i parazgjedhjes në TIMx_CCR1 është i ndezur. Operacionet e leximit/shkrimit i drejtohen regjistrit të parazgjedhjes. Vlera e parazgjedhur TIMx_CCR1 ngarkohet në regjistrin e hijeve gjatë çdo ngjarjeje përditësimi.
*Shënim: për funksionimin e saktë të modit PWM, regjistrat e parazgjedhjes duhet të jenë të ndezur. Kjo nuk është e nevojshme në modin e sinjalit të vetëm (në regjistrin TIMx_CR1 është vendosur bita OPM).

Ok, aktivizojmë gjithçka që na nevojitet për tre kanale të orarit të dytë:

#define TIM2_CCMR1 *(volatile uint8_t *)0x005307
#define TIM2_CCMR2 *(volatile uint8_t *)0x005308
#define TIM2_CCMR3 *(volatile uint8_t *)0x005309

#define PWM_MODE2   0x70 //PWM mode 2, 0b01110000
#define OCxPE       0x08 //preload enable

TIM2_CCMR1 = (PWM_MODE2 | OCxPE);
TIM2_CCMR2 = (PWM_MODE2 | OCxPE);
TIM2_CCMR3 = (PWM_MODE2 | OCxPE);

AR përbëhet nga dy regjistra tetëbitësh, këtu gjithçka është e thjeshtë:

#define TIM2_ARRH  *(volatile uint8_t *)0x00530F
#define TIM2_ARRL  *(volatile uint8_t *)0x005310

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Orari i dytë mund të numërojë vetëm nga poshtë lart, pa ndonjë rregullim, nuk duhet të ndryshohet asgjë. Do të vendosim ndarësin e frekuencës, për shembull, në 256. Ndarësi i orarit të dytë vendoset në regjistrin TIM2_PSCR dhe përfaqëson një fuqi të dysh dhe:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Tani na mbetet të aktivizojmë daljet dhe vetë orarin e dytë. Problemi i parë zgjidhet nga regjistrat Capture/Compare Enable: ka dy, tre kanale shpërndara asimetrikisht mbi to. Këtu gjithashtu mund të kuptojmë se mund të ndryshohet polariteti i sinjalit, dmth në parim do të mund të përdorim edhe PWM Mode 1. Shkruajmë:

#define TIM2_CCER1 *(volatile uint8_t *)0x00530A
#define TIM2_CCER2 *(volatile uint8_t *)0x00530B

#define CC1E  (1<<0) // CCER1
#define CC2E  (1<<4) // CCER1
#define CC3E  (1<<0) // CCER2

TIM2_CCER1 = (CC1E | CC2E);
TIM2_CCER2 = CC3E;

Dhe, përfundimisht, aktivizojmë orarin në regjistrin TIMx_CR1:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Do të shkruajmë një analog të thjeshtë të AnalogWrite(), i cili do të dërgojë vlerat e orarit për krahasim. Regjistrat quhen parashikueshëm Capture/Compare registers, ka dy për çdo kanal: bits 8 të poshtme në TIM2_CCRxL dhe ato të sipërme në TIM2_CCRxH. Duke qenë se kemi vendosur PWM 8-bit, mjafton të shkruajmë vetëm bits e poshtme:

#define TIM2_CCR1L *(volatile uint8_t *)0x005312
#define TIM2_CCR2L *(volatile uint8_t *)0x005314
#define TIM2_CCR3L *(volatile uint8_t *)0x005316

void setRGBled(uint8_t r, uint8_t g, uint8_t b)
{
    TIM2_CCR1L = r;
    TIM2_CCR2L = g;
    TIM2_CCR3L = b;
}

Lexuesi i vëmendshëm do të vërejë se kemi krijuar një PWM pak të defektshëm, i cili nuk është në gjendje të japë 100% mbushje (me vlerën maksimale 255, sinjali invertohet për një cikël orari). Për LED-at kjo nuk ka rëndësi, dhe lexuesi i vëmendshëm tashmë e kupton se si ta rregullojë këtë.

PWM në orarin e dytë funksionon, kalojmë te ai i parë.

Orari i parë ka të njëjtat bita në regjistra të njëjtë (thjesht, ato bita që mbetën "të rezervuara" në orarin e dytë, në të parin përdoren aktivisht për gjëra të avancuara). Prandaj, mjafton të gjejmë adresat e këtyre regjistrave në datasheet dhe të kopjojmë kodin. Dhe të ndryshojmë vlerën e ndarësit të frekuencës, pasi orari i parë kërkon një vlerë të saktë të 16-bit, në dy regjistra. Prescaler High dhe I ulët. Tani gjithçka është bërë dhe... orari i parë nuk funksionon. Cila është problemi?

Mund të zgjidhet problemi vetëm duke e shqyrtuar të gjithë seksionin mbi regjistrat menaxhues të orarit 1, ku kërkojmë atë që nuk e ka orari i dytë. Do të gjendet 17.7.30 Regjistri i Ndërprerjeve (TIM1_BKR), ku ka këtë bit:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Aktivizo daljen kryesore

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Tani me siguri gjithçka është, kodi aty aty.

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

STM8 Multiplex

Multipleximi në STM8

Projekti i tretë mini konsiston në lidhjen e tetë LED RGB në orarin e dytë në modën PWM dhe të bëjmë që ato të tregojnë ngjyra të ndryshme. Në bazë është koncepti i multipleximit të LED, i cili thotë se nëse ndiznim dhe fiknim LED-et shumë shpejt, na do të duket se ato ndriçojnë vazhdimisht (persistence of vision, inercia e perceptimit vizual). Njëherë bëra diçka të tillë në Arduino.

Algoritmi i punës duket kështu:

  • lidha anodĂ«n e LED-it tĂ« parĂ« RGB;
  • e ndizĂ«m atĂ« duke dĂ«rguar sinjale tĂ« nevojshme nĂ« katodat;
  • prita pĂ«rfundimin e ciklit PWM;
  • lidha anodĂ«n e LED-it tĂ« dytĂ« RGB;
  • e ndizĂ«m atĂ«...

Dhe kështu me radhë. Sigurisht, për një punë të bukur është e nevojshme që lidhja e anodës dhe "ndizja" e LED-it të ndodhin në të njëjtën kohë. Ose të paktën pothuajse. Në çdo rast, na duhet të shkruajmë kodin që do të japë vlera në tri kanale të orarit të dytë dhe, me arritjen e UEV, t'i ndryshojë ato dhe njëkohësisht të ndërronte LED-in RGB aktiv.

Duke qenë se kalimi i LED-it bëhet automatikisht, duhet të krijojmë "memorinë vizuale", nga e cila menaxheri i ndërprerjeve do të marrë të dhëna. Ky është një varg i thjeshtë:

uint8_t colors[8][3];

Për të ndryshuar ngjyrën e një LED-i të caktuar, mjafton të shkruajmë vlerat e nevojshme në këtë varg. Ndërsa numri i LED-it aktiv do të menaxhohet nga variabli

uint8_t cnt;

Demux

PĂ«r multiplexim tĂ« saktĂ«, do tĂ« na nevojitet, siç duket, demultiplexer CD74HC238. Demultiplexer Ă«shtĂ« njĂ« çip, i cili realizon nĂ« harduer operatorin <<. PĂ«rmes tre pinĂ«ve hyrĂ«s (bitarĂ«t 0, 1 dhe 2) i japim njĂ« numĂ«r trebitĂ«sh X, dhe ai aktivizon daljen numĂ«r (1<<X). Hyrjet e tjera tĂ« çipit pĂ«rdoren pĂ«r tĂ« shkalluar tĂ« gjithĂ« konstrukcionin. Ky çip na nevojitet jo vetĂ«m pĂ«r tĂ« shkurtuar numrin e pinĂ«ve tĂ« zĂ«nĂ« tĂ« mikrocontrollerit, por gjithashtu pĂ«r siguri – pĂ«r tĂ« mos aktivizuar aksidentalisht mĂ« shumĂ« LED-a se sa Ă«shtĂ« e mundur dhe pĂ«r tĂ« mos djegur mikrocontrollerin. Çipi Ă«shtĂ« shumĂ« i lirĂ«, ia vlen ta mbash gjithmonĂ« nĂ« kuti e shpĂ«timit nĂ« shtĂ«pi.

CD74HC238 do të kujdeset për furnizimin me tension të anodës së LED-it të duhur. Në një mnojës të plotë, ai do të siguronte tension në kolumne përmes P-MOSFET, por në këtë demo mund të lidhet drejtpërdrejt, pasi tërheq 20 mA, sipas vlerat maksimale absolute datasheet-it. Nga datasheet-i CD74HC238 na nevojitet pinout dhe kjo fletore ndihmëse:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
H = nivel i lartĂ« tensioni, L = nivel i ulĂ«t tensioni, X – nuk ka rĂ«ndĂ«si

Lidhim E2 dhe E1 në tokë, E3, A0, A1 dhe A3 në pinat PD5, PC3, PC4 dhe PC5 të STM8. Duke qenë se tabela më sipër përmban si nivele të ulëta ashtu edhe të larta, konfiguroni këto pin si dalje push-pull.

PWM

PWM në timerin e dytë konfigurohet po ashtu si në historinë e kaluar, me dy dallime:

Së pari, duhet të aktivizojmë ndërprerjen për Ngjarjen e Përditësimit (UEV), e cila do të thërrasë funksionin që switch-on LED-in aktiv. Kjo bëhet duke ndryshuar bitin Lejimi i Ndërprerjeve të Përditësimit në regjistrin me emrin e qartë

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
Regjistri i Aktivizimit të Ndërprerjeve

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Dallimi i dytĂ« Ă«shtĂ« i lidhur me njĂ« fenomen tĂ« mnojĂ«simit, siç Ă«shtĂ« ghosting – ndriçimi i padĂ«shiruar i LED-ve. NĂ« rastin tonĂ«, kjo mund tĂ« ndodhĂ« sepse timer-i, i cili thĂ«rret ndĂ«rprerjen nĂ« UEV, vazhdon tĂ« tik-tak, dhe trajtuesi i ndĂ«rprerjes nuk arrin tĂ« ndĂ«rruar LED-in para se timer-i tĂ« fillojĂ« tĂ« jetĂ« aktiv. PĂ«r ta luftuar kĂ«tĂ«, do tĂ« duhet tĂ« inversojmĂ« logjikĂ«n (0 = ndriçimi maksimal, 255 = asnjĂ« ndriçim) dhe tĂ« shmangim vlerat ekstreme tĂ« raportit tĂ« plotĂ«sisĂ«. MĂ« saktĂ«sisht, do tĂ« sigurojmĂ« qĂ« pas UEV, LED-et tĂ« fikĂ«n plotĂ«sisht pĂ«r njĂ« taktikĂ« PWM.

Ndryshojmë polaritetin:

//set polarity 
    TIM2_CCER1 |= (CC1P | CC2P);
    TIM2_CCER2 |= CC3P;

Shmangni vendosjen e r, g dhe b në 255 dhe mos haroni t'i inversoni ato gjatë përdorimit.

Ndërprerjet

Qëllimi i ndërprerjes është që, në rrethana të caktuara, çipi ndalon ekzekutimin e programit kryesor dhe thërret një funksion të jashtëm. Ndërprerjet ndodhin nga ndikime të jashtme ose të brendshme, përfshirë nga timer-i.

Kur krijuam për herë të parë projektin në ST Visual Develop, përveç main.c morëm një dritare me një skedë enigmatike stm8_interrupt_vector.c, e cila u përfshi automatikisht në projekt. Në këtë skedë për çdo ndërprerje është lidhur një funksion NonHandledInterrupt. Na nevojitet të lidhim funksionin tonë me ndërprerjen e nevojshme.

Në datasheet ka një tabelë të vektorëve të ndërprerjeve, ku gjenden të nevojshmet:

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8
13 TIM2 përditësim/përmbushje
14 TIM2 kapje/krahasim

Na duhet të ndërronim LED-in gjatë UEV, kështu që na nevojitet ndërprerja nr. 13.

Për këtë, së pari, në skedën stm8_interrupt_vector.c ndryshojmë emrin e funksionit, përgjegjës për ndërprerjen nr. 13 (IRQ13) nga e paracaktuar në të tonën:

{0x82, TIM2_Overflow}, /* irq13 */

Së dyti, do të duhet të krijojmë një skedë main.h të tillë:

#ifndef __MAIN_H
#define __MAIN_H

@far @interrupt void TIM2_Overflow (void);
#endif

Dhe përfundimisht, të shkruajmë këtë funksion në main.c:

@far @interrupt void TIM2_Overflow (void)
{
    PD_ODR &= ~(1<<5); // fikim demultiplexer
    PC_ODR = (cnt<<3); // shkruajmë vlerën e re në demultiplexer
    PD_ODR |= (1<<5); // aktivizojmë demultiplexer

    TIM2_SR1 = 0; // zerojmë flamurin e Ndërprerjes të Prindodhur

    cnt++; 
    cnt &= 7; // lëvizim numëruesin e LED-it

    TIM2_CCR1L = ~colors[cnt][0]; // dërgojmë në buffer vlerat e inversuara
    TIM2_CCR2L = ~colors[cnt][1]; // për ciklin e ardhshëm PWM
    TIM2_CCR3L = ~colors[cnt][2]; // 

    return;
}

Ka mbetur tĂ« aktivizojmĂ« ndĂ«rprerjet. Kjo bĂ«het me komandĂ«n assembler rim – do tĂ« duhet ta kĂ«rkoni atĂ« nĂ« Manuali i Programimit:

//enable interrupts
_asm("rim");

Komanda tjetĂ«r assembler – sim – fik ndĂ«rprerjet. Ato duhet tĂ« fikĂ«n pĂ«rkohĂ«sisht gjatĂ« shkruarjes sĂ« vlerave tĂ« reja nĂ« “memorinĂ« vizuale”, nĂ« mĂ«nyrĂ« qĂ« njĂ« ndĂ«rprerje e thirrur nĂ« njĂ« moment tĂ« papĂ«rshtatshĂ«m tĂ« mos dĂ«mtojĂ« array-in.

I gjithë kodi është në GitHub.

Lexo fletët teknike 2: SPI në STM32; PWM, timerat dhe ndërprerjet në STM8

Nëse kjo artikull ndihmon ndonjë, do të thotë se nuk e kam shkruar kot. Do të jem i lumtur me komentet dhe vërejtjet, do të përpiqem t'u përgjigjem të gjitha.

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster