Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Π’ Lehenengo zatia Arduino praketatik hazitako zaletasun elektronikoko ingeniariei nola eta zergatik irakurri behar zituzten mikrokontrolagailuentzako fitxa teknikoak eta bestelako dokumentazioa esaten saiatu nintzen. Testua handia izan zen, beraz, artikulu praktiko batean adibide praktikoak erakusteko agindu nion. Tira, bere buruari esne-perretxiko deitzen zion...

Gaur datu-orriak nola erabili erakutsiko dizut STM32 (Blue Pill) eta STM8 kontrolagailuetako zereginak nahiko sinpleak, baina beharrezkoak, ebazteko. Demo proiektu guztiak nire gogoko LEDei eskainita daude, kantitate handietan argiztatuko ditugu, horretarako era guztietako periferiko interesgarriak erabili beharko ditugu.

Testua berriro ere izugarria izan zen, beraz, erosotasunerako edukia egiten ari naiz:

STM32 Blue Pill: DM16 kontrolatzaile duten 634 LED
STM8: sei PWM pin konfiguratzea
STM8: 8 RGB LED hiru pinetan, etenak

Lege-oharra: ez naiz ingeniaria, ez dut elektronikan ezagutza sakona dudanik ematen, artikulua ni bezalako afizionatuentzat dago pentsatuta. Izan ere, duela bi urte xede-publikotzat hartu nuen nire burua. Norbaitek orduan esan izan balu txip ezezagun batean fitxak irakurtzeko beldurrik ez dutela irakurtzeko, ez nuke denbora asko emango Interneten kode zati batzuen bila eta guraizeekin eta zinta itsasgarriekin makuluak asmatzen.

Artikulu honen ardatza datu-orrietan dago, ez proiektuetan; beraz, baliteke kodea ez izatea oso txukuna eta askotan estua izatea. Proiektuak berez oso sinpleak dira, txip berria lehen ezagutzeko egokiak diren arren.

Espero dut nire artikuluak zaletasunean murgiltzeko antzeko fasean dagoen norbait laguntzea.

STM32

DM16 eta SPI duten 634 LED

Blue Pill (STM32F103C8T6) eta DM634 LED kontrolatzailea erabiliz proiektu txiki bat. Fitxategiak erabiliz, kontrolatzailea, STM IO atakak eta SPI konfiguratuko ditugu.

DM634

Taiwango txipa 16 16 biteko PWM irteerarekin, kateetan konekta daiteke. Behe-end 12 biteko eredua etxeko proiektu batetik ezagutzen da Lightpack. Garai batean, DM63x eta TLC5940 ezagunaren artean aukeratuz, DM aukeratu nuen hainbat arrazoirengatik: 1) Aliexpress-en TLC faltsua da zalantzarik gabe, baina hau ez; 2) DM-k PWM autonomo bat du bere maiztasun-sorgailuarekin; 3) Moskun merke eros liteke, Aliren pakete baten zain egon beharrean. Eta, noski, interesgarria izan zen txipa zuk zeuk kontrolatzen ikastea, prest egindako liburutegi bat erabili beharrean. Gaur egun txipak SSOP24 paketean aurkezten dira batez ere; egokitzaile batera soldatzeko errazak dira.

Fabrikatzailea taiwandarra denez, fitxa teknikoa txipa ingelesez txinatar idatzita dago, hau da, dibertigarria izango da. Lehenik pinout-a ikusten dugu (Pin konexioa) zein hanka zertara konektatu ulertzeko eta pinen deskribapena (Pinaren deskribapena). 16 pin:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
DC konketa-iturriak (isurketa irekia)

Putzuak / Irteera irekia – drainatzea; sarrerako korronte iturria; irteera lurrera konektatzen da egoera aktiboan - LEDak katodoen bidez kontrolatzaileari konektatzen dira. Elektrikoki, hau ez da, noski, "hustubide irekia" (hustubide irekia), baina datu-orrietan drainatzeko moduan dauden pinen izendapen hori sarritan aurkitzen da.

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
REXT eta GND arteko kanpoko erresistentziak irteerako korrontearen balioa ezartzeko

Erreferentzia-erresistentzia bat instalatzen da REXT pinaren eta lurraren artean, irteeren barne-erresistentzia kontrolatzen duena, ikusi fitxa teknikoaren 9. orrialdeko grafikoa. DM634-n, erresistentzia hori softwarearen bidez ere kontrola daiteke, distira orokorra ezarriz (distira globala); Artikulu honetan ez naiz xehetasunetan sartuko, 2.2 - 3 kOhm-ko erresistentzia bat jarriko dut hemen.

Txipa nola kontrolatu ulertzeko, ikus dezagun gailuaren interfazearen deskribapena:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Bai, hemen dago, txinera ingelesa bere aintza osoan. Hau itzultzea arazotsua da, nahi izanez gero uler dezakezu, baina beste modu bat dago - begiratu nola funtzionalki antzeko TLC5940 konexioa deskribatzen den datu-orrian:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
... Hiru pin bakarrik behar dira datuak gailuan sartzeko. SCLK seinalearen goranzko ertzak SIN pinetik barne erregistrora aldatzen ditu datuak. Datu guztiak kargatu ondoren, XLAT seinale altu labur batek sekuentzialki transferitutako datuak barne-erregistroetara atxikitzen ditu. Barne-erregistroak XLAT seinale-mailak abiarazitako ateak dira. Datu guztiak bit esanguratsuena transmititzen dira lehenik.

latch – giltza/giltza/giltza.
Goranzko ertza – Pultsuaren lehen ertza
MSB lehenik – bit esanguratsuena (ezkerrekoena) aurrera.
datuak erlojupatzeko – datuak sekuentzialki transmititzea (bitz bit).

Word latch txipetarako dokumentazioan aurkitu ohi da eta hainbat modutara itzultzen da, beraz, ulertzearren, baimenduko dut

hezkuntza programa txiki batLED kontrolatzailea, funtsean, aldaketa-erregistro bat da. "Shift" (mugitzeko) izenean - gailuaren barruan datuen mugimendua bit-bitan: barruan sartzen den bit berri bakoitzak kate osoa aurrera eramaten du aurrean. Inork ez duenez LEDen keinuka kaotikorik ikusi nahi txandan zehar, prozesua motelgailu batek laneko erregistroetatik bereizita dagoen buffer-erregistroetan gertatzen da (latch) itxarongela moduko bat da, non bitak nahi den sekuentzian antolatuta dauden. Dena prest dagoenean, pertsiana irekitzen da eta bitsak lanera joaten dira, aurreko lotea ordezkatuz. Hitza latch mikrozirkuituetarako dokumentazioan ia beti dakar halako motelgailu bat, edozein konbinaziotan erabiltzen den.

Beraz, datu-transferentzia DM634ra honela egiten da: ezarri DAI sarrera urruneko LEDaren bit esanguratsuenaren balioa, tira DCK gora eta behera; ezarri DAI sarrera hurrengo bitaren balioarekin, tira DCK; eta abar bit guztiak transmititu arte (erlojua sartuta), ondoren LAT tiratzen dugu. Hau eskuz egin daiteke (bit-bang), baina hobe da horretarako bereziki egokitutako SPI interfaze bat erabiltzea, gure STM32n bi kopiatan aurkezten baita.

Pilula Urdina STM32F103

Sarrera: STM32 kontrolagailuak Atmega328 baino askoz konplexuagoak dira beldurgarriak diruditen baino. Gainera, energia aurrezteko arrazoiengatik, ia periferiko guztiak itzaltzen dira hasieran, eta erlojuaren maiztasuna barne iturritik 8 MHz-ra dago. Zorionez, STM programatzaileek txipa "kalkulatutako" 72 MHz-ra eramaten duen kodea idatzi zuten, eta ezagutzen ditudan IDE guztien egileek hasierako prozeduran sartu zuten, beraz, ez dugu erlojua egin behar (baina dezakezu benetan nahi baduzu). Baina periferikoak piztu beharko dituzu.

Dokumentazioa: Blue Pill STM32F103C8T6 txip ezagunarekin hornituta dago, horretarako bi dokumentu erabilgarria daude:

Fitxa teknikoan honako hauek interesgarriak izan daitezke:

  • Pinouts - txip pinouts - taulak guk geuk egitea erabakitzen badugu;
  • Memoria-mapa: txip jakin baterako memoria-mapa. Erreferentzia Eskuliburuak lerro osorako mapa bat du, eta gureak ez dituen erregistroak aipatzen ditu.
  • Pin definizioen taula - pinen funtzio nagusiak eta alternatiboak zerrendatzen ditu; "pilula urdinerako" irudi erosoagoak aurki ditzakezu Interneten pin zerrenda batekin eta haien funtzioekin. Hori dela eta, berehala Blue Pill pinout-a Googlen bilatzen dugu eta argazki hau eskura izango dugu:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
NB: Interneteko argazkian akats bat egon da, iruzkinetan adierazitakoa, eskerrik asko. Irudia ordezkatu da, baina hau ikasgai bat da; hobe da datu-orrietatik ez dagoen informazioa egiaztatzea.

Fitxa teknikoa kentzen dugu, Erreferentzia Eskuliburua irekitzen dugu eta hemendik aurrera hura bakarrik erabiltzen dugu.
Prozedura: sarrera/irteera estandarra lantzen dugu, SPI konfiguratzen dugu, beharrezko periferikoak pizten ditugu.

Sarrera Irteera

Atmega328-n, I/O oso sinplea da inplementatzen, horregatik STM32 aukeren ugaritasuna nahasia izan daiteke. Orain ondorioak baino ez ditugu behar, baina hauek ere lau aukera dituzte:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
hustubide ireki, push-pull, push-pull alternatibo, drain ireki alternatibo

"Tira-bultza" (bultza-tira) Arduinoren ohiko irteera da, pinak ALTU edo BAXU balioa har dezake. Baina "hustubide irekiarekin" badaude zailtasunak, nahiz eta egia esan dena erraza den hemen:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Irteerako konfigurazioa / ataka irteerari esleitzen zaionean: / irteerako buffera gaituta: / – drainatzeko modua irekita: "0" irteerako erregistroan N-MOS gaitzen da, "1" irteerako erregistroan ataka Hi-Z moduan uzten du ( P-MOS ez dago aktibatuta ) / – push-pull modua: irteerako erregistroan β€œ0” N-MOS aktibatzen du, irteerako erregistroan β€œ1” P-MOS aktibatzen du.

Hustubide irekiaren arteko alde guztiak (hustubide irekia) "bultza-tira"-tik (bultza-tira) lehen pinean ezin duela ALTA egoera onartu: irteerako erregistroan bat idaztean, erresistentzia handiko moduan sartzen da (handiko inpedantzia, Kaixo-Z). Zero idaztean, pinak berdin jokatzen du bi moduetan, bai logikoki eta bai elektrikoki.

Irteera-modu arruntean, pinak irteera-erregistroaren edukia besterik ez du igortzen. "Alternatiboa" dagozkion periferikoek kontrolatzen dute (ikus 9.1.4):

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Portu-bit bat ordezko funtzio-pin gisa konfiguratuta badago, pin-erregistroa desgaitu egingo da eta pin-a pin periferikora konektatuta dago.

Pin bakoitzaren funtzionaltasun alternatiboak deskribatzen dira Pin definizioak Fitxa teknikoa deskargatutako irudian dago. Pin batek funtzio alternatibo batzuk baditu zer egin behar den galderari, erantzuna datu-orrian oin-ohar batek ematen du:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Hainbat periferikok pin bera erabiltzen badute, funtzio alternatiboen arteko gatazkak saihesteko, periferiko bakarra erabili behar da aldi berean, erloju periferikoa gaitzeko bit erabiliz (RCC erregistro egokian).

Azkenik, irteera moduan dauden pinek erlojuaren abiadura ere badute. Hau energia aurrezteko beste ezaugarri bat da; gure kasuan, gehienezko mailan ezarri eta ahaztu egiten dugu.

Beraz: SPI erabiltzen ari gara, hau da, bi pin (datuekin eta erloju-seinalearekin) "push-pull funtzio alternatiboa" izan behar dute, eta beste batek (LAT) "push-pull erregularra". Baina horiek esleitu aurretik, jor diezaiogun SPIri.

SPI

Beste hezkuntza programa txiki bat

SPI edo Serial Peripheral Interface (interfaze periferiko seriea) MK bat beste MK batzuekin eta, oro har, kanpoko munduarekin konektatzeko interfaze sinple eta oso eraginkorra da. Bere funtzionamenduaren printzipioa goian deskribatu da, non Txinako LED kontrolatzaileari buruz (erreferentzia eskuliburuan, ikusi 25. atala). SPI-k maisu ("master") eta esklabo ("esklabo") moduan funtziona dezake. SPI-k oinarrizko lau kanal ditu, eta horietatik guztiak ezin dira erabili:

  • MOSI, Master Output / Slave Input: pin honek datuak maisu moduan transmititzen ditu eta datuak esklabo moduan jasotzen ditu;
  • MISO, Master Input / Slave Output: aitzitik, maisuan jasotzen du, eta esklaboan transmititzen du;
  • SCK, Serial Clock: datu-transmisioaren maiztasuna ezartzen du maisuan edo erloju-seinalea jasotzen du esklaboan. Funtsean beats jotzea;
  • SS, Slave Select: kanal honen laguntzaz, esklaboak badaki berarengandik zerbait nahi duela. STM32n NSS deitzen da, non N = negatiboa, hau da. kontrolagailua esklabo bihurtzen da kanal honetan lurra badago. Ondo konbinatzen da Open Drain Output moduarekin, baina hori beste istorio bat da.

Beste guztia bezala, SPI-n STM32 funtzionalitate aberatsa da, eta horrek ulertzea zaila egiten du. Esate baterako, SPIrekin ez ezik, I2S interfaze batekin ere lan egin dezake, eta dokumentazioan haien deskribapenak nahasten dira, beharrezkoa da soberan moztea garaiz. Gure zeregina oso erraza da: datuak MOSI eta SCK erabiliz soilik bidali behar ditugu. 25.3.4 atalera joango gara (half-duplex komunikazioa, half-duplex komunikazioa), non aurkituko dugun Erloju 1 eta noranzko bakarreko datu-hari bat (erloju-seinale 1 eta noranzko bakarreko datu-korronte 1):

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Modu honetan, aplikazioak SPI erabiltzen du transmisiorako edo jasotzeko soilik moduan. / Transmititzeko soilik modua duplex moduaren antzekoa da: datuak transmisioko pinean transmititzen dira (MOSI master moduan edo MISO esklabo moduan), eta jasotzeko pina (MISO edo MOSI hurrenez hurren) I/O pin arrunt gisa erabil daiteke. . Kasu honetan, aplikazioak Rx buffer-a alde batera utzi behar du (irakurtzen bada, ez da bertan transferituko daturik egongo).

Bikaina, MISO pina doakoa da, konekta dezagun LAT seinalea. Ikus dezagun Slave Select, STM32n programatikoki kontrola daitekeena, oso erosoa dena. Izen bereko paragrafoa irakurri dugu 25.3.1 SPIren Deskribapen Orokorra atalean:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Software-kontrola NSS (SSM = 1) / Esklaboen hautaketaren informazioa SPI_CR1 erregistroko SSI bit-ean dago. Kanpoko NSS pinak aske izaten jarraitzen du beste aplikazioen beharretarako.

Erregistroetara idazteko ordua da. SPI2 erabiltzea erabaki nuen, bere oinarrizko helbidea bilatu datu-orrian - 3.3 Memoria-mapa atalean:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Tira, has gaitezen:

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

Ireki 25.3.3 atala "SPI modu nagusian konfiguratzea" izenburua duen auto-azalpenarekin:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

1. Ezarri serieko erlojuaren maiztasuna BR[2:0] bitekin SPI_CR1 erregistroan.

Erregistroak izen bereko erreferentziazko eskuliburuaren atalean biltzen dira. Helbide aldaketa (Helbide-desplazamendua) CR1 - 0x00-rako, lehenespenez bit guztiak garbitzen dira (Berrezarri balioa 0x0000):

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

BR bitek kontroladorearen erlojuaren zatitzailea ezartzen dute, horrela SPIak funtzionatuko duen maiztasuna zehazten du. Gure STM32 maiztasuna 72 MHz izango da, LED kontrolatzaileak, bere datu-orriaren arabera, 25 MHz arteko maiztasunarekin funtzionatzen du, beraz, lautan banatu behar dugu (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. Ezarri CPOL eta CPHA bitak datu-transferentziaren eta serieko erlojuaren denboraren arteko erlazioa definitzeko (ikus 240. orrialdeko diagrama)

Hemen datu-orri bat irakurtzen ari garenez eta eskemak aztertzen ez ditugunez, ikus ditzagun CPOL eta CPHA biten testu-deskribapena 704. orrialdean (SPIren Deskribapen Orokorra):

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Erlojuaren fasea eta polaritatea
SPI_CR1 erregistroko CPOL eta CPHA bitak erabiliz, programatikoki lau denbora-erlazio hauta ditzakezu. CPOL (erlojuaren polaritatea) bitak erlojuaren seinalearen egoera kontrolatzen du daturik transmititzen ez denean. Bit honek maisu eta esklabo moduak kontrolatzen ditu. CPOL berrezartzen bada, SCK pina baxua da atseden moduan. CPOL bit ezarrita badago, SCK pina altua da atseden moduan.
CPHA (erloju-fasea) bit ezarrita dagoenean, bit handiko tranpa estrobokoa SCK seinalearen bigarren ertza da (jaisten da CPOL garbi badago, igotzen da CPOL ezarrita badago). Erlojuaren seinalearen bigarren aldaketak jasotzen ditu datuak. CPHA bit garbia bada, bit handiko tranpa estrobokoa SCK seinalearen goranzko ertza da (jaitsiera ertza CPOL ezarrita badago, goranzko ertza CPOL garbitzen bada). Datuak erlojuaren seinalearen lehen aldaketan jasotzen dira.

Ezagutza hori bereganatu ondoren, bi bitek zero geratu behar dutela ondorioztatuko dugu, zeren SCK seinalea baxua izatea nahi dugu erabiltzen ez denean, eta datuak pultsuaren goranzko ertzean transmititzea (ikus. Goranzko ertza DM634 fitxan).

Bide batez, hemen lehen aldiz topatu dugu hiztegiaren ezaugarri bat ST datu-orrietan: horietan "berrezarri bit zerora" esaldia idazten da. pixka bat berrezartzekoEta ez pixka bat garbitzeko, adibidez, Atmega.

3. Ezarri DFF bit-a datu-blokea 8 biteko edo 16 biteko formatua den zehazteko

Zehazki, 16 biteko DM634 bat hartu nuen, 12 biteko PWM datuak transmititzeko trabarik ez izateko, DM633 bezala. Zentzuzkoa da DFF bat ezartzea:

#define DFF         0x0800

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

4. Konfiguratu LSBFIRST bit SPI_CR1 erregistroan bloke-formatua zehazteko

LSBFIRST-ek, bere izenak dioen bezala, bit esanguratsu gutxien duen transmisioa konfiguratzen du lehenik. Baina DM634-k datuak jaso nahi ditu bit esanguratsuenetik hasita. Hori dela eta, berrezarri uzten dugu.

5. Hardware moduan, NSS pinaren sarrera behar bada, aplikatu seinale altua NSS pinari byte-transferentzia-sekuentzia osoan zehar. NSS software moduan, ezarri SSM eta SSI bitak SPI_CR1 erregistroan. NSS pina irteera gisa erabili behar bada, SSOE bit bakarra ezarri behar da.

Instalatu SSM eta SSI NSS hardware modua ahazteko:

#define SSI         0x0100
#define SSM         0x0200

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

6. MSTR eta SPE bitak ezarri behar dira (NSS seinalea altua bada soilik ezarrita geratzen dira)

Egia esan, bit hauekin gure SPI maisu izendatzen dugu eta aktibatu egiten dugu:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//ΠΊΠΎΠ³Π΄Π° всС Π³ΠΎΡ‚ΠΎΠ²ΠΎ, Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ SPI
_SPI2_ (_SPI_CR1) |= SPE;

SPI konfiguratuta dago, idatz ditzagun berehala kontrolatzaileari byteak bidaltzen dituzten funtzioak. Jarraitu irakurtzen 25.3.3 "SPI modu nagusian konfiguratzea":

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Datuak transferitzeko agindua
Transmisioa Tx bufferean byte bat idazten denean hasten da.
Datu-bytea desplazamendu-erregistroan kargatzen da paraleloa modua (barneko busetik) lehenengo bitaren transmisioan zehar, eta gerora igortzen da sekuentziala MOSI pin modua, lehen edo azken bit aurreratzea CPI_CR1 erregistroko LSBFIRST bitaren ezarpenaren arabera. TXE bandera datuak transmititu ondoren ezartzen da Tx buffer-etik desplazamendu-erregistrora, eta eten bat ere sortzen du CPI_CR1 erregistroko TXEIE bita ezartzen bada.

Itzulpenean hitz batzuk nabarmendu ditut STM kontrolagailuetan SPI ezarpenaren ezaugarri bati arreta erakartzeko. Atmegan TXE bandera (Tx Hutsik, Tx hutsik dago eta datuak jasotzeko prest) byte osoa bidali ondoren bakarrik ezartzen da kanpora. Eta hemen bandera hau ezartzen da bytea barneko desplazamendu-erregistroan sartu ondoren. Bit guztiekin batera bultzatzen denez (paraleloan), eta gero datuak sekuentzialki transferitzen direnez, TXE ezartzen da bytea guztiz bidali aurretik. Hau garrantzitsua delako gure LED kontrolatzailearen kasuan, LAT pin-a atera behar dugu bidali ondoren guztiak datuak, alegia. TXE bandera bakarrik ez zaigu nahikoa izango.

Horrek esan nahi du beste bandera bat behar dugula. Ikus dezagun 25.3.7 - "Egoera banderak":

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
<...>
Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
BUSY bandera
BSY bandera hardwareak ezarri eta garbitzen du (bertan idazteak ez du eraginik). BSY banderak SPI komunikazio-geruzaren egoera adierazten du.
Berrezarri egiten da:
transferentzia amaitzen denean (modu nagusian izan ezik, transferentzia etengabea bada)
SPI desgaituta dagoenean
Master mode errore bat gertatzen denean (MODF=1)
Transferentzia etengabea ez bada, BSY bandera garbituko da datu-transferentzia bakoitzaren artean

Ados, hau ondo etorriko zaizu. Ea non dagoen Tx buffera. Horretarako, irakurri "SPI Data Register":

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Bits 15:0 DR[15:0] Datu-erregistroa
Jasotako datuak edo transmititu beharreko datuak.
Datu-erregistroa bi bufferetan banatzen da: bat idazteko (igortzeko buffer) eta bestea irakurtzeko (jasotzeko buffer). Datu-erregistroan idazteak Tx bufferean idazten du, eta datu-erregistrotik irakurtzeak Rx bufferean jasotako balioa itzuliko du.

Beno, eta egoera erregistroa, non TXE eta BSY banderak aurkitzen diren:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Guk idazten dugu:

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

Tira, 16 aldiz bi byte transmititu behar ditugunez, LED kontrolatzaileen irteera kopuruaren arabera, honelako zerbait:

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

    while (_SPI2_(_SPI_SR) & BSY); // finish transmission

    LAT_pulse();
}

Baina oraindik ez dakigu LAT pina nola atera, beraz I/Ora itzuliko gara.

Pinak esleitzea

STM32F1-n, pinen egoeraz arduratzen diren erregistroak nahiko ezohikoak dira. Argi dago Atmega baino gehiago daudela, baina beste STM txipetatik ere desberdinak dira. 9.1 Atala GPIOren Deskribapen Orokorra:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Helburu orokorreko I/O ataka bakoitza (GPIO) 32 biteko konfigurazio-erregistro bi ditu (GPIOx_CRL eta GPIOx_CRH), 32 biteko datu-erregistro bi (GPIOx_IDR eta GPIOx_ODR), 32 biteko ezarri/berrezartzeko erregistroa (GPIOx_BSRR), 16 biteko berrezartzeko erregistroa (GPIOx_BRR) eta 32 biteko. bit blokeatzeko erregistroa (GPIOx_LCKR).

Lehenengo bi erregistroak ezohikoak dira, eta, gainera, nahiko deserosoak, 16 ataka-pinak "anaia bakoitzeko lau bit" formatuan sakabanatuta daudelako. Horiek. zerotik zazpira arteko pinak CRLn daude, eta gainerakoak CRHn. Aldi berean, gainerako erregistroek portuko pin guztien bitak dituzte arrakastaz, askotan erdia "erreserbatuta" geratzen da.

Sinpletasuna lortzeko, has gaitezen zerrendaren amaieratik.

Ez dugu blokeatzeko erregistrorik behar.

Ezarri eta berrezarri erregistroak nahiko dibertigarriak dira, partzialki bikoiztu egiten direlako: dena BSRRn bakarrik idatz dezakezu, non 16 bit altuenak pina zerora berrezartuko baitute, eta behekoak 1ean ezarriko diren edo, gainera erabili BRR, beheko 16 bitak pina berrezarri baino ez dutenak. Bigarren aukera gustatzen zait. Erregistro hauek garrantzitsuak dira pinetarako sarbidea atomikoa ematen dutelako:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Atomic Set edo Berrezarri
Ez dago etenak desgaitu beharrik GPIOx_ODR bit mailan programatzean: bit bat edo gehiago alda daitezke APB2 idazketa atomikoko eragiketa bakarrarekin. Hau aldatu behar den bitaren "1" bat idatziz lortzen da ezarri/berrezarri erregistroan (GPIOx_BSRR edo, berrezarri soilik, GPIOx_BRR). Beste bitak aldatu gabe geratuko dira.

Datu-erregistroek izen nahiko argiak dituzte - IDR = Sarrerako Norabide-erregistroa, sarrera-erregistroa; ODR = Output Norabide-erregistroa, irteera-erregistroa. Oraingo proiektuan ez ditugu beharko.

Eta azkenik, kontrol-erregistroak. Bigarren SPI pinak, hots, PB13, PB14 eta PB15, interesatzen zaizkigunez, berehala begiratzen diogu CRHri:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Eta ikusten dugu 20tik 31ra bitetan zerbait idatzi beharko dugula.

Dagoeneko irudikatu dugu zer nahi dugun pinetatik goian, beraz, hemen pantaila-argazkirik gabe egingo dut, esango dut MODE-k norabidea (sarrera bi bitak 0-an ezarrita badaude) eta pin abiadura (50MHz behar ditugu, hau da, zehazten dituela). biak "1"), eta CNF-k modua ezartzen du: ohiko "push-pull" - 00, "alternatiboa" - 10. Lehenespenez, goian ikusten dugun bezala, pin guztiek dute behetik hirugarren bita (CNF0), moduan jartzen ditu sarrera flotagarria.

Txip honekin beste zerbait egiteko asmoa dudanez, sinpletasunerako MODE eta CNF balio posible guztiak definitu ditut beheko zein goiko kontrol-erregistroetarako.

Nolabait horrela

#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

Gure pinak B atakan daude (oinarrizko helbidea - 0x40010C00), kodea:

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

Eta, horren arabera, LAT-erako definizioak idatz ditzakezu, BRR eta BSRR erregistroek astinduko dituztenak:

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

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

(LAT_baxua inertziagatik, beti izan da horrela, egon dadila)

Orain dena bikaina da, baina ez du funtzionatzen. Hau STM32 denez, elektrizitatea aurrezten dute, hau da, beharrezkoak diren periferikoen erlojua gaitu behar duzu.

Aktibatu erlojua

Erlojua, Erlojua izenez ere ezaguna, erlojuaren arduraduna da. Eta dagoeneko RCC laburdura nabaritu genezake. Dokumentazioan bilatzen dugu: Berrezarri eta Erlojuaren Kontrola da.

Goian esan bezala, zorionez, erlojupekoaren gaiaren zatirik zailena STMko jendeak egin zigun, eta horregatik asko eskertzen dugu (beste behin ere esteka bat emango dizuet Di Halten webgunea, zein nahasia den argi uzteko). Erloju periferikoa gaitzeaz arduratzen diren erregistroak baino ez ditugu behar (Erloju Periferikoa Gaitu Erregistroak). Lehenik eta behin, aurki dezagun RCC-ren oinarrizko helbidea, "Memoriaren mapa"ren hasieran dago:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

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

Eta gero, egin klik plakan zerbait aurkitzen saiatzen zaren estekan, edo, askoz hobeto, joan gaikuntza-erregistroen deskribapenei buruzko ataletan. erregistroak gaitu. Non aurkituko ditugu RCC_APB1ENR eta RCC_APB2ENR:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Eta, horren arabera, SPI2, IOPB (I/O Port B) eta funtzio alternatiboak (AFIO) erlojua barne hartzen duten bitak dituzte.

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

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

//Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ‚Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΡ€Ρ‚Π° B ΠΈ Π°Π»ΡŒΡ‚. Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ  Ρ‚Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ SPI2
_RCC_(_APB1ENR) |= SPI2EN;

Azken kodea aurki daiteke Hemen.

Proba egiteko aukera eta gogoa baduzu, konektatu DM634 honela: DAI PB15-ra, DCK-ra PB13ra, LAT-ra PB14ra. Gidaria 5 voltiotik elikatzen dugu, ez ahaztu lurrak konektatzea.

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

STM8 PWM

PWM STM8-n

Artikulu hau planifikatzen ari nintzela, erabaki nuen, adibide gisa, txip ezezagun baten funtzionalitate batzuk menperatzen saiatzea datu-orri bat soilik erabiliz, botarik gabeko zapatari batekin bukatzeko. STM8 aproposa zen rol honetarako: lehenik eta behin, STM8S103-rekin txinatar plaka pare bat neukan, eta, bigarrenik, ez da oso ezaguna, eta, beraz, Interneten irakurtzeko eta irtenbide bat bilatzeko tentazioa irtenbide horien faltan oinarritzen da.

Txipak ere badu fitxa teknikoa ΠΈ erreferentzia eskuliburua RM0016, lehenengoan pinout eta erregistro helbideak daude, bigarrenean - beste guztia. STM8 C-n programatuta dago IDE izugarri batean ST Ikusizko Garapena.

Erlojua eta I/O

Berez, STM8-k 2 MHz-ko maiztasunean funtzionatzen du, hau berehala zuzendu behar da.

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
HSI (Abiadura Handiko Barne) Erlojua
HSI erloju-seinalea 16 MHz-ko barneko RC osziladore batetik ateratzen da, banatzaile programagarri batekin (1etik 8ra). Erlojuaren zatitzailearen erregistroan ezartzen da (CLK_CKDIVR).
Oharra: hasieran, 8ko zatitzailea duen HSI RC osziladore bat hautatzen da erloju-seinalearen iturri nagusi gisa.

Erregistroaren helbidea datu-orrian aurkitzen dugu, refman-en deskribapena eta erregistroa garbitu behar dela ikusten dugu:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

PWM exekutatu eta LEDak konektatuko ditugunez, ikus dezagun pinout-a:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Txipa txikia da, funtzio asko pin berdinetan esekita daude. Kortxete artean dagoena "funtzionalitate alternatiboa" da, "aukera byteen bidez" aldatzen da (aukera byteak) - Atmega fusibleak bezalako zerbait. Beren balioak programatikoki alda ditzakezu, baina ez da beharrezkoa Funtzio berria berrabiarazi ondoren bakarrik aktibatzen da. Errazagoa da ST Visual Programmer erabiltzea (Visual Develop-ekin deskargatua), byte hauek alda ditzake. Pinoutak erakusten du lehen tenporizadorearen CH1 eta CH2 pinak kortxete artean ezkutatuta daudela; beharrezkoa da AFR1 eta AFR0 bitak STVPn ezartzea, eta bigarrenak bigarren tenporizadorearen CH1 irteera ere transferituko du PD4tik PC5era.

Horrela, 6 pinek kontrolatuko dituzte LEDak: PC6, PC7 eta PC3 lehen tenporizadorerako, PC5, PD3 eta PA3 bigarrenerako.

STM8n I/O pinak konfiguratzea STM32n baino sinpleagoa eta logikoagoa da:

  • Atmega DDR datuen norabide erregistrotik ezaguna (Datuen Zuzendaritza Erregistroa): 1 = irteera;
  • lehen kontrol-erregistroak CR1, irteeran, push-pull modua (1) edo draina irekia (0) ezartzen du; LEDak txiparekin katodoekin konektatzen ditudanez, zeroak uzten ditut hemen;
  • bigarren kontrol-erregistroak CR2, irteeran, erlojuaren abiadura ezartzen du: 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

PWM ezarpena

Lehenik eta behin, defini ditzagun terminoak:

  • PWM maiztasuna – tenporizadoreak markatzen duen maiztasuna;
  • Birkargatu automatikoa, AR – Autokargatu daitekeen balioa zenbatu arte tenporizadoreak (pultsu-aldia);
  • Eguneratzeko gertaera, UEV – tenporizadoreak AR zenbatu duenean gertatzen den gertaera bat;
  • PWM Duty Cycle – PWM betebehar-zikloa, askotan "betebehar-faktorea" deitua;
  • Harrapatu/Konparatu Balioa – Harrapatzeko/konparatzeko balioa, zeinari zenbatu zaion tenporizadoreak zerbait egingo du (PWM-ren kasuan, irteerako seinalea alderantzikatzen du);
  • Aurrekargatu balioa – aurrez kargatutako balioa. Konparatu balioa ezin da aldatu tenporizadorea martxan dagoen bitartean, bestela PWM zikloa hautsiko da. Hori dela eta, transmititutako balio berriak buffer batean jartzen dira eta tenporizadorea atzerako kontaketa amaierara iristen denean eta berrezartzen denean ateratzen dira;
  • Ertz lerrokatuta ΠΈ Zentroan lerrokatuta dauden moduak – lerrokadura mugan zehar eta erdialdean, Atmel-en berdina PWM azkarra ΠΈ Fase zuzeneko PWM.
  • OCiREF, Irteera Konparatu Erreferentzia Seinalea – erreferentzia irteerako seinalea, hain zuzen ere, dagokion pinean PWM moduan agertzen dena.

Pinoutetik argi ikusten denez, bi tenporizadorek PWM gaitasunak dituzte: lehenengoa eta bigarrena. Biak 16 bitekokoak dira, lehenengoak ezaugarri gehigarri asko ditu (bereziki, gora eta behera zenbatu ditzake). Biek berdin lan egin behar dugu, beraz, bistan denez pobreagoa den bigarrenarekin hastea erabaki nuen, ez dagoen zerbait ustekabean ez erabiltzeko. Arazoren bat da erreferentzia eskuliburuko tenporizadore guztien PWM funtzionalitatearen deskribapena lehen tenporizadoreari buruzko kapituluan dagoela (17.5.7 PWM modua), beraz, dokumentuan aurrera eta atzera egin behar duzu denbora guztian.

STM8-n PWM-k abantaila garrantzitsua du Atmega-n PWM-ren aldean:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Muga lerrokatuta PWM
Kontuaren konfigurazioa behetik gora
Behetik gorako zenbaketa aktiboa da TIM_CR1 erregistroko DIR bita garbitzen bada
Adibidea
Adibideak lehen PWM modua erabiltzen du. PWM erreferentzia-seinalea OCiREF altu mantentzen da TIM1_CNT < TIM1_CCRi bitartean. Bestela maila baxua behar da. TIM1_CCRi erregistroko konparazio-balioa autokarga-balioa baino handiagoa bada (TIM1_ARR erregistroa), OCiREF seinalea 1ean mantentzen da. Konparazio balioa 0 bada, OCiREF zeroan mantentzen da....

STM8 tenporizadorea zehar eguneratu gertaera egiaztapenak lehenik alderatu balioa, eta orduan soilik erreferentzia-seinalea sortzen du. Atmegaren tenporizadoreak lehenik eta behin izorratzen du eta gero konparatzen du, ondorioz compare value == 0 irteera orratz bat da, nolabait landu behar dena (adibidez, logika programatikoki alderantziz).

Beraz, zer egin nahi dugu: 8 biteko PWM (AR == 255), behetik gora kontatuta, ertzean zehar lerrokatzea. Bonbillak katodoen bidez txiparekin konektatuta daudenez, PWM-ak 0 atera beharko luke (LED piztuta) arte. alderatu balioa eta 1 ondoren.

Dagoeneko irakurri dugu batzuei buruz PWM modua, beraz, bigarren tenporizadorearen beharrezko erregistroa aurkituko dugu erreferentziazko eskuliburuan esaldi honen bilaketan (18.6.8 - TIMx_CCMR1):

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
110: Lehen PWM modua - behetik gora zenbatzen denean, lehen kanala aktibo dago TIMx_CNT < TIMx_CCR1 bitartean. Bestela, lehen kanala inaktibo dago. [Dokumentuan aurrerago 1. tenporizadoretik kopiatu-itsatsi oker bat dago] 111: Bigarren PWM modua – behetik gora zenbatzen denean, lehen kanala inaktibo dago TIMx_CNT < TIMx_CCR1 bitartean. Bestela, lehen kanala aktibo dago.

LEDak MK-ra katodoen bidez konektatzen direnez, bigarren modua egokitzen zaigu (lehena ere, baina oraindik ez dakigu).

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
3. bit OC1PE: Gaitu pin 1 aurrekarga
0: TIMx_CCR1-en aurrekargatzeko erregistroa desgaituta dago. TIMx_CCR1 helbidera idatz dezakezu edozein unetan. Balio berriak berehala funtzionatzen du.
1: TIMx_CCR1-en aurrekargatzeko erregistroa gaituta dago. Irakurketa/idazketa eragiketak aurrekarga-erregistrora sartzen dira. Aurrekargatutako TIMx_CCR1 balioa itzalen erregistroan kargatzen da eguneratze-gertaera bakoitzean.
*Oharra: PWM moduak behar bezala funtziona dezan, aurrekarga-erregistroak gaituta egon behar dira. Hau ez da beharrezkoa seinale bakarreko moduan (OPM bita TIMx_CR1 erregistroan ezartzen da).

Ados, aktibatu dezagun bigarren tenporizadorearen hiru kanaletarako behar dugun guztia:

#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 zortzi biteko bi erregistroz osatuta dago, dena erraza da:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Bigarren tenporizadoreak behetik gora bakarrik zenbatu dezake, ertzean lerrokatuta, ez da ezer aldatu behar. Ezar dezagun maiztasun zatitzailea, adibidez, 256. Bigarren tenporizadorerako, zatitzailea TIM2_PSCR erregistroan ezartzen da eta biko potentzia da:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Ondorioak eta bigarren tenporizadorea bera piztea besterik ez da geratzen. Lehenengo arazoa erregistroen bidez konpontzen da Harrapatu/Konparatu Gaitu: bi, hiru kanal daude asimetrikoki sakabanatuta. Hemen ere jakin dezakegu posible dela seinalearen polaritatea aldatzea, hau da. printzipioz, posible zen PWM 1. modua erabiltzea. Guk idazten dugu:

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

Eta azkenik, tenporizadorea abiarazten dugu TIMx_CR1 erregistroan:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Idatz dezagun AnalogWrite(ren) analogo sinple bat, benetako balioak tenporizadorera transferituko dituena alderatzeko. Erregistroak aurreikusteko izendatzen dira Harrapatu/Konparatu erregistroak, kanal bakoitzerako bi daude: orden baxuko 8 bitak TIM2_CCRxL-n eta goi mailakoak TIM2_CCRxH-n. 8 biteko PWM bat sortu dugunez, nahikoa da bit esanguratsuenak bakarrik idaztea:

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

Irakurle adiak PWM apur bat akastuna dugula ohartuko da, ezin du % 100eko betetzerik sortu (255eko gehienezko balioarekin, seinalea tenporizadore-ziklo baterako alderantzikatu egiten da). LEDentzat ez du axola, eta irakurle adiak dagoeneko asma dezake nola konpondu.

Bigarren tenporizadorean PWM funtzionatzen du, joan gaitezen lehenengora.

Lehenengo tenporizadoreak bit berdinak ditu erregistro berdinetan (bigarren tenporizadorean "erreserbatuta" geratu ziren bit horiek lehengoan aktiboki erabiltzen direla gauza aurreratu guztietarako). Beraz, nahikoa da erregistro bereko helbideak datu-orrian aurkitzea eta kodea kopiatzea. Tira, aldatu maiztasun zatitzailearen balioa, zeren... lehen tenporizadoreak ez du biko potentzia jaso nahi, baizik eta 16 biteko balio zehatza bi erregistrotan Aurreskaler altua ΠΈ Behe-. Denetarik egiten dugu eta... lehen tenporizadoreak ez du funtzionatzen. Zein da ba arazoa?

Arazoa 1. tenporizadorearen kontrol-erregistroei buruzko atal osoa begiratuz bakarrik konpondu daiteke, non bigarren tenporizadoreak ez duena bilatzen dugun. Egongo dira 17.7.30 Eten erregistroa (TIM1_BKR), non dagoen bit hau:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Gaitu irteera nagusia

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Hori dena ziur orain, kodea han.

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

STM8 Multiplexua

Multiplexatzea STM8-n

Hirugarren mini-proiektua zortzi RGB LED bigarren tenporizadorearekin konektatzea da PWM moduan eta kolore desberdinak erakustea. LED multiplexaren kontzeptuan oinarritzen da, hau da, LEDak oso-oso azkar pizten eta itzaltzen badituzu, etengabe piztuta daudela irudituko zaigu (ikusmenaren iraunkortasuna, ikusmen-pertzepzioaren inertzia). Behin egin nuen horrelako zerbait Arduino-n.

Lan algoritmoa honelakoa da:

  • lehen RGB LEDaren anodoa konektatu;
  • piztu zuen, beharrezko seinaleak katodoetara bidaliz;
  • PWM zikloaren amaiera arte itxaron;
  • bigarren RGB LEDaren anodoa konektatu;
  • piztu zuen...

Bueno, etab. Jakina, funtzionamendu eder bat egiteko beharrezkoa da anodoa konektatuta egotea eta LEDa "piztea" aldi berean. Tira, edo ia. Nolanahi ere, bigarren tenporizadorearen hiru kanaletan balioak aterako dituen kode bat idatzi behar dugu, UEVra iristen denean aldatu eta aldi berean aktibo dagoen RGB LEDa aldatu.

LED aldatzea automatikoa denez, "bideo memoria" bat sortu behar dugu, non eten kudeatzaileak datuak jasoko dituen. Hau array sinple bat da:

uint8_t colors[8][3];

LED zehatz baten kolorea aldatzeko, nahikoa izango da behar diren balioak matrize honetan idaztea. Eta aldagaia LED aktiboaren kopuruaz arduratuko da

uint8_t cnt;

Demux

Multiplexatze egokia egiteko, bitxia bada ere, CD74HC238 demultiplexadorea behar dugu. Demultiplexer - operadorea hardwarean inplementatzen duen txipa <<. Sarrerako hiru pin bidez (0, 1 eta 2 bitak) hiru biteko X zenbaki bat elikatzen dugu, eta erantzun gisa irteera zenbakia aktibatzen du (1<<X). Txiparen gainerako sarrerak diseinu osoa eskalatzeko erabiltzen dira. Txip hau mikrokontrolagailuaren okupatutako pin kopurua murrizteko ez ezik, segurtasunerako ere behar dugu, nahi baino LED gehiago pizteko eta MK ez erretzeko. Txipa zentimo bat kostatzen da eta beti zure etxeko botikinean gorde behar da.

Gure CD74HC238 nahi den LEDaren anodoari tentsioa hornitzeaz arduratuko da. Multiplex osoa batean, zutabeari tentsioa emango lioke P-MOSFET baten bidez, baina demo honetan zuzenean posible da, izan ere 20 mA ateratzen du, arabera balorazio maximo absolutuak fitxan. Bertatik CD74HC238 fitxa teknikoa pinouts eta iruzur orri hau behar ditugu:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
H = tentsio handiko maila, L = tentsio baxuko maila, X - berdin dio

E2 eta E1 lurrera konektatzen ditugu, E3, A0, A1 eta A3 STM5ko PD3, PC4, PC5 eta PC8 pinetara. Goiko taulak maila baxua eta altua dituenez, pin hauek push-pull pin gisa konfiguratzen ditugu.

PWM

Bigarren tenporizadorean PWM aurreko istorioan bezala konfiguratuta dago, bi desberdintasunekin:

Lehenik eta behin, etenaldia gaitu behar dugu Eguneratu gertaera (UEV) LED aktiboa txandakatzen duen funtzio bat deituko duena. Hau bit aldatuz egiten da Eguneratu Eten Gaitu izen adierazgarria duen erregistro batean

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
Eten gaitzeko erregistroa

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Bigarren aldea multiplexazioaren fenomenoari dago lotuta, esaterako ghosting – Diodoen distira parasitoa. Gure kasuan, baliteke tenporizadoreak, UEVn eten bat eragin duelako, markatzen jarraitzen duelako eta eten-kudeatzaileak ez duela denborarik LEDa pizteko tenporizadorea pinetan zerbait idazten hasi baino lehen. Honi aurre egiteko, logika alderantzikatu beharko duzu (0 = distira maximoa, 255 = ez dago ezer pizten) eta muturreko funtzio-zikloaren balioak saihestu beharko dituzu. Horiek. ziurtatu UEV ondoren LEDak guztiz itzaltzen direla PWM ziklo baterako.

Polaritatea aldatzea:

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

Saihestu r, g eta b 255ean ezartzea eta gogoratu horiek erabiltzean alderantzikatu behar dituzula.

Etenaldiak

Eten baten funtsa da egoera jakin batzuetan txipak programa nagusia exekutatzen uzten duela eta kanpoko funtzioren bat deitzen duela. Etenaldiak kanpoko edo barneko eraginengatik gertatzen dira, tenporizadorea barne.

ST Visual Develop-en proiektu bat sortu genuenean, gainera main.c fitxategi misteriotsu batekin leiho bat jaso genuen stm8_interrupt_vector.c, proiektuan automatikoki sartuta. Fitxategi honetan, funtzio bat esleitzen zaio eten bakoitzari NonHandledInterrupt. Gure funtzioa nahi den etenarekin lotu behar dugu.

Fitxategiak eten bektoreen taula bat du, non behar ditugunak aurkituko ditugu:

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n
13 TIM2 eguneratzea/gainezkatzea
14 TIM2 harrapaketa/konparazioa

LED-a aldatu behar dugu UEVn, beraz, #13 etenaldia behar dugu.

Horren arabera, lehenik, espedientean stm8_interrupt_vector.c aldatu 13. etenaren (IRQ13) funtzioaren izen lehenetsia zurea:

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

Bigarrenik, fitxategi bat sortu beharko dugu main.h eduki honekin:

#ifndef __MAIN_H
#define __MAIN_H

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

Eta azkenik, idatzi funtzio hau zure main.c:

@far @interrupt void TIM2_Overflow (void)
{
    PD_ODR &= ~(1<<5); // Π²Ρ‹Ρ€ΡƒΠ±Π°Π΅ΠΌ Π΄Π΅ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ»Π΅ΠΊΡΠΎΡ€
    PC_ODR = (cnt<<3); // записываСм Π² Π΄Π΅ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ»Π΅ΠΊΡΠΎΡ€ Π½ΠΎΠ²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
    PD_ODR |= (1<<5); // Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π΄Π΅ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ»Π΅ΠΊΡΠΎΡ€

    TIM2_SR1 = 0; // сбрасываСм Ρ„Π»Π°Π³ Update Interrupt Pending

    cnt++; 
    cnt &= 7; // Π΄Π²ΠΈΠ³Π°Π΅ΠΌ счСтчик LED

    TIM2_CCR1L = ~colors[cnt][0]; // ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ Π² Π±ΡƒΡ„Π΅Ρ€ ΠΈΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ значСния
    TIM2_CCR2L = ~colors[cnt][1]; // для ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ Ρ†ΠΈΠΊΠ»Π° ШИМ
    TIM2_CCR3L = ~colors[cnt][2]; // 

    return;
}

Etenaldiak gaitzea besterik ez da geratzen. Hau muntatzaile komandoa erabiliz egiten da rim - bilatu beharko duzu Programazio Eskuliburua:

//enable interrupts
_asm("rim");

Mihiztatzaileen beste komando bat da sim - etenaldiak itzaltzen ditu. "Bideo memorian" balio berriak idazten ari diren bitartean itzali behar dira, momentu okerrean eragindako eten batek array-a honda ez dezan.

Kode guztia - GitHub-en.

Irakurri 2. fitxa teknikoak: SPI STM32-n; PWM, tenporizadoreak eta etenaldiak STM8-n

Gutxienez norbaitek artikulu hau erabilgarria ikusten badu, ez dut alferrik idatzi. Pozik jasoko ditut iruzkinak eta oharrak, guztia erantzuten saiatuko naiz.

Iturria: www.habr.com

Gehitu iruzkin berria