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

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

Në pjesën e parë Provova të shpjegoj elektronikëve hobi, të rritur nga Arduino, se si dhe pse duhet të lexojnë datashit dhe dokumentacionin tjetër për mikrocontrolerët. Teksti doli i gjatë, prandaj premtova të paraqes shembuj praktikë në një artikull të veçantë. Mirë, atëherë quhem kërpudha...

Sot do të tregoj se si, me ndihmën e datashit, të zgjidhim disa detyra të thjeshta, por të nevojshme për shumë projekte mbi kontrolerët STM32 (Blue Pill) dhe STM8. Të gjitha projektet demo i kushtohen dritave të mia të preferuara LED, do t'i ndezim ato në numër të madh, për të cilin do të angazhojmë periferi interesante.

Teksti përsëri doli jashtëzakonisht i gjatë, prandaj për lehtësi po bëj përmbajtje:

STM32 Blue Pill: 16 drita LED me driver DM634
STM8: Konfigurojmë gjashtë linja PWM
STM8: 8 drita LED RGB në tre pin, ndërprerje

Diskleimer: Unë nuk jam inxhinier, nuk pretendoj për njohuri të thella në elektronikë, ky artikull është për të njëjtit si unë pasionantë. Në të vërtetë, për publikun target e konsideroja veten time dy vjet më parë. Po të më kishte thënë dikush atëherë se leximin e datashit për një çip të panjohur nuk është e frikshme, nuk do të kisha humbur shumë kohë në kërkimin e disa copave kodi në internet dhe shpikjen e ndihmave me gishta dhe ndihma adhezuese.

Qendra e këtij artikulli janë datashitët, jo projektet, prandaj kodi mund të mos jetë shumë i pastër dhe shpesh i përcaktuar. Vetë projektet janë shumë të thjeshta, megjithatë të përshtatshme për një njohje të parë me një çip të ri.

Shpresoj që artikulli im të ndihmojë dikë në një fazë të ngjashme të futjes në hobin.

STM32

16 drita LED me DM634 dhe SPI

Një projekt i vogël duke përdorur Blue Pill (STM32F103C8T6) dhe driverin e dritës LED DM634. Me ndihmën e datashit, do të kuptojmë driverin, portet IO të STM dhe do të konfigurojmë SPI.

DM634

Çipi tajvanez me 16 dalje PWM 16-bitĂ«she, mund tĂ« lidhen nĂ« zinxhir. Modeli i vogĂ«l 12-bit Ă«shtĂ« i njohur pĂ«r projektin e brendshĂ«m Lightpack. NĂ« kohĂ«n e saj, duke zgjedhur midis DM63x dhe TLC5940 tĂ« njohur, vendosa pĂ«r DM pĂ«r disa arsye: 1) TLC nĂ« Aliexpress Ă«shtĂ« me siguri i falsifikuar, ndĂ«rsa ky – jo; 2) DM ka PWM autonom me gjeneratorin e tij tĂ« frekuencĂ«s; 3) mund ta blija me çmim tĂ« arsyeshĂ«m nĂ« MoskĂ«, e jo tĂ« prisja njĂ« dĂ«rgesĂ« nga Ali. Po ashtu, ishte interesante tĂ« mĂ«soja si ta menaxhoja çipin vetĂ«, e jo tĂ« pĂ«rdorja njĂ« bibliotekĂ« gati. Çipat tani kryesisht janĂ« tĂ« disponueshĂ«m nĂ« formĂ«n SSOP24, dhe nuk Ă«shtĂ« e vĂ«shtirĂ« t’i bashkĂ«ngjitim nĂ« njĂ« adaptues.

Duke qenë se prodhuesi është tajvanez, fletë të dhënash për çipin është shkruar në anglisht kinez, kështu që do të jetë argëtues. Fillimisht shikojmë lidhjet (Pin Connection), në mënyrë që të kuptojmë se cila këmbë lidhet me çfarë dhe përshkrimi i pinëve (Pin Description). 16 daljet:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Burimet e rrymës continue (stoku i hapur)

Sink / Open-drain output – stoku; burim i rrymĂ«s sĂ« ardhshme; dalje, kur Ă«shtĂ« aktive, Ă«shtĂ« e lidhur me tokĂ«n, – LED-tĂ« lidhen me drejtuesin nga katodet. NĂ« mĂ«nyrĂ« elektrike, sigurisht qĂ« nuk Ă«shtĂ« ndonjĂ« «stok i hapur» (open drain), por nĂ« datasheet-et kjo shĂ«njĂ« pĂ«rdoret shpesh pĂ«r pinĂ«t nĂ« mĂ«nyrĂ«n e stokut.

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

Midis pin-it REXT dhe tokĂ«s vendoset njĂ« rezistor reference, qĂ« kontrollon rezistencĂ«n e brendshme tĂ« daljeve, shih grafikun nĂ« fq. 9 tĂ« datasheet-it. NĂ« DM634, kjo rezistencĂ« gjithashtu mund tĂ« menaxhohet nĂ« mĂ«nyrĂ« programore, duke vendosur ndriçimin e pĂ«rgjithshĂ«m (global brightness); nuk do tĂ« hyj nĂ« detaje nĂ« kĂ«tĂ« artikull, thjesht do tĂ« vendos njĂ« rezistor prej 2.2 – 3 kΩ kĂ«tu.

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

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

Ah, ja ai, anglishtja kineze nĂ« gjithĂ« shkĂ«lqimin e saj. TĂ« pĂ«rkthesh kĂ«tĂ« Ă«shtĂ« problematike, mund ta kuptosh nĂ«se dĂ«shiron, por ka njĂ« rrugĂ« tjetĂ«r – tĂ« shohim si pĂ«rshkruhet lidhja nĂ« datasheet pĂ«r TLC5940, qĂ« Ă«shtĂ« funksionalisht e ngjashme:

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

 PĂ«r tĂ« futur tĂ« dhĂ«nat nĂ« pajisje ne duam vetĂ«m tre pinĂ«. Ura e pĂ«rparme e sinjalit SCLK zhvendos tĂ« dhĂ«nat nga pini SIN nĂ« regjistrin e brendshĂ«m. Pas ngarkimit tĂ« tĂ« gjitha tĂ« dhĂ«nave, njĂ« sinjal i shkurtĂ«r i lartĂ« XLAT fikson tĂ« dhĂ«nat e dĂ«rguara radhazi nĂ« regjistrat e brendshĂ«m. Regjistrat e brendshĂ«m – peshore qĂ« aktivizohen nga niveli i sinjalit XLAT. TĂ« gjitha tĂ« dhĂ«nat dĂ«rgohen me bitin mĂ« tĂ« lartĂ« pĂ«rpara.

Latch – peshore/fiksues.
Rising edge – ura e pĂ«rparme e impulsit
MSB first – bitin mĂ« tĂ« lartĂ« (bitin ekstrim tĂ« majtĂ«) pĂ«rpara.
pĂ«r tĂ« clock datat – pĂ«r tĂ« transmetuar tĂ« dhĂ«nat nĂ« mĂ«nyrĂ« sekondare (bit pĂ«r bit).

Fjala latch shpesh paraqitet në dokumentacionin e çipeve dhe përkthehet në mënyra të ndryshme, prandaj për të kuptuar lejoj veten një

pĂ«rmbledhje tĂ« vogĂ«lLED-drajveri – nĂ« thelb njĂ« regjistĂ«r lĂ«vizĂ«s. "LĂ«vizje" (shift) nĂ« emĂ«r do tĂ« thotĂ« lĂ«vizje bitĂ«sh brenda pajisjes: çdo bit i ri qĂ« shtohet brenda shtyn tĂ« gjithĂ« zinxhirin pĂ«rpara. Duke qenĂ« se gjatĂ« lĂ«vizjes askush nuk dĂ«shiron tĂ« shohĂ« njĂ« ndricim kaotik tĂ« LED-Ă«ve, procesi ndodh nĂ« regjistra buffer, tĂ« ndarĂ« nga njĂ« bllokim (latch) – kjo Ă«shtĂ« njĂ« lloj pritjeje, ku bitĂ«t rreshtohen nĂ« rendin e nevojshĂ«m. Kur gjithçka Ă«shtĂ« gati, bllokimi hapet dhe bitĂ«t dĂ«rgohen tĂ« punojnĂ«, duke zĂ«vendĂ«suar grupin e kaluar. Fjala latch nĂ« dokumentacionin e mikroçipave shpesh nĂ«nkupton njĂ« bllokim tĂ« tillĂ«, pa marrĂ« parasysh kombinimet nĂ« tĂ« cilat pĂ«rdoret.

Pra, transmetimi i të dhënave në DM634 bëhet kështu: vendosim hyrjen DAI në vlerën e bitit më të lartë të LED-it të largët, tërheqim DCK lart-poshtë; vendosim hyrjen DAI në vlerën e bitit tjetër, tërheqim DCK; dhe kështu me radhë, derisa të gjithë bitët të jenë transmetuar (clocked in), pas së cilës tërheqim LAT. Këtë mund ta bëjmë manualisht (bit-bang), por është më mirë të përdorim një ndërfaqe të veçantë për këtë, dhe fatmirësisht ajo është e pranishme në STM32 tonë në dy kopje.

Pilula Blu STM32F103

Hyrjet: kontrollorĂ«t STM32 – janĂ« ndjeshĂ«m mĂ« tĂ« komplikuar se Atmega328, pĂ«r sa i pĂ«rket asaj qĂ« mund tĂ« trembin. NĂ« tĂ« njĂ«jtĂ«n kohĂ«, pĂ«r arsye energjetike, nĂ« fillim pothuajse e gjithĂ« periferia Ă«shtĂ« e ndaluar, dhe frekuenca e orĂ«s Ă«shtĂ« 8 MHz nga burimi i brendshĂ«m. FatmirĂ«sisht, programuesit e STM shkruan kodin qĂ« e çon çipin nĂ« "frekuencat" 72 MHz, dhe autorĂ«t e tĂ« gjitha IDE-ve tĂ« njohura qĂ« di unĂ« e pĂ«rfshinĂ« atĂ« nĂ« procedurĂ«n e inicimit, kĂ«shtu qĂ« nuk na duhet ta orientojmĂ« (por mundemi nĂ«se dĂ«shirojmĂ« shumĂ«). MegjithatĂ«, do tĂ« duhet tĂ« aktivizojmĂ« periferi.

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

Në fletën e dhënash na interesojnë:

  • Pinouts – definicionet e çipave – pĂ«r rasti kur vendosim tĂ« bĂ«jmĂ« vetĂ« pllakata;
  • HartĂ« Memorje – harta e memories pĂ«r njĂ« çip specifik. NĂ« Manualin Reference ka njĂ« hartĂ« pĂ«r tĂ« gjithĂ« linjĂ«n, ku pĂ«rmenden regjistrat qĂ« nuk gjenden te ne.
  • Tabela e Definimin e Pin-Ă«ve – njĂ« listĂ« me funksionet kryesore dhe alternative tĂ« pin-Ă«ve; pĂ«r "tabletĂ«n blu", nĂ« internet mund tĂ« gjeni figura mĂ« tĂ« pĂ«rshtatshme me listĂ«n e pin-Ă«ve dhe funksioneve tĂ« tyre. Pra, menjĂ«herĂ« gjejmĂ« pinout pĂ«r Blue Pill dhe mbajmĂ« kĂ«tĂ« figurĂ« nĂ« dorĂ«:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
NB: nĂ« figurĂ«n nga interneti kishte njĂ« gabim, i cili u vĂ«rejt nĂ« komentet, pĂ«r tĂ« cilin falĂ«nderojmĂ«. Figura Ă«shtĂ« zĂ«vendĂ«suar, por kjo Ă«shtĂ« njĂ« mĂ«sim — informacioni qĂ« nuk vjen nga datasheet-et Ă«shtĂ« mĂ« mirĂ« tĂ« verifikohet.

Hiqim datasheet-in, hapim Manualin Reference, tani do të përdorim vetëm atë.
Renditja e veprimeve: mësojmë mbi hyrjen/daljen standarde, konfiguroni SPI, aktivizoni periferi të nevojshme.

Hyrje-dalje

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

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
dalje me stok të hapur, dalje "tërheqëse-dhënëse", alternative "tërheqëse-dhënëse", stok i hapur alternativ

"TĂ«rheqĂ«se-dhĂ«nĂ«se" (push-pull) – njĂ« dalje e njohur nga Arduino, pin-i mund tĂ« ketĂ« ose vlerĂ«n HIGH ose LOW. NdĂ«rsa me "stok tĂ« hapur" dalin vĂ«shtirĂ«si, megjithatĂ« nĂ« tĂ« vĂ«rtetĂ«, gjithçka Ă«shtĂ« e thjeshtĂ«:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Konfigurimi i daljes / kur porta Ă«shtĂ« caktuar pĂ«r dalje: / aktivizohet buferi i daljes: / – mod i 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) / – mod "tĂ«rheqĂ«se-dhĂ«nĂ«se": "0" nĂ« regjistrin e daljes aktivizon N-MOS, "1" nĂ« regjistrin e daljes aktivizon P-MOS.

E gjithë dallimi i stokut të hapur (open drain) nga "tërheqëse-dhënëse" (push-pull) qëndron në faktin se në të parin, pin-i nuk mund të marrë gjendjen HIGH: kur shkruhet një njësi në regjistrin e daljes, ai kalon në modin e rezistencës së lartë (high impedance, Hi-Z). Kur shkruhet zero, pin-i në të dyja modalitetet vepron në të njëjtën mënyrë, si logjikisht ashtu edhe elektrikisht.

Në modin normal të daljes, pin-i thjesht transmeton përmbajtjen e regjistrit të daljes. Në "modalitetin alternativ", ai menaxhohet nga periferia përkatëse (shih. 9.1.4):

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Nëse bita i portës është i konfiguruar si një dalje funksion i alternativ, regjistri i daljes shkëputet, dhe pin-i lidhet me sinjalin e daljes nga periferi.

Funksionaliteti alternativ i çdo pin-i përshkruhet në Definimet e Pin-ëve flet, dhe ajo është në imazhin e shkarkuar. Për pyetjen se çfarë të bëni nëse pini ka disa funksione alternative, përgjigjen e jep nota në flet.

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Nëse disa blloqe periferike përdorin të njëjtin pin, për të shmangur konfliktin midis funksioneve alternative, duhet të përdoret një bllok periferik në të njëjtën kohë, duke kaluar me bitin e aktivizimit të taktimeve të periferisë (në regjistrin përkatës RCC).

Së fundmi, pikat në modalitetin e daljes kanë gjithashtu shpejtësinë e taktimeve. Kjo është një tjetër tipare kursimi energjie, në rastin tonë thjesht vendosim në maksimum dhe harrojmë.

Pra: ne pĂ«rdorim SPI, kjo do tĂ« thotĂ« qĂ« dy pinit (me tĂ« dhĂ«na dhe me sinjal taktim) duhet tĂ« jenĂ« "funksion alternativ tĂ«rheqĂ«si-dhĂ«nĂ«s", dhe njĂ« tjetĂ«r (LAT) – "tĂ«rheqĂ«si i zakonshĂ«m-dhĂ«nĂ«s". Por para se t'i caktojmĂ«, le tĂ« sqarojmĂ« SPI-nĂ«.

SPI

Një shpjegim i vogël

SPI ose Serial Peripheral Interface (ndĂ«rfaqja periferike seriale) – njĂ« ndĂ«rfaqe e thjeshtĂ« dhe tepĂ«r efektive pĂ«r komunikimin e MK me MK tĂ« tjera dhe nĂ« pĂ«rgjithĂ«si me botĂ«n e jashtme. Prinsipi i saj i punĂ«s Ă«shtĂ« pĂ«rshkruar tashmĂ« mĂ« sipĂ«r, atje ku flitet pĂ«r drejtorin LED kinez (nĂ« manualin e referencĂ«s, shiko seksionin 25). SPI mund tĂ« funksionojĂ« nĂ« modalitetin e masterit („pronarit”) dhe tĂ« skllavit („skllavit”). SPI ka katĂ«r kanale bazĂ«, nga tĂ« cilat mund tĂ« aktivizohen jo tĂ« gjithĂ«:

  • MOSI, Master Output / Slave Input: ky pin nĂ« modalitetin e masterit jep tĂ« dhĂ«na, dhe nĂ« modalitetin e skllavit merr tĂ« dhĂ«na;
  • MISO, Master Input / Slave Output: pĂ«rkundrazi, nĂ« master merr, nĂ« skllav jep;
  • SCK, Serial Clock: pĂ«rcakton frekuencĂ«n e transmetimit tĂ« tĂ« dhĂ«nave nĂ« master ose merr sinjal taktim nĂ« skllav. NĂ« thelb, ai rrah bitet;
  • SS, Slave Select: me kĂ«tĂ« kanal skllavi merr vesh se dikush e dĂ«shiron atĂ«. NĂ« STM32 quhet NSS, ku N = negative, dmth kontrollori bĂ«het skllav nĂ«se nĂ« kĂ«tĂ« kanal Ă«shtĂ« toka. Kombinohet mirĂ« me modalitetin Open Drain Output, por kjo Ă«shtĂ« njĂ« histori tjetĂ«r.

Siç është çdo gjë tjetër, SPI në STM32 është i pasur me funksionalitete, të cilat paksa e komplikojnë kuptimin e tij. Për shembull, ai di të punojë jo vetëm si SPI, por edhe si një ndërfaqe I2S, dhe për më tepër, në dokumentacionin e tyre përshkrimi është i ngatërruar, duhet të ndajmë të tepërtin në kohë. Misioni ynë është shumë i thjeshtë: duhet thjesht të dërgojmë të dhëna, duke aktivizuar vetëm MOSI dhe SCK. Shkoni në seksionin 25.3.4 (komunikimi me gjysmë-dupleks, komunikimi gjysmë-dhënës), ku gjejmë 1 clock and 1 unidirectional data wire (1 sinjal taktim dhe 1 rrjedhë të dhënash njëanësore):

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Në këtë modalitet, aplikacioni përdor SPI ose në modalitetin e transmetimit të vetëm, ose të pranimit të vetëm. / Modaliteti i transmetimit të vetëm është i ngjashëm me modalitetin dupleks: të dhënat transmetohen përmes pin-it transmetues (MOSI në modalitetin e mjeshtrit ose MISO në modalitetin e skllavit), dhe pini i pranuar (MISO ose MOSI përkatësisht) mund të përdoret si një pin i zakonshëm hyrës-dalës. Në këtë rast, aplikacioni thjesht duhet të injorojë tamponin Rx (nëse e lexoni, aty nuk do të ketë të dhëna të transmetuara).

Shkëlqyeshëm, pini MISO tani është i lirë, do ta lidhim me sinjalin LAT. Do të merremi me Slave Select, i cili në STM32 mund të kontrollohet programatikisht, që është jashtëzakonisht e përshtatshme. Lexojmë paragrafi me të njëjtin emër të seksionit 25.3.1 Përshkrimi i Përgjithshëm të SPI:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Kontrolli programatik i NSS (SSM = 1) / Informacioni mbi zgjedhjen e skllavit përmbanet në bitin SSI të regjistrit SPI_CR1. Pini i jashtëm NSS mbetet i lirë për nevoja të tjera të aplikacionit.

ËshtĂ« koha tĂ« shkruajmĂ« nĂ« regjistra. Kam vendosur tĂ« pĂ«rdor SPI2, gjejmĂ« adresĂ«n e tij bazĂ« nĂ« dokumentin e tĂ« dhĂ«nave – nĂ« seksionin 3.3 HartĂ« e MemorisĂ«:

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

Pra, le të fillojmë:

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

Hapim seksionin 25.3.3 me emrin qĂ« flet ‘Konfigurimi i SPI nĂ« modalitetin mjeshtĂ«r’:

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

1. Cilësoni frekuencën e taktimeve të interfeces sekuencial me bits BR[2:0] në regjistrin SPI_CR1.

Regjistrat janĂ« tĂ« mbledhur nĂ« seksionin e njĂ«jtĂ« tĂ« manualit referues. Shkalla e adresĂ«s (Address offset) te CR1 – 0x00, si rregull tĂ« gjithĂ« bitĂ«t janĂ« resetuar (Reset value 0x0000):

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

Bitët BR vendosin ndarësin e frekuencës së kontrollorit, duke përcaktuar kështu frekuencën me të cilën do të punojë SPI. Frekuenca e STM32 do të jetë 72 MHz, dhe LED-drivieri, sipas dokumentit të tij të të dhënave, punon me një frekuencë deri në 25 MHz, kështu që duhet të ndajmë me 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 ndërmjet transmetimit të të dhënave dhe taktimeve të interfeces sekuencial (shih skemën në fq. 240)

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

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Faza dhe polariteti i sinjalit të taktimeve
Me ndihmën e bitëve CPOL dhe CPHA të regjistrit SPI_CR1, mund të zgjidhni programatikisht katër variante marrëdhëniesh të kohëve. Biti CPOL (polariteti i sinjalit të taktimeve) kontrollon gjendjen e sinjalit të taktimeve kur të dhënat nuk transmetohen. Ky bit kontrollon modalitetet mjeshtër dhe skllav. Nëse CPOL është resetuar, pini SCK në modalitetin e qetësisë është në nivelin e ulët. Nëse biti CPOL është vendosur, pini SCK në modalitetin e qetësisë është në nivelin e lartë.
Nëse është vendosur bita CPHA (fazën e ciklit të sinjalit), brenda sinjalit SCK, fronti i dytë i sinjalit shërben si strobe për bitin më të lartë (rdhjesa, nëse CPOL është zero, ose rritja, nëse CPOL është e vendosur). Të dhënat regjistrohen me ndryshimin e dytë të ciklit të sinjalit. Nëse bita CPHA është zero, fronti i parë i sinjalit SCK shërben si strobe për bitin më të lartë (rdhjesa, nëse CPOL është i vendosur, ose rritja, nëse CPOL është zero). Të dhënat regjistrohen me ndryshimin e parë të ciklit të sinjalit.

Duke u thelluar në këto njohuri, arrijmë në përfundimin se të dy bita duhet të mbeten zero, sepse duam që sinjali SCK të mbetet i ulur kur nuk përdoret, dhe të dhënat të transmetohen me frontin e rritjes së impulsit (shih Rising Edge në fletën e të dhënave DM634).

Sigurisht, kĂ«tu pĂ«r herĂ« tĂ« parĂ« u pĂ«rballĂ« me njĂ« veçori tĂ« leksikut nĂ« fletat e tĂ« dhĂ«nave ST: nĂ« to fraza ‘tĂ« rivendosĂ«sh bitin nĂ« zero’ shkruhet to reset a bit, e jo to clear a bit, si pĂ«r shembull nĂ« Atmega.

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

E mora veçanërisht DM634 16-bitë për të mos u shqetësuar me transmetimin e të dhënave 12-bitë PWM, siç është DM633. DFF ka kuptim të vendoset në një:

#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 blokut

LSBFIRST, siç tregon emri i tij, konfiguroni transmetimin duke filluar nga bita më i ulët. Por DM634 dëshiron të marrë të dhëna duke filluar nga bita më e lartë. Prandaj, e lëmë të paprekur.

5. Në modalitetin harduerik, nëse kërkohet hyrja nga pina NSS, jepni një sinjal të lartë në pinin NSS gjatë tërë sekuencës së transmetimit të byte-ëve. Në modalitetin programues NSS vendosni bita SSM dhe SSI në regjistrin SPI_CR1. Nëse pini NSS duhet të punojë si dalëse, duhet të vendosni vetëm bitin SSOE.

Vendosim SSM dhe SSI, për të harruar 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ë vendosur bita MSTR dhe SPE (këta mbeten të vendosur vetëm nëse në NSS jepet një sinjal i lartë)

Në fakt, me këta bita ne emërojmë SPI-në tonë si master dhe e aktivizojmë 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-ët tek drejtuesi. Vazhdoni të lexoni 25.3.3 'Konfigurimi i SPI në modalitetin master':

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Rendi i transmetimit të të dhënave
Transmetimi fillon kur një byte shkruhet në tamponin Tx.
Byte i të dhënave ngarkohet në regjistrin e lëvizjes në modalitetin paralel (nga autobusi i brendshëm) gjatë transmetimit të bitit të parë, pas së cilës transmetohet në modalitetin e në modalitetin e pin MOSI, me bitin e parë ose të fundit përpara në varësi të vendosjes së bitit LSBFIRST në regjistrin CPI_CR1. Flagi TXE vendoset pas dërgesës së të dhënave nga buferri Tx në regjistrin e zhvendosjes, dhe gjithashtu krijohet një ndërprerje nëse blloku TXEIE është vendosur në regjistrin CPI_CR1.

Kam nxjerrë disa fjalë në përkthim për të theksuar një veçori të realizimit të SPI në kontrolerët STM. Në Atmega, flagi TXE (Tx Empty, Tx është bosh dhe gati për të pranuar të dhëna) vendoset vetëm pas dërgimit të gjithë bajtëve jashtë. Ndërsa këtu, ky flag vendoset pasi bajti është futur në regjistrin e brendshëm të zhvendosjes. Pavarësisht se ai futet me të gjithë bitët njëherësh (paralelisht), të dhënat dërgohen më pas në mënyrë të njëpasnjëshme, TXE vendoset para se bajti të dërgohet plotësisht. Kjo është e rëndësishme, sepse në rastin e drejtuesit tonë të LED-ve, na duhet të lëvizim pinin LAT pas dërgimit të gjitha të dhënave, dmth, vetëm flagu TXE nuk do të jetë i mjaftueshëm.

Kjo do tĂ« thotĂ« se na nevojitet edhe njĂ« flag tjetĂ«r. Le tĂ« shohim nĂ« 25.3.7 – "FlakĂ«t e Statusit":

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
<
>
Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Flagi BUSY
Flagi BSY vendoset dhe resetohet në mënyrë harduerike (shkrimi në të nuk ndikon në asgjë). Flagi BSY tregon gjendjen e shtresës komunikative SPI.
Ai resetohet:
kur dërgimi përfundon (përveç modalitetit master, nëse dërgimi është i vazhdueshëm)
kur SPI është i çaktivizuar
kur ndodh një gabim në modalitetin master (MODF=1)
Nëse dërgimi nuk është i vazhdueshëm, flagi BSY resetohet midis çdo dërgimi të dhënash

Mirë, do të na duhen. Po përcaktojmë se ku ndodhet buferri Tx. Për këtë, le të lexojmë "Regjistrin e të Dhënave SPI":

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Bitët 15:0 DR[15:0] Regjistri i të Dhënave
Të dhënat e marra ose të dhënat për dërgim.
Regjistri i tĂ« dhĂ«nave ndahen nĂ« dy bufra – njĂ« pĂ«r shkrim (bufri i dĂ«rgimit) dhe njĂ« tjetĂ«r pĂ«r lexim (bufri i pranimit). Shkrimi nĂ« regjistrin e tĂ« dhĂ«nave shkruan nĂ« bufri Tx, ndĂ«rsa leximi nga regjistri i tĂ« dhĂ«nave do tĂ« kthejĂ« vlerĂ«n qĂ« gjendet nĂ« bufri Rx.

Po ashtu, regjistri i statusit, ku do të gjejmë flakët TXE dhe BSY:

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

Shkruajmë:

#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
}

Dhe pasi na duhen të dërgojmë 16 herë nga dy bajta, për numrin e daljeve të drejtuesit të LED-ve, atëherë ndoshta kështu:

void sendLEDdata()
{
    LAT_low();
    uint8_t k = 16;
    do
    {   k--;
        dm_shift16(leds[k]);
    } while (k);

    while (_SPI2_(_SPI_SR) & BSY); // përfundo dërgimin

    LAT_pulse();
}

Por për momentin nuk dimë si të lëvizim pinin LAT, prandaj le të kthehemi në I/O.

Dërgojmë pinët

Në STM32F1, regjistrat që lidhen me gjendjen e pinëve janë mjaft të pazakontë. E qartë është se ka më shumë prej tyre se sa në Atmega, por gjithashtu dallohet nga çipat e tjerë STM. Seksioni 9.1 Përshkrimi i përgjithshëm i GPIO:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Çdo port i hyrje/ daljeve tĂ« pĂ«rgjithshme (GPIO) ka dy regjistra konfigurimi 32-bitĂ« (GPIOx_CRL dhe GPIOx_CRH), dy registre tĂ« dhĂ«nash 32-bitĂ« (GPIOx_IDR dhe GPIOx_ODR), njĂ« regjir 32-bitĂ« tĂ« vendosjes/zhbllokimit (GPIOx_BSRR), njĂ« regjir 16-bitĂ« tĂ« zhbllokimit (GPIOx_BRR) dhe njĂ« regjir 32-bitĂ« bllokues (GPIOx_LCKR).

Sa tĂ« pazakontĂ«, gjithashtu mjaft tĂ« pakĂ«ndshĂ«m, kĂ«tu janĂ« dy regjistra tĂ« parĂ«, sepse 16 pinĂ« tĂ« portit janĂ« shpĂ«rndarĂ« nĂ« to nĂ« formatin "nga katĂ«r bits pĂ«r vĂ«lla". DomethĂ«nĂ«, pinĂ«t nga zero deri nĂ« shtatĂ« janĂ« nĂ« CRL, ndĂ«rsa tĂ« tjerĂ«t janĂ« nĂ« CRH. NdĂ«rkohĂ«, regjistrat e tjerĂ« njĂ«si tĂ« gjithĂ« bitĂ«t e pinĂ«ve tĂ« portit – shpesh duke mbetur gjysmĂ« "tĂ« rezervuar".

Për lehtësinë, do të fillojmë nga fundi i listës.

Ne nuk do ta kemi nevojën për regjistrin bllokues.

Regjistrat e vendosjes dhe zhbllokimit janĂ« mjaft argĂ«tues sepse pjesĂ«risht dublojnĂ« njĂ«ri-tjetrin: mund tĂ« shkruani gjithçka vetĂ«m nĂ« BSRR, ku 16 bitĂ«t mĂ« tĂ« lartĂ« do ta zbresin pinin nĂ« zero, ndĂ«rsa tĂ« voglat – do ta vendosin nĂ« 1, ose gjithashtu mund tĂ« pĂ«rdorni BRR, 16 bitĂ«t e tij mĂ« tĂ« vegjĂ«l qĂ« vetĂ«m e zbresin pinin. MĂ« pĂ«lqen shumĂ« varianti i dytĂ«. KĂ«ta regjistra janĂ« tĂ« rĂ«ndĂ«sishĂ«m sepse sigurojnĂ« akses atomik nĂ« pinĂ«:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Vendosje ose zhbllokim atomik
Nuk është nevoja të çaktivizoni ndërprerjet kur programoni GPIOx_ODR në nivelin e bitëve: mund të ndryshoni një ose më shumë bita me një operacion të vetëm atomik shkrimi APB2. Kjo arrihet duke shkruar "1" në regjistrin e vendosjes/zhbllokimit (GPIOx_BSRR ose, vetëm për zhbllokim, në GPIOx_BRR) të bitit që duhet të ndryshohet. Bitët e tjerë do të qëndrojnë të pandryshuar.

Regjistrat e dhĂ«nash kanĂ« emra mjaft tĂ« folur – IDR = Input Direction Register, regjistri i hyrjes; ODR = Output Direction Register, regjistri i daljes. NĂ« projektin aktual, ata nuk do na nevojiten.

Për ta përfunduar, kemi regjistrat kontrollues. Duke pasur parasysh se na interesojnë pinët e dytë SPI, konkretisht PB13, PB14 dhe PB15, menjëherë shikojmë në CRH:

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

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

Ne kemi diskutuar mĂ« parĂ« pĂ«r atĂ« qĂ« duam nga pins, prandaj kĂ«tu do ta kaloj pa screenshot, thjesht do tĂ« them se MODE pĂ«rcakton drejtimin (input, nĂ«se tĂ« dy bitĂ«t janĂ« tĂ« vendosur nĂ« 0) dhe shpejtĂ«sinĂ« e pin-it (na nevojitet 50MHz, dmth. tĂ« dy pinĂ«t nĂ« "1"), ndĂ«rsa CNF pĂ«rcakton modalitetin: normal "tĂ«rheqje-dhĂ«nies" – 00, "alternativ" – 10. Sipas parashikimit, siç e shohim mĂ« sipĂ«r, tĂ« gjithĂ« pinĂ«t kanĂ« bitin e tretĂ« nga poshtĂ« (CNF0), ai i vendos ata nĂ« modalitet floating input.

Pasi planifikoj të bëj diçka tjetër me këtë çip, për thjeshtësi kam definuar të gjitha vlerat e mundshme të MODE dhe CNF si për regjistrat e kontrollit të poshtëm, ashtu edhe për ata të sipërm.

Kështu po, ndoshta kështu

#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

Pins 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ër rrjedhojë, mund të shkruajmë definicionet për LAT, që do të aktivizojë 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 zakoni, ka qenë gjithmonë kështu, le të mbetet kështu)

Tani gjithçka është fantastike, por nuk funksionon. Sepse është STM32, këtu kursen energji elektrike, dhe domethënë, duhet të aktivizojmë orarin e periferi tuaj.

Aktivizojmë orarin

Orari menaxhohet nga orë, ato janë Clock. Dhe ne tashmë mund të kemi vënë re shkurtesën RCC. Ta kërkojmë në dokumentacion: kjo është Kontrolli i Rindizjes dhe Orarit (Reset and Clock Control).

Siç thuhet mĂ« sipĂ«r, fatmirĂ«sisht, mĂ« e komplikuara nga tema e orarizimit Ă«shtĂ« bĂ«rĂ« pĂ«r ne nga njerĂ«zit e STM, pĂ«r tĂ« cilĂ«t faleminderit shumĂ« (do tĂ« jap pĂ«rsĂ«ri linkun nĂ« faqen e Di Halt’it, nĂ« mĂ«nyrĂ« qĂ« tĂ« kuptohet sa e komplikuar Ă«shtĂ« kjo). Na duhen vetĂ«m regjistrat qĂ« menaxhojnĂ« aktivizimin e orarizimit tĂ« periferi (Peripheral Clock Enable Registers). PĂ«r fillim, le tĂ« gjejmĂ« adresĂ«n bazĂ« tĂ« RCC, ajo Ă«shtĂ« nĂ« fillim tĂ« "HartĂ«s sĂ« Memories":

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

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

Dhe pastaj ose të klikoni në lidhjen ku të provoni të gjeni diçka në tabelë, ose, shumë më mirë, të kaloni përmes përshkrimeve të regjistrave aktivizues nga seksionet për enable registers. Ku do të gjejmë RCC_APB1ENR dhe RCC_APB2ENR:

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

Dhe në to, përkatësisht, bitët që aktivizojnë orarizimin 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 ka mundësi dhe dëshirë për të provuar, atëherë lidhim DM634 kështu: DAI në PB15, DCK në PB13, LAT në PB14. Furnizojmë driverin nga 5 volt, mos harrojmë të bashkojmë tokat.

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

STM8 PWM

PWM në STM8

Kur kur planifikuar këtë artikull, vendosa të provoj të zotëroj ndonjë funksionalitet të një çipi të panjohur vetëm me fletushkën teknike, për të mos përfunduar si një shampanjë pa shampanjë. STM8 ishte i përshtatshëm për këtë rol: së pari, kisha disa pllaka kineze me STM8S103, dhe së dyti, ai nuk është shumë i njohur, kështu që tundimi për të kërkuar një zgjidhje në internet përballet me mungesën e këtyre zgjidhjeve.

PĂ«r çipin ka gjithashtu fletĂ« tĂ« dhĂ«nash dhe manualin reference RM0016, nĂ« tĂ« parin pinout dhe adresat e regjistrave, nĂ« tĂ« dytin – gjithçka tjetĂ«r. STM8 programohet nĂ« C nĂ« njĂ« IDE jo shumĂ« tĂ«rheqĂ«se ST Visual Develop.

Taktime dhe hyrje-dalja

Për default, STM8 punon në një frekuencë prej 2 MHz, kjo duhet të korrigohet menjëherë.

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

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

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Duke qenë se po planifikojmë të aktivizojmë PWM dhe të lidhem me LED, shikojmë pinout-in:

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

Çipi Ă«shtĂ« i vogĂ«l, shumĂ« funksione janĂ« tĂ« lidhura me pin tĂ« njĂ«jtĂ«. Ajo qĂ« Ă«shtĂ« nĂ« kllapa katrore Ă«shtĂ« "funksionalitet alternativ", ai kalon me "bytet e mundĂ«sive" (option bytes) – diçka si fuzat e AtmegĂ«s. Mund t'i ndryshoni vlerat programatikisht, por nuk Ă«shtĂ« e nevojshme, pasi funksionaliteti i ri aktivizohet vetĂ«m pas ri-ngritjes. MĂ« e lehtĂ« Ă«shtĂ« tĂ« pĂ«rdorni ST Visual Programmer (shkarkohet sĂ« bashku me Visual Develop), i cili di tĂ« ndryshojĂ« kĂ«to byte. NĂ« pinout duket se daljet CH1 dhe CH2 tĂ« timerit tĂ« parĂ« janĂ« tĂ« fshehura nĂ« kllapa; duhet tĂ« vendosim bitet AFR1 dhe AFR0 nĂ« STVP, dhe bita e dytĂ« gjithashtu do ta çojĂ« daljen CH1 tĂ« timerit tĂ« dytĂ« nga PD4 nĂ« PC5.

Kështu, ndriçimi i LED do të menaxhohet nga 6 pin: PC6, PC7 dhe PC3 për timerin e parë, PC5, PD3 dhe PA3 për të dytin.

Konfigurimi i vetë pini të hyrje-daljes në STM8 është më i thjeshtë dhe më logjik se sa në STM32:

  • regjistri i drejtimeve tĂ« tĂ« dhĂ«nave DDR (Data Direction Register): 1 = dalje;
  • regjistri i kontrollit CR1 pĂ«r dalje pĂ«rcakton modalitetin "tĂ«rheq dhe shty" (1) ose stok tĂ« hapur (0); pasi unĂ« po lidhem me LED me katodet, lĂ« kĂ«tu zerot;
  • regjistri i dytĂ« tĂ« kontrollit CR2 pĂ«r dalje pĂ«rcakton shpejtĂ«sinĂ« e taktimit: 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 PWM

Në fillim, le të sqarojmë disa termine:

  • Frekuenca PWM – frekuenca me tĂ« cilĂ«n tikuar timeri;
  • Auto-reload, AR – vlera qĂ« ngarkohet automatikisht deri nĂ« tĂ« cilĂ«n do tĂ« llogarisĂ« timeri (periudha e impulsit);
  • Ngjarja e pĂ«rditĂ«simit, UEV – ngjarja qĂ« ndodh kur timeri arriti nĂ« AR;
  • Cikli i PĂ«rmbushjes PWM – koeficienti i mbushjes PWM, shpesh quhet "shkalla e mbushjes";
  • Vlera e Kapjes/ShtesĂ«s – vlera pĂ«r kapjen/shtesĂ«n, deri nĂ« tĂ« cilĂ«n timeri do tĂ« bĂ«jĂ« diçka (nĂ« rastin e PWM – inverton sinjalin dalĂ«s);
  • Vlera e Parakohshme – vlerĂ« e ngarkuar paraprakisht. Vlera e krahasimit nuk mund tĂ« ndryshohet ndĂ«rsa timeri tikun, nĂ« tĂ« kundĂ«rt ndodh kollapsi i ciklit tĂ« PWM. Prandaj, vlerat e reja tĂ« dĂ«rguara vendosen nĂ« njĂ« buffer dhe nxirren prej andej kur timeri arrin fundin e numĂ«rimit dhe reset-het;
  • Modet e Palosjes me RrymĂ« tĂ« DrejtĂ« dhe Modet e Palosjes Qendrore – palosja nĂ« skaj dhe nĂ« qendĂ«r, ato janĂ« tĂ« njĂ«jta si ato tĂ« ATMEL. PWM e ShpejtĂ« dhe PWM e Korrigjuar nĂ« FazĂ«.
  • OCiREF, Sinjali Referues i Krahasimit tĂ« Daljes – sinjali referues dalĂ«s, ndoshta, ajo qĂ« nĂ« modin PWM gjendet nĂ« pinsin pĂ«rkatĂ«s.

Siç Ă«shtĂ« e qartĂ« nga pinout-i, PWM Ă«shtĂ« i disponueshĂ«m nga dy timerat – i pari dhe i dyti. TĂ« dy janĂ« 16-bit, i pari disponon shumĂ« karakteristika shtesĂ« (pĂ«r shembull, mund tĂ« llogarisĂ« edhe nĂ« mĂ«nyrĂ« rritĂ«se dhe zvogĂ«lues). Na nevojitet qĂ« tĂ« dy tĂ« funksionojnĂ« njĂ«soj, prandaj vendosa tĂ« filloj me tĂ« dytin qĂ« Ă«shtĂ« mĂ« i kufizuar, pĂ«r tĂ« mos rĂ«nĂ« rastĂ«sisht nĂ« pĂ«rdorim tĂ« ndonjĂ« funksioni qĂ« nuk e ka. NjĂ« problem i caktuar Ă«shtĂ« se pĂ«rshkrimi i funksionalitetit tĂ« PWM pĂ«r tĂ« gjitha timerat Ă«shtĂ« nĂ« manualin referues nĂ« kapitullin pĂ«r timerin e parĂ« (17.5.7 Moda PWM), prandaj ndonjĂ«herĂ« duhet tĂ« kalojmĂ« nga njĂ«ra nĂ« tjetrĂ«n nĂ« dokument.

PWM në STM8 ka një avantazh të rëndësishëm mbi PWM të Atmega:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
PWM me Palosje në Skaj
Konfigurimi i numërimit nga poshtë lart
Numërimi nga poshtë lart është aktiv, nëse b it DIR në regjistrin TIM_CR1 është resetuar.
Shembulli
Shembulli përdor modin e parë të PWM. Sinjali referues PWM OCiREF mbahet në nivel të lartë, për sa kohë TIM1_CNT < TIM1_CCRi. Në të kundërt, ai merr nivel të ulët. Nëse vlera për krahasim në regjistrin TIM1_CCRi është më e madhe se vlera e auto-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 për herë të parë kontrollon vlerën e krahasimit, dhe pastaj jep sinjalin referues. Në Atmega, timeri së pari punon dhe pastaj krahasohet, si rezultat, kur vlera e krahasimit == 0 Në daljen ka një gjilpërë me të cilën duhet të luftojmë ndonjë mënyrë (p.sh. duke invertuar logjikën programore).

Pra, çfarë duam të bëjmë: 8-bit PWM (AR == 255), llogaritur nga poshtë lart, me rregullim në kufi. Duke qenë se llambat janë lidhur me çipin me katode, PWM duhet të japë 0 (LED ndezur) deri vlerën e krahasimit dhe 1 pas.

Kemi lexuar tashmĂ« pĂ«r disa modalitetet PWM, prandaj gjejmĂ« regjistrin e dytĂ« tĂ« timerit duke kĂ«rkuar nĂ« manualin referues me kĂ«tĂ« frazĂ« (18.6.8 – TIMx_CCMR1):

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
110: Modaliteti i parĂ« PWM – nĂ« llogaritjen nga poshtĂ« lart, kanali i parĂ« Ă«shtĂ« aktiv derisa TIMx_CNT < TIMx_CCR1. NĂ« tĂ« kundĂ«rt, kanali i parĂ« nuk Ă«shtĂ« aktiv. [mĂ« pas nĂ« dokument ka kopjime tĂ« gabuara nga timeri 1]
111: Modaliteti i dytĂ« PWM – nĂ« llogaritjen nga poshtĂ« lart, kanali i parĂ« nuk Ă«shtĂ« aktiv derisa TIMx_CNT < TIMx_CCR1. NĂ« tĂ« kundĂ«rt, kanali i parĂ« Ă«shtĂ« aktiv.

Duke qenë se LED-et janë lidhur me MK me katode, na përshtatet modaliteti i dytë (edhe i pari, por ende nuk e dimë këtë).

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
Bit 3 OC1PE: Aktivizo ngarkimin paraprak të daljes 1
0: Regjistri i ngarkimit paraprak në TIMx_CCR1 është i fikur. Mund të shkruhet në TIMx_CCR1 në çdo kohë. Vlera e re funksionon menjëherë.
1: Regjistri i ngarkimit paraprak në TIMx_CCR1 është i aktivizuar. Operacionet e leximit/shkrimit adresojnë regjistrin e ngarkimit paraprak. Vlera e ngarkuar paraprakisht TIMx_CCR1 ngarkohet në regjistrin e hijeve gjatë secilës ngjarje përditësimi.
*Shënim: për funksionimin e saktë të modalitetit PWM, regjistrat e ngarkimit paraprak duhet të aktivizohen. Kjo nuk është e nevojshme në modalitetin e sinjalit të vetëm (kur bita OPM në regjistrin TIMx_CR1 është e vendosur).

Ok, aktivizojmë gjithçka që na nevojitet për tre kanale të timerit 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 është shumë e thjeshtë:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Timeri i dytë mund të numërojë vetëm nga poshtë lart, me rregullim në kufi, nuk ka nevojë të ndryshohet asgjë. Do të vendosim pjesëtimin e frekuencës, p.sh. në 256. Te timeri i dytë, pjesëtimi vendoset në regjistrin TIM2_PSCR dhe përfaqëson një fuqi të dyshes:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

E mbetur është të aktivizojmë daljet dhe vetë timerin e dytë. Problemi i parë zgjidhet me regjistrat Capture/Compare Aktivizo: ka dy nga ata, tre kanale të shpërndara në mënyrë asimetrike. Këtu gjithashtu mund të mësojmë se mund të ndryshohet polariteti i sinjalit, pra në parim mund të ishte përdorur 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, nisëm timerin në regjistrin TIMx_CR1:

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

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Do të shkruajmë një analog më të thjeshtë të AnalogWrite(), e cila do t'i dërgojë timerit vlerat për krahasim. Regjistrat me siguri quhen Capture/Compare registers, dy dy dy kanale: 8 bitët e para në TIM2_CCRxL dhe 8 bitët e lartë në TIM2_CCRxH. Duke qenë se kemi vendosur PWM me 8 bitë, mjafton të shkruajmë vetëm bitët e poshtëm:

#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 kujdesshëm do të vërejë se kemi një PWM pak defekt, i paaftë për të dhënë 100% mbushje (në vlerën maksimale 255, si si është e invertohet për një cikël timer). Për LED-të, kjo nuk ka rëndësi, dhe lexuesi i kujdesshëm tashmë e kupton se si ta rregullojë këtë.

PWM në timerin e dytë funksionon, kalojmë te i pari.

Timeri i parĂ« ka tĂ« njĂ«jtat bite nĂ« tĂ« njĂ«jtat regjistra (thjesht ato bite qĂ« mbetĂ«n "tĂ« rezervuar" nĂ« timerin e dytĂ«, nĂ« tĂ« parin pĂ«rdoren aktivisht pĂ«r gjĂ«ra tĂ« avancuara). Prandaj, mjafton tĂ« gjeni adresat e kĂ«tyre regjistrave nĂ« fletĂ«kujtim dhe tĂ« kopjoni kodin. Po ashtu, duhen ndryshuar vlerat e ndarĂ«sit tĂ« frekuencĂ«s, sepse timeri i parĂ« do tĂ« marrĂ« njĂ« vlerĂ« precize 16-bit nĂ« dy regjistra, jo njĂ« fuqi e dyshes. Prescaler High dhe I UlĂ«t. E gjithĂ« kjo bĂ«het dhe
 timeri i parĂ« nuk funksionon. ÇfarĂ« ndodhi?

Problemi mund të zgjidhet vetëm duke shikuar tërë seksionin mbi regjistrat e kontrollit të timerit 1, ku kërkojmë atë që nuk e ka timeri i dytë. Do të gjendet 17.7.30 Regjistri i Prishjes (TIM1_BKR), ku ka një bit të tillë:

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

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Tani gjithçka është e saktë, kodi atje gjithashtu.

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

STM8 Multiplex

Multipleximi në STM8

Projekti i tretë përbëhet nga lidhja e tetë RGB LED-ësh në timerin e dytë në mënyrë PWM dhe të bëjë që ata të shfaqin ngjyrat e ndryshme. Në thelb - koncepti i multipleximit të LED-ve, që e bën deri në atë pikë që nëse ndizni dhe fikni LED-të shumë-shumë shpejt, do të duket se ata janë të ndezur vazhdimisht (përshtypja e qëndrueshmërisë, inercia e perceptimit vizual). Njëherë e kam bërë diçka të tillë në Arduino.

Algoritmi i punës duket kështu:

  • lidhi anodin e LED-it tĂ« parĂ« RGB;
  • e ndizni atĂ«, duke dĂ«rguar sinjale tĂ« nevojshme pĂ«r katodet;
  • pritni fundin e ciklit PWM;
  • lidhi anodin e LED-it tĂ« dytĂ« RGB;
  • e ndizni atë 

Dhe kështu me radhë. Sigurisht, për të funksionuar bukur, është e nevojshme që lidhja e anodit dhe "ndizja" e LED-it të ndodhin njëkohësisht. Ose pothuajse. Në çdo rast, duhet të shkruajmë kodin që do të japë vlera në tri kanale të timerit të dytë, dhe kur të arrihet UEV, t'i ndryshojë ato dhe njëkohësisht të ndryshojë RGB-LED-in aktiv në atë moment.

Duke switch LED bëhet automatikisht, duhet të krijohet një "memorie video", nga e cila manipuluesi i ndërprerjeve do të marrë të dhënat. Kjo është një masiv i thjeshtë:

uint8_t colors[8][3];

Për të ndryshuar ngjyrën e një LED të veçantë, mjafton të shkruani vlerat e nevojshme në këtë masiv. Ndërsa për numrin e LED aktiv do të kujdeset variabla

uint8_t cnt;

Demuks

PĂ«r multipleximin e duhur, na nevojitet, siç Ă«shtĂ« e pritur, demultiplexori CD74HC238. Demultiplexori Ă«shtĂ« njĂ« çip, i cila implementon operatorin <<. Duke pĂ«rdorur tre pinĂ« hyrĂ«s (bitĂ«t 0, 1 dhe 2) i ofrojmĂ« njĂ« numĂ«r tre-bitĂ«sh X, dhe ai nĂ« pĂ«rgjigje aktivizon daljen numĂ«r (1<<X). Hyrjet e tjera tĂ« çipit pĂ«rdoren pĂ«r tĂ« shkallĂ«zuar tĂ« gjithĂ« konstrukcionin. Ky çip na nevojitet jo vetĂ«m pĂ«r tĂ« reduktuar numrin e pinĂ«ve tĂ« zĂ«nĂ« tĂ« mikro-kontrollorit, por edhe pĂ«r siguri – qĂ« aksidentalisht tĂ« mos ndizni mĂ« shumĂ« LED se sa Ă«shtĂ« e mundur dhe tĂ« mos digjni MK. Çipi Ă«shtĂ« shumĂ« i lirĂ«, ia vlen tĂ« mbahet gjithmonĂ« nĂ« kitin tuaj tĂ« shtĂ«pisĂ«.

CD74HC238 do të përgjigjet që të furnizojë tensionin në ankorën e LED të duhur. Në një multiplex të plotë, do të dërgonte tensionin në kolonë përmes P-MOSFET, por në këtë demo mund të bëhet direkt, pasi ai tërheq 20 mA, sipas vlerave maksimale absolute në fletën e të dhënave. Nga fleta e të dhënave CD74HC238 na nevojitet pinout dhe ky shënim:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
H = nivel i lartĂ« tensioni, L = nivel i ulĂ«t tensioni, X – çdo gjĂ« Ă«shtĂ« nĂ« rregull

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

PWM

PWM në timerin e dytë konfigurohet ashtu si në historinë e mëparshme, me dy përjashtime:

Së pari, na duhet të aktivizojmë ndërprerjen për Ngjarje e Azhurnimit (UEV), e cila do të thërrasë funksionin që kalon LED aktiv. Kjo bëhet duke ndryshuar bitin Aktivizimi i Ndërprerjes në regjistrin me emrin e dukshëm

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

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

PĂ«rjashtimi i dytĂ« lidhet me njĂ« fenomen tĂ« multipleximit, siç Ă«shtĂ« ghosting – ndriçimi parazitar i diodave. NĂ« rastin tonĂ«, ky ndriçim mund tĂ« shfaqet pĂ«r shkak se timer-i, qĂ« shkakton ndĂ«rprerjen nĂ« UEV, vazhdon tĂ« ikĂ«, dhe manipuluesi i ndĂ«rprerjes nuk arrin ta ndĂ«rron LED pĂ«rpara se timer-i tĂ« fillojĂ« tĂ« shkruajĂ« diçka nĂ« daljet. PĂ«r tĂ« luftuar kĂ«tĂ«, do tĂ« duhet tĂ« invertim logjikĂ«n (0 = ndriçim maksimal, 255 = asgjĂ« nuk ndriçon) dhe tĂ« mos lejojmĂ« vlerat ekstreme tĂ« ngjeshjes. Pra, duhet tĂ« arrijmĂ« qĂ« pas UEV LED-at tĂ« fikĂ«n plotĂ«sisht pĂ«r njĂ« cikĂ«l PWM.

Ndryshojmë polaritetin:

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

Evitojmë vendosjen e r, g dhe b në 255 dhe mos harrojmë t'i invertim kur i përdorim.

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 për shkak të efekteve të jashtme ose të brendshme, përfshirë ato nga timer-i.

Kur krijuam për herë të parë projektin në ST Visual Develop, morëm përveç main.c një dritare me një skedar misterios stm8_interrupt_vector.c, që u përfshi automatikisht në projekt. Në këtë skedar, për çdo ndërprerje është lidhur një funksion NonHandledInterrupt. Ne duhet të lidhim funksionin tonë me ndërprerjen e duhur.

Në datasheet ekziston një tabelë e vektorëve të ndërprerjeve, ku gjejmë të nevojshmet:

Lexo fletët datashit 2: SPI në STM32; PWM, timerët dhe ndërprerjet në STM8
13 Riatdhesim/mbushje TIM2
14 Kapje/krahasim TIM2

Na duhet të ndryshojmë LED-in për UEV, kështu që na nevojitet ndërprerja nr. 13.

Përkatësisht, së pari, në skedarin stm8_interrupt_vector.c ndryshojmë emrin e funksionit që i përgjigjet ndërprerjes nr. 13 (IRQ13) në atë që kemi përzgjedhur:

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

Së dyti, do të duhet të krijojmë një skedar main.h me përmbajtjen e tillë:

#ifndef __MAIN_H
#define __MAIN_H

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

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

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

 TIM2_SR1 = 0; // rivendosim flamurin e Ndërprerjes së Pritur të Azhurnimit

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

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

 return;
}

Kemi mbetur vetĂ«m tĂ« aktivizojmĂ« ndĂ«rprerjet. Kjo bĂ«het me komandĂ«n assemblore rim – do ta kĂ«rkojmĂ« nĂ« Manualin e Programimit:

//enable interrupts
_asm("rim");

NjĂ« komandĂ« tjetĂ«r assemblore – sim – çon nĂ« fikjen e ndĂ«rprerjeve. Ato duhet tĂ« çohen pĂ«rkohĂ«sisht gjatĂ« shkrimit tĂ« vlerave tĂ« reja nĂ« 'memorinĂ« vizuale', nĂ« mĂ«nyrĂ« qĂ« njĂ« ndĂ«rprerje e papĂ«rshtatshme tĂ« mos prishĂ« masĂ«n.

I gjithë kodi është në GitHub.

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

Nëse kjo artikull është e dobishme për dikë, atëherë nuk e kam shkruar kot. Do të jem i lumtur për komentet dhe sugjerimet, do të përpiqem të përgjigjem për të gjitha.

Burimi: habr.com

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